gnats-4.1.0/0000700000175000017500000000000010212665130013344 5ustar chewiechewie00000000000000gnats-4.1.0/config/0000755000175000017500000000000010212665130014623 5ustar chewiechewie00000000000000gnats-4.1.0/config/ChangeLog0000644000175000017500000000043110207423436016400 0ustar chewiechewie000000000000002005-02-24 Chad Walstrom * mh-*, mt-*, mpw/*: Removing historical remnants from old build process. These makefile fragments are not needed with autoconf. * ChangeLog -> ChangeLog.old: Moved ChangeLog to ChangeLog.old, and created new changelog. gnats-4.1.0/config/ChangeLog.old0000644000175000017500000002622707005251730017166 0ustar chewiechewie00000000000000Sun Oct 24 23:54:10 PDT 1999 Jeff Law (law@cygnus.com) * gcc-2.95.2 Released. Mon Aug 16 01:29:24 PDT 1999 Jeff Law (law@cygnus.com) * gcc-2.95.1 Released. Wed Jul 28 21:39:31 PDT 1999 Jeff Law (law@cygnus.com) * gcc-2.95 Released. Sun Jul 25 23:40:51 PDT 1999 Jeff Law (law@cygnus.com) * gcc-2.95 Released. Tue Feb 2 22:51:21 1999 Philip Blundell * mh-armpic: New file. Patch from Jim Pick . * mt-armpic: Likewise. Mon Jan 18 19:41:08 1999 Christopher Faylor * cygwin.mh: Activate commented out dependencies for gdb: libtermcap. Wed Nov 18 20:29:46 1998 Christopher Faylor * cygwin.mh: Add extra libtermcap target information. Add commented out dependency for gdb to libtermcap for future readline requirement. Mon Nov 2 15:15:33 1998 Geoffrey Noer * mh-cygwin32: delete * mh-cygwin: was mh-cygwin32 Mon Aug 31 17:50:53 1998 David Edelsohn * mh-aix43 (NM_FOR_TARGET): Add -X32_64 as well. Sat Aug 29 14:32:55 1998 David Edelsohn * mh-aix43: New file. Mon Aug 10 00:15:47 1998 HJ Lu (hjl@gnu.org) * mt-linux (CXXFLAGS_FOR_TARGET): Add -D_GNU_SOURCE. Wed Apr 22 12:24:28 1998 Michael Meissner * mt-ospace: New file, support using -Os instead of -O2 to compile the libraries. Wed Apr 22 10:53:14 1998 Andreas Schwab * mt-linux (CXXFLAGS_FOR_TARGET): Set this instead of CXXFLAGS. Sat Apr 11 22:43:17 1998 J. Kean Johnston * mh-svsv5: New file - support for SCO UnixWare 7 / SVR5. Thu Mar 26 01:54:25 1998 Geoffrey Noer * mh-cygwin32: stop configuring and building dosrel. Thu Sep 11 16:43:27 1997 Jim Wilson * mh-elfalphapic, mt-elfalphapic: New files. Wed Jul 23 12:32:18 1997 Robert Hoehne * mh-go32 (CFLAGS): Don't set -fno-omit-frame-pointer. Mon Jun 16 19:06:41 1997 Geoff Keating * mh-ppcpic: New file. * mt-ppcpic: New file. Thu Mar 27 15:52:40 1997 Geoffrey Noer * mh-cygwin32: override CXXFLAGS, setting to -O2 only (no debug) Tue Mar 25 18:16:43 1997 Geoffrey Noer * mh-cygwin32: override LIBGCC2_DEBUG_CFLAGS so debug info isn't included in cygwin32-hosted libgcc2.a by default Wed Jan 8 19:56:43 1997 Geoffrey Noer * mh-cygwin32: override CFLAGS so debug info isn't included in cygwin32-hosted tools by default Tue Dec 31 16:04:26 1996 Ian Lance Taylor * mh-linux: Remove. Mon Nov 11 10:29:51 1996 Michael Meissner * mt-ppc: Delete file, options moved to newlib configure. Fri Oct 4 12:21:03 1996 Angela Marie Thomas (angela@cygnus.com) * mh-dgux386: New file. x86 dgux specific flags Mon Sep 30 15:10:07 1996 Stan Shebs * mpw-mh-mpw (EXTRALIBS_PPC_XCOFF): New, was EXTRALIBS_PPC. (EXTRALIBS_PPC): Use shared libraries instead of xcoff. Sat Aug 17 04:56:25 1996 Geoffrey Noer * mh-cygwin32: don't -D_WIN32 here anymore Thu Aug 15 19:46:44 1996 Stan Shebs * mpw-mh-mpw (SEGFLAG_68K, SEGFLAG_PPC): Remove. (EXTRALIBS_PPC): Add libgcc.xcoff. Thu Aug 8 14:51:47 1996 Michael Meissner * mt-ppc: New file, add -mrelocatable-lib and -mno-eabi to all target builds for PowerPC eabi targets. Fri Jul 12 12:06:01 1996 Stan Shebs * mpw: New subdir, Mac MPW configuration support bits. Mon Jul 8 17:30:52 1996 Jim Wilson * mh-irix6: New file. Mon Jul 8 15:15:37 1996 Jason Merrill * mt-sparcpic (PICFLAG_FOR_TARGET): Use -fPIC. Fri Jul 5 11:49:02 1996 Ian Lance Taylor * mh-irix4 (RANLIB): Don't define; Irix 4 does have ranlib. Sun Jun 23 22:59:25 1996 Geoffrey Noer * mh-cygwin32: new file. Like mh-go32 without the CFLAGS entry. Tue Mar 26 14:10:41 1996 Ian Lance Taylor * mh-go32 (CFLAGS): Define. Thu Mar 14 19:20:54 1996 Ian Lance Taylor * mh-necv4: New file. Thu Feb 15 13:07:43 1996 Ian Lance Taylor * mh-cxux (CC): New variable. (CFLAGS, LDFLAGS): Remove. * mh-ncrsvr43 (CC): New variable. (CFLAGS): Remove. * mh-solaris (CFLAGS): Remove. * mh-go32: Remove most variable settings, since they presumed a Canadian Cross, which is now handled correctly by the configure script. * mh-sparcpic (PICFLAG): Set to -fPIC, not -fpic. Mon Feb 12 14:53:39 1996 Andreas Schwab * mh-m68kpic, mt-m68kpic: New files. Thu Feb 1 14:15:42 1996 Stan Shebs * mpw-mh-mpw (CC_MWC68K): Add options similar to those used in CC_MWCPPC, and -mc68020 -model far. (AR_MWLINK68K): Add -xm library. (AR_AR): Define. (CC_LD_MWLINK68K): Remove -d. (EXTRALIBS_MWC68K): Define. Thu Jan 25 16:05:33 1996 Ian Lance Taylor * mh-ncrsvr43 (CFLAGS): Remove -Hnocopyr. Tue Nov 7 15:41:30 1995 Stan Shebs * mpw-mh-mpw (CC_MWC68K, CC_MWCPPC): Remove unused include path. (CC_MWCPPC): Add -mpw_chars, disable warnings, add comments explaining reasons for various flags. (EXTRALIBS_PPC, EXTRALIBS_MWCPPC ): Put runtime library first. Fri Oct 13 14:44:25 1995 Jason Molenda (crash@phydeaux.cygnus.com) * mh-aix, mh-sun: Removed. * mh-decstation (X11_EXTRA_CFLAGS): Define. * mh-sco, mh-solaris, mh-sysv4 (X11_EXTRA_LIBS): Define. * mh-hp300, mh-hpux, mh-hpux8, mh-solaris, mh-sun3, mh-sysv4: Don't hardcode location of X stuff here. Thu Sep 28 13:14:56 1995 Stan Shebs * mpw-mh-mpw: Add definitions for various 68K and PowerMac compilers, add definitions for library and link steps for PowerMacs. Thu Sep 14 08:20:04 1995 Fred Fish * mh-hp300 (CC): Add "CC = cc -Wp,-H256000" to avoid "too much defining" errors from the HPUX compiler. Thu Aug 17 17:28:56 1995 Ken Raeburn * mh-hp300 (RANLIB): Use "ar ts", in case GNU ar was used and didn't build a symbol table. Thu Jun 22 17:47:24 1995 Stan Shebs * mpw-mh-mpw (CC): Define ANSI_PROTOTYPES. Mon Apr 10 12:29:48 1995 Stan Shebs * mpw-mh-mpw (EXTRALIBS): Always link in Math.o, CSANELIB.o, and ToolLibs.o. * mpw-mh-mpw (CC): Define ALMOST_STDC. (CFLAGS): Remove ALMOST_STDC, -mc68881. (LDFLAGS): add -w. * mpw-mh-mpw (CFLAGS): Add -b option to put strings at the ends of functions. * mpw-mh-mpw: New file, host makefile definitions for MPW. Fri Mar 31 11:35:17 1995 Jason Molenda (crash@phydeaux.cygnus.com) * mt-netware: New file. Mon Mar 13 12:31:29 1995 Ian Lance Taylor * mh-hpux8: New file. * mh-hpux: Use X11R5 rather than X11R4. Thu Feb 9 11:04:13 1995 Ian Lance Taylor * mh-linux (SYSV): Don't define. (RANLIB): Don't define. Wed Jan 11 16:29:34 1995 Jason Merrill * m?-*pic (LIBCXXFLAGS): Add -fno-implicit-templates. Thu Nov 3 17:27:19 1994 Ken Raeburn * mh-irix4 (CC): Increase maximum string length. * mh-sco (CC): Define away const, it doesn't work right; elements of arrays of ptr-to-const are considered const themselves. Sat Jul 16 12:17:49 1994 Stan Shebs (shebs@andros.cygnus.com) * mh-cxux: New file, from Bob Rusk (rrusk@mail.csd.harris.com). Sat Jun 4 17:22:12 1994 Per Bothner (bothner@kalessin.cygnus.com) * mh-ncrsvr43: New file from Tom McConnell . Thu May 19 00:32:11 1994 Jeff Law (law@snake.cs.utah.edu) * mh-hpux (CC): Add -Wp,-H256000 to avoid "too much defining" errors from the HPUX 8 compilers. Wed May 4 20:14:47 1994 D. V. Henkel-Wallace (gumby@cygnus.com) * mh-lynxrs6k: set SHELL to /bin/bash Tue Apr 12 12:38:17 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * mh-irix4 (CC): Change -XNh1500 to -XNh2000. Sat Dec 25 20:03:45 1993 Jeffrey A. Law (law@snake.cs.utah.edu) * mt-hppa: Delete. Tue Nov 16 22:54:39 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * mh-a68bsd: Define CC to gcc. Mon Nov 15 16:56:51 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * mh-linux: Don't put -static in LDFLAGS. Add comments. Mon Nov 15 13:37:58 1993 david d `zoo' zuhn (zoo@cirdan.cygnus.com) * mh-sysv4 (AR_FLAGS): change from cq to cr Fri Nov 5 08:12:32 1993 D. V. Henkel-Wallace (gumby@blues.cygnus.com) * mh-unixware: remove. It's the same as sysv4, and config.guess can't tell the difference. So don't allow skew. Wed Oct 20 20:35:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * mh-hp300: Revert yesterday's change, but add comment explaining. Tue Oct 19 18:58:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * mh-hp300: Don't define CFLAGS to empty. Why should hp300 be different from anything else? ("gdb doesn't understand the native debug format" isn't a good enough answer because we might be using gcc). Tue Oct 5 12:17:40 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * mh-alphaosf: Remove, no longer necessary now that gdb knows how to handle OSF/1 shared libraries. Tue Jul 6 11:27:33 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) * mh-alphaosf: New file. Thu Jul 1 15:49:33 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * mh-riscos: New file. Mon Jun 14 12:03:18 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) * mh-aix, mh-aix386, mh-decstation, mh-delta88, mh-hpux, mh-irix4, mh-ncr3000, mh-solaris, mh-sysv, mh-sysv4: remove INSTALL=cp line, now that we're using install.sh globally Fri Jun 4 16:09:34 1993 Ian Lance Taylor (ian@cygnus.com) * mh-sysv4 (INSTALL): Use cp, not /usr/ucb/install. Thu Apr 8 11:21:52 1993 Ian Lance Taylor (ian@cygnus.com) * mt-a29k, mt-ebmon29k, mt-os68k, mt-ose68000, mt-ose68k, mt-vxworks68, mt-vxworks960: Removed obsolete, unused target Makefile fragment files. Mon Mar 8 15:05:25 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * mh-aix386: New file; old mh-aix, plus no-op RANLIB. Thu Oct 1 13:50:48 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * mh-solaris: INSTALL is NOT /usr/ucb/install Mon Aug 24 14:25:35 1992 Ian Lance Taylor (ian@cygnus.com) * mt-ose68000, mt-ose68k: renamed from mt-OSE*. Tue Jul 21 02:11:01 1992 D. V. Henkel-Wallace (gumby@cygnus.com) * mt-OSE68k, mt-680000: new configs. Thu Jul 16 17:12:09 1992 K. Richard Pixley (rich@rtl.cygnus.com) * mh-irix4: merged changes from progressive. Tue Jun 9 23:29:38 1992 Per Bothner (bothner@rtl.cygnus.com) * Everywhere: Change RANLIB=echo>/dev/null (which confuses some shells - and I don't blame them) to RANLIB=true. * mh-solaris: Use /usr/ucb/install for INSTALL. Sun May 31 14:45:23 1992 Mark Eichin (eichin at cygnus.com) * mh-solaris2: Add new configuration for Solaris 2 (sysv, no ranlib) Fri Apr 10 23:10:08 1992 Fred Fish (fnf@cygnus.com) * mh-ncr3000: Add new configuration for NCR 3000. Tue Dec 10 00:10:55 1991 K. Richard Pixley (rich at rtl.cygnus.com) * ChangeLog: fresh changelog. gnats-4.1.0/.todo0000600000175000017500000002153510212656635014334 0ustar chewiechewie00000000000000 GNATS General TODO List Release 4.1: Code cleanups, bug fixes, documentation updates About to add the finishing touches. Prepend $(DESTDIR) to Makefile.in installation targets (Chad) Committed to CVS. Add missing manpages -- one manpage for each application (Chad) getclose added. install-sid added. Update the NEWS file. Finished. Talked about CAN report. Kill install-sid script and update documentation (Chad) Repurposed instead of killing it. Roll in changes to ./debian Finished. Release 4.2: New Features Cleanup build infrastructure w/automake and autoconf Mail handling enhancements Mail-based manipulation of GNATS database (Mel) Trigger-based mail format replies (Mel) Add "To:" header parsing for PR# (prnumber@host.domain.tld) in queue-pr Release 5.0: New Features, Major Changes to DB Layer, RDBMS Database Enhancements DB Abstraction Layer (Mel) Finished but not rolled into GNATS CVS 5.0 branch Oracle RDBMS Backend (Mel) Finished but not rolled in to GNATS CVS 5.0 branch PostgreSQL RDBMS Backend (Mel) Account enhancements PAM Authentication (Pankaj) Patch submitted 2004-06-20. Release 5.x: New Features Security Enhancements TLS integration via gnutls Mail handling enhancements MIME Handling Detach files appropriately for GNATS DB format Convert HTML to TXT? Database Enhancements mbox Backend Maintain mbox archive of all emails Fake Audit trail entries as emails and append to mbox archive Continue to use existing PR datafile for logging events, keywords, and metadata Unassigned Add squirrels, to make pst happy. Add conditional formats Add script hooks, probably for edit formats and such. Need to think about how to integrate in changes to the PR done by the script after all, that's really the whole point Allow fields to not exist; add a "field-always-present" option to the field description Add virtual fields. The output format can use the existing format mechanism. This would necessitate having a "no-display" field flag, so that some fields don't show up in a "full" query (adding all the fields to full" is a rather obnoxious requirement). There should also be a "raw" query that dumps all the real fields as raw contents, for editing purposes (and perhaps for other things). Revise access control mechanisms. Should PRs have a ">Database-Name:" header? Probably, and probably immutable. Can be used when editing a PR, or submitting an initial one. Append-only fields. Need to revise access control first. Document functions. Many of them are undocumented (even newly-added ones, shame). See how much farther we can go with removing knowledge of particular fields from the gnats code. Make it possible to include adm field contents in the configuration file, instead of always using an external config file. The client state is not clean. The API is horrid; clients should not know or care if they're communicating via the network or locally. The original solution was to just allow network access, but that's not really fixing the problem. (We'll know we're there when gnatsd can act as a relay.) The client connection to the server should also be encapsulated in a struct as well. That is, something to describe the client (its hostname, username, password, access level). Could eventually allow for a single server process that handles multiple connections. Change edit-pr to include the "Changed-Why:" header in the initial PR template instead of a separate prompt. Maybe. Should all the fields listed in the input section be required? Configurable? How about rejecting initial erroneous PRs (PRs with bad fields) instead of fixing them up? It sucks that pr-edit --submit < /dev/null could quite presumably create a valid PR. The initial PR filing stuff is way too complicated. In particular, the various field checks should be configured in dbconfig. That would let us remove more builtin fields. Decide if the "exec gnatsd locally" option is a security hole. (Probably.) Make it #if TESTING only? Come up with a better name for the lexer source file. gnats-4.1.0/COPYING0000644000175000017500000004312706620401137014423 0ustar chewiechewie00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. gnats-4.1.0/COPYING.LIB0000644000175000017500000006130307005251727015032 0ustar chewiechewie00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, 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 library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, 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 companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Library 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! gnats-4.1.0/ChangeLog0000600000175000017500000070315410212663162015135 0ustar chewiechewie000000000000002005-03-06 Chad Walstrom * NEWS: A few editorial changes before the Official release of 4.1.0. * .todo, TODO: Added automake/autoconf cleanup item for 4.2 2005-02-24 Chad Walstrom * NEWS: Updated to reflect new enhancements added. 2005-02-24 Chad Walstrom * texinfo/texinfo.tex: Updated to version 4.7 2005-02-22 Mike M. Volokhov * libiberty/*, include/*: Removed. * Makefile.in, configure, configure.in: Remove libiberty stuff. 2004-11-17 Chad Walstrom * libiberty/*, include/*: Updated from GCC 3.4.2 release. * configure.in: Updated to version 4.1.0 * configure: regenerated * NEWS: Entry for 4.1.0, development release. 2004-11-03 Chad Walstrom * NEWS: Entry for 4.1 added. * TODO, .todo: Updated todo list, indicating release 4.1 is finished. * Makefile.in (VERSION): replaced version string with @PACKAGE_VERSION@ substitution variable from configure.in. * configure.in (AC_INIT): Updated to use autoconf v2.50 to specify PACKAGE_NAME, PACKAGE_VERSION, and PACKAGE_BUG. Set version to 4.1. (AC_CONFIG_FILES, AC_OUTPUT): Updated use of these macros to v2.50 * configure: regenerated 2004-06-11 Chad Walstrom * .todo, TODO: Added DevTodo database file and generated new TODO in outline format 2003-07-27 Andrew J. Gray * Makefile.in (VERSION): Changed to 4.0. * NEWS: Entry for 4.0 added. 2003-01-13 Milan Zamazal * config.guess: Updated, taken from Debian's autotools-dev. * config.sub: Likewise. 2002-11-27 Yngve Svendsen * UPGRADING: Note that version 4 tools cannot be used to access version 3.x servers. Remove note about the "preliminariness" (does that word exist?) of the upgrade procedure description. 2002-11-24 Andrew J. Gray * Makefile.in (VERSION): Changed to 3.999.2. 2002-11-03 Yngve Svendsen * MANIFEST: Remove it altogether. It turned out to be completely outdated. * MANIFEST: Remove PROBLEMS entry. Tidy up the entries from the top-level directory. * PROBLEMS: Removed -- it contained nothing of relevance any more. * INSTALL: Cosmetic fixes. * NEWS: Entry for beta 2 added. 2002-10-27 Hans-Albert Schneider * MANIFEST, PROBLEMS: Reflect the renaming of gnatsd.conf to gnatsd.host_access. * INSTALL, MANIFEST, UPGRADING: Reflect the renaming of gnatsd.access to gnatsd.user_access. 2002-10-25 Yngve Svendsen * INSTALL: State that GNU make and Texinfo v4.2 (or newer) are needed in order to install GNATS. 2002-05-21 Milan Zamazal * Makefile.in (distclean-here): Remove `#*'. 2001-12-27 Milan Zamazal * Makefile.in (Makefile): New target. (VERSION): New variable. (dist): Rewritten, creates distribution tarball now. (mostlyclean): Remove *.tar and *.tar.gz files. (mostlyclean): Remove garbage files created by editors. (DISTDIR): New variable. (srcdir, VPATH): New variables. (distcleanhere): New phony target. (maintainer-clean): Depend on `distclean-here' instead of `distclean'. * NEWS: The beta 1 released actually happened in December. 2001-12-10 Milan Zamazal * libiberty/: Updated from gcc-3.0-3.0.3ds0. 2001-11-28 Yngve Svendsen * INSTALL MANIFEST Makefile.in NEWS NEWS.old PROBLEMS README TODO TODO.old UPGRADING UPGRADING.old: Moved up from the gnats subdirectory. README replaces the old build-tools README that was rather irrelevant. * CYGNUS: Removed. No longer relevant. 2001-11-01 Milan Zamazal * Makefile.in (SUBDIRS): Explicit list of subdirectories instead of using @subdirs@, to exclude libiberty. * configure.in: The previous change reverted; fixes PR gnats/294. * configure: Regenerated. 2001-10-29 Milan Zamazal * configure.in (AC_CONFIG_SUBDIRS): `libiberty' removed. * configure: Regenerated. 2001-09-06 Milan Zamazal * Makefile.in (install-gnats): New target. (install-tools): New target. * configure.in: Check for Solaris `const' problems added. * configure: Regenerated. 2001-08-29 Milan Zamazal * config.if: Removed. * config-ml.in: Removed. * config.sub: Updated from automake 1.4-p4. * config.guess: Likewise. 2001-08-24 Milan Zamazal * configure.in: Changed to autoconf. * configure: Regenerated. * Makefile.in: Completely rewritten. 2001-06-24 Milan Zamazal * Makefile.in (install-info): Consider the new `doc' directory. 2001-04-15 Milan Zamazal * config.guess: Support for ia64 architectures added (Debian bug fix). 1999-10-26 Jason Molenda (jsm@bugshack.cygnus.com) * mpw-README, mpw-build.in, mpw-config.in, mpw-configure: These files serve no useful purpose in the gnats repository. Removed. 1999-10-21 Nick Clifton * config-ml.in: Allow suppression of ARM fast multiply multilibs. Sun Oct 3 14:20:22 1999 Jeffrey A Law (law@cygnus.com) * configure.in (fr30): Fix typo. 1999-09-23 Brendan Kehoe * Makefile.in (configure-target-libiberty): Depend on configure-target-newlib, in order to accurately assess the presence or absence of particular headers for the target. 1999-09-22 DJ Delorie * configure.in (host_tools): add less 1999-09-21 Nick Clifton * config.sub: Add fr30 target. * configure.in: Add fr30 target. * MAINTAINERS: Add fr30 maintainer. Tue Sep 7 23:33:57 1999 Linas Vepstas * config.guess: Add OS/390 match pattern. * config.sub: Add mvs, openedition targets. * configure.in (i370-ibm-opened*): New. 1999-08-25 Nick Clifton * configure.in: Do not configure or build ld for AIX platforms. ld is known to be broken on these platforms. 1999-08-06 Michael Meissner * configure.in (*-*-cygwin*): If the build system and the host are both cygwin, build texinfo. Wed Aug 4 02:07:14 1999 Jeffrey A Law (law@cygnus.com) * config.sub (vxworks case): Use os=-vxworks, not os=vxworks. 1999-07-11 Ian Lance Taylor * configure: Add -W -Wall to the default CFLAGS when compiling with gcc. Thu Jul 8 12:32:23 1999 John David Anglin * configure.in: Build ld, binutils & gas for hppa*-*-linux-gnu*. 1999-06-30 Mark Mitchell * configure.in: Build ld on IRIX6. Wed Aug 25 01:12:25 1999 Rainer Orth * config-ml.in: Pass compiler flag corresponding to multidirs to subdir configures. 1999-07-16 Drew Moseley * configure.in (noconfigdirs): Removed autoconf, automake and gprof from the noconfigdirs list for cygwin hosts. Tue Jun 22 23:45:18 1999 Tom Tromey * configure.in (target_libs): Added target-zlib. * Makefile.in (ALL_TARGET_MODULES): Added zlib. (CONFIGURE_TARGET_MODULES): Likewise. (CHECK_TARGET_MODULES): Likewise. (INSTALL_TARGET_MODULES): Likewise. (CLEAN_TARGET_MODULES): Likewise. (configure-target-zlib): New target. (all-target-zlib): Likewise. (all-target-libjava): Depend on all-target-zlib. (configure-target-libjava): Depend on configure-target-zlib. * Makefile.in (configure-target-libjava): Depend on configure-target-newlib. (configure-target-boehm-gc): New target. (configure-target-qthreads): New target. * configure.in (host_tools): Added zip. * Makefile.in (all-target-libjava): Depend on all-zip. (all-zip): New target. (ALL_MODULES): Added all-zip. (NATIVE_CHECK_MODULES): Added check-zip. (INSTALL_MODULES): Added install-zip. (CLEAN_MODULES): Added clean-zip. * configure.in (target_libs): Added target-qthreads. * Makefile.in (ALL_TARGET_MODULES): Added qthreads. (CONFIGURE_TARGET_MODULES): Likewise. (CHECK_TARGET_MODULES): Likewise. (INSTALL_TARGET_MODULES): Likewise. (CLEAN_TARGET_MODULES): Likewise. (all-target-qthreads): New target. (configure-target-libjava): Depend on configure-target-qthreads. (all-target-libjava): Depend on all-target-qthreads. * Makefile.in (ALL_TARGET_MODULES): Added libjava, boehm-gc. (CONFIGURE_TARGET_MODULES): Likewise. (CHECK_TARGET_MODULES): Likewise. (INSTALL_TARGET_MODULES): Likewise. (CLEAN_TARGET_MODULES): Likewise. (all-target-libjava): New target. (all-target-boehm-gc): Likewise. * configure.in (target_libs): Added libjava, boehm-gc. 1999-06-21 Angela Marie Thomas * configure (tooldir): Set OBJCOPY and OBJDUMP appropriately for Canadian cross. 1999-06-11 Drew Moseley * configure (tooldir): Force configure to set OBJCOPY and OBJDUMP appropriately. * Makefile.in (configure-target-cygmon): Make configure-target-cygmon depend on configure-target-bsp. 1999-06-04 Nick Clifton * config.sub: Add mcore target. Tue Jun 8 20:52:22 1999 Andrew Cagney * config-ml.in: Create multi-lib directory path by parts. Do not assume parent directories have been created. Tue Jun 01 16:57:46 1999 Jeff Johnston * configure.in: Enable target-libgloss for sh targets. Sun May 30 16:03:16 1999 Cort Dougan * config.guess (ppc-*-linux-gnu): Also use ld emul elf32ppclinux. Tue May 25 15:18:57 1999 Christopher Faylor * config.sub: Replace missing parenthesis. 1999-05-24 Nick Clifton * config.sub: Tidied up case statements. Tue May 25 11:34:43 1999 Andrew Cagney * config.sub (maybe_os): Missing paren in case statement. Tue May 25 11:20:46 1999 H.J. Lu (hjl@gnu.org) * config.guess (dummy): Changed to $dummy. 1999-05-24 Nick Clifton * config.sub: Updated to match latest EGCS version. 1999-05-22 Ben Elliston * config.guess: Handle NEC UX/4800. Contributed by Jiro Takabatake . * config.guess: Merge with FSF version. Future changes will be more accurately recorded in this ChangeLog. * config.sub: Likewise. 1999-05-18 Ulrich Drepper * configure.in: There is currently no support for gdb on the Netwinder platform. 1999-05-13 Jim Wilson * config.guess (i?86:*:5:7): Change the "7" to "7*" to accept 7.0.1. 1999-05-05 Tom Tromey * ltmain.sh: Added missing `$'. * configure.in (target_libs): Added target-zlib. * Makefile.in (ALL_TARGET_MODULES): Added zlib. (CONFIGURE_TARGET_MODULES): Likewise. (CHECK_TARGET_MODULES): Likewise. (INSTALL_TARGET_MODULES): Likewise. (CLEAN_TARGET_MODULES): Likewise. (configure-target-zlib): New target. (all-target-zlib): Likewise. (all-target-libjava): Depend on all-target-zlib. (configure-target-libjava): Depend on configure-target-zlib. 1999-05-04 Tom Tromey * ltmain.in: [mode link] Reverted change of 1999-04-30. Instead, put `-B' options from command line into new CC. 1999-04-30 Tom Tromey * ltmain.sh: [mode link] Always use CC given by ltconfig. 1999-04-23 Tom Tromey * ltconfig, ltmain.sh: Update to libtool 1.2f. 1999-04-20 Drew Moseley * configure.in (noconfigdirs): Don't build libstub for arm-elf targets. (noconfigdirs): Don't build any bsp stuff for for arm-oabi targets. Bad merge removed these two changes. Thu May 20 10:00:42 1999 Stephen L Moshier * Makefile.in (GCC_FOR_TARGET): Add -I$(build_tooldir)/include. 1999-04-23 Tom Tromey * ltconfig, ltmain.sh: Update to libtool 1.2f. Tue Apr 13 22:50:54 1999 Donn Terry (donn@interix.com) Martin Heller (Ing.-Buero_Heller@t-online.de) * config.guess (interix Alpha): Add. Sun Apr 11 23:55:34 1999 Alexandre Oliva * config-ml.in: On mips*-*-*, if multidirs contains mabi=64, try to link a trivial program with -mabi=64. If it fails, remove mabi=64 from multidirs. 1999-04-11 Richard Henderson * configure.in (i?86-*-beos*): Do config gperf; don't config gdb, newlib, or libgloss. Sat Apr 10 21:50:01 1999 Philipp Thomas (kthomas@gwdg.de) * config.sub: Set basic_machine to i586 when target_alias = k6-*. 1999-04-08 Nick Clifton * config.sub: Add support for mcore targets. 1999-04-07 Michael Meissner * configure.in (d30v-*): Use config/mt-d30v as makefile fragment, not mt-ospace, in order to shut up assembler warning about using symbols that are named the same as registers. 1999-04-07 Drew Moseley * Makefile.in (all-target-cygmon): Added all-target-bsp to the dependency list for all-target-cygmon. 1999-04-05 Doug Evans * config-ml.in: Check $host, not $target, for selective multilibs. (arm-*-*): Allow disabling of biendian, h/w fp, 26 bit apcs, thumb interworking, and underscore prefix multilibs. 1999-04-04 Ian Lance Taylor * missing: Update to version from current automake. Fri Apr 2 15:11:32 1999 H.J. Lu (hjl@gnu.org) * configure (gxx_include_dir): Removed. * configure.in (gxx_include_dir): Handle it. * Makefile.in: Likewise. 1999-03-29 Gavin Romig-Koch * config.sub (mips64vr4111,mips64vr4111el) Add. 1999-03-21 Ben Elliston * config.guess: Correct typo for detecting ELF on FreeBSD. Thu Mar 18 00:17:50 1999 Mark Elbrecht * config/mh-go32: Delete. * config/mh-djgpp: New. Renamed from mh-go32. * configure.in (pc-msdosdjgpp): Set host_makefile_frag to config/mh-djgpp. Thu Mar 11 18:37:23 1999 Drew Moseley * Makefile.in (all-target-bsp): Added all-gcc all-binutils and all-target-newlib to dependency list for all-target-bsp. Thu Mar 11 01:19:31 1999 Mumit Khan * config.sub: Add i386-uwin support. * config.guess: Likewise. Thu Mar 11 01:07:55 1999 Franz Sirl * configure.in: cleanup, add mh-*pic handling for arm, special case powerpc*-*-aix* Wed Mar 10 18:35:07 1999 Jeff Johnston * configure.in (noconfigdirs): Removed target-libgloss so libnosys.a can be built. Wed Mar 10 17:39:09 1999 Drew Moseley * configure.in: Added bsp support to arm-*-coff and arm-*-elf targets. 1999-03-02 Nick Clifton * config.sub: Rename CYGNUS LOCAL to EGCS LOCAL Sun Feb 28 02:20:00 1999 Geoffrey Noer * config.sub: Check for "cygwin*" rather than "cygwin32*" 1999-02-24 Nick Clifton * config.sub: Fix typo in arm recognition. Wed Feb 24 13:51:40 1999 Drew Moseley * configure.in (noconfigdirs): Changed target_configdirs to include target-bsp only for m68k-*-elf* and m68k-*-coff* rather than m68k-*-* since it is not known to work on m68k-aout. Ditto for arm-*-*oabi. Wed Feb 24 12:52:17 1999 Stan Shebs * configure.in (*-*-windows*): Remove, no longer used. * config/mh-windows: Ditto. 1999-02-19 Ben Elliston * config.guess: Automatically recognise ELF on FreeBSD. From Niall Smart and improved by Andrew Cagney. Thu Feb 18 19:55:09 1999 Marc Espie * config.guess: Recognize openbsd-*-hppa. Wed Feb 17 01:38:59 1999 H.J. Lu (hjl@gnu.org) * Makefile.in (REALLY_SET_LIB_PATH): Append $$$(RPATH_ENVVAR) only if it is not empty. 1999-02-17 Nick Clifton Patch from: Scott Bambrough * config.guess: Modified to recognize uname's armv* syntax. * config.sub: Modified to recognize uname's armv* syntax. 1999-02-17 Mark Salter * configure.in: Added target-bsp for sparclite. Mon Feb 8 14:17:24 1999 Richard Henderson * config.sub: Recognize alphapca5[67] and up to alphaev8. 1999-02-08 Nick Clifton * configure.in: Add support for strongarm port. * config.sub: Add support for strongarm target. Sun Feb 7 18:01:54 1999 Mumit Khan * configure.in (*-*-cygwin32*): Use config/mh-cygwin instead of the old name config/mh-cygwin32. Enable texinfo. Thu Feb 4 20:43:25 1999 Ian Lance Taylor * configure.in: Do build ld for ix86 Solaris. Tue Feb 2 19:46:40 1999 Jim Wilson * Makefile.in (EXTRA_GCC_FLAGS): Set AR to $AR instead of $AR_FOR_TARGET. Likewise for RANLIB. Tue Feb 2 20:05:05 1999 Catherine Moore * config.sub (oabi): Recognize. * configure.in (arm-*-oabi): Handle. Sat Jan 30 06:09:00 1999 Robert Lipe (robertlipe@usa.net) * config.guess: Improve detection of i686 on UnixWare 7. Sat Jan 30 08:04:00 1999 Mumit Khan * config.guess: Add support for i386-pc-interix. * config.sub: Likewise. * configure.in: Likewise. * config/mh-interix: New file. Mon Jan 18 13:59:20 1999 Christopher Faylor * Makefile.in: Remove unneeded all-target-libio from from all-target-winsup target since it is now unneeded. Add all-target-libtermcap in its place since it is now needed. Wed Dec 30 20:34:52 1998 Christopher Faylor * configure.in: makefile stub for cygwin target is probably unnecessary. Remove it for now. * config/mt-cygwin: Remove. Wed Dec 30 01:13:03 1998 Christopher Faylor * configure.in: libtermcap.a should be built when cygwin is the target as well as the host. * config.guess: Allow mixed case in cygwin uname output. * Makefile.in: Add libtermcap target. * config/mt-cygwin: New file. libtermcap target info. Tue Dec 15 17:02:58 1998 Bob Manson * configure.in: Add cygmon for x86-coff and x86-elf. Configure cygmon for all sparclite targets, regardless of object format. 1998-12-15 Mark Salter * configure.in: Added target-bsp for several target architectures. * Makefile.in: Added rules for bsp. 1998-12-11 Tom Tromey * Makefile.in (configure-target-libjava): Depend on configure-target-newlib. (configure-target-boehm-gc): New target. (configure-target-qthreads): New target. Wed Dec 23 00:20:50 1998 Jeffrey A Law (law@cygnus.com) * config.sub: Clean up handling of hppa2.0. Tue Dec 22 23:56:31 1998 Rodney Brown (rodneybrown@pmsc.com) * config.guess: Use C code to identify more HP machines. Thu Dec 17 01:22:30 1998 Jeffrey A Law (law@cygnus.com) * config.sub: Handle hppa2.0. Fri Dec 4 01:34:02 1998 Jeffrey A Law (law@cygnus.com) * config.guess: Improve detection of hppa2.0 processors. Fri Dec 4 01:33:05 1998 Niall Smart * config.guess: Recognize FreeBSD using ELF automatically. 1998-11-26 Manfred Hollstein * configure (skip-this-dir): Add handling for new shell script, which might be created by a sub-directory's configure to indicate, this particular directory is "unwanted". * Makefile.in ($(CONFIGURE_TARGET_MODULES)): Likewise. Wed Nov 18 18:28:45 1998 Geoffrey Noer * ltconfig: import from libtool, after changing libtool to account for the cygwin name change. Wed Nov 18 18:09:14 1998 Geoffrey Noer * Makefile.in: CC_FOR_TARGET and CXX_FOR_TARGET should also include newlib/libc/sys/cygwin and newlib/libc/sys/cygwin32. Wed Nov 18 20:13:29 1998 Christopher Faylor * configure.in: Add libtermcap to list of cygwin dependencies. Tue Nov 17 16:57:51 1998 Geoffrey Noer * Makefile.in: modify CC_FOR_TARGET and CXX_FOR_TARGET so that they include winsup/include when it's a cygwin target. 1998-11-12 Tom Tromey * configure.in (host_tools): Added zip. * Makefile.in (all-target-libjava): Depend on all-zip. (all-zip): New target. (ALL_MODULES): Added all-zip. (NATIVE_CHECK_MODULES): Added check-zip. (INSTALL_MODULES): Added install-zip. (CLEAN_MODULES): Added clean-zip. Thu Nov 12 17:27:21 1998 Geoffrey Noer * Makefile.in: lose "32" from comment about cygwin. Thu Nov 5 15:00:31 1998 Nick Clifton * configure.in: Use -Os to build target libraries for the fr30. Wed Nov 4 18:49:43 1998 Dave Brolley * config.sub: Add fr30. Mon Nov 2 15:19:33 1998 Geoffrey Noer * configure.in: drop "32" from config/mh-cygwin32. Check cygwin* instead of cygwin32*. * config.sub: Check cygwin* instead of cygwin32*. 1998-10-20 Syd Polk * Makefile.in configure.in: Add the ability to use tcl8.1 and tk8.1 if desired. Sun Oct 18 18:34:50 1998 Jeffrey A Law (law@cygnus.com) * config.if (cxx_interface, libstdcxx_interface): Do not try to set these if the appropriate directories and files to not exist. Wed Oct 14 10:29:06 1998 Jeffrey A Law (law@cygnus.com) * Makefile.in (DEVO_SUPPORT): Add config.if. Mon Oct 12 12:09:30 1998 Alexandre Oliva * Makefile.in (build_tooldir): New variable, same as tooldir. (CC_FOR_TARGET, GCC_FOR_TARGET, CXX_FOR_TARGET): Add -B$(build_tooldir)/bin/. (BASE_FLAGS_TO_PASS): Pass build_tooldir down. Tue Oct 13 09:17:06 1998 Jeffrey A Law (law@cygnus.com) * config.sub: Bring back lost sparcv9. Wed Sep 30 22:20:50 1998 Robert Lipe * config.sub: Add support for i[34567]86-pc-udk. * configure.in: Likewise. Wed Sep 30 19:23:48 1998 Geoffrey Noer * Makefile.in: add bzip2 package building bits for user tools module * configure.in: ditto 1998-09-30 Manfred Hollstein * configure.in (target_subdir): Remove duplicate line. Tue Sep 29 22:45:41 1998 Felix Lee * Makefile.in (all-automake): fix dependencies. Mon Sep 28 04:04:27 1998 Jeffrey A Law (law@cygnus.com) * configure.in: Minor cleanups for building in the $(target_alias) subdir. 1998-09-22 Jim Wilson * Makefile.in (bootstrap): Set r and s before make all. Use BASE_FLAGS_TO_PASS in make all. (cross): Likewise. 1998-09-20 Mark Mitchell * Makefile.in (bootstrap): Pass TARGET_FLAGS_TO_PASS to `make all'. Sun Sep 20 00:13:02 1998 Richard Henderson * config.sub: Fix typo in last change. 1998-09-19 Michael Hayes * config.sub: Add support for C4x target. * configure.in: Likewise. 1998-09-13 David S. Miller * config.sub: Recognize sparcv9 just like sparc64. Wed Sep 9 15:44:52 1998 Robert Lipe * config.guess: Match "Pent II" or "PentII" for OpenServer. Tue Sep 8 01:18:39 1998 Jeffrey A Law (law@cygnus.com) * config.guess: Correctly identify Pentium II sco boxes. * config.guess: Fix "tr" code. From Weiwen Liu. Sat Sep 5 13:56:52 1998 John Hughes * configure.in: Do not assume x86-svr4 or x86-unixware can handle stabs. Sat Sep 5 02:12:02 1998 Jeffrey A Law (law@cygnus.com) * Makefile.in (TARGET_CONFIGDIRS): Add libchill. (ALL_TARGET_MODULES): Add all-target-libchill. (CONFIGURE_TARGET_MODULES, CHECK_TARGET_MODULES): Similarly. (INSTALL_TARGET_MODULES, CLEAN_TARGET_MODULES): Similarly. (all-target-libchill): Add dependencies. * configure.in (target_libs): Add libchill. Sun Aug 30 22:27:02 1998 Lutz Wohlrab * config.guess: Avoid assumptions about "tr" behaves when LANG is set to something other than English. Sun Aug 30 22:14:44 1998 H.J. Lu (hjl@gnu.org) * configure (gxx_include_dir): Changed to '${prefix}/include/g++'-${libstdcxx_interface}. * config.if: New to determine the interfaces. Sun Aug 30 21:15:19 1998 Mark Klein (mklein@dis.com) * config.guess: Detect and handle MPE/IX. * config.sub: Deal with MPE/IX. Sat Aug 29 14:32:55 1998 David Edelsohn * configure.in: Use mh-aix43. 1998-07-29 Manfred Hollstein * configure: Fix --without/--disable cases for gxx-include-dir. Fri Aug 28 12:28:26 1998 Per Bothner * mdata-sh: Imported. Needed for automake support. Fri Aug 21 13:33:13 1998 Tom Tromey * configure.in (target_libs): Added target-qthreads. * Makefile.in (ALL_TARGET_MODULES): Added qthreads. (CONFIGURE_TARGET_MODULES): Likewise. (CHECK_TARGET_MODULES): Likewise. (INSTALL_TARGET_MODULES): Likewise. (CLEAN_TARGET_MODULES): Likewise. (all-target-qthreads): New target. (configure-target-libjava): Depend on configure-target-qthreads. (all-target-libjava): Depend on all-target-qthreads. Thu Aug 13 12:49:29 1998 H.J. Lu * Makefile.in (taz): Try "chmod -R og=u ." before "chmod og=u `find . -print`". Fri Jul 31 09:38:33 1998 Catherine Moore * configure.in: Add arm-elf and thumb-elf support. Mon Jul 27 16:23:58 1998 Doug Evans * Makefile.in: Undo previous patch. Fri Jul 24 19:55:24 1998 Doug Evans * Makefile.in (INSTALL_TARGET): Move EXTRA_TARGET_HOST_INSTALL_MODULES to here ... (install-no-fixedincludes): and here (INSTALL_MODULES): ... from here. Fri Jul 24 17:01:42 1998 Ian Lance Taylor * config.sub: Merge with FSF. * config.guess: Merge with FSF. Fri Jul 24 08:43:36 1998 Doug Evans * configure (extraconfigdirs): New variable. (SUBDIRS): Add extraconfigdirs and recurse on them too. * Makefile.in (all): Move higher in file. (EXTRA_TARGET_HOST_ALL_MODULES): New variable. (EXTRA_TARGET_HOST_{INSTALL,CHECK}_MODULES): New variables. (ALL_MODULES): Add EXTRA_TARGET_HOST_ALL_MODULES. (CROSS_CHECK_MODULES): Add EXTRA_TARGET_HOST_CHECK_MODULES. (INSTALL_MODULES): Add EXTRA_TARGET_HOST_INSTALL_MODULES. 1998-07-23 Brendan Kehoe * Makefile.in (all-target-libjava): Depend on all-gcc and all-target-newlib. (configure-target-libjava): Depend on $(ALL_GCC). Sat Jul 18 14:32:43 CDT 1998 Robert Lipe * config.guess: (*-pc-sco3.2v5) Add detection for Pentium II. (*-pc-unixware7) Add detection for Pentium II, Pentium Pro. Fri Jul 17 13:30:18 1998 Ian Lance Taylor * ylwrap: Change absolute path checks to check for DOS style path names. * ylwrap: Don't use a full path name if the source file is in the same directory. From hjl@lucon.org (H.J. Lu). * config-ml.in: Default to being verbose, to match Feb 18 change to configure. Thu Jul 16 12:29:51 1998 Ian Lance Taylor Brought over from egcs: Sat Jun 27 22:46:32 1998 Jeffrey A Law (law@cygnus.com) * configure.in (target_subdir): Set to ${target_alias} instead of "libraries". Mon Sep 1 16:45:44 1997 Jim Wilson * configure.in (target_subdir): Set to libraries if enable_multilib. Wed Jul 15 01:00:54 1998 Ian Lance Taylor * Makefile.in ($(CONFIGURE_TARGET_MODULES)): If there are any multilibs, force reconfiguration the first time we create multilib.out in a subdirectory, in case TARGET_SUBDIR is `.'. Tue Jul 14 23:41:03 1998 Ian Lance Taylor * configure.in: Strip any --no option from CONFIG_ARGUMENTS, to avoid confusion with --no-recursion. Tue Jul 14 15:37:41 1998 Geoffrey Noer * configure.in: Win32 hosts shouldn't use install -x * install-sh: remove -x option, and special .exe-handling hack. Tue Jul 14 15:28:41 1998 Richard Henderson * config.guess: Recognize i586-pc-beos. * configure.in: Don't build some bits for beos. Tue Jul 14 13:22:18 1998 Ian Lance Taylor * configure: If CC is set but CFLAGS is not, and CC is gcc, make CFLAGS default to -O2. * ltmain.sh: Add some hacks to make SunOS --enable-shared work when using GNU ld. Fri Jul 10 13:18:23 1998 Ian Lance Taylor * ltmain.sh: Correct install when using a different shell. Tue Jul 7 15:24:38 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Update to libtool 1.2b. Thu Jul 2 13:57:36 1998 Klaus Kaempf * makefile.vms: Update to build binutils/makefile.vms. Add install target. Wed Jul 1 16:45:21 1998 Ian Lance Taylor * ltconfig: Update to correct AIX handling. Sat Jun 27 22:46:32 1998 Jeffrey A Law (law@cygnus.com) * Makefile.in (BASE_FLAGS_TO_PASS): Add TARGET_SUBDIR. * configure.in (target_subdir): Set to ${target_alias} instead of "libraries". 1998-06-26 Manfred Hollstein * Makefile.in (BASE_FLAGS_TO_PASS): Add gcc_version_trigger. (Makefile): Depend on $(gcc_version_trigger). * configure (gcc_version): Change default initializer to empty string. (gcc_version_trigger): New variable; pass this variable down to subdir configures to enable them checking gcc's version themselves. Emit make macros for both gcc_version vars. (topsrcdir): Initialize reliably. (recursion line): Remove --with-gcc-version=${gcc_version}. 1998-06-24 Manfred Hollstein * configure (enable_version_specific_runtime_libs): Implement new flag --enable-version-specific-runtime-libs which installs C++ runtime stuff in $(libsubdir); emit definition in each generated Makefile. (gxx_include_dir): Initialize depending on $enable_version_specific_runtime_libs. 1998-06-24 Manfred Hollstein * configure (gcc_version): Initialize properly depending on how and where configure is started. (recursion line): Pass a --with-gcc-version=${gcc_version} to configures in subdirs. Wed Jun 24 16:01:59 1998 John Metzler * configure.in (noconfigdirs): Add configure pattern for mips tx39 cygmon Tue Jun 23 22:42:32 1998 Mark Alexander * configure.in: Add cygmon and libstub support for mn10200. 1998-06-19 Manfred Hollstein * configure (gcc_version): Add new variable describing the particular gcc version we're building. * Makefile.in (libsubdir): Add new macro for the directory in which the compiler finds executables, libraries, etc. (BASE_FLAGS_TO_PASS): Pass down gcc_version, target_alias and libsubdir. Fri Jun 19 02:36:59 1998 Alexandre Oliva * Makefile.in (local-clean): Remove *.log. (warning.log): Built with warn_summary from build.log. (mail-report.log): Run test_summary. (mail-report-with-warnings.log): Run test_summary including warning.log in the report. Thu Jun 18 11:26:03 1998 Robert Lipe * config.guess: Detection of Pentium II for *-sco-3.2v5*. Mon Jun 15 14:53:54 1998 Andrew Cagney * Makefile.in (grep): Grep no longer depends on libiberty. Fri Jun 12 14:03:34 1998 Syd Polk * Makefile.in: all-snavigator needs all-libgui. Thu Jun 11 19:43:47 1998 Mark Alexander * configure.in: Add cygmon and libstub support for mn10300. Wed Jun 10 11:19:47 1998 Ian Lance Taylor * missing: Update to version from automake 1.3. * ltmain.sh: On installation, don't get confused if the same name appears more than once in the list of library names. Wed Jun 3 14:51:42 1998 Ian Lance Taylor * config.sub: Accept m68060 and m5200 as CPU names. Mon Jun 1 17:25:16 1998 Ian Lance Taylor * configure: Use && rather than using -a in test, because odd strings can confuse test. * configure.in: Likewise. Thu May 28 19:31:13 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Bring in Visual C++ support. Sat May 23 23:44:13 1998 Alexandre Oliva * Makefile.in (boostrap2-lean, bootstrap3-lean, bootstrap4-lean): New targets. Mon May 11 23:11:34 1998 Jeffrey A Law (law@cygnus.com) * COPYING.LIB: Update FSF address. Fri May 8 01:30:20 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Update to libtool 1.2a. * Makefile.in (GASB_SUPPORT_DIRS): Remove intl; already included via GAS_SUPPORT_DIRS. Thu May 7 17:27:35 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Avoid producing a version number if -version-info was not used. Wed May 6 10:26:06 1998 Stu Grossman * Makefile.in: Add dependencies for boehm-gc to libjava. Tue May 5 18:02:24 1998 Ian Lance Taylor * configure.in: Add --with-newlib to CONFIG_ARGUMENTS if we are building with newlib. 1998-04-30 Paul Eggert * Makefile.in (EXTRA_GCC_FLAGS): Remove backslash at end; Solaris `make' causes it to continue to next definition. Wed Apr 29 17:07:10 1998 Stu Grossman * Makefile.in: Added dependencies to all-target-boehm-gc and all-target-libjava to have them configure during the build. Tue Apr 28 18:11:24 1998 Ian Lance Taylor * configure.in: Change alpha to alpha* in several places. Tue Apr 28 07:42:00 1998 Mark Alexander * config.sub: Recognize sparc86x. Tue Apr 28 07:35:02 1998 Michael Meissner * configure.in (--enable-target-optspace): Remove debug echo. Thu Apr 23 21:31:16 1998 Jim Wilson * configure: Set CXXFLAGS from CXXFLAGS, not CFLAGS. Thu Apr 23 12:26:38 1998 Ian Lance Taylor * ltconfig: Update cygwin32 support. * Makefile.in (GAS_SUPPORT_DIRS): Add intl. (BINUTILS_SUPPORT_DIRS, GASB_SUPPORT_DIRS): Likewise. (GDB_SUPPORT_DIRS): Likewise. Wed Apr 22 12:30:10 1998 Michael Meissner * configure.in (target_makefile_frag): If --enable-target-optspace, use -Os to compile target libraries rather than -O2. Default to using -Os for d10v and m32r if --{enable,disable}-target-optspace is not used. * configure.in (target_cflags): Ditto for d30v. Tue Apr 21 23:06:54 1998 Tom Tromey * Makefile.in (all-bfd): Depend on all-intl. (all-binutils): Likewise. (all-gas): Likewise. (all-gprof): Likewise. (all-ld): Likewise. Mon Apr 20 14:26:26 1998 Tom Tromey * Makefile.in (ALL_TARGET_MODULES): Added libjava, boehm-gc. (CONFIGURE_TARGET_MODULES): Likewise. (CHECK_TARGET_MODULES): Likewise. (INSTALL_TARGET_MODULES): Likewise. (CLEAN_TARGET_MODULES): Likewise. (all-target-libjava): New target. (all-target-boehm-gc): Likewise. * configure.in (target_libs): Added libjava, boehm-gc. 1998-04-19 Brendan Kehoe * configure.in (host_tools): Fix typo, lbtool -> libtool. Fri Apr 17 16:20:42 1998 Ian Lance Taylor * Makefile.in (all-bfd): Depend upon all-libiberty. * ltconfig, ltmain.sh: Bring in newer cygwin32 support. Fri Apr 17 12:22:22 1998 Bob Manson * Makefile.in: Add libstub. * configure.in: Ditto. Build libstub for targets that have cygmon support. Tue Apr 14 18:01:55 1998 Ian Lance Taylor * configure.in: Don't set PICFLAG on ix86-cygwin32. Tue Apr 14 12:24:45 1998 J. Kean Johnston * configure.in: Recognise i[3456]96-*-sysv5* as a valid host, and use mh-sysv5 if specified. Support gprof on SCO Open Server. Tue Apr 14 11:33:51 1998 Krister Walfridsson * configure: Define DEFAULT_M4 by searching PATH. * Makfile.in: Use DEFAULT_M4. Mon Apr 13 15:37:24 1998 Ian Lance Taylor * ltconfig: Add cygwin32 support. * Makefile.in, configure.in: Add libtool as a native only directory to configure and build. Wed Apr 8 13:18:56 1998 Philippe De Muyter * Makefile.in (EXTRA_GCC_FLAGS): XFOO lines shortened. Thu Apr 2 14:48:44 1998 Geoffrey Noer * Makefile.in: add ash make rules * configure.in: add ash to native_only and host_tools lists Thu Mar 26 12:53:20 1998 Tom Tromey * Makefile.in (all-gettext, all-intl): New targets. (ALL_MODULES): Added all-gettext, all-intl. (CROSS_CHECK_MODULES): Added check-gettext, check-intl. (INSTALL_MODULES): Added install-gettext, install-intl. (CLEAN_MODULES): Added clean-gettext, clean-intl. * configure.in (host_tools): Added gettext. (native_only): Likewise. (noconfigdirs) [various cases]: Likewise. (host_libs): Added intl. Wed Mar 25 11:49:12 1998 Jason Molenda (crash@bugshack.cygnus.com) * Makefile.in: Revert yesterday's change. (all-target-winsup): all-target-librx stays out of here. Tue Mar 24 16:58:29 1998 Jason Molenda (crash@bugshack.cygnus.com) * Makefile.in (TARGET_CONFIGDIRS, ALL_TARGET_MODULES, CONFIGURE_TARGET_MODULES, CHECK_TARGET_MODULES, INSTALL_TARGET_MODULES, CLEAN_TARGET_MODULES, all-target-winsup): Remove references to librx and libg++. Tue Mar 24 18:28:12 1998 Eric Mumpower * Makefile.in (BASE_FLAGS_TO_PASS): Pass $(lispdir) down to recursive makes Tue Mar 24 11:37:45 1998 Ian Lance Taylor * Makefile.in (CC_FOR_TARGET): Use $(TARGET_SUBDIR) when passing -B for newlib directory. (CXX_FOR_TARGET): Likewise. Mon Mar 23 11:30:21 1998 Jeffrey A Law (law@cygnus.com) * ltconfig: Update after libtool/ltconfig.in change for hpux11. Fri Mar 20 18:51:43 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Update to libtool 1.2. Fri Mar 20 09:32:14 1998 Manfred Hollstein * Makefile.in (install-gcc): Don't specify LANGUAGES here. (install-gcc-cross): Instead, override LANGUAGES here. 1998-03-18 Dave Love * Makefile.in ($(CONFIGURE_TARGET_MODULES)): Set CONFIG_SITE to a non-existent file since /dev/null loses with bash 2.0/autoconf 2.12. Wed Mar 18 09:24:59 1998 Nick Clifton * configure.in: Add Thumb-pe target. Tue Mar 17 16:59:00 1998 Syd Polk * Makefile.in - changed sn targets to snavigator * configure.in - changed sn targets to snavigator Tue Mar 17 10:33:28 1998 Manfred Hollstein * config-ml.in: After building symlink tree call make distclean if a Makefile got linked into ${ml_dir}/${ml_libdir}; this happens to be the case for libiberty. Tue Mar 17 10:22:37 1998 H.J. Lu (hjl@gnu.ai.mit.edu) * configure: When making link, also check the current directory. The configure scripts may create one. Fri Mar 6 01:02:03 1998 Richard Henderson * config.sub: Accept alphapca56 and alphaev6 properly. Fri Mar 6 00:14:55 1998 Franz Sirl * configure.in: Revert 3 Jan change for powerpc-linux-gnulibc1. Mon Feb 23 15:09:18 1998 Bruno Haible * Makefile.in (INSTALL_MODULES): Move install-tcl before install-itcl. (install-itcl): Remove dependency on install-tcl. Mon Feb 23 09:53:28 1998 Mark Alexander * configure.in: Remove libgloss from noconfigdirs for MN10300. Fri Feb 20 16:47:24 1998 Tom Tromey * configure: Don't let builds be done in source tree. Thu Feb 19 13:40:41 1998 Ian Lance Taylor * configure.in: Don't build libgui for a cygwin32 target when not on a cygwin32 host. Wed Feb 18 12:29:00 1998 Jason Molenda (crash@bugshack.cygnus.com) * configure (redirect): Set to null, so default behavior of configure is now --verbose. 1998-02-16 Dave Love * Makefile.in ($(CONFIGURE_TARGET_MODULES)): Run configure with CONFIG_SITE=/dev/null to forestall lossage with site configuration. Mon Feb 16 12:23:53 1998 Manfred Hollstein * Makefile.in (BASE_FLAGS_TO_PASS, EXTRA_TARGET_FLAGS): Really add this change to sync Makefile.in with its ChangeLog entries. Thu Feb 12 15:03:08 1998 H.J. Lu * ltmain.sh (mkdir): Check that the directory doesn't exist before we exit with error, so that we don't get races during parallel builds. Sat Feb 7 15:19:18 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Update from libtool 1.0i. Fri Feb 6 01:33:52 1998 Manfred Hollstein * Makefile.in (BASE_FLAGS_TO_PASS): Don't pass PICFLAG and PICFLAG_FOR_TARGET. (EXTRA_TARGET_FLAGS): Don't pass PICFLAG_FOR_TARGET. * configure: Emit a definition for the new macro enable_shared into each Makefile. * config/mh-sparcpic (PICFLAG): Define to properly according to current multilib configuration. * config/mt-sparcpic (PICFLAG_FOR_TARGET): Define to properly according to current multilib configuration. Thu Feb 5 17:01:12 1998 Jason Molenda (crash@bugshack.cygnus.com) * configure.in (host_tools, native_only): Add libtool. Wed Feb 4 16:53:58 1998 Geoffrey Noer * configure.in: add target-gperf to noconfigdirs for Cygwin32. Fix typo in ming config comment. Wed Feb 4 18:56:13 1998 Ian Lance Taylor * ltconfig, ltmain.sh: Update from libtool 1.0h. Mon Feb 2 19:38:19 1998 Ian Lance Taylor * config.sub: Add tic30 cases, and map c30 to tic30. Fri Jan 30 17:18:32 1998 Geoffrey Noer * configure.in: Remove expect from noconfigdirs when target is cygwin32. OK to build expect and dejagnu with Canadian Cross. Wed Jan 28 12:58:49 1998 Ian Lance Taylor * configure.in: Do build expect, dejagnu, and cvssrc for a cygwin32 host. * config.guess: Use ${UNAME_MACHINE} rather than i386 for cygwin32 and mingw32. Wed Jan 28 10:26:37 1998 Manfred Hollstein * Makefile.in (BASE_FLAGS_TO_PASS): Remove passing $(local_prefix) here as it is not defined in the toplevel Makefile. Tue Jan 27 23:25:06 1998 Manfred Hollstein * configure (package_makefile_rules_frag): New variable, which names a file with generic rules, ... Change comment to mention we now have FIVE parts. * configure: Undo last change. Tue Jan 27 23:15:55 1998 Lassi A. Tuura * config.guess: More accurate determination of HP processor types. * config.sub: More accurate determination of HP processor types. Sat Jan 24 01:59:45 1998 Manfred Hollstein * configure (package_makefile_frag): Move inserting the ${package_makefile_frag} to where it should be according to the comment. Fri Jan 23 00:30:21 1998 Philip Blundell * config.guess: Add support for Linux/ARM. Thu Jan 22 15:14:01 1998 Fred Fish * .cvsignore: Remove *-info and *-install since they match release-info and mpw-install, which we don't want to just ignore. Thu Jan 22 01:38:33 1998 Richard Henderson * configure.in: Revert 3 Jan change for alpha-linux-gnulibc1. Sat Jan 17 21:28:08 1998 Pieter Nagel * Makefile.in (FLAGS_TO_PASS): Pass down gcc_include_dir and local_prefix to sub-make invocations. Sat Jan 17 21:04:59 1998 H.J. Lu (hjl@gnu.org) * configure.in: Check makefile fragments in the source directory. Fri Jan 16 00:41:37 1998 Alexandre Oliva * configure.in: Check whether host and target makefile fragments exist before adding them to *_makefile_frag. Wed Jan 14 23:39:10 1998 Bob Manson * configure.in (target_configdirs): Add cygmon for sparc64-elf. Wed Jan 14 12:48:07 1998 Keith Seitz * configure.in: Make sure we only replace RPATH_ENVVAR on lines which begin with RPATH_ENVVAR, i.e. add "^" to the regexp to sed. * Makefile.in (BASE_FLAGS_TO_PASS): Pass RRPATH_ENVVAR down to sub-makes. 1998-01-13 Lee Iverson (leei@ai.sri.com) * config-ml.in (multi-do): LDFLAGS must include multilib designator. Tue Jan 13 01:13:24 1998 Robert Lipe (robertl@dgii.com) * config.guess: Recognize i[3456]-i586-UnixWare7-sysv5. Sun Jan 4 01:06:55 1998 Mumit Khan * config.sub: Add mingw32 support. * configure.in: Likewise. * mh-mingw32: New file. Sat Jan 3 12:11:05 1998 Franz Sirl * configure.in: Finalize support for {alpha|powerpc}*-*-linux-gnulibc1 Sun Dec 28 11:28:58 1997 Jeffrey A Law (law@cygnus.com) * Makefile.in (INSTALL_TARGET): Do install-gcc first. * configure (gxx_include_dir): Provide a definition for subdirs which do not use autoconf. Wed Dec 24 22:46:55 1997 Jeffrey A Law (law@cygnus.com) * config.guess: Sync with egcs. Picks up new alpha support, BeOS & some additional linux support. Tue Dec 23 12:45:50 1997 Jeffrey A Law (law@cygnus.com) * config.guess: HP 9000/803 is a PA1.1 machine. Sun Dec 21 16:53:12 1997 H.J. Lu (hjl@gnu.ai.mit.edu) * configure.in (host_makefile_frag, target_makefile_frag): Handle multiple config files. (alpha-*-linux*): Treat alpha-*-linux* as alpha-*-linux* and alpha-*-*. Thu Dec 18 13:13:03 1997 Doug Evans * mkdep: New file. Wed Dec 17 09:53:02 1997 Michael Meissner * configure.in (d30v-*-*): Allow configuring of libide, vmake, etc. Tue Dec 16 17:36:05 1997 Ian Lance Taylor * Makefile.in: Add libgui directory. (GDB_TK): Add all-libgui. * configure.in: Add libgui directory. * configure: Add all-libgui to GDB_TK. Mon Dec 15 16:12:28 1997 Nick Clifton * config-ml.in (multidirs): Add m32r to multilib list. Fri Dec 12 10:43:31 1997 Brendan Kehoe * Makefile.in (all-target-gperf): Change dependency to all-target-libstdc++. Thu Dec 11 23:30:51 1997 Fred Fish * config.guess: Add BeOS support. Wed Dec 10 15:10:38 1997 Ian Lance Taylor Source directory cvs renamed to cvssrc: * configure.in (host_tools): Change cvs to cvssrc. (native_only): Likewise. (noconfigdirs) [various cases]: Likewise. * Makefile.in (ALL_MODULES): Change all-cvs to all-cvssrc. (CROSS_CHECK_MODULES): Change check-cvs to check-cvssrc. (INSTALL_MODULES): Change install-cvs to install-cvssrc. (CLEAN_MODULES): Change clean-cvs to clean-cvssrc. (all-cvssrc): Rename target from all-cvs. Wed Dec 3 07:55:59 1997 Jeffrey A Law (law@cygnus.com) * configure (gxx_include_dir): Fix thinko. Tue Dec 2 10:55:34 1997 Jeffrey A Law (law@cygnus.com) * Makefile.in (INSTALL_TARGET_CROSS): Define. (install-cross, install-gcc-cross): New targets. Tue Dec 2 10:08:31 1997 Nick Clifton * configure.in (noconfigdirs): Add support for Thumb target. * config.sub (maybe_os): Add support for Thumb target. Sun Nov 30 16:12:27 1997 Bob Manson * Makefile.in: Add rules for cygmon. * configure.in: Build cygmon for sparc-elf and sparclite-aout. Thu Nov 27 01:31:30 1997 Jeffrey A Law (law@cygnus.com) * Makefile.in (INSTALL_TARGET): Do install-gcc first. * configure (gxx_include_dir): Provide a definition for subdirs which do not use autoconf. Wed Nov 26 11:53:33 1997 Keith Seitz * Makefile.in, configure, configure.in, ChangeLog: merge with foundry's 11/18/97 build Wed Nov 26 16:08:50 1997 Jeffrey A Law (law@cygnus.com) * From Franz Sirl. * config.guess (powerpc*-*-linux): Handle glibc2 beta release found on RedHat Linux systems. Fri Nov 21 09:51:01 1997 Jeffrey A Law (law@cygnus.com) * config.guess (alpha stuff): Merge with FSF to avoid incorrect guesses. Thu Nov 13 11:38:37 1997 Jeffrey A Law (law@cygnus.com) * configure.in (i[3456]86-ncr-sysv4.3*): Tweak. Mon Nov 10 15:23:21 1997 H.J. Lu * ltmain.sh: If mkdir fails, check whether the directory was created anyhow by some other process. Mon Nov 10 14:38:03 1997 Michael Meissner * configure.in (d30v-*-*): Configure all directories. Sun Nov 9 17:36:20 1997 Michael Meissner * configure.in (d30v-*-*): Configure newlib, libiberty directories for the D30V. Sat Nov 8 14:42:59 1997 Michael Meissner * configure.in (d30v-*-*): Configure target-libgloss on the D30V. Fri Nov 7 10:34:09 1997 Rob Savoye * include/libiberty.h: Add extern "C" { so it can be used with C++ progrms. * include/remote-sim.h: Add extern "C" { so it can be used with C++ programs. Thu Oct 30 11:09:29 1997 Michael Meissner * configure.in (d30v-*-*): Configure GCC now. Mon Oct 27 13:17:24 1997 Stan Shebs * configure.in: Remove a "second pass" of tweaking noconfigdirs, is no longer needed. Mon Oct 27 12:03:53 1997 Jason Merrill * Makefile.in: check-target-libio depends on all-target-libstdc++. Sun Oct 26 11:48:27 1997 Manfred Hollstein (manfred@s-direktnet.de) * Makefile.in (bootstrap-lean): Combined with `normal' bootstrap targets using "$@" to provide support for similar but not identical targets without having to duplicate code. Mon Oct 20 15:28:49 1997 Klaus K"ampf * makefile.vms: Fix to work with DEC C. Tue Oct 7 23:58:57 1997 Gavin Koch * config.sub: Add mips-tx39-elf to marketing names. Tue Oct 7 14:24:41 1997 Ian Lance Taylor * ltmain.sh: Handle symlinks in generated script. Wed Oct 1 13:11:27 1997 Ian Lance Taylor * configure: Handle autoconf style directory options: --bindir, --datadir, --includedir, --infodir, --libdir, --libexecdir, --mandir, --oldincludedir, --sbindir, --sharedstatedir, --sysconfdir. * Makefile.in (sbindir, libexecdir, sysconfdir): New variables. (sharedstatedir, localstatedir, oldincludedir): New variables. (BASE_FLAGS_TO_PASS): Pass down bindir, datadir, includedir, infodir, libdir, libexecdir, localstatedir, mandir, oldincludedir, sbindir, sharedstatedir, and sysconfdir. Mon Sep 29 00:38:08 1997 Aaron Jackson * Makefile.in (bootstrap-lean): New target. Wed Sep 24 18:06:27 1997 Stu Grossman * configure.in (d30v): Remove tcl, tk, expect, gdb, itcl, tix, db, sn, and gnuserv from noconfigdirs. Wed Sep 24 15:18:32 1997 Ian Lance Taylor * ltmain.sh: Tweak shell pattern to avoid bug in NetBSD /bin/sh. Thu Sep 18 23:58:27 1997 Jeffrey A Law (law@cygnus.com) * Makefile.in (cross): New target. Thu Sep 18 21:43:23 1997 Alexandre Oliva Jeff Law * Makefile.in (bootstrap2, bootstrap3): New targets. (all-bootstrap): Remove outdated and confusing target. (bootstrap, bootstrap2, bootstrap3): Don't pass BOOT_CFLAGS down. 1997-09-15 02:37 Ulrich Drepper * config/mt-linux: Define CXXFLAGS to make sure -fvtable-thunks is used. * configure.in: Name Linux target fragment. * configure: Rewrite so that project Makefile fragment is inserted first and appears last in the resulting Makefile. Tue Sep 16 09:55:07 1997 Andrew Cagney * Makefile.in (install-itcl): Install tcl first. Sun Sep 14 20:53:42 1997 Geoffrey Noer * config/mh-cygwin32: ok to build split texinfo files Fri Sep 12 16:19:20 1997 Geoffrey Noer * configure.in: remove bison from noconfigdirs for Cygwin32 host Thu Sep 11 16:40:46 1997 H.J. Lu (hjl@gnu.ai.mit.edu) * Makefile.in (local-distclean): Also remove mh-frag mt-frag. * configure.in (skipdirs): Add target-librx for Linux. (alpha-*-linux*): Use config/mh-elfalphapic and config/mt-elfalphapic. Wed Sep 10 21:29:54 1997 Jeffrey A Law (law@cygnus.com) * Makefile.in (bootstrap): New target. Wed Sep 10 15:19:22 1997 Jeffrey A Law (law@cygnus.com) * config.sub: Accept 'amigados' for backward compatability. Mon Sep 8 20:46:20 1997 Ian Lance Taylor * config.guess: Merge with FSF. Sun Sep 7 15:55:28 1997 Gavin Koch * config.sub: Add "marketing-names" patch. Fri Sep 5 16:11:28 1997 Joel Sherrill (joel@OARcorp.com) * configure.in (*-*-rtems*): Do not build libgloss for rtems. Fri Sep 5 12:27:17 1997 Jeffrey A Law (law@cygnus.com) * config.sub: Handle v850-elf. Wed Sep 3 12:15:24 1997 Chris Provenzano * ltconfig: Set CONFIG_SHELL in libtool. * ltmain.sh: Use CONFIG_SHELL instead of /bin/sh Mon Sep 1 16:45:44 1997 Jim Wilson * configure.in (target_subdir): Set to libraries if enable_multilib. Wed Aug 27 16:15:11 1997 Jim Wilson * config.guess: Update from gcc directory. Tue Aug 26 16:46:46 1997 Andrew Cagney * Makefile.in (all-sim): Depends on all-readline. Wed Aug 20 19:57:37 1997 Jason Merrill * Makefile.in (BISON, YACC): Use $$s. (all-bison): Depend on all-texinfo. Tue Aug 19 01:41:32 1997 Jason Merrill * Makefile.in (BISON): Add -L flag. (YACC): Likewise. Mon Aug 18 11:30:50 1997 Nick Clifton * configure.in (noconfigdirs): Add support for v850e target. * config.sub (maybe_os): Add support for v850e target. Mon Aug 18 11:30:50 1997 Nick Clifton * configure.in (noconfigdirs): Add support for v850ea target. * config.sub (maybe_os): Add support for v850ea target. Mon Aug 18 09:24:06 1997 Gavin Koch * config.sub: Add mipstx39. Delete r3900. Mon Aug 18 17:20:10 1997 Jason Molenda (crash@godzilla.cygnus.co.jp) * Makefile.in (all-autoconf): Depends on all-texinfo. Fri Aug 15 23:09:26 1997 Michael Meissner * config-ml.in ({powerpc,rs6000}*-*-*): Update to current AIX and eabi targets. Thu Aug 14 14:42:17 1997 Ian Lance Taylor * configure: Get CFLAGS and CXXFLAGS from Makefile, if possible. * configure: When handling a Canadian Cross, handle YACC as well as BISON. Just set BISON to bison. When setting YACC, prefer bison. * Makefile.in (all-bison): Depend upon all-texinfo. Tue Aug 12 20:09:48 1997 Jason Merrill * Makefile.in (BISON): bison, not byacc or bison -y. (YACC): bison -y or byacc or yacc. (various): Add *-bison as appropriate. (taz): No need to mess with BISON anymore. Tue Aug 12 22:33:08 1997 Ian Lance Taylor * configure: If OSTYPE matches *win32*, try to find a good value for CONFIG_SHELL. Sun Aug 10 14:41:11 1997 Ian Lance Taylor * Makefile.in (taz): Get the version number from AM_INIT_AUTOMAKE in configure.in if it is present. Sat Aug 9 00:58:01 1997 Ian Lance Taylor * Makefile.in (LD_FOR_TARGET): Change ld.new to ld-new. Fri Aug 8 16:30:13 1997 Doug Evans * config.sub: Recognize `arc' cpu. * configure.in: Likewise. * config-ml.in: Likewise. Thu Aug 7 11:02:34 1997 Ian Lance Taylor * Makefile.in ($(INSTALL_X11_MODULES)): Depend upon installdirs. Wed Aug 6 16:27:29 1997 Chris Provenzano * configure: Changed sed delimiter from ':' to '|' when attempting to substitute ${config_shell} for SHELL. On NT ${config_shell} may contain a ':' in it. Wed Aug 6 12:29:05 1997 Jason Merrill * Makefile.in (EXTRA_GCC_FLAGS): Fix for non-bash shells. Wed Aug 6 00:42:35 1997 Ian Lance Taylor * Makefile.in (AS_FOR_TARGET): Change as.new to as-new. Tue Aug 5 14:08:51 1997 Ian Lance Taylor * Makefile.in (NM_FOR_TARGET): Change nm.new to nm-new. * ylwrap: If the program is a relative path, force it to be absolute. Tue Aug 5 12:12:44 1997 Andrew Cagney * configure (tooldir): Set BISON to `bison -y' and not just bison. Mon Aug 4 22:59:02 1997 Andrew Cagney * Makefile.in (CC_FOR_TARGET): When winsup/Makefile present, correctly specify the target build directory $(TARGET_SUBDIR)/winsup for libraries. Mon Aug 4 12:40:24 1997 Jason Merrill * Makefile.in (EXTRA_GCC_FLAGS): Fix handling of macros with values separated by spaces. Thu Jul 31 19:49:49 1997 Ian Lance Taylor * ylwrap: New file. * Makefile.in (DEVO_SUPPORT): Add ylwrap. * ltmain.sh: Handle /bin/sh at start of install program. * Makefile.in (DEVO_SUPPORT): Add ltconfig, ltmain.sh, and missing. * ltconfig, ltmain.sh: New files, from libtool 1.0. * missing: New file, from automake 1.2. Thu Jul 24 12:57:56 1997 Ian Lance Taylor * Makefile.in: Treat tix like tk, putting it in X11_MODULES. Add check-tk to CHECK_X11_MODULES. Wed Jul 23 17:03:29 1997 Ian Lance Taylor * config.sub: Merge with FSF. Tue Jul 22 19:08:29 1997 Ian Lance Taylor * config.guess: Merge with FSF. Tue Jul 22 14:50:42 1997 Robert Hoehne * configure: Treat msdosdjgpp like go32. * configure.in: Likewise. Don't remove gprof for go32. * configure: Change Makefile.tem2 to Makefile.tm2. Mon Jul 21 10:31:26 1997 Stephen Peters * configure.in (noconfigdirs): For alpha-dec-osf*, don't ignore grep. Tue Jul 15 14:33:03 1997 Brendan Kehoe * install-sh (chmodcmd): Set to null if the DST directory already exists. Same as Nov 11th change. Mon Jul 14 11:01:15 1997 Martin M. Hunt * configure (GDB_TK): Needs itcl and tix. Mon Jul 14 00:32:10 1997 Jason Merrill * config.guess: Update from FSF. Fri Jul 11 11:57:11 1997 Martin M. Hunt * Makefile.in (GDB_TK): Depend on itcl and tix. Fri Jul 4 13:25:31 1997 Ian Lance Taylor * Makefile.in (INSTALL_PROGRAM_ARGS): New variable. (INSTALL_PROGRAM): Use $(INSTALL_PROGRAM_ARGS). (INSTALL_SCRIPT): New variable. (BASE_FLAGS_TO_PASS): Pass down INSTALL_SCRIPT. * configure.in: If host is *-*-cygwin32*, set INSTALL_PROGRAM_ARGS to -x. * install-sh: Add support for -x option. Mon Jun 30 15:51:30 1997 Ian Lance Taylor * configure.in, Makefile.in: Treat tix like itcl. Thu Jun 26 13:59:19 1997 Ian Lance Taylor * Makefile.in (WINDRES): New variable. (WINDRES_FOR_TARGET): New variable. (BASE_FLAGS_TO_PASS): Add WINDRES_FOR_TARGET. (EXTRA_HOST_FLAGS): Add WINDRES. (EXTRA_TARGET_FLAGS): Add WINDRES. (EXTRA_GCC_FLAGS): Add WINDRES. ($(DO_X)): Pass down WINDRES. ($(CONFIGURE_TARGET_MODULES)): Set WINDRES when configuring. * configure: Treat WINDRES like DLLTOOL, and WINDRES_FOR_TARGET like DLLTOOL_FOR_TARGET. Wed Jun 25 15:01:26 1997 Felix Lee * configure.in: configure sim before gdb for win32-x-ppc Wed Jun 25 12:18:54 1997 Brendan Kehoe Move gperf into the toplevel, from libg++. * configure.in (target_tools): Add target-gperf. (native_only): Add target-gperf. * Makefile.in (all-target-gperf): New target, depend on all-target-libg++. (configure-target-gperf): Empty rule. (ALL_TARGET_MODULES): Add all-target-gperf. (CONFIGURE_TARGET_MODULES): Add configure-target-gperf. (CHECK_TARGET_MODULES): Add check-target-gperf. (INSTALL_TARGET_MODULES): Add install-target-gperf. (CLEAN_TARGET_MODULES): Add clean-target-gperf. Mon Jun 23 10:51:53 1997 Jeffrey A Law (law@cygnus.com) * config.sub (mn10200): Recognize new basic machine. Thu Jun 19 14:16:42 1997 Brendan Kehoe * configure.in: Don't set ENABLE_MULTILIB, so we'll be passing --enable-multilib down to subdirs; setting TARGET_SUBDIR was enough. Tue Jun 17 15:31:20 1997 Brendan Kehoe * configure.in: If we're building mips-sgi-irix6* native, turn on ENABLE_MULTILIB and set TARGET_SUBDIR. Tue Jun 17 12:20:59 1997 Tom Tromey * Makefile.in (all-sn): Depend on all-grep. Mon Jun 16 11:11:10 1997 Ian Lance Taylor * configure.in: Use mh-ppcpic and mt-ppcpic for powerpc*-* targets. * configure: Set CFLAGS and CXXFLAGS, and substitute them into Makefile. From Jeff Makey . * Makefile.in: Add comment for CFLAGS and CXXFLAGS. * Makefile.in (DISTBISONFILES): Remove. (taz): Don't futz with DISTBISONFILES. Change BISON to use $(DEFAULT_YACC). * configure.in: Build itl, db, sn, etc., when building for native cygwin32. * Makefile.in (LD): New variable. (EXTRA_HOST_FLAGS): Pass down LD. ($(DO_X)): Likewise. Mon Jun 16 11:10:35 1997 Philip Blundell * Makefile.in (INSTALL): Use $(SHELL) when executing install-sh. Fri Jun 13 10:22:56 1997 Bob Manson * configure.in (targargs): Strip out any supplied --build argument before adding our own. Always add --build. Thu Jun 12 21:12:28 1997 Bob Manson * configure.in (targargs): Pass --build if we're doing a cross-compile. Fri Jun 6 21:38:40 1997 Rob Savoye * configure: Use '|' instead of ":" as the separator in sed. Otherwise sed chokes on NT path names with drive designators. Also look for "?:*" as the leading characters in an absolute pathname. Mon Jun 2 13:05:20 1997 Gavin Koch * config.sub: Support for r3900. Wed May 21 17:33:31 1997 Ian Lance Taylor * configure.in: Use install-sh, not install.sh. Wed May 14 16:06:51 1997 Ian Lance Taylor * Makefile.in (taz): Improve check for BISON so it doesn't try to apply it twice. Fri May 9 17:22:05 1997 Ian Lance Taylor * Makefile.in (INSTALL_MODULES): Put install-opcodes before install-binutils. Thu May 8 17:29:50 1997 Ian Lance Taylor * Makefile.in: Add automake targets. * configure.in (host_tools): Add automake. Tue May 6 15:49:52 1997 Ian Lance Taylor * configure: Default CXX to c++, not gcc. * Makefile.in (CXX): Set to c++, not gcc. (CXX_FOR_TARGET): When cross, transform c++, not gcc. Thu May 1 10:11:43 1997 Geoffrey Noer * install-sh: try appending a .exe if source file doesn't exist Wed Apr 30 12:05:36 1997 Jason Merrill * configure.in: Turn on multilib by default. (cross_only): Remove target-libiberty. * Makefile.in (all-gcc): Don't depend on libiberty. Mon Apr 28 18:39:45 1997 Michael Snyder * config.guess: improve algorithm for recognizing Gnu Hurd x86. Thu Apr 24 19:30:07 1997 Ian Lance Taylor * Makefile.in (DEVO_SUPPORT): Add mpw-install. (DISTBISONFILES): Add ld/Makefile.in Tue Apr 22 17:17:28 1997 Geoffrey Noer * configure.in: if target is cygwin32 but host isn't cygwin32, don't configure gdb tcl tk expect, not just gdb. Mon Apr 21 13:33:39 1997 Tom Tromey * configure.in: Added gnuserv everywhere sn appears. * Makefile.in (ALL_MODULES): Added all-gnuserv. (CROSS_CHECK_MODULES): Added check-gnuserv. (INSTALL_MODULES): Added install-gnuserv. (CLEAN_MODULES): Added clean-gnuserv. (all-gnuserv): New target. Thu Apr 17 13:57:06 1997 Per Fogelstrom * config.guess: Fixes for MIPS OpenBSD systems. Tue Apr 15 12:21:07 1997 Ian Lance Taylor * Makefile.in (INSTALL_XFORM): Remove. (BASE_FLAGS_TO_PASS): Remove INSTALL_XFORM. * mkinstalldirs: New file, copied from automake. * Makefile.in (installdirs): Rename from install-dirs. Use mkinstalldirs. Change all users. (DEVO_SUPPORT): Add mkinstalldirs. Mon Apr 14 11:21:38 1997 Ian Lance Taylor * install-sh: Rename from install.sh. * Makefile.in (INSTALL): Change install.sh to install-sh. (DEVO_SUPPORT): Likewise. * configure: Use ${config_shell} with ${moveifchange}. From Thomas Graichen . Fri Apr 11 16:37:10 1997 Niklas Hallqvist * config.guess: Recognize OpenBSD systems correctly. Fri Apr 11 17:07:04 1997 Jason Molenda (crash@godzilla.cygnus.co.jp) * README, Makefile.in (ETC_SUPPORT): Remove references to cfg-paper*, configure.{texi,man,info*}._ Sun Apr 6 18:47:57 1997 Andrew Cagney * Makefile.in (all.normal): Ensure that gcc is built after all the x11 - ie gdb - targets. Tue Apr 1 16:28:50 1997 Klaus Kaempf * makefile.vms: Don't run conf-a-gas. Mon Mar 31 16:26:55 1997 Joel Sherrill * configure.in (hppa1.1-*-rtems*): New target, like hppa-*-*elf*. Sun Mar 30 12:38:27 1997 Fred Fish * configure.in: Remove noconfigdirs case since gdb also configures and builds for tic80-coff. Fri Mar 28 18:28:52 1997 Ian Lance Taylor * configure: Set cache_file to config.cache. * Makefile.in (local-distclean): Remove config.cache. Wed Mar 26 18:49:39 1997 Ian Lance Taylor * COPYING: Update FSF address. Wed Mar 26 10:38:25 1997 Michael Meissner * configure.in (tic80-*-*): Remove G++ libraries and libgloss from noconfigdirs. Mon Mar 24 15:02:39 1997 Ian Lance Taylor * Makefile.in (install-dirs): Don't crash if prefix, and hence MAKEDIRS, is empty. Mon Mar 24 12:40:55 1997 Doug Evans * config.sub: Tweak mn10300 entry. Fri Mar 21 15:35:27 1997 Michael Meissner * configure.in (host_tools): Put sim before gdb, so gdb's configure.tgt can determine if the simulator was configured. Sun Mar 16 16:07:08 1997 Fred Fish * config.sub: Move BeOS $os case to be with other Cygnus local cases. Sun Mar 16 01:34:55 1997 Martin Hunt * config.sub: Remove misplaced comment that broke Linux. Sat Mar 15 22:50:15 1997 Fred Fish * config.sub: Add BeOS support. Mon Mar 10 13:30:11 1997 Tom Tromey * Makefile.in (CHECK_X11_MODULES): Don't run check-tk. Wed Mar 5 12:09:29 1997 Martin * configure.in (noconfigdirs): Remove tcl and tk from noconfigdirs for cygwin32 builds. Fri Feb 28 18:20:15 1997 Fred Fish * configure.in (tic80-*-*): Remove ld from noconfigdirs. Thu Feb 27 14:57:26 1997 Ken Raeburn * Makefile.in (GAS_SUPPORT_DIRS, BINUTILS_SUPPORT_DIRS): Remove make-all.com, use makefile.vms instead. Tue Feb 25 18:46:14 1997 Stan Shebs * config.sub: Accept -lnews*. Tue Feb 25 13:19:14 1997 Andrew Cagney * configure.in (noconfigdirs): Disable target-newlib, target-examples and target-libiberty for d30v. Fri Feb 21 17:56:25 1997 Martin M. Hunt * configure.in (noconfigdirs): Enable ld for d30v. Fri Feb 21 20:58:51 1997 Michael Meissner * configure.in (tic80-*-*): Build compiler. Sun Feb 16 15:41:09 1997 Andrew Cagney * configure.in (d30v-*): Remove sim directory from list of unsupported d30v directories Tue Feb 18 17:32:42 1997 Martin M. Hunt * config.sub, configure.in: Add d30v target cpu. Thu Feb 13 22:04:44 1997 Klaus Kaempf * makefile.vms: New file. * make-all.com: Remove. Wed Feb 12 12:54:18 1997 Jim Wilson * Makefile.in (EXTRA_GCC_FLAGS): Add LIBGCC2_DEBUG_CFLAGS. Sat Feb 8 20:36:49 1997 Michael Meissner * Makefile.in (all-itcl): The rule is all-itcl, not all-tcl. Tue Feb 4 11:39:29 1997 Tom Tromey * Makefile.in (ALL_MODULES): Added all-db. (CROSS_CHECK_MODULES): Addec check-db. (INSTALL_MODULES): Added install-db. (CLEAN_MODULES): Added clean-db. Mon Feb 3 13:29:36 1997 Ian Lance Taylor * config.guess: Merge with latest FSF sources. Tue Jan 28 09:20:37 1997 Tom Tromey * Makefile.in (ALL_MODULES): Added all-itcl. (CROSS_CHECK_MODULES): Added check-itcl. (INSTALL_MODULES): Added install-itcl. (CLEAN_MODULES): Added clean-itcl. Thu Jan 23 01:44:27 1997 Geoffrey Noer * configure.in: build gdb for mn10200 Fri Jan 17 15:32:15 1997 Doug Evans * Makefile.in (all-target-winsup): Depend on all-target-libio. Mon Jan 13 22:46:54 1997 Michael Meissner * configure.in (tic80-*-*): Turn off most targets right now. Fri Jan 3 16:04:03 1997 Ian Lance Taylor * Makefile.in (MAKEINFO): Check for the existence of the Makefile, rather than the makeinfo program. (do-info): Depend upon all-texinfo. Tue Dec 31 16:00:31 1996 Ian Lance Taylor * configure.in: Remove uses of config/mh-linux. * config.sub, config.guess: Merge with latest FSF sources. Fri Dec 27 23:04:33 1996 Fred Fish * config.sub (case $basic_machine): Add tic80 entries. Fri Dec 27 12:07:59 1996 Ian Lance Taylor * config.sub, config.guess: Merge with latest FSF sources. Wed Dec 18 22:46:39 1996 Stan Shebs * mpw-build.in: Build ld before gcc, use NewFolderRecursive. * mpw-config.in: Test for NewFolderRecursive. * mpw-install: Use symbolic name for startup filename. * mpw-README: Add various additional details. Wed Dec 18 13:11:46 1996 Jim Wilson * configure.in (mips*-sgi-irix6*): Remove binutils from noconfigdirs. Wed Dec 18 10:29:31 1996 Jeffrey A Law (law@cygnus.com) * configure.in: Do build gcc and the target libraries for the mn10200. Wed Dec 4 16:53:05 1996 Geoffrey Noer * configure.in: don't avoid building gdb for mn10300 any more * Makefile.in: double-quote GCC_FOR_TARGET line in EXTRA_GCC_FLAGS instead of single-quoting it. Tue Dec 3 23:26:50 1996 Jason Merrill * configure.in: Don't use --with-stabs on IRIX 6. Tue Dec 3 09:05:25 1996 Doug Evans * configure.in (m32r): Build gdb, libg++ now. Sun Dec 1 00:18:59 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * configure.in (mips*-sgi-irix6*): Remove gdb and related directories from noconfigdirs. Tue Nov 26 11:45:33 1996 Kim Knuttila * config.sub (basic_machine): added mips16 configuration Sat Nov 23 19:26:22 1996 Michael Meissner * config.sub: Handle d10v-unknown. Sat Nov 23 10:23:01 1996 Gavin Koch * config.sub: Handle v850-unknown. Thu Nov 21 16:19:44 1996 Geoffrey Noer * Makefile.in: add findutils * configure.in: add findutils to list of host_tools Wed Nov 20 10:09:01 1996 Jeffrey A Law (law@cygnus.com) * config.sub: Handle mn10200 and mn10300. Tue Nov 19 16:35:14 1996 Michael Meissner * configure.in (d10v-*): Do not build librx. Mon Nov 18 13:28:41 1996 Jeffrey A Law (law@cygnus.com) * configure.in (mn10300): Build everything except gdb & libgloss. Wed Nov 13 14:59:46 1996 Per Bothner * config.guess: Patch for Dansk Data Elektronik servers, from Niels Skou Olsen . For ncr, use /bin/uname rather than uname, since GNU uname does not support -p. Suggested by Mark Mitchell . Patch for MIPS R4000 running System V, from Eric S. Raymond . Fix thinko for nextstep. Patch for OSF1 in i?86, from Dan Murphy via Harlan Stenn. Sat Jun 24 18:58:17 1995 Morten Welinder * config.guess: Guess mips-dec-mach_bsd4.3. Thu Oct 10 04:07:04 1996 Harlan Stenn * config.guess (i?86-ncr-sysv*): Emit just enough of the minor release numbers. * config.guess (mips-mips-riscos*): Emit just enough of the release number. Tue Oct 8 10:37:22 1996 Frank Vance * config.guess (sparc-auspex-sunos*): Added. (f300-fujitsu-*): Added. Wed Sep 25 22:00:35 1996 Jeff Woolsey * config.guess: Recognize a Tadpole as a sparc. Wed Nov 13 00:53:09 1996 David J. MacKenzie * config.guess: Don't assume that NextStep version is either 2 or 3. NextStep 4 (aka OpenStep 4) has come out now. Mon Nov 11 23:52:03 1996 David J. MacKenzie * config.guess: Support Cray T90 that reports itself as "CRAY TS". From Rik Faith . Fri Nov 8 11:34:58 1996 David J. MacKenzie * config.sub: Contributions from bug-gnu-utils to: Support plain "hppa" (no version given) architecture, reported by OpenStep. OpenBSD like NetBSD. LynxOs is not a hardware supplier. * config.guess: Contributions from bug-gnu-utils to add support for: OpenBSD like NetBSD. Stratus systems. More Pyramid systems. i[n>4]86 Intel chips. M680[n>4]0 Motorola chips. Use unknown instead of lynx for hardware manufacturer. Mon Nov 11 10:09:08 1996 Brendan Kehoe * install.sh (chmodcmd): Set to null if the DST directory already exists. Mon Nov 11 10:43:41 1996 Michael Meissner * configure.in (powerpc*-{eabi,elf,linux,rtem,sysv,solaris}*): Do not use mt-ppc target Makefile fragment any more. Sun Nov 3 19:17:07 1996 Stu Grossman (grossman@critters.cygnus.com) * configure.in (*-*-windows): Exclude everything but those dirs needed to build windows. Tue Oct 29 16:41:31 1996 Doug Evans * Makefile.in (all-target-winsup): Depend on all-target-librx. Mon Oct 28 17:32:46 1996 Stu Grossman (grossman@critters.cygnus.com) * configure.in: Exclude mmalloc from i386-windows. * config/mh-windows: Add rules for building MSVC makefiles. Thu Oct 24 09:22:46 1996 Stu Grossman (grossman@critters.cygnus.com) * Undo my previous change. Thu Oct 24 12:12:04 1996 Ian Lance Taylor * Makefile.in (EXTRA_GCC_FLAGS): Pass down GCC_FOR_TARGET unconditionally. (MAKEOVERRIDES): Define (revert this part of October 18 change). Thu Oct 24 09:02:07 1996 Stu Grossman (grossman@critters.cygnus.com) * Makefile.in (FLAGS_TO_PASS): Add $(HOST_FLAGS) to allow the host to add it's own flags. * config/mh-windows (HOST_FLAGS): Set srcroot, which is needed for MSVC build procedure. Tue Oct 22 15:20:26 1996 Ian Lance Taylor * configure: Handle GCC_FOR_TARGET like CC_FOR_TARGET. Fri Oct 18 13:37:13 1996 Ian Lance Taylor * Makefile.in (CC_FOR_TARGET): Check for xgcc, not Makefile. (CXX_FOR_TARGET): Likewise. (GCC_FOR_TARGET): Define. (BASE_FLAGS_TO_PASS): Remove GCC_FOR_TARGET. (EXTRA_GCC_FLAGS): Define GCC_FOR_TARGET based on whether CC_FOR_TARGET was specified on the command line. (MAKEOVERRIDES): Don't define. Thu Oct 17 10:27:56 1996 Doug Evans * configure.in (m32r): Fix spelling of libg++ libs. Thu Oct 10 10:37:17 1996 Stan Shebs * config.sub (-apple*): Remove, now redundant. Thu Oct 10 12:30:54 1996 Ian Lance Taylor * configure: Don't get confused by CPU-VENDOR-linux-gnu. * configure: Rework yesterday's sed script patch. * config.sub: Merge with FSF. Wed Oct 9 17:24:59 1996 Per Bothner * config.guess: Merge from FSF. 1996-09-12 Richard Stallman * config.guess: Use pc instead of unknown, for pc clone systems. Change linux to linux-gnu. Mon Jul 15 23:51:11 1996 Karl Heuer * config.guess: Avoid non-portable tr syntax. Wed Oct 9 06:06:46 1996 Jeffrey A Law (law@cygnus.com) * test-build.mk (HOLES): Add "xargs" for gdb. * configure: Avoid hpux10.20 sed bug. Tue Oct 8 08:32:48 1996 Stu Grossman (grossman@critters.cygnus.com) * configure.in config/mh-windows: Add support for windows host (that is a build done under the Microsoft build environment). Tue Oct 8 10:39:08 1996 Ian Lance Taylor * Makefile.in: Replace all uses of srcroot with s, to shrink command line lengths. Patches from Geoffrey Noer : * configure.in: If configuring for newlib, pass --with-newlib to subdirectories. * Makefile.in (CC_FOR_TARGET): If winsup/Makefile exists, pass a -Bnewlib/ and -Lwinsup to gcc. (CXX_FOR_TARGET): Likewise. Mon Oct 7 10:59:35 1996 Ian Lance Taylor * Makefile.in (ETC_SUPPORT): Add configure. Fri Oct 4 12:22:58 1996 Angela Marie Thomas (angela@cygnus.com) * configure.in: Use config/mh-dgux386 for i[345]86-dg-dgux host configuration file. Thu Oct 3 09:28:25 1996 Jeffrey A Law (law@cygnus.com) * configure.in: Break mn10x00 support into separate mn10200 and mn10300 configurations. * config.sub: Likewise. Wed Oct 2 22:27:52 1996 Jeffrey A Law (law@cygnus.com) * configure.in: Add lots of stuff to noconfigdirs for the mn10x00 targets. * config.sub, configure.in: Add mn10x00 support. Wed Oct 2 15:52:36 1996 Klaus Kaempf * make-all.com: Call conf-a-gas, not config-a-gas. Tue Oct 1 01:28:41 1996 James G. Smith * configure.in (noconfigdirs): Don't build libgloss for arm-coff targets. Mon Sep 30 14:24:01 1996 Stan Shebs * mpw-README: Add much more detail for native PowerMac. * mpw-install: New file. * mpw-configure: Add --norecursion and --help options. * mpw-config.in: Translate readme and install files when copying to objdir. * mpw-build.in: Don't always depend on byacc and flex. (install-only-top): New action. Fri Sep 27 17:39:44 1996 Stu Grossman (grossman@critters.cygnus.com) * configure.in: You can now configure GDB for the v850. Tue Sep 24 19:05:12 1996 Stan Shebs * configure.in (noconfigdirs): Don't configure any C++ dirs if targeting D10V. Tue Sep 17 12:15:31 1996 Ian Lance Taylor * config.sub: Recognize mips64vr5000. Mon Sep 16 17:00:52 1996 Ian Lance Taylor * configure.in: Use a single line for host_tools and native_only. Mon Sep 9 12:21:30 1996 Doug Evans * config.sub, configure.in: Add entries for m32r. Thu Sep 5 13:52:47 1996 Tom Tromey * Makefile.in (inet-install): Don't run install-gzip. Wed Sep 4 17:26:13 1996 Stu Grossman (grossman@critters.cygnus.com) * configure.in: Don't config lots of things for *-*-windows*. Sat Aug 31 11:45:57 1996 Stan Shebs * mpw-config.in: Test for mpw-true, true, and null-command scripts. (host_libs, host_tools): Copy from configure.in. * mpw-configure: Don't complain about directories not found. Thu Aug 29 16:44:58 1996 Michael Meissner * configure.in (i[345]86): Recognize i686 for pentium pro. (i[3456]86-*-dgux*): Use config/mh-sysv for the host configuration file. * config.guess (i[345]86): Ditto. Mon Aug 26 18:34:42 1996 Martin M. Hunt * configure.in (noconfigdirs): Removed gdb for D10V. Thu Aug 22 17:13:52 1996 Jeffrey A Law (law@cygnus.com) * configure.in: Remove ld, target-libio, target-libg++, and target-libstdc++ from noconfigdirs. Wed Aug 21 18:56:38 1996 Fred Fish * configure: Fix three locations where shell scripts were being run directly rather than with config_shell. Tue Aug 20 13:08:47 1996 J.T. Conklin * configure.in (v850-*-*): Set up initial $noconfigdirs. * config.sub (basic_machine): Recognize v850. Thu Aug 15 12:19:33 1996 Stan Shebs * mpw-configure: Handle multiple enable/disable options and pass them down recursively, handle -c and -s flags appropriately depending on choice of compiler, add escape mechanism for quoted arguments to gC. Mon Aug 12 13:15:13 1996 Michael Meissner * configure.in (powerpc*-*-*): For eabi, system V.4, Linux, and solaris targets, use config/mt-ppc to set C{,XX}FLAGS_FOR_TARGETS so that -mrelocatable-lib and -mno-eabi are used. * Makefile.in (CONFIGURE_TARGET_MODULES): If target compiler does not support --print-multi-lib, don't abort. Sun Aug 11 20:51:50 1996 Stu Grossman (grossman@critters.cygnus.com) * config/mh-cygwin32 (CFLAGS): Define _WIN32 to be compatible with normal Windows compilation environment. Thu Aug 8 12:18:59 1996 Klaus Kaempf * make-all.com: Run config-a-gas. * setup.com: Don't copy subdirectory files around. Tue Jul 30 17:49:31 1996 Brendan Kehoe * configure.in (*-*-ose): Remove exclusion of libgloss for this target, it now compiles correctly. Sat Jul 27 15:10:43 1996 Stan Shebs * mpw-config.in: Generate Mac include for elf/dwarf2.h. Tue Jul 23 10:47:04 1996 Martin M. Hunt * configure.in (d10v-*-*): Remove ld from $noconfigdirs. Mon Jul 22 13:28:51 1996 Brendan Kehoe * configure.in (native_only): Add gnats. Mon Jul 22 12:27:58 1996 Ian Lance Taylor * Makefile.in (GAS_SUPPORT_DIRS): Add make-all.com and setup.com. (BINUTILS_SUPPORT_DIRS): Likewise. Thu Jul 18 12:55:40 1996 Michael Meissner * configure.in (d10v-*-*): Don't configure ld or gdb until the d10v support is added. Wed Jul 17 14:33:09 1996 Martin M. Hunt * configure.in (d10v-*-*): New target. Mon Jul 15 11:53:00 1996 Jeffrey A Law (law@cygnus.com) * config.guess (HP 9000/811): Recognize this as a PA1.1 machine. Fri Jul 12 23:21:17 1996 Ken Raeburn * Makefile.in (do-tar-gz): New target, split out from tail end of taz target. Run each command separately, don't use pipes. (taz): Use it. Fri Jul 12 12:08:04 1996 Stan Shebs * mpw-configure: Look for g-mpw-make.sed in config/mpw. * mpw-build.in: No builds should depend on building byacc or flex, they are assumed to be installed already. Fri Jul 12 09:52:52 1996 Michael Meissner * Makefile.in (CONFIGURE_TARGET_MODULES): Set r environment variable that CC_FOR_TARGET needs. Thu Jul 11 10:09:45 1996 Michael Meissner * Makefile.in (CONFIGURE_TARGET_MODULES): Determine if the multlib options have changed since the last time the subdirectory was configured, and if it has, reconfigure. (CLEAN_TARGET_MODULES): Delete multilib.out and tmpmulti.out, which CONFIGURE_TARGET_MODULES uses to remember the old multilib options. Wed Jul 10 18:56:59 1996 Doug Evans * Makefile.in (ALL_MODULES,CROSS_CHECK_MODULES,INSTALL_MODULES, CLEAN_MODULES): Add bash. (all-bash): New target. Mon Jul 8 17:33:14 1996 Jim Wilson * configure.in (mips-sgi-irix6*): Use mh-irix6 instead of mh-irix5. Mon Jul 1 13:31:35 1996 Michael Meissner * config.sub (basic_machine): Recognize d10v as a valid processor. Fri Jun 28 12:14:35 1996 Stan Shebs * mpw-configure: Add support for --bindir. * mpw-build.in: Use a GCC-specific build script for GCC actions. Wed Jun 26 17:20:12 1996 Geoffrey Noer * configure.in: add bash, time, gawk to list of hosttools and things to only build for native toolchains Tue Jun 25 23:09:03 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) * Makefile.in (docdir): Remove. Tue Jun 25 19:00:08 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) * Makefile.in (datadir): Set to $(prefix)/share. Mon Jun 24 23:26:07 1996 Geoffrey Noer * configure.in: build diff and patch for cygwin32-hosted toolchains. Mon Jun 24 15:01:12 1996 Joel Sherrill * config.sub: Accept -rtems*. Sun Jun 23 22:41:54 1996 Geoffrey Noer * configure.in: enable dosrel for cygwin32-hosted builds, remove diff from the list of things not buildable via Canadian Cross Sat Jun 22 11:39:01 1996 Jason Merrill * Makefile.in (TARGET_SUBDIR): Move comment to previous line so we don't get ". ". Fri Jun 21 17:24:48 1996 Jim Wilson * configure.in (mips*-sgi-irix6*): Set noconfigdirs appropriately. Thu Jun 20 16:57:40 1996 Ken Raeburn * Makefile.in (taz): Handle case where tex3patch didn't even get checked out. Also, if it was found, put the symlink in a new util subdirectory. Thu Jun 20 12:20:33 1996 Michael Meissner * config.guess (*:Linux:*:*): Add support for PowerPC Linux. Tue Jun 18 14:24:12 1996 Klaus Kaempf (kkaempf@progis.de) * config.sub: Recognize -openvms. * configure.in (alpha*-*-*vms*): Set noconfigdirs. * make-all.com, setup.com: New files. Mon Jun 17 16:34:46 1996 Jason Merrill * Makefile.in (taz): tex3patch moved to texinfo/util. Sat Jun 15 17:13:25 1996 Geoffrey Noer * configure.in: remove make from disable-if-Can-Cross list enable gdb if ${host} and ${target} are cygwin32 Fri Jun 7 18:16:52 1996 Harlan Stenn * config.guess (i?86-ncr-sysv*): Emit minor release numbers. Recognize the NCR 4850 machine and NCR Pentium-based platforms. Wed Jun 5 00:09:17 1996 Per Bothner * config.guess: Combine mips-mips-riscos cases, and use cpp to distinguish sysv/svr4/bsd variants. Based on a patch from Harlan Stenn . Fri Jun 7 14:24:49 1996 Tom Tromey * configure.in: Added copyright notice. * move-if-change: Added copyright notice. Thu Jun 6 16:27:05 1996 Michael Meissner * configure.in (powerpcle-*-solaris*): Until we get shared libraries working, don't build gdb, sim, make, tcl, tk, or expect. Tue Jun 4 20:41:45 1996 Per Bothner * config.guess: Merge with FSF: Mon Jun 3 08:49:14 1996 Karl Heuer * config.guess (*:Linux:*:*): Add guess for sparc-unknown-linux. Fri May 24 18:34:53 1996 Roland McGrath * config.guess (AViiON:dgux:*:*): Fix typo in recognizing mc88110. Fri Apr 12 20:03:59 1996 Per Bothner * config.guess: Combine two OSF1 rules. Also recognize field test versions. From mjr@zk3.dec.com. * config.guess (dgux): Use /usr/bin/uname rather than uname, because GNU uname does not support -p. From pmr@pajato.com. Tue Jun 4 11:07:25 1996 Tom Tromey * Makefile.in (MAKEDIRS): Removed $(tooldir). Tue May 28 12:30:50 1996 Stan Shebs * mpw-README: Document GCCIncludes. Sun May 26 15:16:27 1996 Fred Fish * configure.in (alpha-*-linux*): Set enable_shared to yes. Tue May 21 15:41:39 1996 Stan Shebs * mpw-configure: Handle --enable-FOO and --disable-FOO. Mon May 20 10:12:29 1996 Geoffrey Noer * configure.in (*-*-cygwin32): Configure make. Tue May 7 14:19:42 1996 Tom Tromey * Makefile.in (inet-install): Quote value of INSTALL_MODULES. Fri May 3 08:57:17 1996 Tom Tromey * Makefile.in (all-inet): Depend on all-perl. * Makefile.in (inet-install): New target. * Makefile.in (all-inet): Depend on all-tcl. (all-inet): Depend on all-send-pr. Tue Apr 30 13:55:51 1996 Michael Meissner * configure.in (powerpcle-*-solaris*): Turn off tk and tcl temporarily. Thu Apr 25 11:48:20 1996 Ian Lance Taylor * configure.in: Don't configure --with-gnu-ld on AIX. Thu Apr 25 06:33:36 1996 Michael Meissner * configure.in (powerpcle-*-solaris*): Turn off gdb temporarily. Tue Apr 23 09:07:39 1996 Tom Tromey * Makefile.in (ALL_MODULES): Added all-inet. (CROSS_CHECK_MODULES): Added check-inet. (INSTALL_MODULES): Added install-inet. (CLEAN_MODULES): Added clean-inet. (all-indent): New target. * configure.in (host_tools): Added inet. (native_only): Added inet. (noconfigdirs): Added inet. Fri Apr 19 15:35:29 1996 Ian Lance Taylor * configure.in: Don't configure libgloss if we are not configuring newlib. Wed Apr 17 19:30:01 1996 Rob Savoye * configure.in: Don't configure libgloss for unsupported architectures. Tue Apr 16 11:17:05 1996 Michael Meissner * Makefile.in (CLEAN_MODULES): Add clean-apache. Mon Apr 15 15:09:05 1996 Tom Tromey * Makefile.in (ALL_MODULES): Include all-apache. (CROSS_CHECK_MODULES): Include check-apache. (INSTALL_MODULES): Include install-apache. (all-apache): New target. * configure.in: Added apache everywhere perl is seen. Mon Apr 15 14:59:13 1996 Michael Meissner * Makefile.in: Add support for clean-{module} and clean-target-{module} rules. Wed Apr 10 21:37:41 PDT 1996 Marilyn E. Sander * configure.in (*-*-ose) do not build libgloss. Mon Apr 8 16:16:20 1996 Michael Meissner * config.guess (prep*:SunOS:5.*:*): Turn into powerpele-unknown-solaris2. Mon Apr 8 14:45:41 1996 Ian Lance Taylor * configure.in: Permit --enable-shared to specify a list of directories. Fri Apr 5 08:17:57 1996 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (host==solaris): Pass only the first word of $CC to /usr/bin/which when checking if we're using /usr/ccs/bin/cc. Fri Apr 5 03:16:13 1996 Jason Molenda (crash@phydeaux.cygnus.com) * Makefile.in (BASE_FLAGS_TO_PASS): pass down $(MAKE). Thu Mar 28 14:11:11 1996 Tom Tromey * Makefile.in (ALL_MODULES): Include all-perl. (CROSS_CHECK_MODULES): Include check-perl. (INSTALL_MODULES): Include install-perl. (ALL_X11_MODULES): Include all-guile. (CHECK_X11_MODULES): Include check-guile. (INSTALL_X11_MODULES): Include install-guile. (all-perl): New target. (all-guile): New target. * configure.in (host_tools): Include perl and guile. (native_only): Include perl and guile. (noconfigdirs): Don't build guile and perl; no ports have been done. Tue Mar 26 21:18:50 1996 Andrew Cagney * configure (--enable-*): Handle quoted option lists such as --enable-sim-cflags='-g0 -O' better. Thu Mar 21 11:53:08 1996 Michael Meissner * Makefile.in ({,inst}all-target): New rule so we can make and install all of the target directories easily. Wed Mar 20 18:10:57 1996 Andreas Schwab * configure.in: Add missing global flag in sed substitution when deleting `target-' from ${configdirs}. Thu Mar 14 19:15:06 1996 Ian Lance Taylor * Makefile.in (DO_X): Don't get confused if CC contains `=' in an option. * configure.in (mips*-nec-sysvr4*): Use a host_makefile_frag of config/mh-necv4. * install.sh: Correct misspelling of transformbasename. * config.guess: Recognize mips-*-sysv*. Mon Mar 11 15:36:42 1996 Dawn Perchik * config.sub: Recognize mon960. Sun Mar 10 13:18:38 1996 Ian Lance Taylor * configure: Restore Canadian Cross handling of BISON and LEX, removed in Feb 20 change. Fri Mar 8 20:07:09 1996 Per Bothner * README: Suggestions from Torbjorn Granlund : Mention make install. Remove the old copyright date as well the clumsy and rather pointless copyright on the README file. Fri Mar 8 17:51:35 1996 Ian Lance Taylor * Makefile.in ($(CONFIGURE_TARGET_MODULES)): If there is a Makefile after running symlink-tree, then run `make distclean' to avoid clobbering any generated files in srcdir. Tue Mar 5 08:21:44 1996 J.T. Conklin * configure.in (m68k-*-netbsd*): Build everything now. Wed Feb 28 12:25:46 1996 Jason Merrill * Makefile.in (taz): Fix quoting. Tue Feb 27 11:33:57 1996 Doug Evans * configure.in (sparclet-*-*): Build everything now. Tue Feb 27 14:31:51 1996 Andreas Schwab * configure.in (m68k-*-linux*): New host. Mon Feb 26 14:32:44 1996 Ian Lance Taylor * configure: Check for bison before byacc. Tue Feb 20 23:12:35 1996 Stu Grossman (grossman@critters.cygnus.com) * Makefile.in configure: Change the way LEX and BISON/YACC are set. configure now defines DEFAULT_LEX and DEFAULT_YACC by searching PATH. These are used as fallbacks by Makefile.in if flex/bison/byacc aren't in objdir. Mon Feb 19 11:45:30 1996 Ian Lance Taylor * Makefile.in: Make everything which depends upon all-bfd also depend upon all-opcodes, in case --with-commonbfdlib is used. Thu Feb 15 19:50:50 1996 Michael Meissner * configure.in (host *-*-cygwin32): Don't build gdb if we are building NT native compilers on Unix. Thu Feb 15 17:42:25 1996 Ian Lance Taylor * configure.in: Don't get CC from the host Makefile fragment if we can find gcc in PATH, or if this is a Canadian Cross. Move the Solaris test for /usr/ucb/cc to the post target script, just after the compiler sanity test. Wed Feb 14 16:57:40 1996 Ian Lance Taylor * config.sub: Merge with FSF. Tue Feb 13 14:27:48 1996 Ian Lance Taylor * Makefile.in (RPATH_ENVVAR): New variable. (REALLY_SET_LIB_PATH): Use it. * configure.in: On HP/UX, set RPATH_ENVVAR to SHLIB_PATH. Mon Feb 12 15:28:49 1996 Doug Evans * config.sub, configure.in: Recognize sparclet cpu. Mon Feb 12 15:33:59 1996 Christian Bauernfeind * config.guess: Support m68k-cbm-sysv4. Sat Feb 10 12:06:42 1996 Andreas Schwab * config.guess (*:Linux:*:*): Guess m68k-unknown-linux and m68k-unknown-linuxaout from linker help string. Put quotes around $ld_help_string. Thu Dec 7 09:03:24 1995 Tom Horsley * config.guess (powerpc-harris-powerunix): Add guess for port to new target. Thu Feb 8 15:37:52 1996 Brendan Kehoe * config.guess (UNAME_VERSION): Recognize X4.x as an OSF version. Mon Feb 5 16:36:51 1996 Ian Lance Taylor * configure.in: If --enable-shared was used, set SET_LIB_PATH to $(REALLY_SET_LIB_PATH) in Makefile. * Makefile.in (SET_LIB_PATH): New variable. (REALLY_SET_LIB_PATH): New variable. ($(DO_X)): Use $(SET_LIB_PATH). (install.all, gcc-no-fixedincludes, $(ALL_MODULES)): Likewise. ($(NATIVE_CHECK_MODULES), $(CROSS_CHECK_MODULES)): Likewise. ($(INSTALL_MODULES), $(CONFIGURE_TARGET_MODULES)): Likewise. ($(ALL_TARGET_MODULES), $(CHECK_TARGET_MODULES)): Likewise. ($(INSTALL_TARGET_MODULES), $(ALL_X11_MODULES)): Likewise. ($(CHECK_X11_MODULES), $(INSTALL_X11_MODULES)): Likewise. (all-gcc, all-bootstrap, check-gcc, install-gcc): Likewise. (install-dosrel): Likewise. (all-opcodes): Depend upon all-libiberty. Sun Feb 4 16:51:11 1996 Steve Chamberlain * config.guess (*:CYGWIN*): New Sat Feb 3 10:42:35 1996 Michael Meissner * Makefile.in (all-target-winsup): All all-target-libiberty. Fri Feb 2 17:58:56 1996 Michael Meissner * configure.in (noconfigdirs): Add missing # in front of comment. Thu Feb 1 14:38:13 1996 Geoffrey Noer * configure.in: add second pass to things added to noconfigdirs so *-gm-magic can exclude libgloss properly. Thu Feb 1 11:10:16 1996 Stan Shebs * mpw-configure (extralibs_name, rez_name): Set correctly for MWC68K compiler. * mpw-README: Add more info on the necessary build tools. Thu Feb 1 10:22:38 1996 Steve Chamberlain * configure.in, config.sub: Recognize cygwin32. Wed Jan 31 14:17:10 1996 Richard Henderson * config.guess, config.sub: Recognize A/UX. Wed Jan 31 13:52:14 1996 Ian Lance Taylor * config.sub: Merge with gcc/config.sub. Thu Jan 25 11:01:10 1996 Raymond Jou * mpw-build.in (do-binutils): Add build of stamps. Thu Jan 25 17:05:26 1996 James G. Smith * config.sub: Add recognition for mips64vr4100*-* targets. Wed Jan 24 12:47:55 1996 Brendan Kehoe * test-build.mk: Add checking of `hpux9' rather than just `hpux'. Add creation of gconfigargs with `--enable-shared' turned on. ($(host)-stamp-stage2-configured): Pass $(gconfigargs). ($(host)-stamp-stage3-configured): Likewise. (HOLES): Add chatr and ldd. (i386-ncr-sysv4.3*): Add use of /usr/ccs/bin in the PATH and HOLE_DIRS. Wed Jan 24 20:32:30 1996 Torbjorn Granlund * configure: Pass --nfp to recursive configures. Mon Jan 22 10:41:56 1996 Steve Chamberlain * Makefile.in (DLLTOOL): New. (DLLTOOL_FOR_TARGET): New. (EXTRA_HOST_FLAGS): Pass down DLLTOOL. (EXTRA_TARGET_FLAGS): Ditto. (EXTRA_GCC_FLAGS): Ditto. (CONFIGURE_TARGET_MODULES): Ditto. (DO_X): Ditto. * configure: Add DLLTOOL. Fri Jan 19 13:30:15 1996 Stan Shebs SCO OpenServer 5 changes from Robert Lipe : * configure.in (i[345]86-*-sco3.2v5*): Use mh-sysv instead of mh-sco, since old workarounds no longer needed, and don't build ld, since libraries have weak symbols in COFF. Sun Jan 14 23:01:31 1996 Fred Fish * Makefile.in (CONFIGURE_TARGET_MODULES): Add missing ';'. Fri Jan 12 15:25:35 1996 Ian Lance Taylor * configure.in: Make sure that ${CC} can be used to compile an executable. Wed Jan 3 17:54:41 1996 Doug Evans * Makefile.in (newlib.tar.gz): Delete building of newlib's info files. Mon Jan 1 19:09:14 1996 Brendan Kehoe * configure.in (noconfigdirs): Put ld or gas in this early, if the user specifically used --with-gnu-ld=no or --with-gnu-as=no. Sat Dec 30 16:08:57 1995 Doug Evans * config-ml.in: Add support for --disable-{softfloat,m68881,m68000,m68020} on m68*-*-*. Simplify setting of multidirs from --disable-foo. Fri Dec 29 07:56:11 1995 Michael Meissner * Makefile.in (EXTRA_GCC_FLAGS): If any of the make variables LANGUAGES, BOOT_CFLAGS, STMP_FIXPROTO, LIMITS_H_TEST, LIBGCC1_TEST, LIBGCC2_CFLAGS, LIBGCC2_INCLUDES, and ENQUIRE are non-empty, pass them on to the GCC make. (all-bootstrap): New rule that is like all-gcc, except it executes the GCC bootstrap rule instead of the GCC all rule. Wed Dec 27 15:51:48 1995 Doug Evans * config-ml.in (ml_realsrcdir): New, to account for ${subdir}. Tue Dec 26 11:45:31 1995 Michael Meissner * config.guess (AViiON:dgux:*:*): Update from FSF to add pentium DG/UX support. Fri Dec 15 10:01:27 1995 Stan Cox * config.sub (i*86*) Change [345] to [3456] Wed Dec 20 17:41:40 1995 Brendan Kehoe * configure.in (noconfigdirs): Add gas or ld if --with-gnu-as=no or --with-gnu-ld=no. Wed Dec 20 15:15:35 1995 Michael Meissner * config-ml.in (rs6000*, powerpc*): Add switches to control which AIX multilibs get built. Mon Dec 18 17:55:46 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (i386-win32): Don't build expect if we're not building the tcl subdir. Mon Dec 18 11:47:19 1995 Stan Shebs * Makefile.in: (configure-target-examples, all-target-examples): New targets, configure and build example programs. Fri Dec 15 16:13:03 1995 Stan Shebs * mpw-configure: If an mpw-config.in generated a file mk.sed, use it as input to sedit the generated MPW makefile. * mpw-README: Add a suggestion about Gestalt.h. Wed Dec 13 16:43:51 1995 Ian Lance Taylor * config.sub: Accept *-*-ieee*. Tue Dec 12 11:52:57 1995 Ian Lance Taylor * Makefile.in (local-distclean): Remove $(TARGET_SUBDIR). From Ronald F. Guilmette . Mon Dec 11 15:31:58 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (host==powerpc-pe): Add many directories to noconfigdirs for powerpc-pe native. (target==i386-win32): add tcl, make to noconfigdirs if canadian cross. (target==powerpc-pe): duplicate i386-win32 entry. Sat Dec 9 14:58:28 1995 Jim Wilson * configure.in (noconfigdirs): Exclude target-newlib for all versions of vxworks, not just vxworks5.1. Mon Dec 4 12:05:40 1995 Stan Shebs * mpw-configure: Add support for exec-prefix. Mon Dec 4 10:22:50 1995 Jeffrey A. Law * config.guess: Recognize HP model 816 machines as having a PA1.1 processor. Mon Dec 4 12:38:15 1995 Ian Lance Taylor * configure: Ignore new autoconf configure options. Thu Nov 30 14:45:25 1995 J.T. Conklin * config/mt-v810 (CC_FOR_TARGET): Add -ansi flag. NEC compiler defaults to K&R mode, but doesn't have varargs.h, so we have to compile in ANSI mode. Thu Nov 30 16:57:33 1995 Per Bothner * config.guess: Recognize Pentium under SCO. From Robert Lipe . Wed Nov 29 13:49:08 1995 J.T. Conklin * configure.in (noconfigdirs): Disable target-libio on v810-*-*. * config/mt-v810 (CC_FOR_TARGET, AS_FOR_TARGET, AR_FOR_TARGET, RANLIB_FOR_TARGET): Set as appropriate for NEC v810 toolchain. Wed Nov 29 12:12:01 1995 Ian Lance Taylor * configure.in: Don't configure gas for alpha-dec-osf*. Tue Nov 28 17:16:48 1995 Ian Lance Taylor * configure.in: Default to --with-stabs for some targets for which it makes sense: mips*-*-*, alpha*-*-osf*, i[345]86*-*-sysv4* and i[345]86*-*-unixware*. Mon Nov 27 13:44:15 1995 Ian Lance Taylor * config-ml.in: Get list of multidirs using gcc --print-multi-lib rather than basing it on the target. Simplify handling of options controlling which directories to configure. Remove extraneous slash in multi-clean target. Fri Nov 24 17:29:29 1995 Doug Evans * config-ml.in: Prefix more variables with ml_ so they don't collide with configure's. Wed Nov 22 11:27:02 1995 Ian Lance Taylor * configure: Don't turn -v into --v. Tue Nov 21 16:48:02 1995 Doug Evans * configure.in (targargs): Fix typo. * Makefile.in (DEVO_SUPPORT): Add symlink-tree. Tue Nov 21 14:08:28 1995 Ian Lance Taylor * configure.in: Strip --host and --target options from CONFIG_ARGUMENTS, and always configure for --host only. Add --with-cross-host option when building with a cross-compiler. * configure: Canonicalize the arguments put into config.status by always using `=' for an option with an argument. Pass a presumed --host or --target explicitly. Fri Nov 17 17:50:30 1995 Stan Shebs * config.sub: Merge -macos*, -magic*, -pe*, and -win32 cases into general OS recognition case. Fri Nov 17 17:42:25 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (target_configdirs): add target-winsup only for win32 target systems. Thu Nov 16 14:04:47 1995 Ian Lance Taylor * Makefile.in (all-target-libgloss): Depend upon configure-target-newlib, since when libgloss is built it looks to see if the newlib directory exists. Wed Nov 15 14:47:52 1995 Ken Raeburn * Makefile.in (DEVO_SUPPORT): Use config-ml.in instead of cfg-ml-*.in. Wed Nov 15 11:45:23 1995 Ian Lance Taylor * configure: Handle LD and LD_FOR_TARGET when configuring a Canadian Cross. Tue Nov 14 15:03:12 1995 Jason Molenda (crash@phydeaux.cygnus.com) * config/mh-i386win32: add LD_FOR_TARGET. Tue Nov 14 14:56:11 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (target_libs): add target-winsup. (target==i386-win32): add patch diff flex make to $noconfigdirs. (target==ppcle-pe): remove ld from $noconfigdirs. Tue Nov 14 01:25:50 1995 Doug Evans * Makefile.in (CONFIGURE_TARGET_MODULES): Pass --with-target-subdir. Preserve relative path names in $srcdir. Build symlink tree if configuring cross target dir and srcdir=. (= no VPATH support). (configure-target-libg++): Depend on configure-target-librx. * cfg-ml-com.in, cfg-ml-pos.in: Deleted. * config-ml.in: New file. * symlink-tree: New file. * configure: Ensure srcdir="." if that's what it is. Mon Nov 13 12:34:20 1995 Stan Shebs * mpw-README: Clarify some phrasing, add notes about CodeWarrior includes and FLEX_SKELETON setting. * mpw-configure (--with-gnu-ld): New option, controls whether to use PPCLink or ld with PowerMac GCC. * mpw-build.in (all-grez, do-grez, install-grez): New targets. * mpw-config.in: Configure grez if targeting Mac. * config.sub: Accept pmac and pmac-mpw as names for PowerMacs, accept mpw and mac-mpw as names for m68k Macs, change macos7 to just macos. * configure.in: Configure grez resource compiler if targeting Mac. * Makefile.in (all-grez, install-grez): New targets. Wed Nov 8 17:33:51 1995 Jason Merrill * configure: CXX defaults to gcc, not g++. If we find gcc in the path, set CC to gcc -O2. Tue Nov 7 15:45:17 1995 Ian Lance Taylor * configure: Default ${build} correctly. Avoid picking up extra spaces when reading CC and CXX from Makefile. When doing a Canadian Cross, use plausible default values for numerous variables. * configure.in: When doing a Canadian Cross, don't try to configure tools whose configure script can't handle it. Mon Nov 6 19:32:17 1995 Jim Wilson * cfg-ml-com.in (sh-*-*): Add m2 and ml/m2 to multidirs. Sun Nov 5 00:15:41 1995 Per Bothner * configure: Remove dubious bug reporting address. Fri Nov 3 08:17:54 1995 Per Bothner * Makefile.in ($(CONFIGURE_TARGET_MODULES)): If subdir has configure script, run that instead of this directory's configure. In either case, print a message that we're configuring the sub-dir. Thu Nov 2 23:23:36 1995 Per Bothner * configure.in: Before checking for the existence of various files, use sed to filter out "target-". Thu Nov 2 13:24:56 1995 Ian Lance Taylor * Makefile.in (DO_X): Split rule to decrease command line length for systems with small ARG_MAX values. From phdm@info.ucl.ac.be (Philippe De Muyter). Wed Nov 1 15:18:35 1995 Jason Molenda (crash@phydeaux.cygnus.com) * Makefile.in (all-patch): depend on all-libiberty. Wed Nov 1 12:23:20 1995 Ian Lance Taylor * configure.in: If the only directory in target_configdirs which actually exists is libiberty, then set target_configdirs to empty, to avoid trying to build a target libiberty in a gas or gdb distribution. Tue Oct 31 17:52:39 1995 J.T. Conklin * configure.in (host_makefile_frag): Use m68k-sun-sunos* instead of m68k-sun-* when selecting mh-sun3 to avoid matching NetBSD/sun3 systems. Tue Oct 31 16:57:32 1995 Jim Wilson * configure.in (copy_dirs): Use sys-include instead of include for --with-headers option. Tue Oct 31 10:29:36 1995 steve chamberlain * Makefile.in, configure.in: Make winsup builds work with new scheme. Mon Oct 30 18:57:09 1995 Ian Lance Taylor * configure.in: Build the linker on AIX. Mon Oct 30 12:27:16 1995 Per Bothner * Makefile.in (CC_FOR_TARGET, CXX_FOR_TARGET): Add $(TARGET_SUBDIR) where needed. Mon Oct 30 12:45:25 1995 Doug Evans * Makefile.in (all-gcc): Fix typo. Sat Oct 28 10:27:59 1995 Per Bothner * Makefile.in ($(CHECK_TARGET_MODULES)): Fix typo. Fri Oct 27 23:14:12 1995 Per Bothner * configure.in: Rename libFOO to target-libFOO, and xiberty to target-xiberty, to provide more flexibility. (target_subdir): Define. Create if cross. Set TARGET_SUBDIR in Makefile to ${target_subdir}. * Makefile.in: Rename all-libFOO -> all-target-libFOO, all-xiberty -> all-target-libiberty, configure-libFOO -> configure-target-libFOO, check-libFOO -> check-target-libFOO, etc. ($(DO_X)): Iterate over TARGET_CONFIGDIRS after SUBDIRS. ($(CONFIGURE_TARGET_MODULES), $(CHECK_TARGET_MODULES), $(ALL_TARGET_MODULES), $(INSTALL_TARGET_MODULES)): Update accordingly. (configure-target-XXX): Depend on $(ALL_GCC), not all-gcc, to allow ALL_GCC="" to only configure. (DEVO_SUPPORT): Add cfg-ml-com.in and cfg-ml-pos.in. (ETC_SUPPORT, ETC_SUPPORT_PFX): Merge; update 'taz' accordingly. (LIBGXX_SUPPORT_DIRS): Remove xiberty. Sat Oct 28 01:53:49 1995 Ken Raeburn * Makefile.in (taz): Build "info" in etc explicitly. Fri Oct 27 09:32:30 1995 Stu Grossman (grossman@cygnus.com) * configure.in: Make sure that CC is undefined (as opposed to null) if toplevel/config/mh-{host} doesn't define it. Fixes a problem with autoconf trying to configure on a host without GCC. Thu Oct 26 22:35:01 1995 Stan Shebs * mpw-configure: Set host alias from choice of host compiler, only use generic MPW Makefile sed if present, edit a file named "hacked_Makefile.in" instead of "Makefile.in" if present. * mpw-README: Add problem notes about CW6 and CW7. Thu Oct 26 05:45:10 1995 Ken Raeburn * Makefile.in (taz): Use ";" instead of ";;". Wed Oct 25 15:18:24 1995 Per Bothner * Makefile.in (taz): Grep for '^diststuff:' or '^info:' in sub-directory Makefiles, instead of using DISTSTUFFDIRS and DISTDOCDIRS. (DISTSTUFFDIRS, DISTDOCDIRS): Removed - no longer used. (newlib.tar.gz): Don't pass DISTDOCDIRS to recursive make. Wed Oct 25 14:43:55 1995 Per Bothner * Makefile.in (DISTDOCDIRS): Remove ld gprof bnutils gas libg++ gdb and gnats, because they are now subsumed by DISTSTUFFDIRS. Move bfd to DISTSTUFFDIRS. Tue Oct 24 18:19:09 1995 Jason Molenda (crash@phydeaux.cygnus.com) * Makefile.in (X11_LIB): Removed. (X11_FLAGS_TO_PASS): pass only X11_EXTRA_CFLAGS and X11_EXTRA_LIBS. * configure.in (host_makefile_frag): mh-aix & mh-sun removed. Sun Oct 22 13:04:42 1995 Michael Meissner * cfg-ml-com.in (powerpc*): Shorten some of the multilib directory names. Fri Oct 20 18:02:10 1995 Michael Meissner * cfg-ml-com.in (powerpc*-eabi*): Add mcall-aixdesc varients. Thu Oct 19 10:40:57 1995 steve chamberlain * configure.in (i[345]86-*-win32): Always build newlib. Don't configure cvs, autoconf or texinfo. * Makefile.in (LD_FOR_TARGET): New. (BASE_FLAGS_TO_PASS, EXTRA_TARGET_FLAGS, CONFIGURE_TARGET_MODULES): Pass down LD_FOR_TARGET. Wed Oct 18 15:53:56 1995 steve chamberlain * winsup: New directory. * Makefile.in: Build winsup. * configure.in: Winsup is configured when target is win32. Can only build win32 target GDB when native. Mon Oct 16 09:42:31 1995 Jeffrey A Law (law@cygnus.com) * config.guess: Recognize HP model 819 machines as having a PA 1.1 processor. Mon Oct 16 10:49:43 1995 Ian Lance Taylor * configure: Fix sed loop which substitutes for CC and CXX to avoid bug found in various sed implementations. Wed Oct 11 16:16:20 1995 Michael Meissner * cfg-ml-com.in (powerpc-*-eabisim): Delete separate rule for simulator. Use standard powerpc-*-eabi*. Mon Oct 9 17:21:56 1995 Ian Lance Taylor * configure.in: Stop putting gas and binutils in noconfigdirs for powerpc-*-aix* and rs6000-*-*. Mon Oct 9 12:38:40 1995 Michael Meissner * cfg-ml-com.in (powerpc*-*-eabisim*): Add support for building -mcall-aixdesc libraries. Fri Oct 6 16:17:57 1995 Ken Raeburn Mon Sep 25 22:49:32 1995 Andreas Schwab * config.sub (arm | armel | armeb): Fix shell syntax. Fri Oct 6 14:40:28 1995 Michael Meissner * cfg-ml-com.in ({powerpc,rs6000}-ibm-aix*): Add multilibs for -msoft-float and -mcpu=common support. (powerpc*-*-eabisim*): Add support for building -mcall-aix libraries. Thu Oct 5 13:26:37 1995 Brendan Kehoe * configure.in: Allow configuration and build of emacs19 for the alpha. Wed Oct 4 22:05:36 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (CC): Get ^CC, not just any old CC, from ${host_makefile_frag}. Wed Oct 4 21:55:00 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (CC): Try to get CC from ${srcdir}/${host_makefile_frag}, not ${host_makefile_frag}. Wed Oct 4 21:44:12 1995 Jason Molenda (crash@phydeaux.cygnus.com) * Makefile.in (TARGET_CONFIGDIRS): configure targetdirs only if it exists in $(srcdir). Wed Oct 4 11:52:31 1995 Ian Lance Taylor * configure: If CC and CXX are not set in the environment, set them, based on either an existing Makefile or on searching for gcc in PATH. Substitute for CC and CXX in Makefile. * configure.in: Remove libm from target_libs. Separate target_configdirs from configdirs. If CC is not set in environment, try to get it from a host Makefile fragment. Rewrite changes of configdirs to use skipdirs instead. A few minor tweaks. Take directories out of target_configdirs as they are taken out of configdirs. Remove existing Makefile files from subdirectories. Substitute for TARGET_CONFIGDIRS and CONFIG_ARGUMENTS in Makefile. * Makefile.in (TARGET_CONFIGDIRS): New variable, automatically set by configure.in. (CONFIG_ARGUMENTS): Likewise. (CONFIGURE_TARGET_MODULES): New variable. ($(DO_X)): Loop over TARGET_CONFIGDIRS as well as SUBDIRS. ($(CONFIGURE_TARGET_MODULES)): New target. (configure-libg++, configure-libio): New targets. (all-libg++): Depend upon configure-libg++. (all-libio): Depend upon configure-libio. (configure-libgloss, all-libgloss): New targets. (configure-libstdc++): New target. (all-libstdc++): Depend upon configure-libstdc++. (configure-librx, all-librx): New targets. (configure-newlib): New target. (all-newlib): Depend upon configure-newlib (configure-xiberty): New target. (all-xiberty): Depend upon configure-xiberty. Sat Sep 30 04:32:59 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in (host i[345]86-*-win32): Expand the noconfigdirs again. Thu Sep 28 21:18:49 1995 Stan Shebs * mpw-configure: Fix sed command file name. Thu Sep 28 17:39:56 1995 steve chamberlain * configure.in (host i[345]86-*-win32): Reduce the noconfigdirs again. Wed Sep 27 12:24:00 1995 Ian Lance Taylor * configure.in: Don't configure ld and gdb for powerpc*-*-winnt* or powerpc*-*-pe*, since they are not yet supported. Tue Sep 26 14:30:01 1995 Stan Shebs Add PowerMac support and many other enhancements. * mpw-configure: New option --cc to select compiler to use, paste options set according to --cc into the generated Makefile, generate the Makefile by sed'ing the Unix Makefile.in if mpw-make.sed is present. * mpw-config.in: Don't test for gC1, test for mpw-touch, add forward includes for PowerPC include files. * mpw-build.in: Build using Makefile.PPC if present. (do-byacc, etc): Remove separate version resource builds. (do-gas): Build "stamps" before "all". (do-gcc): Build "stamps-h" and "stamps-c" before "all". * mpw-README: Update to reflect --cc option, PowerMac support, and recently-reported compatibility problems. Fri Sep 22 12:15:42 1995 Doug Evans * cfg-ml-com.in (m68*-*-*): Only build multilibs for embedded m68k systems (-aout, -coff, -elf, -vxworks). (--with-multilib-top): Pass to recursive invocations. Tue Sep 19 13:51:05 1995 J.T. Conklin * configure.in (noconfigdirs): Disable libg++ and libstdc++ on v810-*-*. Mon Sep 18 23:08:26 1995 J.T. Conklin * configure.in (noconfigdirs): Disable bfd, binutils, gas, gcc, gdb, ld and opcodes on v810-*-*. Sat Sep 16 18:31:08 PDT 1995 Angela Marie Thomas * config/mh-ncrsvr43: Removed AR_FLAGS Tue Sep 12 18:03:31 1995 Ian Lance Taylor * Makefile.in (DO_X): Change do-realclean to do-maintainer-clean. (local-maintainer-clean): New target. (maintainer-clean): New target. (realclean): Just depend upon maintainer-clean. Fri Sep 8 17:11:14 1995 J.T. Conklin * configure.in (noconfigdirs): Disable gdb on m68k-*-netbsd*. Fri Sep 8 16:46:29 1995 Ian Lance Taylor * configure.in: Build ld in mips*-*-bsd* case. Thu Sep 7 20:03:41 1995 Ken Raeburn * config.sub: Accept -lites* OS. From Ian Dall. Fri Sep 1 08:06:58 1995 James G. Smith * config.sub: recognise mips64vr4300 and mips64vr4300el as valid targets. Wed Aug 30 21:06:50 1995 Jason Molenda (crash@phydeaux.cygnus.com) * configure.in: treat i386-win32 canadian cross the same as i386-go32 canadian cross. Thu Aug 24 14:53:20 1995 Michael Meissner * cfg-ml-com.in (powerpc*-*-eabisim): Add support for PowerPC running under the simulator to build a reduced set of libraries. (powerpc-*-eabiaix): Add fine grained multilib support added to other powerpc targets yesterday. Wed Aug 23 09:41:56 1995 Michael Meissner * cfg-ml-com.in (powerpc*): Add support for -disable-biendian, -disable-softfloat, -disable-relocatable, -disable-aix, and -disable-sysv to control which multilib libraries get built. Thu Aug 17 16:03:41 1995 Ken Raeburn * configure: Add Makefile.tem to list of files to remove in trap handler. Mon Aug 14 19:27:56 1995 Per Bothner * config.guess (*Linux*): Add missing "exit"s. Also, need specific check for alpha-unknown-linux (uses COFF). Fri Aug 11 15:38:20 1995 Per Bothner * config.guess: Merge with FSF: Wed Jun 28 17:57:27 1995 David Edelsohn * config.guess (AIX4): More robust release numbering discovery. Thu Jun 22 19:01:24 1995 Kenneth Stailey (kstailey@eagle.dol-esa.gov) * config.guess (i386-sequent-ptx): Properly get version number. Thu Jun 22 18:36:42 1995 Uwe Seimet (seimet@iris1.chemie.uni-kl.de) * config.guess (mips:*:4*:UMIPS): New case. Mon Aug 7 09:21:35 1995 Doug Evans * configure.in (i386-go32 host): Fix typo (deja-gnu -> dejagnu). (i386-win32 host): Likewise. Don't build readline. Fri Aug 4 13:04:36 1995 Fred Fish * Makefile.in (GDB_SUPPORT_DIRS): Add utils. (DEVO_SUPPORT): Add mpw-README, mpw-build.in, mpw-config.h and mpw-configure. Wed Aug 2 16:32:40 1995 Ken Raeburn * configure.in (appdirs): Use =, not ==, in test expression when trying to build the text to print in the warning message for Solaris users. Mon Jul 31 09:56:18 1995 steve chamberlain * cfg-ml-com.in (z8k-*-coff): Add 'std' multilib build. Fri Jul 28 00:16:31 1995 Jeffrey A. Law * config.guess: Recognize lynx-2.3. Thu Jul 27 15:47:59 1995 steve chamberlain * config.sub (z8ksim): Deleted (z8k-*-coff): New, this is the one true name of the target. Thu Jul 27 14:33:33 1995 Doug Evans * cfg-ml-pos.in (dotdot): Work around SunOS sed bug. Thu Jul 27 13:31:05 1995 Fred Fish (fnf@cygnus.com) * config.guess (*:Linux:*:*): First try asking the linker what the default object file format is (elf, aout, or coff). Then if this fails, try previous methods. Thu Jul 27 11:28:17 1995 J.T. Conklin * configure.in: Don't build newlib for *-*-vxworks5.1. Thu Jul 27 11:18:47 1995 Brendan Kehoe * configure.in: Don't build newlib for a29k-*-vxworks5.1. * test-build.mk: Add setting of --with-headers for a29k-vxworks5.1. Tue Jul 25 21:25:39 1995 Doug Evans * cfg-ml-pos.in (MULTITOP): Trim excess trailing "/.". Fri Jul 21 10:41:12 1995 Doug Evans * cfg-ml-com.in: New file. * cfg-ml-pos.in: New file. Wed Jul 19 00:37:27 1995 Jeffrey A. Law * COPYING.NEWLIB: Add HP free copyright to list. Tue Jul 18 10:58:51 1995 Michael Meissner * config.sub: Recognize -eabi* for the system, not just -eabi. Mon Jul 3 13:44:51 1995 Steve Chamberlain * Makfile.in (DLLTOOL_FOR_TARGET): New name, pass it down. * config.sub, configure.in (win32): New target and host. Wed Jun 28 23:57:08 1995 Steve Chamberlain * configure.in: Add i386-pe configuration. Fri Jun 23 14:28:44 1995 Stan Shebs * mpw-build.in (install): Install GDB after LD. Thu Jun 22 17:10:53 1995 Stan Shebs * mpw-config.in (elf/mips.h): Always forward-include, needed for GDB to build. Wed Jun 21 15:17:30 1995 Rob Savoye * testsuite: New directory for customer acceptance and whole tool chain tests. Wed Jun 21 16:50:29 1995 Ken Raeburn * configure: If per-host line isn't found, but AC_OUTPUT is found and a configure script exists, run it instead. Thu Jun 15 21:09:24 1995 Per Bothner * config.guess: Update from FSF, for alpha-dec-winnt3.5 and Crays. Tue Jun 13 21:43:27 1995 Rob Savoye * configure: Set build_{cpu,vendor,os,alias} to host values when --build isn't specified. Mon Jun 5 18:26:36 1995 Jason Merrill * Makefile.in (PICFLAG, PICFLAG_FOR_TARGET): New macros. (FLAGS_TO_PASS): Pass them. (EXTRA_TARGET_FLAGS): Ditto. * config/m?-*pic: Define PICFLAG* instead of LIB*FLAGS*. Wed May 31 22:27:42 1995 Jim Wilson * Makefile.in (all-libg++): Depend on all-libstdc++. Thu May 25 22:40:59 1995 J.T. Conklin * configure.in (noconfigdirs): Enable all packages for i386-unknown-netbsd. Sat May 20 13:22:31 1995 Angela Marie Thomas * configure.in (noconfigdirs): Don't configure tk for i386-go32 hosted builds (DOS builds) Thu May 18 18:08:49 1995 Ken Raeburn Changes for ARM based on patches from Richard Earnshaw: * config.sub: Handle armeb and armel. * configure.in: Omit arm linker only for riscix. Thu May 11 17:23:26 1995 Per Bothner * config.guess: Update from FSF. Tue May 9 15:52:05 1995 Michael Meissner * config.sub: Recognize powerpcle as the little endian varient of the PowerPC. Recgonize ppc as a PowerPC variant, and ppcle as a powerpcle variant. Convert pentium into i586, not i486. Add p5 alias for i586. Map new x86 variants p6, k5, nexgen into i586 temporarily. Tue May 2 16:29:41 1995 Jeff Law (law@snake.cs.utah.edu) * configure.in (hppa*-*-lites*): Treat like hppa*-*-*elf*. Sun Apr 30 21:38:09 1995 Jeff Law (law@snake.cs.utah.edu) * config.sub: Accept -lites* as a basic system type. Thu Apr 27 11:33:29 1995 Michael Meissner (meissner@cygnus.com) * config.guess (*:Linux:*:*): Check for whether the pre-BFD linker is installed, and if so return linuxoldld as the system name. Wed Apr 26 10:59:02 1995 Jeff Law (law@snake.cs.utah.edu) * config.guess: Add hppa1.1-hp-lites support. Tue Apr 25 11:08:11 1995 Rob Savoye * configure.in: Don't build newlib for m68k-vxworks5.1. Wed Apr 19 17:02:43 1995 Jim Wilson * configure.in (mips-sgi-irix6): Use mh-irix5. Fri Apr 14 15:21:17 1995 Doug Evans * Makefile.in (all-gcc): Depend on all-ld (for libgcc1-test). Wed Apr 12 16:06:01 1995 Jason Merrill * test-build.mk: Enable building of shared libraries on IRIX 5 and OSF/1. Fix compiler flags. * build-all.mk: Support Linux and OSF/1 3.0. Fix compiler flags. Tue Apr 11 18:55:40 1995 Doug Evans * configure.in: Recognize --with-newlib. (sparc-*-sunos4*): Build sim, dejagnu, expect, tcl if cross target. Mon Apr 10 11:42:22 1995 Stan Shebs Merge in support for Mac MPW as a host. (Old change descriptions retained for informational value.) * mpw-config.in: Add generic include forwards for cpu-specific include files in aout and elf directories. * mpw-configure: Added copyright. * mpw-config.in: Check for presence of required build tools. (target_libs): Add newlib. (target_tools): Add examples. (Read Me): Generate as "Read Me for MPW" instead. * mpw-build.in: Base sub-builds on all-foo instead of do-foo. (all-byacc, do-byacc, all-flex, do-flex, do-newlib): New actions. (do-gas, do-gcc, do-gdb, do-ld): Build Version.r first. * mpw-configure: Remove subdir-specific makefile hackery, delete mk.tmp after using it. * mpw-build.in (all): Display start and end times. * mpw-configure (host_canonical): Set. (target_cpu): Always add to makefiles. (ARCHDEFS, EMUL): Add to makefile only if nonempty. (TM_FILE, XM_FILE, NM_FILE): No longer add to makefile. (mpw-mh-mpw): Look for in srcdir and srcroot. Use sed instead of mpw-edit-prefix to edit prefix definitions. * mpw-build.in: (install-only): New target. * mpw-configure (host_alias, target_alias): Rename from hostalias and targetalias, add into generated Makefile. (mk.tmp): If present, add into generated Makefile. * mpw-build.in (all-gas): Build config.h first before gas proper. * mpw-configure (config.status): Write only if changed. * mpw-config.in (readline): Configure it (not built, just used for definitions). * mpw-config.in (elf/mips.h): Add a forward include. * mpw-config.in: Forward-include most .h files in include into extra-include. (readline): Don't build. mpw-build.in (install): Install GDB. * mpw-configure (prefix, mpw_prefix): Handle it. * mpw-config.in (mmalloc, readline): Don't configure. * mpw-build.in (thisscript): Rename to ThisScript. Use mpw-build instead of BuildProgram everywhere. (mmalloc, readline): Don't build. * mpw-README: New file, basic documentation about the MPW port. * mpw-config.in: Use forward-include to create include files. * mpw-configure: Add more things to the top of each configured Makefile, including contents of config/mpw-mh-mpw. * mpw-config.in (extra-include): Create this directory and fill it with Posix-like include files when configuring. * config.sub (apple, mac, mpw): Add various aliases. * mpw-build.in: New file, top-level build script fragment for MPW. * mpw-configure: New file, configure script for MPW. * mpw-config.in: New file, config fragment for MPW. Fri Apr 7 19:33:16 1995 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in (host_libs): Remove glob, since it is gone from the sources. Fri Mar 31 11:36:17 1995 Jason Molenda (crash@phydeaux.cygnus.com) * Makefile.in: define empty GDB_NLM_DEPS var. * configure.in(target_makefile_frag): use config/mt-netware for netware targets. Thu Mar 30 13:51:43 1995 Ian Lance Taylor * config.sub: Merge in recent FSF changes. Remove linux special cases. Tue Mar 28 14:47:34 1995 Jason Molenda (crash@phydeaux.cygnus.com) build-all.mk,config/mh-solaris: revert these two changes: Tue Mar 30 10:03:09 1993 Ian Lance Taylor (ian@cygnus.com) * build-all.mk: Use CC=cc -Xs on Solaris. Mon Mar 29 19:59:26 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config/mh-solaris: SunPRO C needs -Xs to be able to get a working xmakefile for Emacs. Tue Mar 21 10:43:32 1995 Jim Kingdon (kingdon@lioth.cygnus.com) * glob/*: Removed. Schauer's 24 Feb 1994 readline change made us stop using it. * Makefile.in: Nuke all references to glob subdirectory. Thu Mar 16 13:35:30 1995 Jason Merrill * configure.in: Fix --enable-shared logic in per-host. Mon Mar 13 12:33:15 1995 Ian Lance Taylor * configure.in (*-hp-hpux[78]*): Use mh-hpux8. Mon Mar 6 10:21:58 1995 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in (noconfigdirs): Don't build gas on AIX, for powerpc*-*-aix* as well as for rs6000*-*-aix*. Wed Mar 1 12:51:53 1995 Ian Lance Taylor * configure: Fix --cache-file to work if the file argument is a relative path. Tue Feb 28 17:36:07 1995 Ian Lance Taylor * configure: If the --cache-file is used, pass it down to configure in subdirectories. Mon Feb 27 12:52:46 1995 Kung Hsu * config.sub: add vxworks29k configuration. Fri Feb 10 16:12:26 1995 Ken Raeburn * Makefile.in (taz): Do "diststuff" part quietly. Sun Feb 5 14:16:35 1995 Doug Evans * config.sub: Mini-merge with gcc/config.sub. Sat Feb 4 12:11:35 1995 Jim Wilson * config.guess (IRIX): Sed - to _. Fri Feb 3 11:54:42 1995 J.T. Conklin * Makefile.in (source-vault, binary-vault): New targets. Thu Jan 26 13:00:11 1995 Michael Meissner * config.sub: Recognize -eabi as a basic system type. Thu Jan 12 13:13:23 1995 Jason Merrill * configure.in (enable_shared stuff): Fix typo. Thu Jan 12 01:36:51 1995 deanm@medulla.LABS.TEK.COM (Dean Messing) * Makefile.in (BASE_FLAGS_TO_PASS): Fix typo in passing LIBCXXFLAGS*. Wed Jan 11 16:29:53 1995 Jason Merrill * Makefile.in (LIBCXXFLAGS_FOR_TARGET): Add -fno-implicit-templates. Mon Jan 9 12:48:01 1995 Jim Kingdon * configure.in (rs6000-*-*): Don't build gas. Wed Jan 4 23:53:49 1995 Ian Lance Taylor * Makefile.in: Use /x/x/ instead of /brokensed/brokensed/, to reduce command line length. (AS_FOR_TARGET): Check for as.new, not Makefile. (NM_FOR_TARGET): Check for nm.new, not Makefile. Wed Jan 4 13:02:39 1995 Per Bothner * config.guess: Merge from FSF. Thu Dec 15 17:11:37 1994 Ian Lance Taylor * configure: Don't use $ when handling program_suffix. Mon Dec 12 12:09:37 1994 Stu Grossman (grossman@cygnus.com) * configure.in: Configure tk for hppa/hpux. Fri Dec 2 15:55:38 1994 Per Bothner * Makefile.in (LIBGXX_SUPPORT_DIRS): Add libstdc++. Tue Nov 29 19:37:56 1994 Per Bothner * Makefile.in: Move -fno-implicit-template from CXXFLAGS to LIBCXXFLAGS. Tests are better run without it. Wed Nov 23 10:29:25 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (all-ispell): Depend on all-emacs19 instead of all-emacs. Mon Nov 21 11:14:01 1994 J.T. Conklin * configure.in (*-*-netware*): Don't configure xiberty. Mon Nov 14 08:49:15 1994 Stu Grossman (grossman@cygnus.com) * configure.in: Remove tk from native_only list. Fri Nov 11 15:31:26 1994 Bill Cox (bill@rtl.cygnus.com) * build-all.mk: Add mips-ncd-elf target to sun4 targets for special NCD build. Mon Nov 7 20:58:17 1994 Ken Raeburn * Makefile.in (DEVO_SUPPORT): Remove configure.bat and makeall.bat, they're only useful for binutils snapshots. (binutils.tar.gz, gas+binutils.tar.gz): Add configure.bat and makeall.bat to specified SUPPORT_FILES. Mon Nov 7 17:25:18 1994 Bill Cox (bill@cirdan.cygnus.com) * build-all.mk: Add Ericsson targets to sun4 and solaris hosts. Add BNR's sun4 target to solaris host, so their build-from-source will be tested in-house first. Sat Nov 5 18:43:30 1994 Jason Merrill (jason@phydeaux.cygnus.com) * Makefile.in (LIBCFLAGS): New variable. (CFLAGS_FOR_TARGET): Ditto. (LIBCFLAGS_FOR_TARGET): Ditto. (LIBCXXFLAGS): Ditto. (CXXFLAGS_FOR_TARGET): Ditto. (LIBCXXFLAGS_FOR_TARGET): Ditto. (BASE_FLAGS_TO_PASS): Pass them. (EXTRA_TARGET_FLAGS): Ditto. * configure.in, config/m[th]-*pic: Support --enable-shared. Sat Nov 5 15:44:00 1994 Per Bothner * configure.in (target_libs): Include libstdc++ again. * config.guess: Update from FSF (for FreeBSD). Thu Nov 3 16:32:30 1994 Ken Raeburn * Makefile.in (DEVO_SUPPORT): Include configure.bat and makeall.bat. (DISTDOCDIRS): Add `etc'. (ETC_SUPPORT_PFX): New variable. (taz): Include anything from etc starting with a word in ETC_SUPPORT_PFX. Wed Oct 26 16:19:35 1994 Ian Lance Taylor * config.sub: Update for recent FSF changes. Remove obsolete h8300hds entry. Add -windows* and -osx as basic os. Minor spacing changes. Thu Oct 20 18:41:56 1994 Per Bothner * configure.in (target_libs): Remove libstdc++ for libg++-2.6.1. * config.guess: Merge with FSF. * configure.in: Match on i?86-ncr-sysv4.3, not i?86-ncr-sysv43. Thu Oct 20 19:26:56 1994 Ken Raeburn * configure: Since the "trap 0" handler will override the exit status on many systems, only use it for "exit 1", and make it set a non-zero exit status; reset it before "exit 0". Also, check exit status of config.sub, and error out if it failed. Wed Oct 19 18:49:55 1994 Rob Savoye (rob@cygnus.com) * Makefile.in: (ALL_TARGET_MODULES,INSTALL_TARGET_MODULES) Build and install libgloss. Tue Oct 18 15:25:24 1994 Ian Lance Taylor * Makefile.in (all-binutils): Depend upon all-byacc. * configure.in: Don't build emacs on Irix 5. Mon Oct 17 16:22:12 1994 J.T. Conklin (jtc@phishhead.cygnus.com) * configure.in (*-*-netware*): Add libio. Thu Oct 13 15:51:20 1994 Jason Merrill (jason@phydeaux.cygnus.com) * Makefile.in (ALL_TARGET_MODULES): Add libstdc++. (CHECK_TARGET_MODULES): Ditto. (INSTALL_TARGET_MODULES): Ditto. (TARGET_LIBS): Ditto. (all-libstdc++): Note dependencies. Thu Oct 13 01:43:08 1994 Ken Raeburn * Makefile.in (BINUTILS_SUPPORT_DIRS): Add gas. Tue Oct 11 12:12:29 1994 Jason Merrill (jason@phydeaux.cygnus.com) * Makefile.in (CXXFLAGS): Use -fno-implicit-templates instead of -fexternal-templates. * configure.in (target_libs): Add libstdc++. (noconfigdirs): Add libstdc++ as appropriate. Thu Oct 6 18:00:54 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Update from FSF. Tue Oct 4 12:05:42 1994 Ian Lance Taylor * configure: Use ${config_shell} when running ${configsub}. Mon Oct 3 14:28:34 1994 Doug Evans * config.sub: No longer recognize h8300h. Mon Oct 3 12:40:54 1994 Ian Lance Taylor * config.sub: Remove extraneous differences between config.sub and gcc/config.sub. Sat Oct 1 00:23:12 1994 Ken Raeburn * Makefile.in (DISTSTUFFDIRS): Add gas. Thu Sep 22 19:04:55 1994 Doug Evans (dje@canuck.cygnus.com) * COPYING.NEWLIB: New file. Mon Sep 19 18:25:40 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess (HP-UX): Patch from Harlan Stenn to also emit release level. Wed Sep 7 13:15:25 1994 Jim Wilson (wilson@sphagnum.cygnus.com) * config.guess (sun4*:SunOS:*:*): Change '-JL' to '_JL'. Tue Sep 6 23:23:18 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.sub: Merge nextstep cleanup from FSF. Mon Sep 5 05:01:30 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) * configure.in (arm-*-*): Don't configure ld for this target. Thu Sep 1 09:35:00 1994 J.T. Conklin (jtc@phishhead.cygnus.com) * configure.in (*-*-netware): don't configure libg++, libio, librx, or newlib. Wed Aug 31 13:52:08 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure.in (alpha-dec-osf*): Use osf*, not osf1*. Don't configure ld--it works, but it doesn't support shared libraries. Sun Aug 28 18:13:45 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess (*-unknown-freebsd*): Get rid of possible trailing "(Release)" in version string. Patch from Paul Richards . Sat Aug 27 15:00:49 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Fix i486-ncr-sysv43 -> i486-ncr-sysv4.3. Fix type: *-next-neststep -> *-next-nextstep. * config.guess: Merge from FSF: Fri Aug 26 18:45:25 1994 Philippe De Muyter (phdm@info.ucl.ac.be) * config.guess: Recognize powerpc-ibm-aix3.2.5. Wed Apr 20 06:36:32 1994 Philippe De Muyter (phdm@info.ucl.ac.be) * config.guess: Recognize UnixWare 1.1 (UNAME_SYSTEM is SYSTEM_V instead of UNIX_SV for UnixWare 1.0). Sat Aug 27 01:56:30 1994 Stu Grossman (grossman@cygnus.com) * Makefile.in (all-gdb): Add dependencies on all-gcc and all-ld to make gdb/nlm/* build after the compiler and linker. Fri Aug 26 14:30:05 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess (netbsd, freebsd, linux): Accept any machine, not just i[34]86. (m68k-atari-sysv4): Relocate to match FSF version. * config.guess: More merges from the FSF: Add a space before function call or macro invocation. Tue May 10 16:53:55 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * config.guess: Add trap cmd to remove dummy.c and dummy when interrupted. Wed Apr 20 18:07:13 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * config.guess (dummy.c): Redirect stderr for `hostinfo' command. (dummy): Redirect stderr from compilation of dummy.c. Sat Apr 9 14:59:28 1994 Christian Kranz (kranz@sent5.uni-duisburg.de) * config.guess: Distinguish between NeXTStep 2.1 and 3.x. Fri Aug 26 13:42:20 1994 Ken Raeburn (raeburn@kr-laptop.cygnus.com) * configure: Accept and ignore --cache*, for compatibility with new autoconf. Fri Aug 26 13:05:27 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Merge from FSF: Thu Aug 25 20:28:51 1994 Richard Stallman * config.guess (Pyramid*:OSx*:*:*): New case. (PATH): Add /.attbin at end for finding uname. (dummy.c): Handle i860-alliant-bsd. Follow whitespace conventions. Wed Aug 17 18:21:02 1994 Tor Egge (tegge@pvv.unit.no) * config.guess (M88*:DolphinOS:*:*): New case. Thu Aug 11 17:00:13 1994 Stan Cox (coxs@dg-rtp.dg.com) * config.guess (AViiON:dgux:*:*): Use TARGET_BINARY_INTERFACE to select whether to use ELF or COFF. Sun Jul 24 16:20:53 1994 Richard Stallman * config.guess: Recognize i860-stardent-sysv and i860-unknown-sysv. Sun May 1 10:23:10 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) * config.guess: Guess the OS version for HPUX. Tue Mar 1 21:53:03 1994 Karl Heuer (kwzh@hal.gnu.ai.mit.edu) * config.guess (UNAME_VERSION): Recognize aix3.2.4 and aix3.2.5. Fri Aug 26 11:19:08 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure.in: Recognize --with-headers, --with-libs, and --without-newlib. * Makefile.in (all-xiberty): Depend upon all-ld. Wed Aug 24 12:36:50 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure.in: Change i[34]86 to i[345]86. Mon Aug 22 10:58:33 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure (version): A few more tweaks to help message. Fri Aug 19 12:40:25 1994 Per Bothner (bothner@kalessin.cygnus.com) * Makefile.in: Remove (for now) librx as a host library, now that we're building it for target. Fri Aug 19 10:49:17 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure: Fix up help message; from karl@owl.hq.ileaf.com (Karl Berry). Tue Aug 16 16:11:08 1994 Per Bothner (bothner@kalessin.cygnus.com) * configure.in: Also configure librx. Mon Aug 15 16:51:45 1994 Per Bothner (bothner@kalessin.cygnus.com) * Makefile.in: Update various rules to reflect that librx is now needed for libg++. Fri Aug 12 18:07:21 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * config.sub: Accept mips64orion and mips64orionel as a CPU name. Mon Aug 8 11:36:17 1994 Stan Shebs (shebs@andros.cygnus.com) * configure.in: Configure the examples directory. Thu Aug 4 16:12:36 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure: Simplify Jun 2 1994 change. Wed Aug 3 04:58:16 1994 D. V. Henkel-Wallace (gumby@cygnus.com) * change CC to /usr/latest/bin/gcc for lynx host builds, since /bin/gcc isn't good enough to build gcc. Wed Jul 27 09:07:14 1994 Fred Fish (fnf@cygnus.com) * Makefile.in (GDB_SUPPORT_FILES): Remove (setup-dirs-gdb, gdb.tar.gz, make-gdb.tar.gz): Remove old rules. (gdb.tar.gz): Add new rule to use standard distribution building mechanism. Mon Jul 25 11:10:06 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in: Warn about use of /usr/ucb/cc on Solaris. From Bill Cox . Sat Jul 23 12:19:46 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Recognize ISC. Patch from kwzh@gnu.ai.mit.edu. Fri Jul 22 17:53:59 1994 Stu Grossman (grossman@cygnus.com) * configure: Search current dir first in .gdbinit. Fri Jul 22 11:28:30 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.sub: Recognize freebsd (merged from gcc config.sub). Thu Jul 21 14:10:52 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.sub: Refer to NeXT's operating system as nextstep. * config.sub (case $basic_machine): Re-order the cases, to match the order in the FSF version (which is mostly alphabethical). Merge in some additions and changes from the FSF. Sat Jul 16 12:03:08 1994 Stan Shebs (shebs@andros.cygnus.com) * config.guess: Recognize m68k-atari-sysv4 and m88k-harris-csux7. * config.sub: Recognize cxux7. * configure.in: Use mh-cxux for m88k-harris-cxux*. Mon Jul 11 14:37:39 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.sub: Fix typo powerpc -> powerpc-*. Sat Jul 9 13:03:43 1994 Michael Tiemann (tiemann@blues.cygnus.com) * Makefile.in: `all-emacs19' depends on `all-byacc'. * Makefile.in: Add all-emacs19 and install-emacs19 rules (in parallel with all-emacs and install-emacs). Top-level command `make all-emacs19 CC=gcc' now behaves as `make all-emacs CC=gcc'. Thu Jun 30 16:53:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * test-build.mk ($(host)-stamp-stage2-installed): Remove $(relbindir)/make before doing ``make install'', and use $(GNU_MAKE) while doing it. Avoids problem on SunOS with installing over running make binary. ($(host)-stamp-stage3-installed): Likewise. Tue Jun 28 13:43:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Recognize Mach. Mon Jun 27 16:41:14 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * configure: Check ${exec_prefixoption}, not ${exec_prefix}, to see whether --exec-prefix was used. Sun Jun 26 21:15:54 1994 Per Bothner (bothner@kalessin.cygnus.com) * README: Explicitly mention libg++/README. (Zoo's idea.) Tue Jun 21 12:45:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in: Add all-librx target similar to all-libproc. Wed Jun 8 23:11:55 1994 Stu Grossman (grossman@cygnus.com) * config.guess: Rearrange tests for Alpha-OSF1 to properly deal with post 1.2 uname bogosity. Thu Jun 9 00:27:59 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure: Remove temporary files on receipt of a signal. Tue Jun 7 12:06:24 1994 Ian Lance Taylor (ian@cygnus.com) * configure: If there is a package_makefile_frag, remove ${subdir}/Makefile.tem after copying it in. Mon Jun 6 21:35:02 1994 D. V. Henkel-Wallace (gumby@cygnus.com) * build_all.mk: support rs6000 lynx identifies itself as rs6000-lynx-lynxos2.2.2. Also, use /usr/cygnus/progressive/bin/gcc since /bin/gcc is too feeble to compile a modern gcc. Mon Jun 6 16:06:34 1994 Karen Christiansen (karen@cirdan.cygnus.com) * brought devo/test-build.mk update-to-date with progressive/ test-build.mk. Add lynx targets and hppa flag info. Sat Jun 4 17:23:54 1994 Per Bothner (bothner@kalessin.cygnus.com) * configure.in: Use mh-ncrsvr43. Patch from Tom McConnell . Fri Jun 3 17:47:24 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess (i386-unknown-bsdi): No longer need to check #if defined(__bsdi__) && defined(__i386__). Thu Jun 2 18:56:46 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure: Set program_transform_nameoption correctly. Thu Jun 2 10:57:06 1994 Karen Christiansen (karen@cirdan.cygnus.com) * brought build-all.mk update-to-date with progressive build-all.mk, added new targets and hppa info. Thu Jun 2 00:12:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure: If config.guess result is a prefix of the user specified target, assume a native build and use the user specified target as the host alias. Remove SunOS patch suffix removal hack. * configure.in: Remove SunOS patch suffix removal hack. * Makefile.in (CROSS_CHECK_MODULES): Remove check-flex, since it's in NATIVE_CHECK_MODULES. Wed Jun 1 10:49:41 1994 Bill Cox (bill@rtl.cygnus.com) * Makefile.in: Rename HOST_ONLY to NATIVE. * configure: Delete SunOs patch suffix from host_canonical and build_canonical variables that are prepended to Makefiles. * configure.in: Add comments for easier maintenance. Tue May 31 19:39:47 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in: Add all-libproc target similar to all-gui. Tue May 31 17:16:33 1994 Tom Lord (lord@cygnus.com) * Makefile.in (CHECK_MODULES): split into HOST_ONLY_CHECK_MODULES and CROSS_CHECK_MODULES. Tue May 31 16:36:36 1994 Paul Eggert (eggert@twinsun.com) * config.guess (i386-unknown-bsdi): New system to guess. Wed May 25 16:47:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in: Add all-gui target (but not yet build by "all"). Thu May 26 08:53:19 1994 Bill Cox (bill@rtl.cygnus.com) * config.sub: Move deletion of patch suffix from here... * configure.in: To here, at Ian's suggestion. The top- level scripts might need to know of a patch level. Wed May 25 09:15:54 1994 Bill Cox (bill@rtl.cygnus.com) * config.sub: Strip off patch suffix so rtl is recognized as a sunos4.1.3 machine, even though it's been patched. Fri May 20 08:25:49 1994 Steve Chamberlain (sac@deneb.cygnus.com) * Makefile.in (INSTALL_LAST): Delete. (INSTALL_DOSREL): New. Thu May 19 17:12:12 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in: Use ld for i[34]86-*-sysv4* and sparc-*-solaris2*. Don't set use_gnu_ld to no for *-*-sysv4; that only controls whether we pass down --with-gnu-ld anyhow. Thu May 19 09:29:12 1994 Steve Chamberlain (sac@cygnus.com) * Makefile.in (INSTALL_LAST): Change operation so it works on more flavors of make. * configure.in (go32): Don't build libg++ or libio. Fri May 13 13:28:34 1994 Steve Chamberlain (sac@cygnus.com) * Makefile.in (Move HOST_PREFIX_1 and friends up so they can be overriden by templates. Sat May 7 16:46:44 1994 Steve Chamberlain (sac@cygnus.com) * configure.in (target==go32): Don't build gdb. * dosrel: New directory. Fri May 6 14:19:25 1994 Steve Chamberlain (sac@cygnus.com) * configure.in (host==go32): Configure dosrel too. * Makefile.in (INTALL_TARGET): Call INSTALL_LAST last. (HOST_CC, HOST_PREFIX, HOST_PREFIX_1): Undefine, they should be set by incoming names or templates. (INSTALL_LAST): New rule. * config/mh-go32: New fragment. Thu May 5 17:35:05 1994 Stan Shebs (shebs@andros.cygnus.com) * config.sub (sparclitefrw, sparclitefrwcompat): Don't set the os. Thu May 5 20:06:45 1994 Ken Raeburn (raeburn@cujo.cygnus.com) * config/mh-lynxrs6k: Renamed from mh-lynxosrs6k, to make it unique in 8.3 naming schemes. * configure.in (appdirs): New variable. Currently empty, but will be used in gas distribution. If nonempty, lists a set of directories at least one of which must get configured, or top level configuration is considered to have failed. (rs6000-*-lynxos*): Use new file name. Thu May 5 13:38:36 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) Eliminate XTRAFLAGS. * Makefile.in (CC_FOR_TARGET): If newlib exists, refer to the newlib include files using -idirafter, and also use -nostdinc. (CXX_FOR_TARGET): Likewise. (XTRAFLAGS): Removed. (BASE_FLAGS_TO_PASS): Remove XTRAFLAGS_FOR_TARGET. (EXTRA_HOST_FLAGS): Remove XTRAFLAGS. (EXTRA_TARGET_FLAGS, EXTRA_GCC_FLAGS): Likewise. ($(DO_X)): Don't pass down XTRAFLAGS. Thu May 5 00:16:36 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) * configure.in (mips*-dec-bsd*): New target; do build linker. (mips*-*-bsd*): New target; don't build linker. Wed May 4 20:10:10 1994 D. V. Henkel-Wallace (gumby@cygnus.com) * configure.in: support rs6000-*-lynxos* configuration. support sunos4 as a cross target. * config.sub: look for lynx*, not lynx since the OS version may legitimately be part of the name. Tue May 3 21:48:11 1994 Ken Raeburn (raeburn@cujo.cygnus.com) * configure.in (i[34]86-*-sco*): Move to be with other i386 targets. (romp-*-*): New target. Skip various binary utilities. (vax-*-*): New target. Don't build newlib. (vax-*-vms): Renamed from *-*-vms. Don't build opcodes or newlib. Thu Apr 28 15:03:05 1994 David J. Mackenzie (djm@rtl.cygnus.com) * configure.in: Only set host_makefile_frag if config directory exists. Wed Apr 27 12:14:30 1994 David J. Mackenzie (djm@rtl.cygnus.com) * install.sh: If $dstdir exists, don't check whether each component does. Tue Apr 26 18:11:33 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * test-build.mk (HOLES): Add sleep; used by rcs/src/conf.sh. Mon Apr 25 15:06:34 1994 Stan Shebs (shebs@andros.cygnus.com) * configure.in (*-*-lynxos*): Don't configure newlib for either native or cross Lynx. Sat Apr 16 11:58:16 1994 Doug Evans (dje@canuck.cygnus.com) * config.sub (sparc64-elf): Fix os. (z8k): Remove duplicate. Thu Apr 14 23:33:17 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * Makefile.in (gcc-no-fixedincludes): Touch gcc/include/fixed, not gcc/stmp-fixproto, to try to prevent fixproto from being run. Wed Apr 13 15:14:52 1994 Bill Cox (bill@cygnus.com) * configure: Make file links cleanly even if Lynx fails on an NFS symlink (at least fail cleanly). Mon Apr 11 10:58:56 1994 Jim Wilson (wilson@sphagnum.cygnus.com) * test-build.mk (CC): For mips-sgi-irix4, change -XNh1500 to -XNh2000. Sat Apr 9 15:10:45 1994 David J. Mackenzie (djm@rtl.cygnus.com) * configure: Unknown options are fatal again. Fri Apr 8 12:01:41 1994 David J. Mackenzie (djm@cygnus.com) * configure: Ignore --x-includes and --x-libraries, for Autoconf compatibility. Thu Apr 7 17:31:43 1994 Doug Evans (dje@canuck.cygnus.com) * build-all.mk: Add `clean' target. Wed Apr 6 20:44:56 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * config.guess: Add SINIX support. * configure.in: Add mips-*-sysv4* support. Mon Apr 4 17:41:44 1994 Doug Evans (dje@canuck.cygnus.com) * build-all.mk: Document all useful targets. If canonhost is sparc-sun-solaris2.3, change it to sparc-sun-solaris2. If canonhost is mips-sgi-irix4.0.5H, change it to mips-sgi-irix4. Thu Mar 31 04:55:57 1994 David J. Mackenzie (djm@rtl.cygnus.com) * configure: Support --silent, --quiet. Wed Mar 30 21:37:38 1994 David J. Mackenzie (djm@rtl.cygnus.com) * configure: Support --disable-FEATURE. Tue Mar 29 19:15:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Recognize NCR running SVR4.3. Mon Mar 28 14:55:15 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Make BSDI generate i386-unknown-bsd386. Patch from Paul Eggert . Mon Mar 28 12:54:52 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in (powerpc-*-aix*): Treat like rs6000-*-*. Sat Mar 26 11:25:48 1994 David J. Mackenzie (djm@rtl.cygnus.com) * configure: Make unrecognized options give nonfatal warnings instead of fatal errors, and pass them to any subdirectory configures in case they recognize them. Make --x equivalent to --with-x. Fri Mar 25 21:52:10 1994 David J. Mackenzie (djm@rtl.cygnus.com) * configure: Add --enable-* options. Clean up usage message and some comments. Thu Mar 24 09:12:53 1994 Doug Evans (dje@canuck.cygnus.com) * Makefile.in (NM_FOR_TARGET): Build tree version is now nm.new. Sun Mar 20 11:28:22 1994 Jeffrey A. Law (law@snake.cs.utah.edu) * configure.in (hppa*-*-*): Enable binutils. Sat Mar 19 11:50:16 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * config.sub: Recognize cisco. Fri Mar 18 16:42:32 1994 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (CXXFLAGS): Add -fexternal-templates. Tue Mar 15 11:25:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: about target *-hitachi-hiuxwe2, don't print more than one configuration name. Add comment. Sun Mar 6 23:13:38 1994 Hisashi MINAMINO (minamino@sra.co.jp) * config.guess: about target *-hitachi-hiuxwe2, fixed machine guessing order. [Hitachi's CPU_IS_HP_MC68K macro is incorrect.] Sun Mar 13 09:10:08 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in (TAGS): Just build TAGS in each subdirectory, rather than the "make ls" stuff which used to be here. Fri Mar 11 12:52:39 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Recognize i[34]86-unknown-freebsd. From Shawn M Carey . Thu Mar 3 14:24:21 1994 Per Bothner (bothner@kalessin.cygnus.com) * configure.in (noconfigdirs for alpha): Remove libg++ and libio. Wed Mar 2 13:28:48 1994 Jim Kingdon (kingdon@deneb.cygnus.com) * config.guess: Check for ptx. Mon Feb 28 16:46:50 1994 Kung Hsu (kung@mexican.cygnus.com) * config.sub: Add os9k checking. Thu Feb 24 07:09:04 1994 Jeffrey A. Law (law@snake.cs.utah.edu) * config.guess: Handle OSF1 running on HPPA processors Fri Feb 18 14:14:00 1994 Ken Raeburn (raeburn@rtl.cygnus.com) * configure: If subdir configure fails, print out a message with subdirectory name, in case subdir's configure code didn't identify itself. Fri Feb 18 12:50:15 1994 Doug Evans (dje@cygnus.com) * configure.in: Remove embedded newlines from configdirs. Avoid mismatches of substrings. Fix matching strings at end of configdirs. Fri Feb 11 15:33:33 1994 Stu Grossman (grossman at cygnus.com) * config.guess: Add Lynx/rs6000 config support. Tue Feb 8 13:41:09 1994 Ken Raeburn (raeburn@rtl.cygnus.com) * configure.in (alpha-dec-osf1*, alpha*-*-*): Build gas. Mon Feb 7 15:42:36 1994 Jeffrey A. Law (law@cygnus.com) * configure.in (hppa*-*-osf*): Treat this just like most other PA configurations (eg no binutils or ld). (hppa*-*-*elf*): These configurations have binutils and ld. Sun Feb 6 16:35:07 1994 Jeffrey A. Law (law@snake.cs.utah.edu) * config.sub (hiux): Fix typo. From m-kasahr@sramhc.sra.co.JP. Sat Feb 5 01:00:33 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in (rs6000-*-*): Build gas. Wed Feb 2 13:57:57 1994 Jeffrey A. Law (law@snake.cs.utah.edu) * Makefile.in: Avoid bug in losing hpux sed. Wed Feb 2 14:53:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in, test-build.mk: Remove MUNCH_NM; it was only needed for GDB and GDB has been fixed to not need it. Mon Jan 31 18:40:55 1994 Stu Grossman (grossman at cygnus.com) * config/mh-lynxosrs6k: Account for lack of ranlib! Sun Jan 30 17:58:06 1994 Ken Raeburn (raeburn@cujo.cygnus.com) * config.guess: Recognize vax hosts. Fri Jan 28 15:29:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com) * configure (while loop): Don't use "break 2" inside case statement -- the case statement isn't an enclosing loop. Mon Jan 24 18:40:06 1994 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Clean up NeXT support, to allow nextstep on Intel machines. Make OS be nextstep. Sun Jan 23 18:47:22 1994 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) * config.guess: Add alternate forms for Convex. Thu Jan 20 16:13:41 1994 Stu Grossman (grossman at cygnus.com) * configure: Completely rewrite option processing. Take advantage of pattern-matching to avoid invoking test frequently. Also clean up host and target defaulting logic. Mon Jan 17 15:06:56 1994 Ken Raeburn (raeburn@cujo.cygnus.com) * Makefile.in: Replace all occurrances of "rootme" with "r" and "$${rootme}" with "$$r", to increase the likelihood that the do-* commands (plus user environment) will fit SCO limits. Thu Jan 6 11:20:57 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in: Don't issue warnings about directories which are not being configured if -norecursion is set. Correct test for --with-gnu-as and --with-gnu-ld to not get confused by substring matches. * configure.in: Don't build gas for alpha-dec-osf1*. Tue Jan 4 17:10:19 1994 Stu Grossman (grossman at cygnus.com) * configure: Back out Per's change of 12/19/1993. It changes the behavior of configure in unexpected and confusing ways. Also, use different delim char when calculating program_transform_name so that the name can contain slashes. Sat Jan 1 13:45:31 1994 Rob Savoye (rob@darkstar.cygnus.com) * configure.in, config.sub: Add support for VSTa micro-kernel. Sat Dec 25 20:00:47 1993 Jeffrey A. Law (law@snake.cs.utah.edu) * configure.in: Nuke hacks which were used to get a special version of GAS for HPPA configurations. Sun Dec 19 20:40:44 1993 Per Bothner (bothner@kalessin.cygnus.com) * configure: If only ${target_alias} is given, use that as the default for ${host_alias}. * configure: Add missing back-slashes before nested quotes. Wed Dec 15 18:07:18 1993 david d `zoo' zuhn (zoo@andros.cygnus.com) * Makefile.in (BASE_FLAGS_TO_PASS): add YACC=$(BISON) Tue Dec 14 21:25:33 1993 Per Bothner (bothner@cygnus.com) * config.guess: Recognize some Tektronix configurations. From Kaveh R. Ghazi . Sat Dec 11 11:18:00 1993 Steve Chamberlain (sac@thepub.cygnus.com) * config.sub: Match any flavor of SH. Thu Dec 2 17:16:58 1993 Ken Raeburn (raeburn@cujo.cygnus.com) * configure.in: Don't try to configure newlib for Alpha. Thu Dec 2 14:35:54 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in: Don't build ld for Irix 5. Don't build gas, libg++ or libio for any Alpha target. * configure.in (mips*-sgi-irix5*): New target; use mh-irix5. * config/mh-irix5. New file for Irix 5. Wed Dec 1 17:00:33 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (GZIPPROG): Renamed from GZIP, which gzip uses for default arguments -- so it tried to compress itself. Tue Nov 30 13:45:15 1993 david d `zoo' zuhn (zoo@andros.cygnus.com) * configure.in (notsupp): ensure that a space is always at the end of the configdirs list, since the grep checks for an explicit space Tue Nov 16 15:04:27 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in (target i386-sysv4.2): don't build ld, since static versions of many libraries are not available. Tue Nov 16 14:28:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Recognize Apollos (using environment variables). * configure.in: Don't configure ld, binutils, or gprof for Apollo. Thu Nov 11 12:03:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Recognize Sony news mips running newsos. Wed Nov 10 16:57:00 1993 Mark Eichin (eichin@cygnus.com) * Makefile.in (all-cygnus, build-cygnus): "fi else" needs to be "fi ; else" for bash. Tue Nov 9 15:54:01 1993 Mark Eichin (eichin@cygnus.com) * Makefile.in (BASE_FLAGS_TO_PASS): pass SHELL. Fri Nov 5 08:07:27 1993 D. V. Henkel-Wallace (gumby@blues.cygnus.com) * config.sub: accept unixware as an alias for svr4.2. Fix some inconsistancies with the gcc version. Fri Nov 5 15:14:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in (DISTDOCDIRS): Add gdb. Fri Nov 5 11:59:42 1993 Per Bothner (bothner@kalessin.cygnus.com) * Makefile.in (DISTDOCDIRS): Add libg++ and libio. Fri Nov 5 10:35:05 1993 Ken Raeburn (raeburn@rover.cygnus.com) * Makefile.in (taz): Only build "info" in DISTDOCDIRS. (DISTDOCDIRS): Don't assume libg++ and gdb folks necessarily want this now. Thu Nov 4 18:58:23 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.sub: Accept hiux* as an OS name. * Makefile.in: Change RUNTEST_FLAGS back to RUNTESTFLAGS per etc/make-stds.texi. The underscore came from gcc, and dje now agrees that RUNTESTFLAGS is the correct name. Thu Nov 4 10:49:01 1993 Per Bothner (bothner@kalessin.cygnus.com) * install.sh: Remove 'set -e'. It makes any conditionals in the script useless. * config.guess: Automatically recognize arm-acorn-riscix Patch from Richard Earnshaw (rwe11@cl.cam.ac.uk). Thu Nov 04 08:08:04 1993 Jeffrey Wheat (cassidy@cygnus.com) * Makefile.in: Change RUNTESTFLAGS to RUNTEST_FLAGS Wed Nov 3 22:09:46 1993 Ken Raeburn (raeburn@rtl.cygnus.com) * Makefile.in (DISTDOCDIRS): New variable. (taz): Edit local Makefile.in sooner, instead of proto-toplev Makefile.in later. Build "info" and "dvi" in DISTDOCDIRS. Wed Nov 3 21:31:52 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in (hppa target): check the source directory for the pagas sub-directory Wed Nov 3 11:12:22 1993 Doug Evans (dje@canuck.cygnus.com) * config.sub: Allow -aout* and -elf*. Wed Nov 3 11:08:33 1993 Ken Raeburn (raeburn@rtl.cygnus.com) * configure.in: Don't build ld on i386-solaris2, same as for sparc-solaris2. Tue Nov 2 14:21:25 1993 Per Bothner (bothner@kalessin.cygnus.com) * Makefile.in (taz): Add texinfo/lgpl.texinfo (for libg++). Tue Nov 2 13:38:30 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * configure.in: Configure gdb for alpha. Mon Nov 1 10:42:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in (CXXFLAGS): Add -O. Wed Oct 27 10:45:06 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * config.guess: added support for DG Aviion Tue Oct 26 14:37:37 1993 Ken Raeburn (raeburn@rover.cygnus.com) * configure.in: Produce warning message for subdirectories not configurable for this host/target combination. Don't try to configure gdb for vms. Mon Oct 25 11:22:15 1993 Ken Raeburn (raeburn@rover.cygnus.com) * Makefile.in (taz): Replace "byacc" with "bison -y" in the appropriate files before making "diststuff". (DISTBISONFILES): New var: list of files to be edited. (DISTSTUFFDIRS): Add binutils. Fri Oct 22 20:32:15 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * config.sub: also handle mipsel and mips64el (for little endian mips) Fri Oct 22 07:59:20 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in: Add * to end of all OS names. Thu Oct 21 11:38:28 1993 Stan Shebs (shebs@rtl.cygnus.com) * configure.in: Build newlib for LynxOS native. Wed Oct 20 09:56:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Add support for delta 88k running SVR3. * configure.in: Add comment about HP compiler vs. emacs. Tue Oct 19 16:02:22 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in: don't build ld on solaris2 (not a viable option due to bugs in getpwnam & getpwuid) Tue Oct 19 15:13:56 1993 Ken Raeburn (raeburn@rtl.cygnus.com) * configure.in: Accept alpha-dec-osf1*, not just -osf1, since config.guess will produce a full version number. Tue Oct 19 15:58:01 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in: Build linker and binutils for alpha-dec-osf1. Tue Oct 19 11:41:55 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in: Remove -O from CXXFLAGS for consistency with CFLAGS, and gdb/testsuite/Makefile.in. Sat Oct 9 18:39:07 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in: recognize mips*- instead of mips- Fri Oct 8 14:15:39 1993 Ken Raeburn (raeburn@cygnus.com) * config.sub: Accept linux*coff and linux*elf as operating systems. Thu Oct 7 12:57:19 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * config.sub: Recognize mips64, and mips3 as an alias for it. Wed Oct 6 13:54:21 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * configure.in: Remove alpha-dec-osf*, no longer necessary now that gdb knows how to handle OSF/1 shared libraries. Tue Oct 5 11:55:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in: Recognize hppa*-*-hiux* (currently synonym for hpux). * config.guess: Recognize Hitachi's HIUX. * config.sub: Recognize h3050r* and hppahitachi. Remove redundant cases for hp9k[23]*. Mon Oct 4 16:15:09 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in: default to '--with-gnu-as' and '--with-gnu-ld' if gas and ld are in the source tree and are in ${configdirs}. If ${use_gnu_as} or ${use_gnu_ld} are 'no', then don't set the the --with options (but still pass them down on the command line, if they were explicitly specified). Fri Sep 24 19:11:13 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure: substitute SHELL value in Makefile.in with ${CONFIG_SHELL} Thu Sep 23 18:05:13 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * configure.in: Build gas, ld, and binutils for *-*-sysv4* and *-*-solaris2* targets. Sun Sep 19 17:01:41 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * Makefile.in: define M4, and pass it down to sub-makes; all-autoconf now depends on all-m4 Sat Sep 18 00:38:23 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * Makefile.in ({AR,RANLIB}_FOR_TARGET): make contingent on presence of {ar,ranlib} instead of a configured directory Wed Sep 15 08:41:44 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) * config.guess: Accept 34?? as well as 33?? for NCR. Mon Sep 13 12:28:43 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in: grab mt-hppa for HPPA targets; use 'gas ' instead of 'gas' in sed commands, since 'gash' is now in the tree as well. Fri Sep 10 11:23:52 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure: grab values for $(CC) and $(CXX) from the environment, so that someone can do "CC=gcc configure; make" and have it work right (matching the way that autoconf works now) * configure.in, Makefile.in: add support for gash, the tcl interface to Galaxy * config.guess: add NetBSD variants (hp300, x86) Thu Sep 9 16:48:52 1993 Jason Merrill (jason@deneb.cygnus.com) * install.sh: Support -d option (in the manner of SunOS 4 install, as it is more deterministic than that of GNU install) (chmodcmd): Set file to mode 755 by default (should also do default chgrp and chown, but I don't feel like dealing with that now) Tue Sep 7 11:59:39 1993 Doug Evans (dje@canuck.cygnus.com) * config.sub: Remove h8300hhms alias. Tue Aug 31 11:00:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in: Match *-*-solaris2* not *-sun-solaris2*. Mon Aug 30 18:29:10 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * Makefile.in (gcc-no-fixedincludes): touch stmp-fixproto as well as stmp-fixinc Wed Aug 25 16:35:59 1993 K. Richard Pixley (rich@sendai.cygnus.com) * config.sub: recognize m88110-bug-coff. Tue Aug 24 10:23:24 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * Makefile.in (all-libio): all dependencies on the toolchain used to build this (gcc, gas, ld, etc) Fri Aug 20 17:24:24 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Deal with OSF/1 1.3 on alpha. Thu Aug 19 11:43:04 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * install.sh: add some 'else true' clauses for portability * configure.in: don't build libio for h8[35]00-*-* targets Tue Aug 17 19:02:31 1993 Per Bothner (bothner@kalessin.cygnus.com) * Makefile.in: Add support for new libio. Sun Aug 15 20:48:55 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * install.sh: If one command fails, don't try the rest. Don't try to remove $dsttmp (via trap) unless we have already created it. If $src doesn't exist, detect it and exit with an error. * config.guess: Recognize BSD on hp300. Wed Aug 11 18:35:13 1993 Per Bothner (bothner@kalessin.cygnus.com) * config.guess: Map (9000/[34]??:HP-UX:*:*) to m68k-hp-hpux. Bug report from "Hamish (H.I.) Macdonald" . Wed Aug 11 15:37:51 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (all-send-pr): depends on all-gnats Wed Aug 11 16:56:03 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Fix typo (9000/8??:4.3bsd -> 9000/7??:4.3bsd). Fri Aug 6 14:45:02 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * config.guess: From michael@mercury.cs.mun.ca (Michael Rendell): Added test for mips-mips-riscos5. Thu Aug 5 15:45:08 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure.in: use mh-hp300 for 68k HP hosts Mon Aug 2 11:56:53 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * configure: add support for CONFIG_SHELL, so that you can use some alternate shell for evaluating configure scripts Sun Aug 1 11:36:27 1993 Fred Fish (fnf@deneb.cygnus.com) * Makefile.in (make-gdb.tar.gz): Sed bug reporting address in configure script to bug-gdb@prep.ai.mit.edu when building distribution archive. * Makefile.in (COMPRESS): Remove def. * Makefile.in (gdb.tar.gz, make-gdb.tar.gz): Renamed from gdb.tar.Z and make-gdb.tar.Z respectively. * Makefile.in (make-gdb.tar.gz): Now only build gzip'd archive. * Makefile.in (make-gdb.tar.gz): Minor changes to move closer to convergence with 'taz' target in Makefile.in. Fri Jul 30 12:34:57 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * install.sh (dsttmp): use trap to ensure that tmp files go away on error conditions Wed Jul 28 11:57:36 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * Makefile.in (BASE_FLAGS_TO_PASS): remove LOADLIBES Tue Jul 27 12:43:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * Makefile.in (install-dirs): Deal with a prefix like /gnu; its parent is '/' not ''. * Makefile.in (DEVO_SUPPORT): Add comments about ChangeLog. Fri Jul 23 09:53:37 1993 Jason Merrill (jason@wahini.cygnus.com) * configure: if ${newsrcdir}/configure doesn't exist, don't assume that ${newsrcdir}/configure.in does. Tue Jul 20 11:28:50 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * test-build.mk: support for CONFIG_SHELL Mon Jul 19 21:54:46 1993 Fred Fish (fnf@deneb.cygnus.com) * config.sub (netware): Add as a basic system type. Wed Jul 14 12:03:11 1993 K. Richard Pixley (rich@sendai.cygnus.com) * Makefile.in (Makefile): depend on configure.in. Also drop the $(srcdir)/ from the dependency on Makefile.in. Tue Jul 13 20:10:58 1993 Doug Evans (dje@canuck.cygnus.com) * config.sub: Recognize h8300hhms as h8300h-hitachi-hms. (h8300hhms is temporary until multi-libraries are implemented). * configure.in: Handle h8300h too. Sun Jul 11 17:35:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Recognize dpx/2 as m68k-bull-sysv3. Thu Jul 8 18:26:12 1993 John Gilmore (gnu@cygnus.com) * configure: Remove extraneous output when guessing host type. * config.guess: Remove extraneous output when guessing using C compiler rather than uname, or when guessing fails. Wed Jul 7 17:58:14 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) * Makefile.in: remove all.cross and install.cross targets * configure: remove CROSS=-DCROSS_COMPILE and ALL=all.cross definitions Tue Jul 6 10:39:44 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) * configure.in (target sh): Build gprof. Thu Jul 1 16:52:56 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config.sub: change -solaris to -solaris2 Thu Jul 1 15:46:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in: Use config/mh-riscos for mips-*-sysv*. Wed Jun 30 09:31:58 1993 Ian Lance Taylor (ian@cygnus.com) * configure: Correct error message for missing Makefile.in to print correct directory. Tue Jun 29 13:52:16 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * install.sh: kludge around 386BSD shell bug Tue Jun 29 13:06:49 1993 Per Bothner (bothner@rtl.cygnus.com) * config.guess: Recognize NeXT. * config.guess: Recognize i486-ncr-sysv4. * Makefile.in (taz): rm $(TOOL)-$$VER before linking. Tue Jun 29 12:50:57 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (MAKEINFOFLAGS): New variable. (FLAGS_TO_PASS): Pass MAKEINFO as MAKEINFO MAKEINFOFLAGS. * build-all.mk, test-build.mk: Pass down --no-split as MAKEINFOFLAGS when hosted on DOS. Compile DOS hosted without -g. Thu Jun 24 13:39:11 1993 Per Bothner (bothner@rtl.cygnus.com) * Makefile.in (DEVO_SUPPORT): Add COPYING COPYING.LIB install.sh. Wed Jun 23 12:59:21 1993 Per Bothner (bothner@rtl.cygnus.com) * Makefile.in (libg++.tar.z): New rule. * Makefile.in (taz): Replace 'configure -rm' by 'make distclean'. * Makefile.in (taz): Only do a single chmod. Fri Jun 18 12:03:10 1993 david d `zoo' zuhn (zoo at majipoor.cygnus.com) * install.sh: don't use dirname anymore (replaced with sed usage) Thu Jun 17 18:43:42 1993 Fred Fish (fnf@cygnus.com) * Makefile.in: Change extension for gzip'd files from '.z' to '.gz' per new FSF standard usage. Thu Jun 17 16:58:50 1993 david d `zoo' zuhn (zoo at majipoor.cygnus.com) * configure: put quotes around the final value of program_transform_name Tue Jun 15 16:48:51 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: new install.sh support; update install-info rules Wed Jun 9 12:31:34 1993 Ian Lance Taylor (ian@cygnus.com) * configure.in: Build diff for crosses, but not for go32 host. * configure.in: Build gprof only for native, and don't build it for mips-*-*, rs6000-*-*, or i[34]86-*-sco*. Mon Jun 7 13:12:11 1993 david d `zoo' zuhn (zoo at deneb.cygnus.com) * configure.in: don't build gas,ld,binutils on for *-*-sysv4 Mon Jun 7 11:40:11 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * configure.in (host_tools): Add gnats. Fri Jun 4 13:30:42 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: install gcc, do installation of $(INSTALL_MODULES) with $(FLAGS_TO_PASS) on the command line * config.sub: Recognize lynx and lynxos Fri Jun 4 10:59:56 1993 Ian Lance Taylor (ian@cygnus.com) * config.sub: Accept -ecoff*, not just -ecoff. Thu Jun 3 17:38:54 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * Makefile.in (taz): Use .gz suffix instead of .z. (binutils.tar.gz, gas+binutils.tar.gz, gas.tar.gz): Fixed target names. Thu Jun 3 00:27:06 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in (vault-install): add an 'else true' (for Ultrix) Wed Jun 2 18:19:16 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in (install-no-fixedincludes): install gcc last, so that rebuilds that might happen during 'make install' don't get bogus gcc include files Wed Jun 2 16:14:10 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) Change from Utah for HPPA support: * config.guess: Recognize hppa1.x-hp-bsd. Wed Jun 2 11:53:33 1993 Per Bothner (bothner@rtl.cygnus.com) * config.guess: Add support for Motorola Delta 68k, up to r3v7. Patch from pot@fly.cnuce.cnr.it (Francesco Potorti`). Tue Jun 1 17:48:42 1993 Rob Savoye (rob at darkstar.cygnus.com) * config.sub: Add support for rom68k and bug boot monitors. Mon May 31 09:36:37 1993 Jim Kingdon (kingdon@cygnus.com) * Makefile.in: Make all-opcodes depend on all-bfd. Thu May 27 08:05:31 1993 Ian Lance Taylor (ian@cygnus.com) * config.guess: Added special check for i[34]86-univel-sysv4*. Wed May 26 16:33:40 1993 Ian Lance Taylor (ian@cygnus.com) * config.guess: For i[34]86-unknown-sysv4 use UNAME_MACHINE for the processor rather than assuming i486. Wed May 26 09:40:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * config.guess: Recognize SunOS6 as Solaris3. Tue May 25 23:03:11 1993 Per Bothner (bothner@cygnus.com) * config.guess: Fix typo. Avoid #elif (not in K&R 1). Recognize SunOS 5.* only (and not [6-9].*) as being Solaris2. Tue May 25 12:44:18 1993 Ian Lance Taylor (ian@cygnus.com) * build-all.mk (all-cross): New target for Canadian Cross. Added Q2 go32 targets. * test-build.mk: Configure go32 cross sparclite-aout and mips-idt-ecoff -with-gnu-ld. Moved build binary directory from PARTIAL_HOLE_DIRS to BUILD_HOLES_DIRS. Mon May 24 15:30:06 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: fix Alpha GDB typo; also, don't build DejaGnu for GO32 hosted toolchains Mon May 24 14:18:41 1993 Rob Savoye (rob at darkstar.cygnus.com) * configure: change so "-exec-prefix" gets passed down rather than "-exec_prefix" so autoconf generated Makefiles get the exec_prefix set right. Fri May 21 10:42:25 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config.guess: get the Solaris2 minor version number * Makefile.in: add standards.texi and make-stds.texi to ETC_SUPPORT Fri May 21 06:20:52 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * config.guess: Recognize some Sequent platforms. Thu May 20 14:33:48 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: added the vault-install target * configure.in: actually use the Sun3 makefile fragment that's in config, also added the release dir to configdirs Thu May 20 14:19:18 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * Makefile.in (taz): Fix modes on stuff in $(TOOL) dir also. Tue May 18 20:26:41 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: remove some program from Alpha targetted toolchains Tue May 18 15:23:19 1993 Ken Raeburn (raeburn@cygnus.com) * Makefile.in (DISTSTUFFDIRS): Renamed from PROTODIRS. Add ld and gprof. (taz): Run "make diststuff" in those directories instead of "make proto-dir". Look for "VERSION=" only at start of line in subdir Makefile. Use "gzip -9" for compression. (TEXINFO_SUPPORT, DIST_SUPPORT, BINUTILS_SUPPORT_DIRS): New vars. (binutils.tar.z): New target. Mon May 17 17:01:15 1993 Ken Raeburn (raeburn@deneb.cygnus.com) * Makefile.in (taz): Include gpl.texinfo. Fri May 14 06:48:38 1993 Ken Raeburn (raeburn@deneb.cygnus.com) * Makefile.in (setup-dirs): Merged into "taz" target. (taz): Only do `proto-dir' stuff if a directory is actually needed for this target. Wed May 12 13:09:44 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (MUNCH_NM): New variable, defined to be $(NM). (FLAGS_TO_PASS): Pass down MUNCH_NM. (HOST_CC, HOST_PREFIX, HOST_PREFIX_1): New variables. (EXTRA_GCC_FLAGS): Pass down HOST_* variables. (gcc-no-fixedincludes): Correct for current gcc Makefile. Tue May 11 10:14:25 1993 Fred Fish (fnf@cygnus.com) * Makefile.in (make-gdb.tar.Z): Add configure, config.guess, config.sub, and move-if-change to gdb testsuite distribution archive, so the testsuite can be extracted, configured, and run separately from the gdb distribution. Blow away the Chill tests that require a Chill compiled executable, since GNU Chill is not yet publically available. Mon May 10 17:22:26 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * test-build.mk: set environment variables in a single command, instead of a list of assignments and exports * config.guess: recognize Alpha/OSF1 systems Mon May 10 14:55:51 1993 K. Richard Pixley (rich@rtl.cygnus.com) * configure: Change help message to prefer --options rather than -options. Mon May 10 05:58:35 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) * config.sub: Convergent Tech. "miniframe" uses m68010, sez zippy@ecst.csuchico.edu. * config.guess: Recognize miniframe. Sun May 9 17:47:57 1993 Rob Savoye (rob at darkstar.cygnus.com) * Makefile.in: Use srcroot to find runtest rather than rootme. Pass RUNTESTFLAGS and EXPECT down in BASE_FLAGS_TO_PASS. Fri May 7 14:55:59 1993 Ian Lance Taylor (ian@cygnus.com) * test-build.mk: Extensive additions to support building on a machine other than the host. Wed May 5 08:35:04 1993 Ken Raeburn (raeburn@deneb.cygnus.com) * configure (tooldir): Fix for i386-aix again. Mon May 3 19:00:27 1993 Per Bothner (bothner@cygnus.com) * configure, Makefile.in: Change definition of $(tooldir) to match the FSF. Fri Apr 30 15:55:21 1993 Fred Fish (fnf@cygnus.com) * config.guess: Recognize i[34]86/SVR4. Fri Apr 30 15:52:46 1993 Steve Chamberlain (sac@thepub.cygnus.com) * Makefile.in (all-gdb): gdb depends on sim. Thu Apr 29 23:30:48 1993 Fred Fish (fnf@cygnus.com) * Makefile.in (gdb.tar.Z): Make prototype gdb testsuite directory at the same time we make the prototype gdb directory. * Makefile.in (make-gdb.tar.Z): Make the testsuite distribution files at the same time as the gdb base release distribution. Thu Apr 29 12:50:37 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (check): Use individual check targets rather than DO_X rule. (check-gcc): Added. Thu Apr 29 09:50:07 1993 Jim Kingdon (kingdon@cygnus.com) * config.sub: Use sysv3.2 not sysv32 for canonical OS for System V release 3.2. Thu Apr 29 10:33:22 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * config.sub: Recognize hppaosf. * configure.in: Do configure ld/binutils/gas for it. Tue Apr 27 06:25:34 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) * configure (tooldir): Alter syntax used to set this, for systems where "\$" isn't handled right, like i386-aix. Thu Apr 22 08:17:35 1993 Ian Lance Taylor (ian@cygnus.com) * configure: Pass program-transform-name, not program_transform_name, to recursive configures. Thu Apr 22 02:58:21 1993 Ken Raeburn (raeburn@cygnus.com) * Makefile.in (gas+binutils.tar.z): New rule for building snapshots of gas+ld+binutils. Mon Apr 19 17:41:30 1993 Per Bothner (bothner@cygnus.com) * config.guess: Recognize AIX3.2 as distinct from 3.1. Sat Apr 17 17:19:50 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: rename m88k-motorola-m88kbcs to m88k-motorola-sysv * config/mh-delta88: remove extraneous GCC references Tue Apr 13 16:52:16 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (GNATS): Set back to all-gnats. Sat Apr 10 12:04:07 1993 Ian Lance Taylor (ian@cygnus.com) * test-build.mk: Pass -with-gnu-as for known MIPS native and MIPS targets, rather than for MIPS hosts. Fri Apr 9 13:51:06 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: add comment for --with-x default values * config.guess: handle Motorola Delta88 box for SVR3 and SVR4. * Makefile.in: add check-* targets for each of the directories in the tree. Add a definition of RUNTEST that will use the one we just built, if it exists. Pass this down via FLAGS_TO_PASS. Thu Apr 8 09:21:30 1993 Ian Lance Taylor (ian@cygnus.com) * configure.in: Removed obsolete references to bfd_target and target_makefile_frag. * build-all.mk: Set assorted targets for Q2. * config.sub: Recognize z8k-sim and h8300-hms. * test-build.mk: Really don't pass host to configure. (HOLES): Added uname. Wed Apr 7 15:48:19 1993 Ian Lance Taylor (ian@cygnus.com) * configure: Handle an empty program-prefix, program-suffix or program-transform-name correctly. Tue Apr 6 13:48:41 1993 Ian Lance Taylor (ian@cygnus.com) * build-all.mk: -G 8 no longer required for MIPS targets. * test-build.mk: Don't pass host argument to configure; make it guess. Tue Apr 6 10:36:53 1993 Fred Fish (fnf@cygnus.com) * Makefile.in (gdb.tar.Z): Fix for building gzip'd distribution. * Makefile.in (COMPRESS): New macro, like GZIP. Fri Apr 2 09:02:31 1993 Ian Lance Taylor (ian@cygnus.com) * test-build.mk: Use -with-gnu-as for mips-sgi-irix4 as well. * build-all.mk: Set GCC to gcc -O -G 8 for MIPS targets, since gcc with gas currently defaults to -G 0. Thu Apr 1 08:25:42 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (all-flex): flex depends on byacc. * build-all.mk: If host not specified, use config.guess. Pass TAG to test-build.mk as RELEASE_TAG. * test-build.mk (configargs): New variable containing arguments to pass to configure. Set to -with-gnu-as on mips-dec-ultrix. (FLAGS_TO_PASS): Pass down RELEASE_TAG. * config.guess: Use /bin/uname when checking -X argument on SCO, to avoid invoking GNU uname which doesn't understand -X. * test-build.mk: Don't use /usr/unsupported/bin/as on AIX. * configure.in: Build gas for mips-*-*. Wed Mar 31 21:20:58 1993 K. Richard Pixley (rich@rtl.cygnus.com) * Makefile.in (all.normal): insert missing backslash. Wed Mar 31 12:31:56 1993 Ian Lance Taylor (ian@cygnus.com) * build-all.mk, config/mh-irix4: Bump -XNh value to 1500 to match gcc requirements. * Makefile.in: Complete overhaul to merge many almost identical targets. Tue Mar 30 20:17:01 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * Makefile.in (setup-dirs-gdb): Renamed from setup-dirs. (gdb.tar.Z): Adjusted. * Makefile.in (setup-dirs, taz): New targets; should be general enough to adapt for gdb sometime. Build only .z file. (gas.tar.z): New target. Tue Mar 30 10:03:09 1993 Ian Lance Taylor (ian@cygnus.com) * build-all.mk: Use CC=cc -Xs on Solaris. Mon Mar 29 19:59:26 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config/mh-sun3: cc needs -J to compile cp-parse.c correctly * config/mh-solaris: SunPRO C needs -Xs to be able to get a working xmakefile for Emacs. Thu Mar 25 15:14:30 1993 Fred Fish (fnf@cygnus.com) * Makefile.in: Incorporate changes suggested by wilson@cygnus.com for handling BISON for FSF releases. Thu Mar 25 06:19:48 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) * configure: Actually implement the change zoo just documented. Wed Mar 24 13:02:44 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) * configure: when using config.guess, only set target_alias when it's not already been set (ie, on the command line) Mon Mar 22 23:07:39 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: add installcheck target, set GNATS to install-gnats Sun Mar 21 16:46:12 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure: add support for package_makefile_fragment, handle the case where a directory has a configure.in file but no Makefile.in more gracefully (with an actual understandable error message, even); add support for --without (and add this to the usage message); also explicitly add a --host=${host_alias} to the command line when config.guess is used Sun Mar 21 12:11:58 1993 Jim Wilson (wilson@sphagnum.cygnus.com) * configure: Must use both --host and --target in recursive calls. Thu Mar 18 12:31:35 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: Change deja-gnu to dejagnu. Mon Mar 15 15:44:35 1993 Ian Lance Taylor (ian@cygnus.com) * configure.in (h8300-*-*, h8500-*-*): Don't build libg++. Fri Mar 12 18:30:14 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: canonicalize all instances to *-*-solaris2*, also strip out a number of tools to not build for go32 host Wed Mar 10 12:08:27 1993 K. Richard Pixley (rich@rtl.cygnus.com) * config.guess: add GPL. * Makefile.in, config.guess, config.sub, configure: bump copyrights to 93. Wed Mar 10 07:12:48 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (do-info): Removed obsolete check for existence of localenv file. * Makefile.in (MAKEOVERRIDES): Define to be empty. Wed Mar 10 03:11:56 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: a couple of 'else true' for decstation, support for TclX * configure.in: configure tclX too; don't remove Tk on RS/6000 anymore Tue Mar 9 16:06:12 1993 K. Richard Pixley (rich@cygnus.com) * Makefile.in (setup-dirs): change invocation of make to $(MAKE). Mon Mar 8 14:52:11 1993 Ken Raeburn (raeburn@cambridge) * config.guess: Recognize i386-ibm-aix (PS/2). * configure.in: Use config/mh-aix386 file for it. Mon Mar 8 11:12:43 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (GCC_FOR_TARGET): Eliminated definition; use CC_FOR_TARGET instead. (BASE_FLAGS_TO_PASS): Pass GCC_FOR_TARGET=$(CC_FOR_TARGET). Wed Mar 3 16:00:28 1993 Steve Chamberlain (sac@ok.cygnus.com) * Makefile.in: Add sim to list of directories sent with gdb Wed Mar 3 11:42:39 1993 Ken Raeburn (raeburn@cygnus.com) * configure.in: Put back mips-dec-bsd* case. Tue Mar 2 21:15:58 1993 Fred Fish (fnf@cygnus.com) (Ultrix 2.2 support from Michael Rendell ) * configure.in (vax-*-ultrix2*): Add Ultrix 2.2 triplet. * config.guess: Change 'VAX*:ULTRIX:*:*' to 'VAX*:ULTRIX*:*:*'. * config/mh-vaxult2: New file. Tue Mar 2 18:11:03 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: remove no-op mips-dec-bsd* in "case $target" * Makefile.in (dir.info): only run gen-info-dir if it exists, (install-info): install dir.info only if it exists, (all-expect, install-expect): pass along X11_FLAGS_TO_PASS Tue Mar 2 09:01:30 1993 Ken Raeburn (raeburn@cygnus.com) * configure.in: For vms target, skip bfd, ld, binutils. Do build gas for mips-dec-bsd. Tue Mar 2 08:35:24 1993 Ian Lance Taylor (ian@cygnus.com) * configure (makesrcdir): If ${srcdir} is relative and not ".", and ${subdir} is not ".", set makesrcdir based on ${invsubdir}. Tue Feb 23 14:18:28 1993 Mike Werner (mtw@poseidon.cygnus.com) * configure.in: Added "dejagnu" to hosttools list. Mon Feb 22 23:28:38 1993 Per Bothner (bothner@rtl.cygnus.com) * config.sub, configure.in, config.guess: Add support for Bosx, an AIX variant from Bull. Patches from F.Pierresteguy@frcl.bull.fr. Sun Feb 21 11:15:22 1993 Mike Werner (mtw@poseidon.cygnus.com) * devo/dejagnu: Initial creation of devo/dejagnu. Migrated dejagnu testcases and support files for testing software tools to reside as subdirectories, currently called "testsuite", within the directory of the software tool. Migrated all programs, support libraries, etc. beloging to dejagnu proper from devo/deja-gnu to devo/dejagnu. These files were moved "as is" with no modifications. The changes to these files which will allow them to configure, build, and execute properly will be made in a future update. Fri Feb 19 20:19:39 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in: Change send_pr to send-pr. * configure.in: Likewise. * send_pr: Renamed directory to send-pr. Fri Feb 19 19:00:13 1993 Per Bothner (bothner@cygnus.com) * Makefile.in: Add some extra semi-colons (needed if SHELL=bash). Fri Feb 19 00:59:33 1993 John Gilmore (gnu@cygnus.com) * README: Update for gdb-4.8 release. * Makefile.in (gdb.tar.Z): Add texinfo/tex3patch. Build gdb-xxx.tar.z (gzip'd) file also. Thu Feb 18 09:16:17 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: make all-diff depend on all-libiberty Tue Feb 16 16:06:31 1993 K. Richard Pixley (rich@cygnus.com) * config.guess: add vax-ultrix in the spirit of mips-ultrix. Tue Feb 16 05:57:15 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in, Makefile.in: add hello, tar, gzip, recode, indent Tue Feb 16 00:58:20 1993 John Gilmore (gnu@cygnus.com) * Makefile.in (DEVO_SUPPORT): Remove etc directory (ETC_SUPPORT): Only add the files GDB wants from etc/. (gdb.tar.Z): Use ETC_SUPPORT. Use byacc when building the file. Thu Feb 11 20:14:28 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: makeinfo binary is in a new location Tue Feb 9 12:42:27 1993 Ian Lance Taylor (ian@cygnus.com) * config.sub: Accept -ecoff as an OS. * Makefile.in: Various changes to eliminate a level of make recursion and reduce the required command line length. (BASE_FLAGS_TO_PASS): New variable holding flags passed to all sub-makes. (EXTRA_HOST_FLAGS, EXTRA_TARGET_FLAGS, EXTRA_GCC_FLAGS): New variables holding settings for specific sub-makes. (FLAGS_TO_PASS, TARGET_FLAGS_TO_PASS, GCC_FLAGS_TO_PASS): Rewrote in terms of BASE_FLAGS_TO_PASS. (TARGET_LIBS): New variable listing directories which use TARGET_FLAGS_TO_PASS. (subdir_do): Eliminated. (do-*): New set of targets to replace subdir_do. (various): All targets which used subdir_do now depend on do-*. (local-clean): Renamed from do_clean. (local-distclean): New target, dependency of distclean and realclean. (install-info): Don't create directories. Depend on dir.info rather than calling make recursively. (install-dir.info): Eliminated. (install-info-dirs): Create all info directories here. (dir.info): Depend upon do-install-info. * test-build.mk (HOLES): Added false. Sat Feb 6 14:05:09 1993 Per Bothner (bothner@rtl.cygnus.com) * config.guess: Recognize BSDI and BSDJ (Jolitz 386bsd). Thu Feb 4 20:49:18 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in (info): remove dependency on all-texinfo. The problem was really in texinfo/C, not at this level. Thu Feb 4 13:38:41 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (info): Added dependency on all-texinfo (PR 2112). Thu Feb 4 01:50:53 1993 John Gilmore (gnu@cygnus.com) * Makefile.in (make-gdb.tar.Z): Change BISON to 'bison -y' for GDB releases. Wed Feb 3 17:22:16 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * configure: Include srcdir in message about target of link not being found. Don't convert `-' to `_' in `with' options being passed to subdirs. Tue Feb 2 18:57:59 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: add uudecode to host_tools * Makefile.in: added {all,install}-uudecode targets, added them to the appropriate lists Tue Feb 2 11:45:53 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (all-gcc): Added dependency on all-gas. * configure.in (mips-*-*): Build ld and binutils. Mon Feb 1 12:35:41 1993 K. Richard Pixley (rich@rtl.cygnus.com) * configure: check return code from mkdir, print error message and exit on failure. Sat Jan 30 16:40:28 1993 John Gilmore (gnu@cygnus.com) * Makefile.in (make-gdb.tar.Z): New location for texinfo.tex. Thu Jan 28 15:09:59 1993 Ian Lance Taylor (ian@cygnus.com) * test-build.mk (HOLES): Added tar, cpio and uudecode. Wed Jan 27 16:50:32 1993 Jim Wilson (wilson@sphagnum.cygnus.com) * config.sub (h8500): Recognize this as a cpu type. Sat Jan 23 20:32:01 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure: source directory missing is no longer a warning * configure.in: recognize irix[34]* instead of irix[34] * Makefile.in: define and pass down X11_LIB * config/mh-sco: define X11_LIB to the mess that SCO ODT requires Sat Jan 23 13:49:40 1993 Per Bothner (bothner@cygnus.com) * guess-systype: Renamed to ... * config.guess: ... by popular request. * configure.in, Makefile.in: Update accordingly. Thu Jan 21 12:20:55 1993 Per Bothner (bothner@cygnus.com) * guess-systype: Patches from John Eaton : + Add Convex, Cray/Unicos, and Encore/Multimax support. + Execute ./dummy instead of assuming . is in PATH. Tue Jan 19 17:18:06 1993 Per Bothner (bothner@cygnus.com) * guess-systype: New shell script. Attempts to guess the canonical host name of the executing host. Only a few hosts are supported so far. * configure: Call guess-systype if no host is specified. Tue Jan 19 08:26:07 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (gcc-no-fixedincludes): Made to work with current gcc Makefile. Fri Jan 15 10:27:02 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (GCC_FLAGS_TO_PASS): New variable. (all-gcc, install-gcc, subdir_do): Use it. Wed Jan 13 17:06:45 1993 Jim Wilson (wilson@sphagnum.cygnus.com) * Makefile.in: Rename uninstalled gcc driver from gcc to xgcc. Wed Jan 6 20:29:16 1993 Mike Werner (mtw@rtl.cygnus.com) * Makefile.in: Removed explicit setting of SUBDIRS. SUBDIRS is now set exclusively by configure, using configure.in . Wed Jan 6 13:44:11 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * test-build.mk: set $PATH for all builds * Makefile.in: pass TARGET_FLAGS_TO_PASS for xiberty and libm Wed Jan 6 11:02:10 1993 Fred Fish (fnf@cygnus.com) * Makefile.in (GCC_FOR_TARGET): Supply a default that matches the one used in gcc/Makefile.in, so that a null expansion doesn't override the one needed to build gcc with a native cc. Tue Jan 5 07:55:12 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) * configure: Accept -with arguments. Sun Jan 3 15:15:09 1993 Steve Chamberlain (sac@thepub.cygnus.com) * Makefile.in: added h8300sim Tue Dec 29 15:06:00 1992 Ian Lance Taylor (ian@cygnus.com) * config/mh-sco: Don't override BISON definition. * build-all.mk: If canonhost is i386-unknown-sco3.2v4, change it to i386-sco3.2v4. Set TARGETS and CFLAGS for i386-sco3.2v4. (all-cygnus, native, build-cygnus): Make $(canonhost)-stamp-3stage-done, not $(host).... * test-build.mk (stamp-3stage-compared): Use tail +10c for i386-sco3.2v4. Added else true to if command. Mon Dec 28 12:08:56 1992 Ken Raeburn (raeburn@cygnus.com) * config.sub: (from FSF) Sequent uses a BSD-like OS. Mon Dec 28 08:32:06 1992 Minh Tran-Le (mtranle@paris.intellicorp.com) * configure.in (i[34]86-*-isc*): added; uses mh-sysv. Thu Dec 24 17:26:24 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: don't remove binutils from Solaris builds Thu Dec 24 14:08:38 1992 david d`zoo' zuhn (zoo@cygnus.com) * Makefile.in: get rid of earlier definitions for *clean, also handle the recursive info rule better Thu Dec 24 12:40:21 1992 Per Bothner (bothner@rtl.cygnus.com) * Makefile.in (mostlyclean, distclean, realclean): Fix to do more-or-less the right thing. Wed Dec 16 10:25:31 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: Add lines defining CC and CXX, and use CXX rather than gcc in definitions of CXX_FOR_BUILD and CXX_FOR_TARGET. Tue Dec 15 00:34:32 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: change all $(host_cpu)-$(host_vendor)-$(host_os) to $(host_canonical). * configure.in: split the configdirs list into 4 categories (native v. cross, library v. tool) and handle the cross-only and native- only in more reasonable (and correct!) way. Mon Dec 14 17:04:22 1992 Stu Grossman (grossman at cygnus.com) * configure.in (hppa*-*-*): Don't remove bfd and gdb from configdirs anymore. Sun Dec 13 00:37:26 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: extensive cleanup:: removed all of the explicit clean-* targets, collapsed many wrappers around subdir_do into one, added additional targets to satisfy standards.texi, deleted some old targets, some changes for consistency Fri Dec 11 20:18:02 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: handle some programs as cross-only, and others as native only * test-build.mk: handle partial holes in a more generic manner * Makefile.in: m4 depends on libiberty Mon Dec 7 06:43:27 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config/mh-sco: don't default $(CC) to gcc Thu Dec 3 21:52:11 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: add m4, textutils, fileutils, sed, shellutils, time, wdiff, and find to configdirs * Makefile.in: all, clean, and install rules for the new programs added to configure.in Mon Nov 30 14:54:34 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: use mh-sun for all *-sun-* hosts * config/mh-solaris: rework standard X location to use $OPENWINHOME, if defined. * config/mh-sun: handle X11 include locations * config/mh-decstation: define NeedFunctionPrototypes to 0, to work around dain-bramaged DECwindows include files Fri Nov 27 18:35:54 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: define flags for X11 include files and library file locations, pass them down to the programs that need this info * build-all.mk: added a 'native' target, to 3stage the native toolchain * config/{mh-hpux,mh-solaris}: define the "standard" locations for the vendor supplied X11 headers and libraries Sun Nov 22 18:59:13 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: start building libg++ for HP-UX targets Wed Nov 18 19:33:11 1992 John Gilmore (gnu@cygnus.com) * README: Update references to files moved into etc/. Sun Nov 15 09:36:08 1992 Fred Fish (fnf@cygnus.com) * config.sub (i386sol2, i486sol2): i[34]86-unknown-solaris2. * configure.in (i[34]86-*-solaris2*): Use config/mh-sysv4. Thu Nov 12 08:50:42 1992 Ian Lance Taylor (ian@cygnus.com) * configure: accept dash as well as underscore in long option names for FSF compatibility. Wed Nov 11 08:04:37 1992 Ian Lance Taylor (ian@cygnus.com) * config.sub: added -sco3.2v4 support from FSF. Sun Nov 8 21:14:30 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: expand the section that adds or removes directories from the list of programs to build, to handle native vs. cross in addition to host v. native Sat Nov 7 18:52:27 1992 Per Bothner (bothner@rtl.cygnus.com) * Makefile.in: Replace C++ in macro names with CXX. This is less likely to break ... Sat Nov 7 15:16:58 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * test-build.mk: add -w to GNU_MAKE Fri Nov 6 23:10:37 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config.sub: remove 'sparc'-->'sparc-sun' default transformation, add 'sparc' to list of recognized cpus. This needed to make 'sparc-aout' expand to 'sparc-unknown-aout' instead of 'sparc-sun-aout'. Delete some redundant ose68 variants. Recognize -wrs as an os, then changes that into $CPU-wrs-vxworks. * configure.in: remove most references to gdbtest, regularize target based program removal * test-build.mk: import from p3 tree (many fixes and changes) Fri Nov 6 20:59:00 1992 david d `zoo' zuhn (zoo@cygnus.com) * Makefile.in: added rules to handle tcl, tk, and expect * configure.in: handle those directories if they exist Thu Nov 5 14:35:41 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config.sub: removed bogus hppabsd and hppahpux names, since "hppa" is not a valid cpu (hppa1.1 or hppa1.0 are, though) Thu Oct 29 00:12:41 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: all-gcc now depends on all-binutils. all-libg++ depends upon all-xiberty * Makefile.in: changes from p3, including: Thu Oct 8 15:00:17 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (XTRAFLAGS): include newlib directories if newlib/Makefile exists, rather than if host != target. Fri Sep 25 13:41:52 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: added -nostdinc to XTRAFLAGS if we are using gcc from the same source tree and not building a cross-compiler. This matters for the libg++ configuration if reconfiguring a tree that has already been installed. Thu Sep 10 10:35:51 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: added -I for newlib/targ-include to XTRAFLAGS, to pick up the machine and system specific header files. * Makefile.in: added AS_FOR_TARGET, passed down in TARGET_FLAGS_TO_PASS. Added CC_FOR_BUILD, which is intended to be the C compiler to use to create programs which are run in the build environment, set it to default to $(CC), and passed it down in FLAGS_TO_PASS and TARGET_FLAGS_TO_PASS. Mon Sep 7 22:34:42 1992 Ian Lance Taylor (ian@cirdan.cygnus.com) * Makefile.in: add $(host) = $(target) tests back to *_FOR_TARGET. We need them for unusual native builds, like systems without ranlib. * configure: also define $(host_canonical) and $(target_canonical), which are the full, canonical names for the given host and target Sun Nov 1 16:38:17 1992 Per Bothner (bothner@cygnus.com) * Makefile.in: Added separate definitions for C++. Fri Oct 30 11:37:52 1992 Fred Fish (fnf@cygnus.com) * configure.in (configdirs): Add deja-gnu. Fri Oct 23 00:39:18 1992 John Gilmore (gnu@cygnus.com) * README: Update for configure.texi and gdb-4.7 release. Wed Oct 21 21:54:27 1992 John Gilmore (gnu@cygnus.com) * Makefile.in: Move "all" target to top of file. Previously, first target was ".PHONY" which caused BSD4.4 make to build .PHONY when make was run without arguments. Mon Oct 19 01:17:54 1992 John Gilmore (gnu@cygnus.com) * Makefile.in: Add COPYING.LIB to GDB releases, now that there's Library-copylefted code in libiberty. Tue Oct 13 01:22:32 1992 John Gilmore (gnu@cygnus.com) * config.sub: Replace m68kmote with plain old m68k. Fri Oct 9 03:14:24 1992 John Gilmore (gnu@cygnus.com) * Makefile.in: Remove space from blank line, avoid Make complaints. Thu Oct 8 18:41:45 1992 Ken Raeburn (raeburn@cygnus.com) * config.sub: Complain if no argument is given. Added support for 386bsd as OS and target alias. Thu Oct 8 15:07:22 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (XTRAFLAGS): include newlib directories if newlib/Makefile exists, rather than if host != target. Mon Oct 5 03:00:09 1992 Mark Eichin (eichin at tweedledumber.cygnus.com) * config.sub: recognize sparclite-wrs-vxworks. * Makefile.in (install-xiberty): added *-xiberty make rules (from p3.) Added clean-xiberty to clean. Thu Oct 1 17:59:19 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: use *-*-* instead of nested cases for host and target Tue Sep 29 14:11:18 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: added -nostdinc to XTRAFLAGS if we are using gcc from the same source tree and not building a cross-compiler. This matters for the libg++ configuration if reconfiguring a tree that has already been installed. Sep 20 08:53:10 1992 Fred Fish (fnf@cygnus.com) * config.sub (i486v/i486v4): Merge in from FSF version. Fri Sep 18 00:32:00 1992 Mark Eichin (eichin@cygnus.com) * configure: only set PWD if it is already set. Thu Sep 17 23:05:53 1992 Mark Eichin (eichin@cygnus.com) * configure: just set PWD=`pwd` at the top, since Ultrix sh doesn't have unset and all success paths (and most error paths) out set it anyway. (Note: should change all uses of ${PWD=`pwd`} to just ${PWD} to avoid confusion.) Tue Sep 15 16:00:54 1992 Ian Lance Taylor (ian@cygnus.com) * configure: always set $(tooldir) to $(libdir)/$(target_alias), even for a native compilation. Tue Sep 15 02:22:56 1992 John Gilmore (gnu@cygnus.com) Changes to make the gdb.tar.Z rule work better. * Makefile.in (GDB_SUPPORT_DIRS): Add opcodes. (DEVO_SUPPORT): Add configure.texi. (bfd-ilrt.tar.Z): Remove ancient rule. Thu Sep 10 10:43:19 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: added -I for newlib/targ-include to XTRAFLAGS, to pick up the machine and system specific header files. * configure.in, config.sub: added new target m68010-adobe-scout, with alias of adobe68k. Changed configure.in to check for -scout before -sco* to avoid a false match. * Makefile.in: added AS_FOR_TARGET, passed down in TARGET_FLAGS_TO_PASS. Added CC_FOR_BUILD, which is intended to be the C compiler to use to create programs which are run in the build environment, set it to default to $(CC), and passed it down in FLAGS_TO_PASS and TARGET_FLAGS_TO_PASS. Wed Sep 9 12:21:42 1992 Ian Lance Taylor (ian@cygnus.com) * Makefile.in: added TARGET_FLAGS_TO_PASS, CC_FOR_TARGET, AR_FOR_TARGET, RANLIB_FOR_TARGET, NM_FOR_TARGET. Pass TARGET_FLAGS_TO_PASS, which defines CC, AR, RANLIB and NM as the FOR_TARGET variants, to newlib and libg++. Tue Sep 8 17:28:30 1992 Ken Raeburn (raeburn@cambridge.cygnus.com) * Makefile.in (all-gas, all-gdb): Require all-opcodes to be built first. Wed Sep 2 02:50:05 1992 John Gilmore (gnu@cygnus.com) * config.sub: Accept `elf' as an environment. Tue Sep 1 15:48:30 1992 Steve Chamberlain (sac@thepub.cygnus.com) * Makefile.in (all-opcodes): cd into the right directory Sun Aug 30 21:12:11 1992 Ian Lance Taylor (ian@cygnus.com) * configure: added -program_transform_name option, used as argument to sed when installing programs. configure.texi: added documentation for -program_prefix, -program_suffix and -program_transform_name. Thu Aug 27 21:59:44 1992 John Gilmore (gnu@cygnus.com) * config.sub: Accept i486 where i386 ok. Thu Aug 27 13:04:42 1992 Brendan Kehoe (brendan@rtl.cygnus.com) * config.sub: accept we32k Mon Aug 24 14:05:14 1992 Ian Lance Taylor (ian@cygnus.com) * config.sub, configure.in: accept OSE68000 and OSE68k. * Makefile.in: don't create all directories for ``make install''; let the subdirectories create the ones they need. Tue Aug 11 23:13:17 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * COPYING: new file, GPL v2 Tue Aug 4 01:12:43 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: use the new gen-info-dir, which needs a template argument (which also lives in texinfo) * configure.texi, standards.texi: fix INFO-DIR-ENTRY Mon Aug 3 15:41:28 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config/mh-solaris: removed the -xs from CFLAGS (let the people with Sun's C compiler deal with it themselved) Mon Aug 3 00:34:17 1992 Fred Fish (fnf@cygnus.com) * config.sub (ncr3000): Change i386 to i486. Thu Jul 23 00:12:17 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: add install-rcs, install-grep to install-no-fixedincludes, removed install-bison and install-libgcc Tue Jul 21 01:01:50 1992 david d `zoo' zuhn (zoo@cygnus.com) * configure.in: grab the HPUX makefile fragment if on HPUX Mon Jul 20 11:02:09 1992 D. V. Henkel-Wallace (gumby@cygnus.com) * Makefile.in: eradicate bison spoor (ditto libgcc). configure.in: recognise m68{k,000}-ericsson-OSE. es1800 is alias for m68k-ericsson-OSE Sun Jul 19 17:49:02 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: rearrange the parts that remove programs from configdirs, based now on HOST==TARGET or by canonical triple. Fri Jul 17 22:52:49 1992 K. Richard Pixley (rich@rtl.cygnus.com) * test-build.mk: recurse explicitly with -f test-build.mk when appropriate. predicate stage3 and comparison on the existence of gcc. That is, if gcc isn't around, we aren't three-staging. On very clean, also remove ...stamp-co. Build in-place before doing other builds. Thu Jul 16 18:33:09 1992 Steve Chamberlain (sac@thepub.cygnus.com) * Makefile.in, configure.in: add tgas Thu Jul 16 16:05:28 1992 K. Richard Pixley (rich@rtl.cygnus.com) * Makefile.in: a number of changes merged in from progressive. * configure.in: add libm. * .cvsignore: ignore some stuff that comes from test-build.mk. Wed Jul 8 00:01:30 1992 Stu Grossman (grossman at cygnus.com) * config/mh-solaris: Use -xs when compiling so that Sun-C puts a symbol-table into the executable. Tue Jul 7 00:24:52 1992 Fred Fish (fnf@cygnus.com) * config.sub: Add es1800 (m68k-ericsson-es1800). Tue Jun 30 20:24:41 1992 D. V. Henkel-Wallace (gumby@cygnus.com) * configure: Add program_suffix (parallel to program_prefix) * Makefile.in: adjust directory-creating script for losing decstation Mon Jun 22 23:43:48 1992 Per Bothner (bothner@cygnus.com) * configure: Minor $subdir-related fixes. Mon Jun 22 18:30:26 1992 Steve Chamberlain (sac@thepub.cygnus.com) * configure: fix various problems with propogating makefile_target_frag in subdirs. * configure.in: config libgcc if its there Fri Jun 19 15:19:40 1992 Stu Grossman (grossman at cygnus.com) * config.sub: HPPA merge. Mon Jun 15 12:31:52 1992 Fred Fish (fnf@cygnus.com) * config/mh-ncr3000 (INSTALL): Don't use /usr/ucb/install, it is broken on ncr 3000's. Sun Jun 14 10:29:19 1992 John Gilmore (gnu at cygnus.com) * Makefile.in: Replace all-bison with all-byacc in all dependency lines for other tools (which now use byacc). Fri Jun 12 22:21:57 1992 John Gilmore (gnu at cygnus.com) * config.sub: Add sun4sol2 => sparc-sun-solaris2. Tue Jun 9 17:18:11 1992 Fred Fish (fnf at cygnus.com) * config/{mh-ncr3000, mh-sysv4}: Add INSTALL. Thu Jun 4 12:07:32 1992 Mark Eichin (eichin@cygnus.com) * Makefile.in: make gprof rules similar to byacc rules (instead of vestigal $(unsubdir) that didn't work...) Thu Jun 4 00:37:05 1992 Per Bothner (bothner@rtl.cygnus.com) * config.sub: Add support for Linux. * Makefile.in: Use $(FLAGS_TO_PASS) more consistently (at least for libg++). Tue Jun 02 20:03:00 1992 david d `zoo' zuhn (zoo@cygnus.com) * configure.texi: fix doc for the -nfp option to configure Tue Jun 2 17:20:52 1992 Michael Tiemann (tiemann@cygnus.com) * Makefile.in (all-binutils): ar needs flex, so depend on all-flex. Sun May 31 15:04:08 1992 Mark Eichin (eichin at cygnus.com) * config.sub: changed [^-]+ to [^-][^-]* so that it works under Sun sed. (BSD 4.3 sed doesn't handle [^-]+ either.) * configure.in: added solaris* host_makefile_frag hook. Sun May 31 01:10:34 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config.sub: changed recognition of m68000 so that various m68k types can be specified via m680[01234]0 Sat May 30 21:01:06 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * config.sub (basic_machine): fix sed so that '-foo' isn't completely substituted out while .+'-foo' loses the '-foo' Wed May 27 23:18:52 1992 Michael Tiemann (tiemann@rtl.cygnus.com) * config.sub ($os): Add -aout. Fri May 22 14:00:02 1992 Per Bothner (bothner@cygnus.com) * configure: If host_makefile_frag is absolute, don't prefix ${invsubdir} (relevant to libg++ auto-configure). Thu May 21 18:00:09 1992 Michael Tiemann (tiemann@rtl.cygnus.com) * Makefile.in (tooldir): Define it. (all-ld): Depend on all-flex. Sun May 10 21:45:59 1992 Per Bothner (bothner@rtl.cygnus.com) * Makefile.in (check): Fix libg++ special case. Fri May 8 08:31:41 1992 K. Richard Pixley (rich@cygnus.com) * configure: do not bury `pwd` into config.status, thus do fewer pwd's. * configure: print the "Building in" message only when building in other than "." AND verbose. * configure: remove -s, rework -v to better accomodate guested configures. * standards.texi: updated to 3 may, fixed librid <-> libdir typo. Fri May 1 18:00:50 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: macroize flags passed on recursion. remove fileutils. Thu Apr 30 08:56:20 1992 K. Richard Pixley (rich@cygnus.com) * configure: get makesrcdir right for subdirs deeper than 1. * Makefile.in: pass INSTALL, INSTALL_DATA, INSTALL_PROGRAM on install. Fri Apr 24 15:51:51 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: don't print subdir_do or recursion lines. Fri Apr 24 15:22:04 1992 K. Richard Pixley (rich@cygnus.com) * standards.texi: added menu item. * Makefile.in: build and install standards.info. * standards.texi: new file. Wed Apr 22 18:06:55 1992 K. Richard Pixley (rich@rtl.cygnus.com) * configure: test for and move config.status pieces from ${subdir}/. Wed Apr 22 14:38:34 1992 Fred Fish (fnf@cygnus.com) * config/mh-delta88, config/mh-ncr3000: Replace MINUS_G with CFLAGS per new configuration strategy. * configure: Test for existance of files before trying to mv them, to avoid numerous non-existance messages. Tue Apr 21 12:31:33 1992 K. Richard Pixley (rich@cygnus.com) * configure: correct final line of config.status. * configure: patch from eggert. Avoids a protection problem if the original Makefile.in is read only. * configure: use move-if-change from gcc to create config.status. Some makefiles depend on config.status to tell if a directory has been reconfigured for a different host. This change prevents those directories from remaking everything in the case where the reconfig was only intended to rebuild a Makefile. * configure: test for config.sub with "config.sub sun4" rather than "config.sub ${host_alias}". Otherwise we can't tell a bad host alias from a missing config.sub. Mon Apr 20 18:16:36 1992 K. Richard Pixley (rich@rtl.cygnus.com) * Makefile.in: explicitly pass CFLAGS on recursion. no longer pass MINUS_G (this can be done with CFLAGS). Default CFLAGS to -g. Fri Apr 17 18:27:51 1992 Per Bothner (bothner@cygnus.com) * configure: mkdir ${subdir} as needed. Wed Apr 15 17:37:22 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in,configure.in: added autoconf. Wed Apr 15 17:27:34 1992 K. Richard Pixley (rich@rtl.cygnus.com) * Makefile.in: no longer pass against on recursion. * Makefile.in: added .NOEXPORT: so that stray makefile_frag definitions are not inherited. * configure: correct makesrcdir when subdir is . Tue Apr 14 11:56:09 1992 Per Bothner (bothner@cygnus.com) * configure: Add support for 'subdirs' variable, which is like 'configdirs', except that configure doesn't re-invoke itself for subdirs, it just creates a Makefile for each subdir. * configure.texi: Document subdirs. Mon Apr 13 18:50:16 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * configure.in: added flex to configdirs Mon Apr 13 18:43:55 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: remove clean-stamps from clean. Sat Apr 11 03:52:03 1992 John Gilmore (gnu at cygnus.com) * configure.in: Add gdbtest to configdirs. Fri Apr 10 23:11:49 1992 Fred Fish (fnf@cygnus.com) * Makefile.in (MINUS_G): Add macro, default to -g, pass on to recursive makes. * configure.in: Recognize new ncr3000 config. Wed Apr 8 23:08:12 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in, configure.in: removed references to gdbm. Tue Apr 7 16:48:20 1992 Per Bothner (bothner@cygnus.com) * config.sub: Don't canonicalize os value newsos* to bsd (readline needs to check for newsos). (This fix was earlier made Jan 31, but got re-broken.) Mon Apr 6 14:34:08 1992 Stu Grossman (grossman at cygnus.com) * configure.in: sco is an os, not a vendor! * configure: Quote $( better. Keep various shells happy. Tue Mar 31 16:32:57 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: eliminate stamp-files. Mon Mar 30 22:20:23 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: add send_pr. remove "force" from .stmp-gprof rule. Supress echoing of all the "if [ -d ... $(MAKE)" lines. Wed Mar 25 15:20:04 1992 Stu Grossman (grossman@cygnus.com) * config.sub: fix iris/iris3. Wed Mar 25 10:34:19 1992 K. Richard Pixley (rich@cygnus.com) * configure: re-add -rm. Tue Mar 24 23:50:16 1992 K. Richard Pixley (rich@cygnus.com) * Maskefile.in: add .stmp-rcs to all. * configure.in: remove gas from rs6000 build, use aix host fragment. Mon Mar 23 19:43:35 1992 K. Richard Pixley (rich@cygnus.com) * configure: pass down site_option during recursion. Thu Mar 19 16:49:36 1992 Stu Grossman (grossman at cygnus.com) * Makefile.in (all.cross): Add .stmp-bfd .stmp-readline. Wed Mar 18 15:29:33 1992 Mike Stump (mrs@cygnus.com) * configure: Change exec_prefix so that it really defaults to prefix. Sat Mar 14 17:20:38 1992 Fred Fish (fnf@cygnus.com) * Makefile.in, configure.in: Add support for mmalloc library. Fri Mar 13 18:44:18 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: add stmp dependencies for a few more things. Thu Mar 12 04:56:24 1992 K. Richard Pixley (rich@cygnus.com) * configure: adjusted error message on objdir/srcdir configure collision, per john's suggestion. * Makefile.in: add libiberty stmp to all and all.cross. Wed Mar 11 02:07:52 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in: remove force dependencies, add grep to all. Tue Mar 10 21:49:18 1992 K. Richard Pixley (rich@mars.cygnus.com) * Makefile.in: drop flex. make stamp files work. * configure: added test for conflicting configuration in srcdir, remove trailing slashes from srcdir. Otherwise emacs gdb mode gets cranky. use relative paths for configure and srcdir whenever possible. Send some error messages to stderr that were going to stdout. Tue Mar 10 18:01:55 1992 Per Bothner (bothner@cygnus.com) * Makefile.in: Fix libg++ rule to check for gcc directory before using gcc/gcc. Also pass XTRAFLAGS. Thu Mar 5 21:45:07 1992 K. Richard Pixley (rich@sendai) * Makefile.in: added stmp-files so that directories aren't polled when they are already built. * configure.texi: fixed a node pointer problem. Thu Mar 5 12:05:58 1992 Stu Grossman (grossman at cygnus.com) * config.sub configure.in config/mh-irix4 gdb/configure.in gdb/mips-tdep.c gdb/mipsread.c gdb/procfs.c gdb/signame.h gdb/tm-irix3.h gdb/tm-mips.h gdb/xm-irix4.h gdb/config/mt-irix3 gdb/config/mh-irix4 texinfo/configure.in: Port to SGI Irix-4.x. Wed Mar 4 02:57:46 1992 K. Richard Pixley (rich@rtl.cygnus.com) * configure: -recurring becomes -silent. corrected help message for -site= option. * Makefile.in: mkdir $(exec_prefix) and $(tooldir). Tue Mar 3 14:51:21 1992 K. Richard Pixley (rich@rtl.cygnus.com) * configure: when building Makefile for crosses, replace tooldir and program_prefix. default srcdir from location of config.sub. remove "for host in hosts" and "for target in targets" loops. Wed Feb 26 19:48:25 1992 K. Richard Pixley (rich@rtl.cygnus.com) * Makefile.in: Do not pass bindir or mandir to cvs. Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) * Makefile.in, configure.in: removed traces of namesubdir, -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced copyrights to '92, changed some from Cygnus to FSF. * configure.texi: remove most references to multiple hosts, multiple targets, subdirs, etc. * configure.man: removed rcsid. reference config.sub not config.subr. * Makefile.in: mkdir $(infodir) on install-info. Wed Feb 19 15:41:13 1992 John Gilmore (gnu at cygnus.com) * configure.texi: Explain better about .gdbinit and about the environment that configure.in sections run in. Fri Feb 7 07:55:00 1992 John Gilmore (gnu at cygnus.com) * configure.in: Ultrix is only a decstation if it's a MIPS. Fri Jan 31 21:54:51 1992 John Gilmore (gnu at cygnus.com) * README: DOC.configure => cfg-paper.texi. Fri Jan 31 21:48:18 1992 Stu Grossman (grossman at cygnus.com) * config.sub (near case $os): Don't convert newsos* to bsd! Fri Jan 31 02:27:32 1992 John Gilmore (gnu at cygnus.com) * Makefile.in: Reinstall change from gdb-4.3 that reduces the number of copies of COPYING that go into the GDB tar file. Thu Jan 30 16:17:30 1992 Stu Grossman (grossman at cygnus.com) * bfd/configure.in, config/mh-sco, gdb/config/mh-i386sco, gdb/config/mt-i386v32, gdb/configure.in, readline/configure.in: Fix SCO configuration stuff. Tue Jan 28 23:51:07 1992 Per Bothner (bothner at cygnus.com) * Makefile.in: For libg++, make sure the -I pointing to the gcc directory goes *after* all the libg++-local -I flags. Also, move just-gcc dependency from just-libg++ to all-libg++. Tue Jan 28 12:56:24 1992 Stu Grossman (grossman at cygnus.com) * configure: Change -x to -f to keep Ultrix /bin/test happy. Sat Jan 18 17:45:11 1992 Stu Grossman (grossman at cygnus.com) * Makefile.in (make-gdb.tar.Z): Remove texinfo targets. Sat Jan 18 17:03:21 1992 Fred Fish (fnf at cygnus.com) * config.sub: Add stratus configuration frags. Also submitted to FSF. Sat Jan 18 15:35:29 1992 Stu Grossman (grossman at cygnus.com) * Makefile.in (DEV_SUPPORT): add configure.man. * config.sub(Decode manufacturer-specific): add -none*. Fri Jan 17 17:58:05 1992 Stu Grossman (grossman at cygnus.com) * Makefile.in: remove form feeds to make Sun's make happy. (DEVO_SUPPORT): DOC.configure => cfg-paper.texi. Sat Jan 4 16:11:44 1992 John Gilmore (gnu at cygnus.com) * Makefile.in (AR_FLAGS): Make quieter. Thu Jan 2 22:57:12 1992 John Gilmore (gnu at cygnus.com) * configure.in: Add libg++. * configure: When verbose, don't output the command line at each level; it will be unremarkably the same as the previous version, which will be the same as what the user typed. Fri Dec 27 16:26:47 1991 K. Richard Pixley (rich at cygnus.com) * configure.in, Makefile.in: fix clean-info, add flex. add fileutils. * configure: be less sensitive to spaces in Makefile.in. Do not look for sources in "..". Doing so breaks subdirectories that might have their own configure. If a subdir has it's own configure script, use it. Thu Dec 26 16:30:26 1991 K. Richard Pixley (rich at cygnus.com) * cfg-paper.texi: some changes suggested by rms. Thu Dec 26 10:13:36 1991 Fred Fish (fnf at cygnus.com) * config.sub: Merge in some small additions from the FSF version, taken from the gcc distribution, to bring the Cygnus and FSF versions into closer sync. Fri Dec 20 11:34:18 1991 Fred Fish (fnf at cygnus.com) * configure.in: Changed svr4 references to sysv4. Thu Dec 19 15:54:29 1991 K. Richard Pixley (rich at cygnus.com) * configure: added -V for version number option. Wed Dec 18 15:39:34 1991 K. Richard Pixley (rich at cygnus.com) * DOC.configure, cfg-paper.texi: revised, updated, and texinfo'd. renamed from DOC.configure to cfg-paper.texi. Mon Dec 16 23:05:19 1991 K. Richard Pixley (rich at rtl.cygnus.com) * configure, config.subr, config.sub: config.subr is now config.sub again. Fri Dec 13 01:17:06 1991 K. Richard Pixley (rich at cygnus.com) * configure.texi: new file, in progress. * Makefile.in: build info file and install the man page for configure. * configure.man: new file, first cut. * configure: find config.subr again now that configuration "none" has gone. removed all traces of the -ansi option. removed all traces of the -languages option. * config.subr: resync from rms. Wed Dec 11 22:25:20 1991 K. Richard Pixley (rich at rtl.cygnus.com) * configure, config.sub, config.subr: merge config.sub into config.subr, call the result config.subr, remove config.sub, use config.subr. * Makefile.in: revised install for dir.info. Tue Dec 10 00:04:35 1991 K. Richard Pixley (rich at rtl.cygnus.com) * configure.in: add decstation host makefile frag. * Makefile.in: BISON now bison -y again. also install-gcc on install. clean-gdbm on clean. infodir belongs in datadir. Make directories for info install. Build dir.info here then install it. Mon Dec 9 16:48:33 1991 K. Richard Pixley (rich at rtl.cygnus.com) * Makefile.in: fix for bad directory tests. Sat Dec 7 00:17:01 1991 K. Richard Pixley (rich at rtl.cygnus.com) * configure: \{1,2\} appears to be a sysv'ism. Use a different regexp. -srcdir relative was being handled incorrectly. * Makefile.in: unwrapped some for loops so that parallel makes work again and so one can focus one's attention on a particular package. Fri Dec 6 00:22:08 1991 K. Richard Pixley (rich at rtl.cygnus.com) * configure: added PWD as a stand in for `pwd` (for speed). use elif wherever possible. make -srcdir work without -objdir. -objdir= commented out. Thu Dec 5 22:46:52 1991 K. Richard Pixley (rich at rtl.cygnus.com) * configure: +options become --options. -subdirs commented out. added -host, -datadir. Renamed -destdir to -prefix. Comment in Makefile now at top of generated Makefile. Removed cvs log entries. added -srcdir. create .gdbinit only if there is one in ${srcdir}. * Makefile.in: idestdir and ddestdir go away. Added copyrights and shift gpl to v2. Added ChangeLog if it didn't exist. docdir and mandir now keyed off datadir by default. Fri Nov 22 07:38:11 1991 K. Richard Pixley (rich at rtl.cygnus.com) * Freshly created ChangeLog. Local Variables: mode: change-log left-margin: 8 fill-column: 76 version-control: never End: gnats-4.1.0/INSTALL0000644000175000017500000000543507561207620014427 0ustar chewiechewie00000000000000 Installing GNATS Version 4 This is a very brief overview of the installation procedure for GNATS version 4. It is strongly recommended that you refer to the file gnats.texi or the online manual currently located at http://sources.redhat.com/gnats/gnats_toc.html, specifically Chapter 3, Installing GNATS, before you try to install and operate GNATS. The items marked `*Note' below refer to sections of chapter 3 in the GNATS manual. Installing GNATS ================ There are several steps you need to follow to fully configure and install GNATS on your system. You need `root' access in order to create a new account for the user `gnats' and to install the GNATS utilities. You may need `root' access on some systems in order to set up mail aliases and to allow this new account access to `cron' and `at'. If you are updating an older version of GNATS rather than installing from scratch, see the UPGRADING file. NOTE: You will need to have GNU make and GNU Texinfo (version 4.2 or newer) in order to install GNATS 4. To build GNATS, you must: * Run `configure', with correct options if the defaults are unsuitable for your site. *Note Configuring and compiling the software: Configure and make. Default installation locations are detailed in *Note Where GNATS lives: Default installation locations. * Compile the GNATS programs on your system. *Note Configuring and compiling the software. * Create an initial database by using the `mkdb' command. *Note Installing the default database. * Set up periodic jobs, using cron, to handle Problem Reports arriving by mail. *Note Setting up periodic reports. * Set up mail aliases for GNATS. *Note Setting up mail aliases. * Install the GNATS tools and utilities locally, and install the user tools (`query-pr', `edit-pr', `send-pr') on every machine in your local network. *Note Installing the user tools. * Install the GNATS network daemon `gnatsd'. *Note Installing the daemon. * Update the local configuration files dbconfig categories submitters responsible states classes addresses gnatsd.user_access in `DATABASEDIR/gnats-adm', as well as the files gnatsd.host_access databases in `PREFIX/etc/gnats' (usually /usr/local/etc/gnats). *Note Changing your local configuration: Local configuration. * If you have people outside your organization who will be submitting PRs or who are supposed to be able to query and/or edit PRs, you either need to instruct them to obtain and build the GNATS tools `query-pr', `edit-pr' and `send-pr' for their systems or set up a remote access interface to GNATS, such as Gnatsweb. *Note Installing the user tools. gnats-4.1.0/Makefile.in0000644000175000017500000000566210207435253015441 0ustar chewiechewie00000000000000# The top-level Makefile for GNU GNATS # Copyright (C) 2001, 2002 Milan Zamazal # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA VERSION = @PACKAGE_VERSION@ DISTDIR = gnats-$(VERSION) srcdir = @srcdir@ VPATH = @srcdir@ SUBDIRS = gnats send-pr doc # Standard GNU targets .PHONY: all install install-strip uninstall clean distclean distclean-here \ mostlyclean maintainer-clean TAGS info dvi dist check # GNATS specific targets .PHONY: all-gnats all-tools all: all-gnats all-gnats: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done all-tools: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done install: install-gnats install-gnats: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done install-strip: $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' $@ install-tools: $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' $@ uninstall: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done mostlyclean: -rm -f TAGS *.tar *.tar.gz -rm -f .\#* *~* for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done clean: mostlyclean for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done distclean: clean distclean-here for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done distclean-here: -rm -f Makefile config.status config.cache config.log -rm -f .\#* \#* *~* -rm -f *.orig *.rej maintainer-clean: distclean-here for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done Makefile: $(srcdir)/Makefile.in config.status ./config.status TAGS: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done info: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done dvi: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done dist: maintainer-clean ./configure $(MAKE) $(MAKE) distclean -rm -rf $(DISTDIR) mkdir $(DISTDIR) find \( -maxdepth 1 -not -name . -not -name .. -not -name $(DISTDIR) \ -not -name debian \) -print0 | \ xargs --null cp -al --target-directory=$(DISTDIR) find $(DISTDIR) \( -name CVS -o -name .cvsignore \) -print0 | \ xargs --null --no-run-if-empty rm -r -find $(DISTDIR) -type d -print0 | \ xargs --null --no-run-if-empty rmdir -p 2>/dev/null set -e; for i in gnats/configure gnats/configure.in; do \ sed 's/-Werror//' $(DISTDIR)/$$i >$(DISTDIR)/$$i.tmp; \ mv $(DISTDIR)/$$i.tmp $(DISTDIR)/$$i; \ done tar cvf $(DISTDIR).tar $(DISTDIR) rm -rf $(DISTDIR) gzip -9 $(DISTDIR).tar check: for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done gnats-4.1.0/NEWS0000600000175000017500000002341610212662213014052 0ustar chewiechewie00000000000000GNATS 4.1.0, March 2005 ========================== This is GNATS 4.1.0, a release that incorporates multiple bug fixes and enhancements that have been committed to CVS since the release of GNATS 4.0. Notable enhancements include: - Upgrade to autoconf 2.59 generated configure scripts. - New PR numbers are reported to the client upon new submissions - Rewrite of install-sid. Now, rather than editing send-pr, which can be installed on a read-only partition, install-sid creates or edits user or site configuration files ~/.send-pr.conf or /etc/gnats/send-pr.conf. - Removal of libiberty, old manpages, and old build framework cruft - Performance enhancements to indexing code - Various cleanups and bugfixes. See the ChangeLog files for details. GNATS 4.0.1, November 2004 ========================== This is the GNATS 4.0.1 release, a patch release to address a potential security vulnerability with string formatting in gnats/misc.c that was described in: http://lists.gnu.org/archive/html/bug-gnats/2004-06/msg00028.html http://www.zone-h.org/advisories/read/id=4889 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0623 http://www.debian.org/security/2004/dsa-590 Additional string formatting fixes were applied to avoid buffer overflows in constructing formatted date strings. GNATS 4.0, August 2003 ====================== This is the GNATS 4.0 release. GNATS 4 has major changes since GNATS 3, see the beta 1 news below for an overview of the changes. This release includes several bug-fixes and documentation improvements since the beta 2 release. GNATS 4.0 beta 2, November 2002 =============================== This is the second beta release of GNATS 4.0. We have a new maintainer, Andrew Gray, and development has picked up pace a bit. This release contains a great many bug-fixes and a limited selection of new or expanded functionality. This list indicates the most important changes made since beta 1. - Myriads of bug-fixes have been made since beta 1. See the ChangeLog for details. - A new field `Notify-List' has been added to the standard dbconfig. This replaces the old GNATS 3 X-Gnats-Notify functionality. E-mail addresses entered in this field are used to CC people on PR changes that generate Audit-Trail entries. As part of this, the -c / --cc option to send-pr was removed. - The fields Cases, Quarter, Keywords and Date-Required have been removed from the default dbconfig. - gnatsd.access has been renamed to gnatsd.user_access. - Password matching and the gnats-pwconv utility have been fixed, they were both broken in beta 1. - Slightly redesigned access model. See "Controlling access to databases" appendix in the manual. - It is now possible to require certain fields to be nonempty upon initial PR submission by using the `require' keyword in the `initial-entry' section of the dbconfig file. Along with the previously undocumented "on-change require" field definition keyword this makes it possible to specify that certain fields can never be empty. - The manual includes a new appendix titled `dbconfig recipes', containing dbconfig customizations that are hopefully useful in themselves, but which should also serve to illustrate the great power of dbconfig. - The manual is now fully compliant with GNATS 4. GNATS 4.0 beta 1, December 2001 =============================== This is the first beta release of GNATS 4.0. Two alpha releases were made in 1999, but a lot of work has been done since then, both implementation- and design-wise. GNATS 4 amounts to a full rewrite compared with GNATS 3, and the major changes and additions to functionality divide into four main areas: - Remote network access to the GNATS server. - Vastly improved customizability, allowing sites to customize virtually all aspects of GNATS behaviour. - Much more powerful database queries. - Documentation has been thoroughly revised. - Password encryption. Remote access The GNATS network daemon gnatsd now allows direct PR submission, allowing remote tools such as send-pr to speak directly to the GNATS server over the network instead of assembling the PR and submitting it by e-mail. gnatsd can now also verify the contents of new PRs before they are submitted, and remote tools are now also able to get such data as field default values directly from gnatsd. All the tools supplied with GNATS, such as send-pr, query-pr and edit-pr now honor the GNATSDB environment variable. When accessing a GNATS database on the local system, this variable should simply contain the name of the database to access, but in order to access a remote GNATS server, the syntax host:port:name for the value of GNATSDB is now supported. In addition, all the tools now support a --database option with the same syntax as the GNATSDB environment variable. Customizability The most important new customization feature, frequently requested by GNATS 3 users, is the ability to add custom fields. GNATS 4 contains a small number of `built-in' fields, such as PR number and Category that are required to be present in all setups, but apart from that, what fields are defined and what characteristics they have is completely customizable. The old GNATS `config' file is gone, replaced by a much more powerful file named `dbconfig', containing the following main sections: - Overall database configuration, mainly containing the settings from the old `config' file, such as beginning and end of business hours, enable/disable submitter acknowledgment etc. - Field configuration, containing field names, datatypes, on-change actions etc. - Query definitions, allowing definition of named queries. - Audit Trail format. - Mail formats, allowing for easy customization of acknowledgment and notification e-mail messages etc. - Index file format. - Description of which fields are required to be present on initial PR submission. Powerful database queries GNATS 3 had severely limited query functionality, and this version contains an entirely rewritten query engine with full support for complex cross-field regular expression searches. For legacy applications, the query-pr tool also supports the version 3 query syntax. Documentation The GNATS manual has been almost completely rewritten, thoroughly documenting the new features present in GNATS 4. It also contains more in-depth technical information, such as the full gnatsd command set, than earlier editions. Password encryption GNATS 4.0 supports encrypted passwords in the gnatsd.access file. Traditional UNIX DES crypt() encryption, as well as the more secure MD5 is supported. Sites upgrading from GNATS 3 need to use the gnats-pwconv tool in the distribution in order to translate their gnatsd.access file to GNATS 4 format, even if they want to continue to use plaintext passwords. gnats-pwconv supports conversion to crypt() and MD5 as well. The distribution also contains the gnats-passwd tool for password file management. Other changes Miscellaneous other changes to features and functionality include: - The Emacs interface has been completely rewritten. - The --gnats-release-based option to configure has been removed. This option was used to make GNATS include special fields such as Release-Note, required by some sites. Since fields are now configurable in the dbconfig file, this build-time option is no longer necessary. - The `site' functionality, with the mkdist tool, is gone. In GNATS 3, client tools such as send-pr could be packaged and distributed to submitter sites with the proper configuration files included. This was never very well or thoroughly implemented, but something similar may appear in later versions of GNATS. This should not be critical, since tools such as send-pr now get most of the data they need, such as list of categories etc., directly from gnatsd over the network. - In addition to supporting much more advanced queries, query-pr now supports the specification of a C-style format string on the command line with the --format option. - pr-mail, pr-addr, npr-addr and sub-type have been removed and their functionality has instead been added to query-pr. - The file-pr command has been replaced by edit-pr --submit - There is a new tool, mkdb, which is used to initialize a new database. - There is a new tool, `diff-prs' which lists the fields that have changed between two PRs. - GNATS_ROOT is no longer. The GNATSDB environment variable is now used to determine which database to use (or the -d or --database option to the client tools). - Databases must now be specified by name, so the --directory option in all the client tools has been replaced by a --database option. - Category directories are now created on-the-fly by default, obviating the need for the mkcat tool. This can be switched off in the `dbconfig' file, so mkcat is still present in the distribution. - Most programs in the distribution now come with man pages. - A new access level, `listdb' has been added. This is like `none', except that it allows access to the LSDB command which is needed by third-party tools such as Gnatsweb, which need to get a list of available databases before presenting a login screen. - The gnatsd command set has been significantly simplified. There are fewer but more powerful commands now. - gnatsd now takes care of Audit-Trail entries and sending e-mails for edits, making implementation of clients easier. - gnatsd.conf has been renamed to gnatsd.host_access. - Support for binary index files. This is the default in GNATS 4 and removes the problems with separator quoting that was a huge problem in GNATS 3, causing frequent index file corruption. - gnatsd now has a --maximum-access-level option, allowing a site to limit all access to a certain level. - Parsing of time zones in e-mail headers is far more robust, no longer depending on the recognition of a myriad different time zone abbreviations. gnats-4.1.0/NEWS.old0000644000175000017500000007703307401177736014664 0ustar chewiechewie00000000000000September 21st, 1999 GNATS 4.0 alpha.2 "squirrel-2" This is another update to the alpha release. This one theoretically allows adding new fields by merely inserting them in the configuration file, and changing the header strings of fields, but this capability has not been tested. It's still very preliminary, and there are any number of known bugs. Lots of work remains (separating the header name from the field name would be a start, and fixing the known bugs). I wanted to get this out so that the .2 people that care would perhaps play with it, but that seems unlikely ("CVS? What's that?"). August 24th, 1999 GNATS 4.0 alpha "squirrel-1" I, Bob Manson having usurped GNATS maintainership from the tenacious and wily grasp of Jason Molenda (who valiantly fought for hours, nay days over it), I have decided to further muddy the waters and try to add my own mark of ownership upon that which is GNATS. This is a horribly preliminary release of what will become GNATS 4.0. It is considered way-blooding-nasty software, and you will verily lose if you try to use it for anything other than playing. It has successfully been built on Solaris 2.6, Linux with glibc2.1, and some release of FreeBSD (uname returns 2.2.8, whatever that means). The most obvious external change is that the format of the fields in the database are described in an external file (field-config). Eventually it will be possible to add new fields via this configuration file. Presently this may only be used to change existing fields, and it is not even possible to change simple things like the name of a field. The format of field-config is documented via some random and sundry comments within it. Eventually the parser will say something slightly more useful than "syntax error at line xxx", and the lexer will cease spewing out unrecognized keywords and characters to stdout. Until that day, be amused. nquery-pr has been deleted, and its functionality is (mostly) merged into query-pr. ("Mostly" meaning that it is necessary to specify a network-specific option such as --host in order to get it to do network queries; this is lame lossage that needs to be fixed.) It is also possible to do boolean searches via query-pr. Two new options, `--and' and `--or' have been added. There is currently no support for this functionality via the network interface. Boolean searches are constructed left-to-right, and there is currently no parenthesis or other way to restructure queries. Eventually a full expression query syntax will be added, although the current search functionality will be maintained. Internally the code has undergone major surgery. (I'm not even sure where to start describing this.) Searches are now consolidated into a "QueryExpr" struct. All of the global variables in qvariable.c have been deleted, as well as most of the miscellaneous ones. The madness with "is_remote", and the random end-of-line variables is gone. A lot of static infrastructure surrounding fields has been removed. A generic interface has been added to the "random administrative files"; the contents thereof may eventually be merged into the field-config file. Several new structures have been added. And with plenty of other bad losingness added, I'm sure. I just read the "PROBLEMS" file for the first time. Hopefully most of the real bug-type problems listed are moot. except for the documentation issues. ("Documentation is like castor oil: programmers hate it, so managers claim it must be good for you.") There's still a pile of work to do; much of it has been documented in the TODO file. Note that in these changes a Juniper-specific field has been added. This has been my benchmark for where in the process things are; when it's totally included in the external config with no mention of it elsewhere, that's presumably a good sign. --------------------------------------------------------------------- November 7th, 1999 GNATS 3.113 This release fixes a number of small bugs that remained in the 3.112 release. We're working towards a final stable 3.x release--there are probably one or two more 3.x releases to go to catch the last few small problems. The main problem addressed in 3.113 is a bug where the Resent-Cc generated by gnats did not put commas between addresses. The result was that e-mail notifications about PRs were not delivered correctly. Gnatsweb has been upgraded to v2.5. tkgnats has been upgraded to v3.0.14. The following PRs in the gnats database are fixed with 3.113: gnats/6 gnats/8 gnats/11 gnats/13 gnats/17 The following people helpfully provided patches for this release: Darrin B. Jewell Martti Kuparinen Andreas Luik Palle Girgensohn Thanks everyone! September 21st, 1999 GNATS 3.112 This release is a bug-fix release off of 3.111; no new features were added. Any future development should be part of the 4.0 trunk, although 3.x will probably be maintained for some period of time. This addresses the "coredump in file-pr" bug. It also includes some additional changes from Debian to work around glibc-2.1 misfeatures, as well as fixing a few GNATS bugs dealing with memory misallocations. August 26th, 1999 GNATS 3.111 This release is a bug-fix release off of 3.110; no new features were added. Any future development should be part of the 4.0 trunk, although 3.x will probably be maintained for some period of time. April 8th, 1999 GNATS 3.110 The Official GNATS homepage is now: http://sourceware.cygnus.com/gnats/ We're not keeping it as up to date as we should, so keep your bookmarks for the Cyclic GNATS pages and all of the other wonderful stuff out there on the web live. This release is primarily a bug-fix release off of 3.108, with some relatively minor new features and portability fixes. There was no 3.109 due to some early code accidently leaking out. See the gnats/ChangeLog file for details. The bigest news was actually down in the contrib/ directory -- Ken Cox has provided an absolutely fantastic WWW based front end to GNATS called gnatsweb which supports all the new features, such as multiple databases and customized fields. We've dropped the CERN WWW gnats and Dan's wwwgnats packages out of the distribution since they were not being maintained by the authors and no longer worked with later versions of GNATS. For users of the Juniper web-based reports, I've made some major improvements in the query/report generation interface, and will either be stealing some of Ken's ideas for stored reports, or hooking in an alternate report generation mechanism into the existing gnatsweb. November 18th, 1998 GNATS 3.108 Major changes to the way GNATSD does locking. Please update your front-end programs that edit PR's through GNATSD as appropriate. The code has been cleaned up significantly, but is not compatible with old lock methods. See ChangeLog and UPGRADING for details. October 21, 1998 GNATS 3.107 GNATS is even more Y2K compliant then 3.106 (getdate.y fixed). Multiple Database Support One set of GNATS clients can now handle multiple databases. It's no longer necessary to recompile for each database. A new file, gnats-adm/gnats-db.conf, contains GNATS_ROOT and alias names for each database. Network clients such as nquery-pr and npr-edit only accept the alias names. See the documentation in the info files (make info). Expanded Index The GNATS index now contains all PR fields except for the multitext fields such as Description and How-To-Repeat. This gives a tremendous performance improvement to query operations. In a database of 2000 PRs, a query for a string in the Synopsis field dropped from 4 minutes to 2 seconds. Any front-end or utility that accesses GNATS index files directly will likely need modification. Note also that the index delimiter has changed from ":" to "|". Host and User Access Control The gnastd.conf file now accepts IP addresses as well as host names. Wildcard characters "*" and "?" are supported for both. The second field of this file is now the default access allowed for the host. Access levels are: deny, none, view, viewconf, edit and admin. A new file, gnats-adm/gnatsd.access, contains userids, passwords and access levels for the specific database. Wildcards are supported for the userids and passwords. The same file can be placed into /etc, where a fourth field comes into play that is a list of database aliases. Wildcards are supported for these aliases. Thus, the file becomes a global place to store and manage these permissions. See the documentation in the info files (make info). Upgrading From Previous Version of GNATS (QuickStart) The GNATS index changed in release 3.106 and now again in release 3.107. The following steps will update you. They assume that your GNATS_ROOT is /usr/local/share/gnats/gnats-db and you've built the sources in /usr/local/src/gnats/gnats-3.107-beta. Change for own own situation. From any prior version of GNATS prior to 3.106 (even the ancient 3.2) to GNATS 3.107: $ cd /usr/local/share/gnats $ cp -pR gnats-db gnats-db.BACKUP $ cd gnats-db/gnats-adm $ /usr/local/src/gnats/gnats-3.107-beta/gnats/gen-closed-date --test $ /usr/local/src/gnats/gnats-3.107-beta/gnats/gen-closed-date $ gen-index > index From GNATS 3.106 to GNATS 3.107: $ cd /usr/local/share/gnats/gnats-db/gnats-adm $ mv index index-3.106 $ gen-index > index June 26, 1998 3.106 fixes a number of the limitations found in earlier versions of GNATS: GNATS is now Y2K compliant. Customizable classes and states This upgrade implements customizable classes and states (previously, the lists of possible Problem Report classes and states were hardwired into GNATS). The states patch is from the Cyclic web page and the class patch is based on it. State and Class Types Both the "classes" and "states" files have a new field, "type". Your existing "classes" and "states" files will have to be modified because this new field has been place between the name and description. The only defined class type is "class", but it's not actually used for anything. The only defined state types are "open" and "closed". The "open" state isn't currently used for anything. Changing the state of a PR to any state of type "closed" will set the Closed-Date field with a time stamp. Changing the state of a PR from one "closed" state to another will leave the Closed-Date field as it was. Changing the state of a PR from any state of type "closed" to a non-closed state will clear the Closed-Date field. The "--skip-closed" option of query-pr and nquery-pr looks at the state types for the "closed" type, not for a state name of "closed". New PR field "Release-Note:" (multitext) The "Release-Note:" field was added for human readable (user friendly) comments about problems or fixes (suitable for incorporation into release notes for a given software distribution). New PR field >Closed-Date: The Closed-Date field works in conjunction with the state type "closed". See State and Class Types above. query-pr, nquery-pr and gnatsd checking "Closed-Date" date field There are new query-pr and nquery-pr inquires for PRs closed before or after a specified date: [-z | --closed-before=date] [-Z | --closed-after=date]. For gnatsd: CBFR and CAFT. New program "gen-closed-date" to help with transition to this release - adds Closed-Date field for all existing PRs, with time set for PRs with a State that is of type "closed". - changes the Audit-Trail from "oldstate-newstate" to "oldstate->newstate". - it restores the original PR file timestamp after each PR is rewritten. - run with "--test" arg to see what it will do without actually making any updates. Running make will build this program but it doesn't get installed because you should only need to run it once. Running it repeatedly does no harm. You may decide after running it once that you want the "suspended" state to be type "closed". Just update the states file and rerun gen-closed-date. New option to list the GNATS config file This helps front-end and script writers to more easily determine the GNATS configuration, especially when used remotely. The new query-pr and nquery-pr option is: [-G | --list-config]. For gnatsd: LCFG. Query output listings consistant and complete The Last-Modified and Closed-Date fields have been added to the SQL output format. The new Closed-Date field has been added to the default output format. GNATS 3.106 includes a number of the unofficial patches found on the Cyclic GNATS pages at (http://www.cyclic.com/cyclic-pages/gnats.html). The following patches have been incorporated in one form or another; some have been modified a great deal: Bugfix in free_responsible This patch fixes a bug in the routine to free a variable of the type "Responsible". Check if Reply: valid category When you send a reply to a problem report mailing, with the subject line beginning with: "Re: Foo/15", GNATS will append the letter to Problem report #15. The problem is that GNATS does not check to see if Foo is a valid category. What if someone sent a letter to the bugs address about something to do with OS/2: "Re: OS/2 version problem"? That letter would be appended to Problem report number 2. This [7]patch adds this category check to check-if-reply. Default Category for new PRs The official version of GNATS has "pending" hard-coded as the default category for new problem reports. This patch allows the GNATS administrator to put a default category into the config file (i. e. DEFAULT_CATEGORY="category"). query-pr, nquery-pr and gnatsd checking "Last-Modified" date field There are new query-pr and nquery-pr inquires for PRs modified before or after a specified date: [-B | --modified-before=date] [-M | --modified-after=date]. For gnatsd: MBFR and MAFT. Documentation: Submitting a PR via direct e-mail This new section in the GNATS documentation (in the file s-usage.texi) describes what happens when you create a problem report by sending mail to the support site address. Deriving the Submitter ID from e-mail headers Sometimes a Problem Report comes in without a Submitter ID. This patch to file-pr lets GNATS derive the submitter ID from the "From:" mail header. We have added a new file, called "addresses", which maps e-mail address fragments to Submitter IDs. Putting "Unformatted" text into the "Description" field When a problem report comes in as unformatted text (i. e. someone sends e-mail to the "bugs" address), the text is put into the "Unformatted" field. Since the submitter intends for this text to be the description of the problem, it would be nice if GNATS put the text into the "Description" field. This patch does this, indenting the text by one space. Mail replies to appended letters This patch fixes a couple of formatting errors in the mail GNATS sends in reply to appended letters. BISON output file in Makefile for getdate.c When Makefile compiles getdate.y, it runs the BISON parser generator. This patch deals with problems in the naming of the files which bison outputs. [This patch was replaced by one done by Brendan --pst] Customizable states This patch implements customizable states (previously, the list of possible Problem Report states was hardwired into GNATS). (See the customizable classes above.) Error handling This patch from Mike Sutton fixes a few problems in error reporting. August 18, 1997 This is the 3.104 beta release of GNATS. This is NOT the last beta release. It's still in need of documentation across the board, but I wanted to send this out to get people started on trying it out. It's available on ftp.cygnus.com in /pub/gnats as `gnats-3.104-beta.tar.gz'. Also available are a set of diffs between 3.102 and 3.104, to make it easier for folks to jump straight forward and not apply two sets (from 3.102->3.103, then 3.103->3.104). That set is in `gnats-3.102-3.104-diffs.gz'. This beta is coming out very soon after the 3.103 beta, due to a fundamental bug in the Makefile of that release. I've also dropped in a few other changes, all from "Jonathan I. Kamens" . Thanks Jonathan! I've also updated TkGNATS in the contrib section to the latest release. The file gnats/PROBLEMS has a list of known problems with GNATS; folks are encouraged to fix any of them they might want to. Even investigating a bug further is helpful. By the way, I'm looking for someone to take over maintenance of GNATS, and bring it forward to its much-needed 4.0 release. (Or at the very least, to volunteer to update the documentation so we can finally DO a GNATS 4.0 release.) Please drop me a line if you're interested. Changes in this (and the 3.103) beta release were: * Some screwups wrt the libexec changes made 3.103 install things incorrectly. * The check-db.sh contributed script has been fixed to look in the libexecdir instead of the libdir. * The tkgnats included has now been updated to the latest beta version. * Support for Kerberos 4 on regular BSD systems has been fixed. Compatability with using Kerberos 5 is also added. * The mkdist.sh script can now handle having the files in the dist directory be gzipped. * The contributed delete-pr script has been fixed to get the right variables from the configuration. * David MacKenzie has adjusted all of GNATS to use the GNU standard file system layout; e.g., using `libexec' and `share' instead of putting non-library files in `lib'. * The configuration will now detect if you have GNU m4 installed. * Jonathan Kamens has made it possible to separately install the architecture-dependent pieces for the main server on one machine, and the independent pieces for the clients. * When editing a PR under emacs, use of an invalid name for a responsible party is now detected. pr-addr now accepts `-s' or `--strict'. * Ken Raeburn has done a variety of cleaning on the various clients, including the addition of `-P' or `--port', where applicable, to specify a new port to connect to. * In addition, he adjusted npr-edit to do all of its writes and then look for replies upon completion, to reduce the network delays in using check_pr. * A few bugs in getclose have been fixed to properly do date calculation, and properly parse the dates it's given. * A fundamental bug in npr-edit caused problems on the alpha. * The locking and unlocking of the database are now handled a little more cleanly by the server. * A fix was contributed by Jonathan Kamens to make emacs automatically tell if a particular PR has already been sent---if so, prompt the user before it proceeds to re-send it. The other changes include: * A fundamental fix has been made in pr.c, so that reading in a PR will go much faster; we now double the buffer's size each time we reach its limit. In the past, we only added on BUFSIZ bytes to it, which made us end up reallocating the memory far too many times. * GNATS no longer interprets a line beginning with `>' in the header of the message as a sign that the headers are no longer in effect. * The emacs mode for editing PRs now accept `C-c C-y' to change the `>Severity:' field, and `C-c C-p' to change the `>Priority:' field; either will also put an entry in the audit trail, allowing you to provide an explanation for the change. This makes such changes more easily tracked. * a crash in find_responsible has been fixed by making sure to zero out the receiving array before reading in the list of responsible names; thus, if the `alias' field of the responsible file is missing, we won't end up with garbage in memory * the definition of INSTALL in the GNATS Makefile has been adjusted to let installation in subdirectories work properly in all cases * A bug in the Makefile's creation of the config file has been fixed, so that GNATS_ADDR will always show up. * send-pr no longer pays attention to interrupt signals, since editing the created PR with emacs as your editor allowed send-pr to abort the sending of the PR if you hit `C-g' * send-pr now gets the correct DATADIR definition if you're using GCC_EXEC_PREFIX. * the GNATS PROBLEMS file has been considerably expanded and cleaned up * query-pr and nquery-pr now accept `-y regexp' or `--synopsis=regexp' to search for any PR that contains the given regexp in its `>Synopsis:' field; they also accept `-A regexp' or `--release=regexp' to search for a PR with the regexp in its `>Release:' field. * the daemon will now accept `SYNP regexp' to search for a particular synopsis; `RLSE regexp' to search for a certain value of the `>Release:' field; and `BFOR date' (when configured --with-release-based) and `AFTR date' to search for values of the `>Date-Required:' field. * config/tkgnats has been updated to the 2.0b4 release. * getclose, pr-age, pr-stat, and gnatsd all now accept -V or --version * A bug in the emacs mode has been fixed, so addresses of the form Joe T. User will automatically have the name contained within quotation marks: "Joe T. User"; otherwise, most mail systems would give an error when it sees the period. * Some compile problems with the NeXT system compiler have been fixed. * query-pr now accepts the `-D' debug option of nquery-pr, and ignores it. * A nquery-pr manual page has been added, and a few errors in the exiting pages have been fixed. The missing arguments to query-pr have also been put in place in its man page. * The GNATS install manual now mentions that you probably need GNU m4 in order to build GNATS. In the list of steps to take for installation, the creation of the GNATS account has been moved before the actual running of `make install'. The usage manual now documents the `C-c C-f' (change field) command under emacs. * A new program `getclose' will find you any PRs that were modified between a set of three dates: between two which qualify it as definitely "applied" during that time, and a third date, which will point out those that may or may not be fully resolved in that time. * contrib/scripts has a few handy scripts (two in Korn shell) from Brian Abernathy. * contrib/elisp has the new `gnats-admin.el' from Roger Hayes. * A few bug-fixes in terms of string length have been fixed, to avoid memory errors. * The GNATS daemon has been adjusted to do case-insensitive checks for hostnames trying to access the server. * npr-edit now supports the locking and unlocking of the GNATS database with `--lockdb' and `--unlockdb'. Add LKDB and UNDB commands to the server. * If you're already editing a PR, we now go immediately to that buffer rather than wait for an error to tell us we have it. * Make sure GNATS:RUN-IN-BACKGROUND is null before we do the forced unlocking of remaining buffers. * Indentation of changed fields via GNATS::INDENT has been changed to be in line with the other fields. We'd originally forced it to be one off so it's obvious which fields have changed; let's see how helpful it really was. * Bug fixed in the creation of indexes, causing possible memory corruption. * Configure adjusted for finding the Kerberos library. * Add more portable solution for finding out the hostname. * texinfo has been updated to the 2.8 release. * with the elisp interface to GNATS, gnats:run-in-background defaults to t to make the checking and filing of a PR happen in the background to the emacs process; setting gnats:run-in-background to nil keeps it all in the foreground, as with previous releases. * have new "release based" approach with --with-release-based, adding new `quarter' and `keywords' fields to PRs * cmds.c, clean up general code layout * add checks for netdb.h * default server name now `gnats', not `gnatsserv' * new nedit-pr script, to do network-based editing * add BFOR and AFTR to daemon, for PRs before/after/between certain dates * add VDAT command to daemon, to verify that a date format can be used * make gnats-el.in more friendly to emacs 18 * fix lots of bugs wrt ANSI compliance of the code, clean up array use and unfreed memory * the ability to use a username other than `gnats' by configuring with `--with-gnats-user=name'. This will communicate the desired name down through all of the programs to be built and used. * the server now has a RSET command, to return the daemon to its startup state * the notify field of the submitters file is correctly added to the `Cc:' header of PRs as they're edited. * Ken Raeburn has written a new GNATS summary mode for emacs, used by the command `summ-pr'. Give query-pr or nquery-pr the appropriate options (like --responsible or --state), and you'll get a nice buffer to view or edit those PRs as you choose. * the elisp mode for send-pr fixes a bug about mail-default-reply-to being set to t by default starting with emacs 19.29 * send-pr now takes -s/--severity, to specify the severity on the command line. Also, -c/--cc let you give a Cc: header on the command line. * It's now possible to have multiple GNATS databases on one system. Use --with-gnats-service, --with-gnats-port, --with-gnats-server, and --with-gnats-root when configuring it. It'll install the programs into separte directories (based on --exec-prefix and --prefix), which you can then create symbolic links for somewhere else, or set your PATH depending on which one you want to use. * Modified to use autoconf 2.3 for configuring it. Major improvement in portability combined with this shift. * Added Kerberos support. * Added functionality for a network-based GNATS, rather than having to NFS-mount the directory. Includes a GNATS daemon, network-based query-pr, and new programs like pr-mail (list who should be sent mail about a given PR), and sub-type (give the type of a submitter). The protocol for the server is designed to be versatile and open up future tools. * The mechanism is in place to do remote PR editing and viewing from within emacs. A script-version of a remote edit-pr isn't done yet. * Considerable speedups were done. * Major code cleanup across the board. * Fixed hundreds of bugs since the last gnats release, including memory conflicts, areas that caused crashes, files and directories not being closed, etc. * Cleaned up the GNATS elisp code. * Improved the errors emitted to be more uniform. * Speed increase in many things, including the most concentrated parts of the system (e.g., setting up the lists of mail headers and PR fields). * A new ">Last-Modified:" field, to track when a PR was edited. * Editing a PR will automatically Cc: anyone listed in the notify field of the submitters list. * A few bugs were fixed in file-pr, most notably of which is looking up the PR by number given `category/number' in the Subject: field of a reply. This will stop PRs from ending up in pending if the PR has changed category. Also, the responsible person is no longer set to include their full name in the field, since nothing else keeps it there. * Looking up the responsible address for a PR has been adjusted when editing the PR, so we can let the editor allow names that don't necessarily appear in the `responsible' list, but are valid nonetheless. (You will now only need to list folks in the responsible list if they don't have an account on the system running the server.) * The lock for a PR now gives the pid of the process, and what program locked it. * Argument parsing for gnatsd has been adjusted to properly check the various arguments it can get, including multi-word arguments. * The GNATS:KEEP-EDITED-BUFFERS variable in emacs is now used correctly. * The elisp code is now mostly functional with emacs 18. * file-pr will now find the PR properly in a message that happens to use the Subject: style of `Re[2]: foo/1234: ...'. * Skipping closed PRs is no longer case-sensitive for matching. * The date_required field is now set modify_pr---this used to cause the tools to crash when they were built --with-release-based. * The send-pr elisp code now uses CALL-PROCESS rather than SHELL-COMMAND to get the template PR. It's also been fixed to properly use the MAIL-DEFAULT-REPLY-TO variable. * Minor mistakes in the docs were fixed. * The configure scripts have been fixed to not use the default prefix value of `NONE' if --prefix wasn't specified. * contrib/wwwgnats/wwwgnats.shar is the new version by Karl Berry of the Web interface to GNATS. The support for remote queries and editing is the most dramatic addition. The original approach, requiring the GNATS tree to be exported, will still work. However, the new release will include a daemon and clients, to make it more extendable. Build GNATS as you normally would, configuring it with just: ./configure If you want to install GNATS in a directory other than /usr/local, add the flag `--prefix=/usr/wherever'. Likewise, if you want to install all of the binaries in separate directories, but only maintain one copy of the host-independent files, add `--exec-prefix=/usr/wherever/H-hosttype'. To point GNATS at a particular root for your files, use something like --with-gnats-root=/usr/local/gnats-db If you want to build everything, not just the tools to query and edit, add the flag `--with-full-gnats'. That will make it build the support files like `file-pr', and the daemon, `gnatsd'. By default, the daemon and clients are set to use port 1529. Add the line support 1529/tcp # GNATS to your /etc/services file (or wherever). If you want a different port, simply change it there---you shouldn't have to change it within GNATS. Please note that as of August 7, 1997, we do need to pick a new port since another software package has taken the 1529 port. I'm perfectly willing to move it to port 1629, but we need someone to officially register the port to make sure it stays reserved. (No time to do it myself.) In your inetd.conf file, put something like: -- cut -- support stream tcp nowait gnats /usr/local/etc/gnatsd gnatsd -- cut -- adjusting the path accordingly. To make inetd start spawning the GNATS daemon when connected on that port, send it a HUP signal. By default, the server for the GNATS daemon is assumed to be one with the cname of `gnatsserv'. If you'd like something else, use --with-gnats-server=hostname Please try this on as many hosts as you can, using both the system compiler and the GNU C compiler. To force it to use the system's one, you can do $ CC=cc ./configure to make sure it doesn't find gcc. To build GNATS, just type `make'. If you are using the GNU compiler (aka, if you try to type `gcc' you get it), you'll want to do `make CC=gcc'. In the gnats-adm directory, you'll want to edit `gnatsd.conf'. It lists the hosts allowed to access your server. Or, if you're using Kerberos, it shows the sites that don't require Kerberos authentication. The format is open for revision at the moment; only the first field matters: site.com:: The second field may be used for things like controlling what categories, submitter-id'd PRs, etc can be accessed from that site. In the file that logs syslog messages (/var/adm/messages, for example) you'll find the notification of denied access. Please note that this is a BETA release. Please try to investigate the source of problems before you send me mail about it; don't just say, "It doesn't work!" One of the main reasons for this release is to check the portability and reliability of the new code. Please send any comments or questions to both `brendan@cygnus.com' and `bug-gnats@gnu.org'. Thanks! Brendan gnats-4.1.0/TODO0000600000175000017500000002460010212663042014040 0ustar chewiechewie00000000000000 GNATS General TODO List - 1.Release 4.1: Code cleanups, bug fixes, documentation updates Added: Fri Jun 11 10:36:54 2004 Completed: completed on Wed Nov 3 15:19:27 2004 Duration: 20w 5d 5h 42m elapsed Priority: veryhigh (About to add the finishing touches.) - 1.Prepend $(DESTDIR) to Makefile.in installation targets (Chad) Added: Fri Jun 11 11:08:38 2004 Completed: completed on Fri Jun 11 14:07:23 2004 Duration: 2h 58m elapsed Priority: veryhigh (Committed to CVS.) - 2.Add missing manpages -- one manpage for each application (Chad) Added: Fri Jun 11 11:11:57 2004 Completed: completed on Tue Nov 2 18:14:30 2004 Duration: 20w 4d 8h 2m elapsed Priority: high (getclose added. install-sid added.) - 3.Update the NEWS file. Added: Wed Nov 3 00:18:58 2004 Completed: completed on Wed Nov 3 15:18:58 2004 Duration: 15h 0m elapsed Priority: high (Finished. Talked about CAN report.) - 4.Kill install-sid script and update documentation (Chad) Added: Fri Jun 11 11:09:17 2004 Completed: completed on Wed Nov 3 00:17:18 2004 Duration: 20w 4d 14h 8m elapsed Priority: medium (Repurposed instead of killing it.) - 5.Roll in changes to ./debian Added: Tue Nov 2 18:15:01 2004 Completed: completed on Wed Nov 3 15:19:12 2004 Duration: 21h 4m elapsed Priority: medium (Finished.) 2.Release 4.2: New Features Added: Fri Jun 11 10:37:02 2004 Completed: incomplete Duration: incomplete Priority: high 1.Cleanup build infrastructure w/automake and autoconf Added: Sun Mar 6 13:43:21 2005 Completed: incomplete Duration: incomplete Priority: high 2.Mail handling enhancements Added: Fri Jun 11 14:48:24 2004 Completed: incomplete Duration: incomplete Priority: medium 1.Mail-based manipulation of GNATS database (Mel) Added: Fri Jun 11 14:49:11 2004 Completed: incomplete Duration: incomplete Priority: medium 2.Trigger-based mail format replies (Mel) Added: Fri Jun 11 14:49:28 2004 Completed: incomplete Duration: incomplete Priority: medium 3.Add "To:" header parsing for PR# (prnumber@host.domain.tld) in queue-pr Added: Fri Jun 11 14:49:40 2004 Completed: incomplete Duration: incomplete Priority: medium 3.Release 5.0: New Features, Major Changes to DB Layer, RDBMS Added: Fri Jun 11 10:37:07 2004 Completed: incomplete Duration: incomplete Priority: medium 1.Database Enhancements Added: Fri Jun 11 14:53:57 2004 Completed: incomplete Duration: incomplete Priority: high 1.DB Abstraction Layer (Mel) Added: Fri Jun 11 14:52:27 2004 Completed: incomplete Duration: incomplete Priority: high (Finished but not rolled into GNATS CVS 5.0 branch) 2.Oracle RDBMS Backend (Mel) Added: Fri Jun 11 14:52:39 2004 Completed: incomplete Duration: incomplete Priority: high (Finished but not rolled in to GNATS CVS 5.0 branch) 3.PostgreSQL RDBMS Backend (Mel) Added: Fri Jun 18 15:04:16 2004 Completed: incomplete Duration: incomplete Priority: medium 2.Account enhancements Added: Fri Jun 11 14:56:29 2004 Completed: incomplete Duration: incomplete Priority: medium 1.PAM Authentication (Pankaj) Added: Fri Jun 11 14:56:45 2004 Completed: incomplete Duration: incomplete Priority: high (Patch submitted 2004-06-20.) 4.Release 5.x: New Features Added: Mon Jun 21 10:57:48 2004 Completed: incomplete Duration: incomplete Priority: low 1.Security Enhancements Added: Mon Jun 21 16:29:21 2004 Completed: incomplete Duration: incomplete Priority: high 1.TLS integration via gnutls Added: Mon Jun 21 16:29:48 2004 Completed: incomplete Duration: incomplete Priority: high 2.Mail handling enhancements Added: Fri Jun 11 14:55:10 2004 Completed: incomplete Duration: incomplete Priority: medium 1.MIME Handling Added: Fri Jun 11 14:50:49 2004 Completed: incomplete Duration: incomplete Priority: medium 1.Detach files appropriately for GNATS DB format Added: Fri Jun 11 14:51:48 2004 Completed: incomplete Duration: incomplete Priority: high 2.Convert HTML to TXT? Added: Fri Jun 11 14:51:15 2004 Completed: incomplete Duration: incomplete Priority: medium 3.Database Enhancements Added: Mon Jun 21 11:20:54 2004 Completed: incomplete Duration: incomplete Priority: medium 1.mbox Backend Added: Mon Jun 21 11:22:00 2004 Completed: incomplete Duration: incomplete Priority: low 1.Maintain mbox archive of all emails Added: Fri Jun 11 14:55:27 2004 Completed: incomplete Duration: incomplete Priority: medium 2.Fake Audit trail entries as emails and append to mbox archive Added: Fri Jun 11 14:55:41 2004 Completed: incomplete Duration: incomplete Priority: medium 3.Continue to use existing PR datafile for logging events, keywords, and metadata Added: Fri Jun 11 14:55:58 2004 Completed: incomplete Duration: incomplete Priority: medium 5.Unassigned Added: Fri Jun 11 13:50:51 2004 Completed: incomplete Duration: incomplete Priority: verylow 1.Add squirrels, to make pst happy. Added: Fri Jun 11 14:42:32 2004 Completed: incomplete Duration: incomplete Priority: high 2.Add conditional formats Added: Fri Jun 11 13:56:21 2004 Completed: incomplete Duration: incomplete Priority: medium 3.Add script hooks, probably for edit formats and such. Need to think about how to integrate in changes to the PR done by the script Added: Fri Jun 11 13:57:38 2004 Completed: incomplete Duration: incomplete Priority: medium (after all, that's really the whole point) 4.Allow fields to not exist; add a "field-always-present" option to the field description Added: Fri Jun 11 13:58:17 2004 Completed: incomplete Duration: incomplete Priority: medium 5.Add virtual fields. Added: Fri Jun 11 13:59:28 2004 Completed: incomplete Duration: incomplete Priority: medium (The output format can use the existing format mechanism. This would necessitate having a "no-display" field flag, so that some fields don't show up in a "full" query (adding all the fields to full" is a rather obnoxious requirement). There should also be a "raw" query that dumps all the real fields as raw contents, for editing purposes (and perhaps for other things).) 6.Revise access control mechanisms. Added: Fri Jun 11 14:39:12 2004 Completed: incomplete Duration: incomplete Priority: medium 7.Should PRs have a ">Database-Name:" header? Probably, and probably immutable. Can be used when editing a PR, or submitting an initial one. Added: Fri Jun 11 14:39:27 2004 Completed: incomplete Duration: incomplete Priority: medium 8.Append-only fields. Need to revise access control first. Added: Fri Jun 11 14:40:05 2004 Completed: incomplete Duration: incomplete Priority: medium 9.Document functions. Many of them are undocumented (even newly-added ones, shame). Added: Fri Jun 11 14:41:10 2004 Completed: incomplete Duration: incomplete Priority: medium 10.See how much farther we can go with removing knowledge of particular fields from the gnats code. Added: Fri Jun 11 14:42:03 2004 Completed: incomplete Duration: incomplete Priority: medium 11.Make it possible to include adm field contents in the configuration file, instead of always using an external config file. Added: Fri Jun 11 14:42:59 2004 Completed: incomplete Duration: incomplete Priority: medium 12.The client state is not clean. The API is horrid; clients should not know or care if they're communicating via the network or locally. The original solution was to just allow network access, but that's not really fixing the problem. (We'll know we're there when gnatsd can act as a relay.) Added: Fri Jun 11 14:43:55 2004 Completed: incomplete Duration: incomplete Priority: medium 13.The client connection to the server should also be encapsulated in a struct as well. That is, something to describe the client (its hostname, username, password, access level). Could eventually allow for a single server process that handles multiple connections. Added: Fri Jun 11 14:44:32 2004 Completed: incomplete Duration: incomplete Priority: medium 14.Change edit-pr to include the "Changed-Why:" header in the initial PR template instead of a separate prompt. Maybe. Added: Fri Jun 11 14:24:46 2004 Completed: incomplete Duration: incomplete Priority: low 15.Should all the fields listed in the input section be required? Configurable? How about rejecting initial erroneous PRs (PRs with bad fields) instead of fixing them up? It sucks that pr-edit --submit < /dev/null could quite presumably create a valid PR. Added: Fri Jun 11 14:25:50 2004 Completed: incomplete Duration: incomplete Priority: low 16.The initial PR filing stuff is way too complicated. In particular, the various field checks should be configured in dbconfig. That would let us remove more builtin fields. Added: Fri Jun 11 14:38:18 2004 Completed: incomplete Duration: incomplete Priority: low 17.Decide if the "exec gnatsd locally" option is a security hole. (Probably.) Make it #if TESTING only? Added: Fri Jun 11 14:38:30 2004 Completed: incomplete Duration: incomplete Priority: low 18.Come up with a better name for the lexer source file. Added: Fri Jun 11 14:41:35 2004 Completed: incomplete Duration: incomplete Priority: low gnats-4.1.0/TODO.old0000644000175000017500000000335707401177736014653 0ustar chewiechewie00000000000000Things we plan to do, but either didn't have time yet or want to put more thought into it: * getclose.c - rewrite to use dates from expanded index instead of parsing the Audit-Trail. * pr-age.c - rewrite to use dates from expanded index instead of parsing Arrival-Date. * pr-stat.c - rewrite to use dates from expanded index instead of parsing the Audit-Trail and Arrival-Date. * make the elisp mode for edit-pr track the Synopsis, the way the script does * allow multiple -t options * compile the regexps in query-pr earlier * make the field names configurable at build time * Generalize the system so it can have a stub to handle mail that comes in without a PR form enclosed. For example, regexps to glean what the category should be given the available information. * totally rework the $(libdir)/gnats/SITE files * clean up the logging stuff in file-pr * make category changes more intelligent -- send notification to involved parties, understand replies to old categories, treat pending less like a real category * deja-gnu regression tests * allow specification of ACKNOWLEDGE on a submitter basis * support category aliases * make gnats-adm/index a dbm file for speed * make gnats-mode's locking more like emacs' locking of files in general (i.e. only when modified); first-change-hook in Emacs 19 should be useful * add logical negation of the search rules for query-pr * dist targets in the Makefiles * fixup "//" in paths Things we'd like to see happen (using the routines in libgnats should help): * a GNATS administration front-end, to make coordination of the files and other things more useful Things we're thinking about: * use forms mode for the elisp send-pr? * cache query-pr results? * allow PRs to reside in multiple categories gnats-4.1.0/UPGRADING0000644000175000017500000001672507571232026014644 0ustar chewiechewie00000000000000 Upgrading a GNATS 3 installation to GNATS 4 This document covers upgrading from a reasonably new GNATS 3.1xx installation to GNATS 4. If your installation is older than circa version 3.109, you need to review the UPGRADING.old file before carrying out the steps detailed here. Overview ======== Although almost all of the GNATS internals have been redesigned and rewritten for GNATS 4, little has changed in the format and structure of the database data. The only change that needs to be taken into account when upgrading is the fact that the database index format is binary in a default installation of GNATS 4. Thus, you will need to regenerate your database index by using the gen-index tool. Apart from building and installing new binaries, the major changes which impinge on the upgrade procedure are all on the configuration side. The main database configuration file, dbconfig, is far more complex and powerful than the old config file, and while the installation process creates a sensible set of default values which are similar to GNATS 3.11x's defaults, you still need to migrate any changes you may have made to your own local configuration. Another aspect which needs consideration are remote submitter sites. Such sites either need to be instructed to upgrade their locally installed copies of the GNATS user tools (send-pr, edit-pr and query-pr), or they should be given access through interfaces such as Gnatsweb. Note that tools from version 3.x of GNATS cannot access GNATS 4 servers and version 4 tools cannot access version 3.x servers. Since the GNATS network daemon has been completely reworked, with an entirely new command set, all network-based interfaces, such as Gnatsweb and TkGnats need to be upgraded to versions that support GNATS 4. Currently, Gnatsweb is the only network-based interface which has been rewritten for GNATS 4. The contrib directory of this distribution contains some third-party interfaces, and the README file contains pointers to where one can obtain the newest versions of these tools. This document only deals with upgrading GNATS itself. Third-party tools should have separate upgrading instructions in their distributions. Upgrading ========= 1. Before you begin, make a backup of your entire GNATS database directory hierarchy, the GNATS executables directory and the GNATS user tools (send-pr, query-pr etc.) The locations of these may vary, but in a default GNATS 3 installation, the database(s) reside under /usr/local/share/gnats, the executables are located in /usr/local/libexec/gnats and the user tools reside in /usr/local/bin. 2. (optional) In order to avoid confusing your users, you may want to remove the old GNATS 3 executables and tools, escpecially if you plan to install GNATS 4 in a different location than version 3. 3. Build and install GNATS 4. See the INSTALL file and the GNATS manual for details. It is recommended that you use the --with-gnats-default-db option when running configure, in order to set the default database to be one of your already existing GNATS 3 databases. 4. Edit the GNATS `databases' file, located in SYSCONFDIR/gnats. In a default GNATS 4 installation this is /usr/local/etc/gnats. Add entries for all your old GNATS 3 databases. 5. In GNATS 3, the file gnatsd.conf specifies minimum access levels for the different hosts accessing the GNATS daemon, gnatsd. There is one gnatsd.conf for each database. In GNATS 4, these files have been replaced by a single file named gnatsd.host_access which contains settings that apply across all the databases on the server. This file is located in the same directory as the `databases' file. You need to combine the host access settings from all your GNATS 3 databases and add them to the gnatsd.host_access file. Note that you are no longer able to control host access on a per-database basis. Optionally, you may delete the old gnatsd.conf files. 6. Next, you need to migrate the settings in the old `config' files of your databases to corresponding `dbconfig' files. The database you specified with the --with-gnats-default-db configure option got a default `dbconfig' installed. This default file contains field definitions etc. which makes this version of GNATS behave almost exactly like older versions. Copy this default file to the gnats-adm directories of any other GNATS databases that you may have on your host before you proceed to migrate your old config settings. The following is a list of the configuration directives that may be present in a `config' file and their counterparts (if any) in GNATS 4. GNATS_ADDR This setting has no counterpart in GNATS 4, since GNATS no longer needs to know its own mail address. GNATS_ADMIN This setting is now set in the `responsible' file in the gnats-adm directory of your database(s). GNATS_SITE GNATS 4 has no concept of a named `site', so this directive is obsolete. SUBMITTER Obsolete, since it relates to GNATS_SITE. DEFAULT_RELEASE DEFAULT_ORGANIZATION The GNATS 4 `dbconfig' file has separate configuration sections for each defined field. Field defaults are set with the "default" keyword in these sections. See the treatment of the `dbconfig' file in the GNATS 4 manual for details. NOTIFY Controlled by the "notify-about-expired-prs" setting in the `dbconfig' file. ACKNOWLEDGE Controlled by the "send-submitter-ack" setting in the `dbconfig' file. DEFAULT_SUBMITTER The default submitter is now always the first entry in the `submitters' file of your database. KEEP_RECEIVED_HEADERS Controlled by the "keep-all-received-headers" setting in the `dbconfig' file. DEBUG_MODE Controlled by the "debug-mode" setting in the `dbconfig' file. BDAY_START BDAY_END BWEEK_START BWEEK_END Controlled by the settings "business-day-hours" and "business-week-days" in the `dbconfig' file. DEFINE_CATEGORY The default category for PRs that arrive without one is the first category listed in the `categories' file of your database. See the section on the dbconfig file in the GNATS manual, chapter 4 for details. After your are done migrating the settings, you may optionally delete the old config files. Since there are many more configuration settings available in the GNATS 4 `dbconfig' file, you should take some time to review them all before proceeding. 7. The file gnatsd.access has been renamed to gnatsd.user_access. Furthermore, GNATS 4 uses a different password format than older versions since it supports crypt() and MD5 passwords (see the GNATS manual, Appendix C, "Controlling access to databases" for details.) You need to translate your old gnatsd.access files to the new format by using the gnats-pwconv tool which was installed in the EXEC-PREFIX/libexec/gnats directory, typically /usr/local/libexec/gnats. See "Administrative utilities" in Chapter 4 of the GNATS manual for details on how to use gnats-pwconv. 8. The final step involves regenerating the indexes of your databases. For this, log in as the user `gnats'. Then run the gen-index command for each of your databases. See "Administrative utilities" in Chapter 4 of the GNATS manual for details on how to use gen-index. 9. Sit back and enjoy your new GNATS 4 setup... gnats-4.1.0/UPGRADING.old0000644000175000017500000001055507401177736015424 0ustar chewiechewie00000000000000 Upgrading From Previous Version of GNATS (QuickStart) ===================================================== The GNATS index changed in release 3.106 and again in release 3.107. The following steps will help update you. They assume that your GNATS_ROOT is /usr/local/share/gnats/gnats-db and you've built the sources in /usr/local/src/gnats/gnats-3.107-beta. Change for own own situation. Run these steps logged in as the GNATS_USER!!! From any prior version of GNATS prior to 3.106 (even the ancient 3.2) to GNATS 3.107 (see gen-closed-date notes below): $ cd /usr/local/share/gnats $ cp -pR gnats-db gnats-db.BACKUP $ cd gnats-db/gnats-adm $ /usr/local/src/gnats/gnats-3.107-beta/gnats/gen-closed-date --test $ /usr/local/src/gnats/gnats-3.107-beta/gnats/gen-closed-date $ gen-index > index From GNATS 3.106 to GNATS 3.107: $ cd /usr/local/share/gnats/gnats-db/gnats-adm $ mv index index-3.106 $ gen-index > index From GNATS 3.107 to 3.108 The GNATS lock files for PR's being edited are now all placed into /usr/local/share/gnats/gnats-db/gnats-adm/locks/ instead of the directory where the PR is stored. No attempt is made by the installation to move any existing locks to this directory. Notes to Script and Front-End Client Writers ============================================ The following changes should be noted by anybody writing scripts that access GNATS files, or developing gnats clients. These notes are not complete. Please read the BETA and Changelog files carefully. GNATS 3.109 - Added delete-pr and check-db programs. GNATS 3.106 - Configurable states and classes. - New fields: Release-Note (multitext) and Closed-Date. Closed-Date is managed by GNATS; no need to parse the Audit-Trail for close dates. - SQL query output: two fields added: Last-Modified and Closed-Date. GNATS 3.107 - GNATS index expanded to include all non-multitext fields, and the separator character changed from ":" to "|". - Multiple database support and user access control. GNATS 3.108 - Previously, gnatsd (and npr-edit) always unlocked PRs when an update was attempted, but pr-edt (edit-pr) didn't. Now neither one does and the client must do the unlock. - Previously, gnatsd and npr-edit returned the full text of the PR when locking it, but pr-edit did not. Now they all do. - Previously, gnatsd and npr-edit didn't attempt to lock the entire database when locking a PR, but edit-pr did. Now none of these do. - gnatsd now escapes single dots on a line when sending multitext fields across the network (by adding another dot), and removes the escapes when receiving all data across the network. npr-edit and nquery-pr are updated to handle this. - gnatsd LOCK and FULL now both properly terminate the PR text with "\r\n.\r\n". npr-edit is updated to handle this. - Edit lock files are now all kept in gnats-adm/locks. - gnatsd commands HELP and DBLA are now unrestricted. DBLS is set to "admin" access level. - new gnatsd command CHEK to check PRs before submitting for edit/update. npr-edit uses this new function, which uses the same code as pr-edit. - new gnatsd command MLRS to get the mailing address of a person in the responsible file. This is the gnatsd equivalent of pr-addr, used by the new program npr-addr. - new program npr-addr for network functionality of pr-addr. "gen-closed-date" for upgrading from versions prior to gnats-3.106 ================================================================== - run gen-closed-date logged in as the GNATS_USER!!! - adds Closed-Date field for all existing PRs, with time set for PRs with a State that is of type "closed". - changes the Audit-Trail from "oldstate-newstate" to "oldstate->newstate". - it restores the original PR file timestamp after each PR is rewritten. - run with "--test" arg to see what it will do without actually making any updates. Running make will build this program but it doesn't get installed because you should only need to run it once. Running it repeatedly does no harm. You may decide after running it once that you want the "suspended" state to be type "closed". Just update the states file and rerun gen-closed-date. gnats-4.1.0/config.guess0000744000175000017500000011576307610536310015716 0ustar chewiechewie00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002 Free Software Foundation, Inc. timestamp='2002-09-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # 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 Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # This shell variable is my proudest work .. or something. --bje set_cc_for_build='tmpdir=${TMPDIR-/tmp}/config-guess-$$ ; (old=`umask` && umask 077 && mkdir $tmpdir && umask $old && unset old) || (echo "$me: cannot create $tmpdir" >&2 && exit 1) ; dummy=$tmpdir/dummy ; files="$dummy.c $dummy.o $dummy.rel $dummy" ; trap '"'"'rm -f $files; rmdir $tmpdir; exit 1'"'"' 1 2 15 ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; rm -f $files ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; unset files' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. eval $set_cc_for_build cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; 2-1307) UNAME_MACHINE="alphaev68" ;; 3-1307) UNAME_MACHINE="alphaev7" ;; esac fi rm -f $dummy.s $dummy && rmdir $tmpdir echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`$dummy` if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi rm -f $dummy.c $dummy && rmdir $tmpdir fi ;; esac echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3D:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` rm -f $dummy.c && rmdir $tmpdir echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:3*) echo i386-pc-interix3 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` rm -f $dummy.c && rmdir $tmpdir test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` rm -f $dummy.c && rmdir $tmpdir test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) echo `uname -p`-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp 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` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gnats-4.1.0/config.sub0000744000175000017500000007167407610536310015363 0ustar chewiechewie00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002 Free Software Foundation, Inc. timestamp='2002-09-05' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # 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. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39 | mipstx39el \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3d) basic_machine=alpha-cray os=-unicos ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic4x | c4x*) basic_machine=tic4x-unknown os=-coff ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; windows32) basic_machine=i386-pc os=-windows32-msvcrt ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gnats-4.1.0/configure0000744000175000017500000032317410207435635015306 0ustar chewiechewie00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for gnats 4.1.0. # # Report bugs to . # # Copyright (C) 2003 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 Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='gnats' PACKAGE_TARNAME='gnats' PACKAGE_VERSION='4.1.0' PACKAGE_STRING='gnats 4.1.0' PACKAGE_BUGREPORT='bug-gnats@gnu.org' ac_subdirs_all="$ac_subdirs_all gnats send-pr doc" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT LEX LEXLIB LEX_OUTPUT_ROOT YACC LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # 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. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= 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 ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -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 | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$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 ;; -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 ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) 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 ;; -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=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 ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && 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'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac 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 echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 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 # 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 its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | 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 if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS # # 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 gnats 4.1.0 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 \`..'] _ACEOF cat <<_ACEOF 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] --datadir=DIR read-only architecture-independent data [PREFIX/share] --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] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of gnats 4.1.0:";; esac cat <<\_ACEOF 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 CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory 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 . _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style 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 elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd "$ac_popdir" done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF gnats configure 4.1.0 generated by GNU Autoconf 2.59 Copyright (C) 2003 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 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by gnats $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { 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` hostinfo = `(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=. echo "PATH: $as_dir" done } >&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_sep= 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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$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 ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >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 # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" 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. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 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 `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 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 { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`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. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } 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 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 { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. subdirs="$subdirs gnats send-pr doc" 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_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" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done 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 echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out 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. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; 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 | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$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 echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* 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 -std1 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 -std1. */ int osf4_cc_array ['\x00' == 0 ? 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 # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext 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 for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_LEX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then echo "$as_me:$LINENO: result: $LEX" >&5 echo "${ECHO_T}$LEX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test -z "$LEXLIB" then echo "$as_me:$LINENO: checking for yywrap in -lfl" >&5 echo $ECHO_N "checking for yywrap in -lfl... $ECHO_C" >&6 if test "${ac_cv_lib_fl_yywrap+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char yywrap (); int main () { yywrap (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_fl_yywrap=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_fl_yywrap=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_fl_yywrap" >&5 echo "${ECHO_T}$ac_cv_lib_fl_yywrap" >&6 if test $ac_cv_lib_fl_yywrap = yes; then LEXLIB="-lfl" else echo "$as_me:$LINENO: checking for yywrap in -ll" >&5 echo $ECHO_N "checking for yywrap in -ll... $ECHO_C" >&6 if test "${ac_cv_lib_l_yywrap+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ll $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char yywrap (); int main () { yywrap (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_l_yywrap=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_l_yywrap=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_l_yywrap" >&5 echo "${ECHO_T}$ac_cv_lib_l_yywrap" >&6 if test $ac_cv_lib_l_yywrap = yes; then LEXLIB="-ll" fi fi fi if test "x$LEX" != "x:"; then echo "$as_me:$LINENO: checking lex output file root" >&5 echo $ECHO_N "checking lex output file root... $ECHO_C" >&6 if test "${ac_cv_prog_lex_root+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # The minimal lex program is just a single line: %%. But some broken lexes # (Solaris, I think it was) want two %% lines, so accommodate them. cat >conftest.l <<_ACEOF %% %% _ACEOF { (eval echo "$as_me:$LINENO: \"$LEX conftest.l\"") >&5 (eval $LEX conftest.l) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5 echo "$as_me: error: cannot find output from $LEX; giving up" >&2;} { (exit 1); exit 1; }; } fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5 echo "${ECHO_T}$ac_cv_prog_lex_root" >&6 rm -f conftest.l LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5 echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6 if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c ac_save_LIBS=$LIBS LIBS="$LIBS $LEXLIB" cat >conftest.$ac_ext <<_ACEOF `cat $LEX_OUTPUT_ROOT.c` _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_lex_yytext_pointer=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS rm -f "${LEX_OUTPUT_ROOT}.c" fi echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5 echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6 if test $ac_cv_prog_lex_yytext_pointer = yes; then cat >>confdefs.h <<\_ACEOF #define YYTEXT_POINTER 1 _ACEOF fi fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_YACC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then echo "$as_me:$LINENO: result: $YACC" >&5 echo "${ECHO_T}$YACC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" ac_config_files="$ac_config_files 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, don't put newlines in cache variables' values. # 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. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *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 \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" 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}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ 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[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $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} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by gnats $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet 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 Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ gnats config.status 4.1.0 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. 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=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; 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 if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; 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 fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@subdirs@,$subdirs,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@LEX@,$LEX,;t t s,@LEXLIB@,$LEXLIB,;t t s,@LEX_OUTPUT_ROOT@,$LEX_OUTPUT_ROOT,;t t s,@YACC@,$YACC,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac # 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. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;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,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # 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 || { (exit 1); exit 1; } fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file and --srcdir arguments so they do not pile up. ac_sub_configure_args= ac_prev= for ac_arg in $ac_configure_args; do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -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=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_sub_configure_args="--prefix=$prefix $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d $srcdir/$ac_dir || continue { echo "$as_me:$LINENO: configuring in $ac_dir" >&5 echo "$as_me: configuring in $ac_dir" >&6;} { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then ac_sub_configure="$SHELL '$ac_srcdir/configure.gnu'" elif test -f $ac_srcdir/configure; then ac_sub_configure="$SHELL '$ac_srcdir/configure'" elif test -f $ac_srcdir/configure.in; then ac_sub_configure=$ac_configure else { echo "$as_me:$LINENO: WARNING: no configuration information is in $ac_dir" >&5 echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative path. ac_sub_cache_file=$ac_top_builddir$cache_file ;; esac { echo "$as_me:$LINENO: running $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 echo "$as_me: running $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval $ac_sub_configure $ac_sub_configure_args \ --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir || { { echo "$as_me:$LINENO: error: $ac_sub_configure failed for $ac_dir" >&5 echo "$as_me: error: $ac_sub_configure failed for $ac_dir" >&2;} { (exit 1); exit 1; }; } fi cd "$ac_popdir" done fi gnats-4.1.0/configure.in0000644000175000017500000000202110207435253015667 0ustar chewiechewie00000000000000dnl Process this file with autoconf to produce a configure script. dnl dnl Copyright (C) 2001 Milan Zamazal dnl dnl This file is part of GNU GNATS. dnl dnl GNU GNATS is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2, or (at your option) dnl any later version. dnl dnl GNU GNATS is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with GNU GNATS; see the file COPYING. If not, write to the Free dnl Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. dnl AC_PREREQ(2.5) AC_INIT(gnats,4.1.0,bug-gnats@gnu.org) AC_CONFIG_SUBDIRS(gnats send-pr doc) AC_PROG_CC AC_PROG_LEX AC_PROG_YACC AC_CONFIG_FILES([Makefile]) AC_OUTPUT gnats-4.1.0/install-sh0000744000175000017500000001273607005251727015402 0ustar chewiechewie00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # 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. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # 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 $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 gnats-4.1.0/ltconfig0000744000175000017500000025164407005251727015134 0ustar chewiechewie00000000000000#! /bin/sh # ltconfig - Create a system-specific libtool. # Copyright (C) 1996-1999 Free Software Foundation, Inc. # Gordon Matzigkeit , 1996 # # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # 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. # A lot of this script is taken from autoconf-2.10. # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} echo=echo if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell. exec "$SHELL" "$0" --no-reexec ${1+"$@"} fi # Find the correct PATH separator. Usually this is `:', but # DJGPP uses `;' like DOS. if test "X${PATH_SEPARATOR+set}" != "Xset"; then UNAME=${UNAME-`uname 2>/dev/null`} case X$UNAME in *-DOS) PATH_SEPARATOR=';' ;; *) PATH_SEPARATOR=':' ;; esac fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi if test "X${echo_test_string+set}" != "Xset"; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if (echo_test_string="`eval $cmd`") 2>/dev/null && echo_test_string="`eval $cmd`" && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then break fi done fi if test "X`($echo '\t') 2>/dev/null`" != 'X\t' || test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for dir in $PATH /usr/ucb; do if test -f $dir/echo && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then echo="$dir/echo" break fi done IFS="$save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif test -f /bin/ksh && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running ltconfig again with it. ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}" export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"} else # Try using printf. echo='printf "%s\n"' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then # Cool, printf works : elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL" export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL $0 --fallback-echo" elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then echo="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e s/^X//' sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # The name of this program. progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` # Constants: PROGRAM=ltconfig PACKAGE=libtool VERSION=1.2f TIMESTAMP=" (1.385 1999/03/15 17:24:54)" ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5' ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5' rm="rm -f" help="Try \`$progname --help' for more information." # Global variables: default_ofile=libtool can_build_shared=yes enable_shared=yes # All known linkers require a `.a' archive for static linking. enable_static=yes enable_fast_install=yes enable_dlopen=unknown ltmain= silent= srcdir= ac_config_guess= ac_config_sub= host= nonopt= ofile="$default_ofile" verify_host=yes with_gcc=no with_gnu_ld=no need_locks=yes ac_ext=c objext=o libext=a cache_file= old_AR="$AR" old_CC="$CC" old_CFLAGS="$CFLAGS" old_CPPFLAGS="$CPPFLAGS" old_LD="$LD" old_LN_S="$LN_S" old_NM="$NM" old_RANLIB="$RANLIB" old_DLLTOOL="$DLLTOOL" old_AS="$AS" # Parse the command line options. args= prev= for option do case "$option" in -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then eval "$prev=\$option" prev= continue fi case "$option" in --help) cat <&2 echo "$help" 1>&2 exit 1 ;; *) if test -z "$ltmain"; then ltmain="$option" elif test -z "$host"; then # This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 # if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then # echo "$progname: warning \`$option' is not a valid host type" 1>&2 # fi host="$option" else echo "$progname: too many arguments" 1>&2 echo "$help" 1>&2 exit 1 fi ;; esac done if test -z "$ltmain"; then echo "$progname: you must specify a LTMAIN file" 1>&2 echo "$help" 1>&2 exit 1 fi if test ! -f "$ltmain"; then echo "$progname: \`$ltmain' does not exist" 1>&2 echo "$help" 1>&2 exit 1 fi # Quote any args containing shell metacharacters. ltconfig_args= for arg do case "$arg" in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ltconfig_args="$ltconfig_args '$arg'" ;; *) ltconfig_args="$ltconfig_args $arg" ;; esac done # A relevant subset of AC_INIT. # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 5 compiler messages saved in config.log # 6 checking for... messages and results if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>>./config.log # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test -n "$cache_file" && test -r "$cache_file"; then echo "loading cache $cache_file within ltconfig" . $cache_file fi if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi if test -z "$srcdir"; then # Assume the source directory is the same one as the path to LTMAIN. srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'` test "$srcdir" = "$ltmain" && srcdir=. fi trap "$rm conftest*; exit 1" 1 2 15 if test "$verify_host" = yes; then # Check for config.guess and config.sub. ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/config.guess; then ac_aux_dir=$ac_dir break fi done if test -z "$ac_aux_dir"; then echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 echo "$help" 1>&2 exit 1 fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub # Make sure we can run config.sub. if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then : else echo "$progname: cannot run $ac_config_sub" 1>&2 echo "$help" 1>&2 exit 1 fi echo $ac_n "checking host system type""... $ac_c" 1>&6 host_alias=$host case "$host_alias" in "") if host_alias=`$SHELL $ac_config_guess`; then : else echo "$progname: cannot guess host type; you must specify one" 1>&2 echo "$help" 1>&2 exit 1 fi ;; esac host=`$SHELL $ac_config_sub $host_alias` echo "$ac_t$host" 1>&6 # Make sure the host verified. test -z "$host" && exit 1 elif test -z "$host"; then echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 echo "$help" 1>&2 exit 1 else host_alias=$host fi # Transform linux* to *-*-linux-gnu*, to support old configure scripts. case "$host_os" in linux-gnu*) ;; linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` esac host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` case "$host_os" in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "${COLLECT_NAMES+set}" != set; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Determine commands to create old-style static archives. old_archive_cmds='$AR cru $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= # Set a sane default for `AR'. test -z "$AR" && AR=ar # If RANLIB is not set, then run the test. if test "${RANLIB+set}" != "set"; then result=no echo $ac_n "checking for ranlib... $ac_c" 1>&6 IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/ranlib; then RANLIB="ranlib" result="ranlib" break fi done IFS="$save_ifs" echo "$ac_t$result" 1>&6 fi if test -n "$RANLIB"; then old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" fi # Set sane defaults for `DLLTOOL' and `AS', used on cygwin. test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$AS" && AS=as # Check to see if we are using GCC. if test "$with_gcc" != yes || test -z "$CC"; then # If CC is not set, then try to find GCC or a usable CC. if test -z "$CC"; then echo $ac_n "checking for gcc... $ac_c" 1>&6 IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for dir in $PATH; do IFS="$save_ifs" test -z "$dir" && dir=. if test -f $dir/gcc; then CC="gcc" break fi done IFS="$save_ifs" if test -n "$CC"; then echo "$ac_t$CC" 1>&6 else echo "$ac_t"no 1>&6 fi fi # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". if test -z "$CC"; then echo $ac_n "checking for cc... $ac_c" 1>&6 IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" cc_rejected=no for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/cc; then if test "$dir/cc" = "/usr/ucb/cc"; then cc_rejected=yes continue fi CC="cc" break fi done IFS="$save_ifs" if test $cc_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $CC shift if test $# -gt 0; then # We chose a different compiler from the bogus one. # However, it has the same name, so the bogon will be chosen # first if we set CC to just the name; use the full file name. shift set dummy "$dir/cc" "$@" shift CC="$@" fi fi if test -n "$CC"; then echo "$ac_t$CC" 1>&6 else echo "$ac_t"no 1>&6 fi if test -z "$CC"; then echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 exit 1 fi fi # Now see if the compiler is really GCC. with_gcc=no echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 echo "$progname:564: checking whether we are using GNU C" >&5 $rm conftest.c cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then with_gcc=yes fi $rm conftest.c echo "$ac_t$with_gcc" 1>&6 fi # Allow CC to be a program name with arguments. set dummy $CC compiler="$2" echo $ac_n "checking for object suffix... $ac_c" 1>&6 $rm conftest* echo 'int i = 1;' > conftest.c echo "$progname:586: checking for object suffix" >& 5 if { (eval echo $progname:587: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then # Append any warnings to the config.log. cat conftest.err 1>&5 for ac_file in conftest.*; do case $ac_file in *.c) ;; *) objext=`echo $ac_file | sed -e s/conftest.//` ;; esac done else cat conftest.err 1>&5 echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi $rm conftest* echo "$ac_t$objext" 1>&6 echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 pic_flag= special_shlib_compile_flags= wl= link_static_flag= no_builtin_flag= if test "$with_gcc" = yes; then wl='-Wl,' link_static_flag='-static' case "$host_os" in beos* | irix5* | irix6* | osf3* | osf4*) # PIC is the default for these OSes. ;; aix*) # Below there is a dirty hack to force normal static linking with -ldl # The problem is because libdl dynamically linked with both libc and # libC (AIX C++ library), which obviously doesn't included in libraries # list by gcc. This cause undefined symbols with -static flags. # This hack allows C programs to be linked with "-static -ldl", but # we not sure about C++ programs. link_static_flag="$link_static_flag ${wl}-lC" ;; cygwin* | mingw* | os2*) # We can build DLLs from non-PIC. ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. pic_flag='-m68020 -resident32 -malways-restore-a4' ;; *) pic_flag='-fPIC' ;; esac else # PORTME Check for PIC flags for the system compiler. case "$host_os" in aix3* | aix4*) # All AIX code is PIC. link_static_flag='-bnso -bI:/lib/syscalls.exp' ;; hpux9* | hpux10* | hpux11*) # Is there a better link_static_flag that works with the bundled CC? wl='-Wl,' link_static_flag="${wl}-a ${wl}archive" pic_flag='+Z' ;; irix5* | irix6*) wl='-Wl,' link_static_flag='-non_shared' # PIC (with -KPIC) is the default. ;; cygwin* | mingw* | os2*) # We can build DLLs from non-PIC. ;; osf3* | osf4*) # All OSF/1 code is PIC. wl='-Wl,' link_static_flag='-non_shared' ;; sco3.2v5*) pic_flag='-Kpic' link_static_flag='-dn' special_shlib_compile_flags='-belf' ;; solaris*) pic_flag='-KPIC' link_static_flag='-Bstatic' wl='-Wl,' ;; sunos4*) pic_flag='-PIC' link_static_flag='-Bstatic' wl='-Qoption ld ' ;; sysv4.2uw2* | sysv4.3* | sysv5*) pic_flag='-KPIC' link_static_flag='-Bstatic' wl='-Wl,' ;; uts4*) pic_flag='-pic' link_static_flag='-Bstatic' ;; *) can_build_shared=no ;; esac fi if test -n "$pic_flag"; then echo "$ac_t$pic_flag" 1>&6 # Check to make sure the pic_flag actually works. echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $pic_flag -DPIC" echo "$progname:717: checking if $compiler PIC flag $pic_flag works" >&5 if { (eval echo $progname:718: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then # Append any warnings to the config.log. cat conftest.err 1>&5 case "$host_os" in hpux9* | hpux10* | hpux11*) # On HP-UX, both CC and GCC only warn that PIC is supported... then they # create non-PIC objects. So, if there were any warnings, we assume that # PIC is not supported. if test -s conftest.err; then echo "$ac_t"no 1>&6 can_build_shared=no pic_flag= else echo "$ac_t"yes 1>&6 pic_flag=" $pic_flag" fi ;; *) echo "$ac_t"yes 1>&6 pic_flag=" $pic_flag" ;; esac else # Append any errors to the config.log. cat conftest.err 1>&5 can_build_shared=no pic_flag= echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* else echo "$ac_t"none 1>&6 fi # Check to see if options -o and -c are simultaneously supported by compiler echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -c -o conftest2.o" echo "$progname:760: checking if $compiler supports -c -o file.o" >&5 if { (eval echo $progname:761: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest2.o; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then echo "$ac_t"no 1>&6 compiler_c_o=no else echo "$ac_t"yes 1>&6 compiler_c_o=yes fi else # Append any errors to the config.log. cat conftest.err 1>&5 compiler_c_o=no echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* if test x"$compiler_c_o" = x"yes"; then # Check to see if we can write to a .lo echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -c -o conftest.lo" echo "$progname:788: checking if $compiler supports -c -o file.lo" >&5 if { (eval echo $progname:789: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then echo "$ac_t"no 1>&6 compiler_o_lo=no else echo "$ac_t"yes 1>&6 compiler_o_lo=yes fi else # Append any errors to the config.log. cat conftest.err 1>&5 compiler_o_lo=no echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* else compiler_o_lo=no fi # Check to see if we can do hard links to lock some files if needed hard_links="nottested" if test "$compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no echo "$ac_t$hard_links" 1>&6 $rm conftest* if test "$hard_links" = no; then echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2 need_locks=warn fi else need_locks=no fi if test "$with_gcc" = yes; then # Check to see if options -fno-rtti -fno-exceptions are supported by compiler echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c" echo "$progname:840: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 if { (eval echo $progname:841: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then echo "$ac_t"no 1>&6 compiler_rtti_exceptions=no else echo "$ac_t"yes 1>&6 compiler_rtti_exceptions=yes fi else # Append any errors to the config.log. cat conftest.err 1>&5 compiler_rtti_exceptions=no echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* if test "$compiler_rtti_exceptions" = "yes"; then no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' else no_builtin_flag=' -fno-builtin' fi fi # Check for any special shared library compilation flags. if test -n "$special_shlib_compile_flags"; then echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : else echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 can_build_shared=no fi fi echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 $rm conftest* echo 'main(){return(0);}' > conftest.c save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $link_static_flag" echo "$progname:884: checking if $compiler static flag $link_static_flag works" >&5 if { (eval echo $progname:885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then echo "$ac_t$link_static_flag" 1>&6 else echo "$ac_t"none 1>&6 link_static_flag= fi LDFLAGS="$save_LDFLAGS" $rm conftest* if test -z "$LN_S"; then # Check to see if we can use ln -s, or we need hard links. echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 $rm conftestdata if ln -s X conftestdata 2>/dev/null; then $rm conftestdata LN_S="ln -s" else LN_S=ln fi if test "$LN_S" = "ln -s"; then echo "$ac_t"yes 1>&6 else echo "$ac_t"no 1>&6 fi fi # Make sure LD is an absolute path. if test -z "$LD"; then ac_prog=ld if test "$with_gcc" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 echo "$progname:917: checking for ld used by GCC" >&5 ac_prog=`($CC -print-prog-name=ld) 2>&5` case "$ac_prog" in # Accept absolute paths. /* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we are not using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then echo $ac_n "checking for GNU ld... $ac_c" 1>&6 echo "$progname:941: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 echo "$progname:944: checking for non-GNU ld" >&5 fi if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog"; then LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" fi if test -n "$LD"; then echo "$ac_t$LD" 1>&6 else echo "$ac_t"no 1>&6 fi if test -z "$LD"; then echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 exit 1 fi fi # Check to see if it really is or is not GNU ld. echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 # I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then with_gnu_ld=yes else with_gnu_ld=no fi echo "$ac_t$with_gnu_ld" 1>&6 # See if the linker supports building shared libraries. echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 allow_undefined_flag= no_undefined_flag= need_lib_prefix=unknown need_version=unknown # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments archive_cmds= archive_expsym_cmds= old_archive_from_new_cmds= export_dynamic_flag_spec= whole_archive_flag_spec= thread_safe_flag_spec= hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=unsupported runpath_var= always_export_symbols=no export_symbols_cmds='$NM $libobjs | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an egrep regular expression of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms= case "$host_os" in cygwin* | mingw*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$with_gcc" != yes; then with_gnu_ld=no fi ;; freebsd2* | sunos4*) exclude_expsyms="_GLOBAL_OFFSET_TABLE_" ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case "$host_os" in aix3* | aix4*) # On AIX, the GNU linker is very broken ld_shlibs=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF ;; amigaos*) archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; sunos4*) archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' wlarc= hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; beos*) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=yes # Extract the symbol export list from an `--export-all' def file, # then regenerate the def file from the symbol export list, so that # the compiled dll only exports the symbol export list. export_symbols_cmds='rm -f $objdir/$soname-ltdll.c~ sed -e "/^# \/\* ltdll.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ (cd $objdir && $CC -c $soname-ltdll.c)~ $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs~ sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols' archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~ _lt_hint=1; for symbol in `cat $export_symbols`; do echo " \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def; _lt_hint=`expr 1 + \$_lt_hint`; done~ $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts' old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' ;; *) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi else # PORTME fill in a description of your system's linker (not GNU ld) case "$host_os" in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$with_gcc" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4*) allow_undefined_flag= if test "$with_gcc" = yes; then if strings `${CC} -print-prog-name=collect2` | \ grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported fi archive_cmds='$CC -shared ${wl}-bnoentry -o $objdir/$soname $libobjs $deplibs $linkopts' else always_export_symbols=yes archive_expsym_cmds='$CC -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bM:SRE ${wl}-bnoentry' hardcode_direct=yes fi hardcode_minus_L=yes # Though LIBPATH variable hardcodes shlibpath into executable, # it doesn't affect searching for -l* libraries; this confuses # tests in mdemo. hardcode_shlibpath_var=unsupported hardcode_libdir_flag_spec='-L$libdir' ;; amigaos*) archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; cygwin* | mingw*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib /OUT:$oldlib$oldobjs' fix_srcfile_path='`cygpath -w $srcfile`' ;; freebsd1*) ld_shlibs=no can_build_shared=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_minus_L=no # verified on 2.2.6 hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd*) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_minus_L=no hardcode_shlibpath_var=no ;; hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +s +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_direct=yes hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10* | hpux11*) archive_cmds='$LD -b +h $soname +s +b $install_libdir -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_direct=yes hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; irix5* | irix6*) if test "$with_gcc" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' else archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF fi hardcode_libdir_flag_spec='${wl}-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; openbsd*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def' old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' ;; osf3* | osf4*) if test "$with_gcc" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; sco3.2v5*) archive_cmds='$LD -G -o $lib $libobjs $deplibs $linkopts' hardcode_direct=yes ;; solaris*) no_undefined_flag=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no ;; sunos4*) # Why do we need -Bstatic? To avoid inter-library dependencies, maybe... if test "$with_gcc" = yes; then # Use -fPIC here because libgcc is multilibbed archive_cmds='$CC -shared ${wl}-Bstatic -fPIC -o $lib $libobjs $deplibs $linkopts' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=no ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=no ;; *) ld_shlibs=no can_build_shared=no ;; esac fi echo "$ac_t$ld_shlibs" 1>&6 if test -z "$NM"; then echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 case "$NM" in /* | [A-Za-z]:[/\\]*) ;; # Let the user override the test with a path. *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/nm; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then NM="$ac_dir/nm -B" break elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then NM="$ac_dir/nm -p" break else NM=${NM="$ac_dir/nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags fi fi done IFS="$ac_save_ifs" test -z "$NM" && NM=nm ;; esac echo "$ac_t$NM" 1>&6 fi # Check for command to grab the raw symbol name followed by C symbol from nm. echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Transform the above into a raw symbol and a C symbol. symxfrm='\1 \2\3 \3' # Transform an extracted symbol line into a proper C declaration global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" # Define system-specific variables. case "$host_os" in aix*) symcode='[BCDT]' ;; cygwin* | mingw*) symcode='[ABCDGISTW]' ;; hpux*) # Its linker distinguishes data from code symbols global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" ;; irix*) symcode='[BCDEGRST]' ;; solaris*) symcode='[BDT]' ;; esac # If we're using GNU nm, then use its standard symbol codes. if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then symcode='[ABCDGISTW]' fi # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Write the raw and C identifiers. global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no $rm conftest* cat > conftest.c <&5 if { (eval echo $progname:1448: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then # Now try to grab the symbols. nlist=conftest.nm if { echo "$progname:1451: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if egrep ' nm_test_var$' "$nlist" >/dev/null; then if egrep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.c #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c' cat <> conftest.c #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = { EOF sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c cat <<\EOF >> conftest.c {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$objext conftestm.$objext save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="conftestm.$objext" CFLAGS="$CFLAGS$no_builtin_flag" if { (eval echo $progname:1503: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then pipe_works=yes else echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi LIBS="$save_LIBS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi $rm conftest* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else global_symbol_pipe= fi done echo "$ac_t$pipe_works" 1>&6 if test -z "$global_symbol_pipe"; then global_symbol_to_cdecl= fi # Check hardcoding attributes. echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 hardcode_action= if test -n "$hardcode_libdir_flag_spec" || \ test -n "$runpath_var"; then # We can hardcode non-existant directories. if test "$hardcode_direct" != no && \ test "$hardcode_minus_L" != no && \ test "$hardcode_shlibpath_var" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi echo "$ac_t$hardcode_action" 1>&6 reload_flag= reload_cmds='$LD$reload_flag -o $output$reload_objs' echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 # PORTME Some linkers may need a different reload flag. reload_flag='-r' echo "$ac_t$reload_flag" 1>&6 test -n "$reload_flag" && reload_flag=" $reload_flag" # PORTME Fill in your ld.so characteristics library_names_spec= libname_spec='lib$name' soname_spec= postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" file_magic_cmd= file_magic_test_file= deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [regex]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given egrep regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 case "$host_os" in aix3*) version_type=linux library_names_spec='${libname}${release}.so$versuffix $libname.a' shlibpath_var=LIBPATH # AIX has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}.so$major' ;; aix4*) version_type=linux # AIX has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. # We preserve .a as extension for shared libraries though AIX4.2 # and later linker supports .so library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a' shlibpath_var=LIBPATH deplibs_check_method=pass_all ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' ;; beos*) library_names_spec='${libname}.so' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux library_names_spec='${libname}.so$major ${libname}.so' soname_spec='${libname}.so' finish_cmds='PATH="$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH deplibs_check_method='file_magic ELF 32-bit LSB shared object' file_magic_cmd=/usr/bin/file file_magic_test_file=/shlib/libc.so sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw*) version_type=windows if test "$with_gcc" = yes; then library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a' else library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' fi dynamic_linker='Win32 ld.exe' deplibs_check_method='file_magic file format pei*-i386.*architecture: i386' file_magic_cmd='objdump -f' need_lib_prefix=no # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; freebsd1*) dynamic_linker=no ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case "$version_type" in freebsd-elf*) deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /usr/lib/libc.so*` library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' need_version=no need_lib_prefix=no ;; freebsd-*) deplibs_check_method=unknown library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' need_version=yes ;; esac finish_cmds='PATH="$PATH:/sbin" OBJFORMAT="'"$objformat"'" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH ;; gnu*) version_type=linux library_names_spec='${libname}${release}.so$versuffix ${libname}.so' shlibpath_var=LD_LIBRARY_PATH ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. dynamic_linker="$host_os dld.sl" version_type=sunos need_lib_prefix=no need_version=no shlibpath_var=SHLIB_PATH library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' soname_spec='${libname}${release}.sl$major' # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5*) version_type=irix soname_spec='${libname}${release}.so' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' shlibpath_var=LD_LIBRARY_PATH deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" # or should it be pass_all? file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /lib/libc.so*` shlibpath_overrides_runpath=no ;; irix6*) version_type=irix need_lib_prefix=no need_version=no soname_spec='${libname}${release}.so' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' case "$LD" in # libtool.m4 will add one of these switches to LD *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no # even though /usr/local/lib is always searched, the man-page says # shared libraries should not be installed there if they use an ABI # different from -32, so we'd better not search for shared libraries # there either sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" # or should it be pass_all? file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /lib${libsuff}/libc.so*` ;; # No shared lib support for Linux oldld, aout, or coff. linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) dynamic_linker=no ;; # This must be Linux ELF. linux-gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' finish_cmds='PATH="$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` if test -f /lib/ld.so.1; then dynamic_linker='GNU ld.so' else # Only the GNU ld.so supports shared libraries on MkLinux. case "$host_cpu" in powerpc*) dynamic_linker=no ;; *) dynamic_linker='Linux ld.so' ;; esac fi ;; netbsd*) version_type=sunos if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' finish_cmds='PATH="$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' soname_spec='${libname}${release}.so$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH ;; openbsd*) version_type=sunos if test "$with_gnu_ld" = yes; then need_lib_prefix=no need_version=no fi library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH ;; os2*) libname_spec='$name' need_lib_prefix=no library_names_spec='$libname.dll $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4*) version_type=osf soname_spec='${libname}${release}.so' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' shlibpath_var=LD_LIBRARY_PATH # deplibs_check_method='pass_all' # Although pass_all appears to work, it copies symbols from static libraries # into shared ones and exports them. So, when a program is linked with two # or more libraries that have got copies of the same symbols, link fails # This was only tested on osf4: deplibs_check_method='file_magic COFF format alpha shared library' file_magic_cmd=/usr/bin/file file_magic_test_file=/shlib/libc.so sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}.so$major' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib" file_magic_cmd=/usr/bin/file file_magic_test_file=/lib/libc.so ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH case "$host_vendor" in ncr) deplibs_check_method='pass_all' ;; esac ;; uts4*) version_type=linux library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac echo "$ac_t$dynamic_linker" 1>&6 test "$dynamic_linker" = no && can_build_shared=no # Report the final consequences. echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then case "$deplibs_check_method" in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | egrep "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4*) test "$enable_shared" = yes && enable_static=no ;; esac echo "$ac_t$enable_shared" 1>&6 # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes echo "checking whether to build static libraries... $enable_static" 1>&6 if test "$hardcode_action" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi echo $ac_n "checking for objdir... $ac_c" 1>&6 rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. objdir=_libs fi rmdir .libs 2>/dev/null echo "$ac_t$objdir" 1>&6 if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then lt_cv_dlopen=no lt_cv_dlopen_libs= echo $ac_n "checking for dlopen""... $ac_c" 1>&6 echo "$progname:1977: checking for dlopen" >&5 if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen(); int main() { /* 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_dlopen) || defined (__stub___dlopen) choke me #else dlopen(); #endif ; return 0; } EOF if { (eval echo $progname:2004: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlopen=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_dlopen=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="dlopen" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 echo "$progname:2022: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 echo "$progname:2059: checking for dld_link in -ldld" >&5 ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for shl_load""... $ac_c" 1>&6 echo "$progname:2096: checking for shl_load" >&5 if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load(); int main() { /* 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_shl_load) || defined (__stub___shl_load) choke me #else shl_load(); #endif ; return 0; } EOF if { (eval echo $progname:2123: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_shl_load=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_shl_load=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="shl_load" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for LoadLibrary""... $ac_c" 1>&6 echo "$progname:2141: checking for LoadLibrary" >&5 if eval "test \"`echo '$''{'ac_cv_func_LoadLibrary'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char LoadLibrary(); int main() { /* 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_LoadLibrary) || defined (__stub___LoadLibrary) choke me #else LoadLibrary(); #endif ; return 0; } EOF if { (eval echo $progname:2168: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_LoadLibrary=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_LoadLibrary=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'LoadLibrary`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="LoadLibrary" else echo "$ac_t""no" 1>&6 fi fi fi fi fi fi if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes fi case "$lt_cv_dlopen" in dlopen) for ac_hdr in dlfcn.h; do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "$progname:2210: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int fnord = 0; EOF ac_try="$ac_compile conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo $progname:2220: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi done if test "x$ac_cv_header_dlfcn_h" = xyes; then CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" fi eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" LIBS="$lt_cv_dlopen_libs $LIBS" echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 echo "$progname:2248: checking whether a program can dlopen itself" >&5 if test "${lt_cv_dlopen_self+set}" = set; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then lt_cv_dlopen_self=cross else cat > conftest.c < #endif #include #ifdef RTLD_GLOBAL # define LTDL_GLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LTDL_GLOBAL DL_GLOBAL # else # define LTDL_GLOBAL 0 # endif #endif /* We may have to define LTDL_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LTDL_LAZY_OR_NOW # ifdef RTLD_LAZY # define LTDL_LAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LTDL_LAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LTDL_LAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LTDL_LAZY_OR_NOW DL_NOW # else # define LTDL_LAZY_OR_NOW 0 # endif # endif # endif # endif #endif fnord() { int i=42;} main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); if(ptr1 || ptr2) exit(0); } exit(1); } EOF if { (eval echo $progname:2302: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then lt_cv_dlopen_self=yes else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* lt_cv_dlopen_self=no fi rm -fr conftest* fi fi echo "$ac_t""$lt_cv_dlopen_self" 1>&6 if test "$lt_cv_dlopen_self" = yes; then LDFLAGS="$LDFLAGS $link_static_flag" echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 echo "$progname:2321: checking whether a statically linked program can dlopen itself" >&5 if test "${lt_cv_dlopen_self_static+set}" = set; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then lt_cv_dlopen_self_static=cross else cat > conftest.c < #endif #include #ifdef RTLD_GLOBAL # define LTDL_GLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LTDL_GLOBAL DL_GLOBAL # else # define LTDL_GLOBAL 0 # endif #endif /* We may have to define LTDL_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LTDL_LAZY_OR_NOW # ifdef RTLD_LAZY # define LTDL_LAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LTDL_LAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LTDL_LAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LTDL_LAZY_OR_NOW DL_NOW # else # define LTDL_LAZY_OR_NOW 0 # endif # endif # endif # endif #endif fnord() { int i=42;} main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); if(ptr1 || ptr2) exit(0); } exit(1); } EOF if { (eval echo $progname:2375: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then lt_cv_dlopen_self_static=yes else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* lt_cv_dlopen_self_static=no fi rm -fr conftest* fi fi echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6 fi ;; esac case "$lt_cv_dlopen_self" in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case "$lt_cv_dlopen_self_static" in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # Copy echo and quote the copy, instead of the original, because it is # used later. ltecho="$echo" if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then ltecho="$CONFIG_SHELL \$0 --fallback-echo" fi LTSHELL="$SHELL" LTCONFIG_VERSION="$VERSION" # Only quote variables if we're using ltmain.sh. case "$ltmain" in *.sh) # Now quote all the things that may contain metacharacters. for var in ltecho old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ old_LN_S old_DLLTOOL old_AS AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \ reload_flag reload_cmds wl \ pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ thread_safe_flag_spec whole_archive_flag_spec libname_spec \ library_names_spec soname_spec \ RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \ file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \ finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ hardcode_libdir_flag_spec hardcode_libdir_separator \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do case "$var" in reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ postinstall_cmds | postuninstall_cmds | \ finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case "$ltecho" in *'\$0 --fallback-echo"') ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac trap "$rm \"$ofile\"; exit 1" 1 2 15 echo "creating $ofile" $rm "$ofile" cat < "$ofile" #! $SHELL # `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. # # Copyright (C) 1996-1999 Free Software Foundation, Inc. # Gordon Matzigkeit , 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # 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. # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="sed -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi ### BEGIN LIBTOOL CONFIG EOF cfgfile="$ofile" ;; *) # Double-quote the variables that need it (for aesthetics). for var in old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ old_LN_S old_DLLTOOL old_AS; do eval "$var=\\\"\$var\\\"" done # Just create a config file. cfgfile="$ofile.cfg" trap "$rm \"$cfgfile\"; exit 1" 1 2 15 echo "creating $cfgfile" $rm "$cfgfile" cat < "$cfgfile" # `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) EOF ;; esac cat <> "$cfgfile" # Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # # CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\ # LD=$old_LD NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\ # DLLTOOL="$old_DLLTOOL" AS="$old_AS" \\ # $0$ltconfig_args # # Compiler and other test output produced by $progname, useful for # debugging $progname, is in ./config.log if it exists. # The version of $progname that generated this script. LTCONFIG_VERSION=$LTCONFIG_VERSION # Shell to use when invoking shell scripts. SHELL=$LTSHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$ltecho # The archiver. AR=$AR # The default C compiler. CC=$CC # The linker used to build libraries. LD=$LD # Whether we need hard or soft links. LN_S=$LN_S # A BSD-compatible nm program. NM=$NM # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$reload_flag reload_cmds=$reload_cmds # How to pass a linker flag through the compiler. wl=$wl # Object file suffix (normally "o"). objext="$objext" # Old archive suffix (normally "a"). libext="$libext" # Additional compiler flags for building library objects. pic_flag=$pic_flag # Does compiler simultaneously support -c and -o options compiler_c_o=$compiler_c_o # Can we write directly to a .lo ? compiler_o_lo=$compiler_o_lo # Must we lock files when doing compilation ? need_locks=$need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$link_static_flag # Compiler flag to turn off builtin functions. no_builtin_flag=$no_builtin_flag # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$whole_archive_flag_spec # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$thread_safe_flag_spec # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$library_names_spec # The coded name of the library, if different from the real name. soname_spec=$soname_spec # Commands used to build and install an old-style archive. RANLIB=$RANLIB old_archive_cmds=$old_archive_cmds old_postinstall_cmds=$old_postinstall_cmds old_postuninstall_cmds=$old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$old_archive_from_new_cmds # Commands used to build and install a shared archive. archive_cmds=$archive_cmds archive_expsym_cmds=$archive_expsym_cmds postinstall_cmds=$postinstall_cmds postuninstall_cmds=$postuninstall_cmds # Method to check whether dependent libraries are shared objects. deplibs_check_method=$deplibs_check_method # Command to use when deplibs_check_method == file_magic file_magic_cmd=$file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$allow_undefined_flag # Flag that forces no undefined symbols. no_undefined_flag=$no_undefined_flag # Commands used to finish a libtool library installation in a directory. finish_cmds=$finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$global_symbol_to_cdecl # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$hardcode_libdir_separator # Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Compile-time system search path for libraries sys_lib_search_path_spec=$sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path" # Set to yes if exported symbols are required always_export_symbols=$always_export_symbols # The command to extract exported symbols export_symbols_cmds=$export_symbols_cmds # Symbols that should not be listed in the preloaded symbols exclude_expsyms=$exclude_expsyms # Symbols that must always be exported include_expsyms=$include_expsyms EOF case "$ltmain" in *.sh) echo '### END LIBTOOL CONFIG' >> "$ofile" echo >> "$ofile" case "$host_os" in aix3*) cat <<\EOF >> "$ofile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "${COLLECT_NAMES+set}" != set; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # Append the ltmain.sh script. cat "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1) chmod +x "$ofile" ;; *) # Compile the libtool program. echo "FIXME: would compile $ltmain" ;; esac test -n "$cache_file" || exit 0 # AC_CACHE_SAVE trap '' 1 2 15 cat > confcache <<\EOF # 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. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # 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. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache exit 0 # Local Variables: # mode:shell-script # sh-indentation:2 # End: gnats-4.1.0/ltmain.sh0000644000175000017500000031403007005251727015210 0ustar chewiechewie00000000000000# ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun ltconfig. # # Copyright (C) 1996-1999 Free Software Foundation, Inc. # Gordon Matzigkeit , 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # 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. # Check that we have a working $echo. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell, and then maybe $echo will work. exec $SHELL "$0" --no-reexec ${1+"$@"} fi # The name of this program. progname=`$echo "$0" | sed 's%^.*/%%'` modename="$progname" # Constants. PROGRAM=ltmain.sh PACKAGE=libtool VERSION=1.2f TIMESTAMP=" (1.385 1999/03/15 17:24:54)" default_mode= help="Try \`$progname --help' for more information." magic="%%%MAGIC variable%%%" mkdir="mkdir" mv="mv -f" rm="rm -f" # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e 1s/^X//' sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' SP2NL='tr \040 \012' NL2SP='tr \012 \040' # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). # We save the old values to restore during execute mode. if test "${LC_ALL+set}" = set; then save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL fi if test "${LANG+set}" = set; then save_LANG="$LANG"; LANG=C; export LANG fi if test "$LTCONFIG_VERSION" != "$VERSION"; then echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 fi if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then echo "$modename: not configured to build any kind of library" 1>&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 fi # Global variables. mode=$default_mode nonopt= prev= prevopt= run= show="$echo" show_help= execute_dlfiles= lo2o="s/\\.lo\$/.${objext}/" # Parse our command line options once, thoroughly. while test $# -gt 0 do arg="$1" shift case "$arg" in -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then case "$prev" in execute_dlfiles) eval "$prev=\"\$$prev \$arg\"" ;; *) eval "$prev=\$arg" ;; esac prev= prevopt= continue fi # Have we seen a non-optional argument yet? case "$arg" in --help) show_help=yes ;; --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" exit 0 ;; --config) sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0 exit 0 ;; --debug) echo "$progname: enabling shell trace mode" set -x ;; --dry-run | -n) run=: ;; --features) echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit 0 ;; --finish) mode="finish" ;; --mode) prevopt="--mode" prev=mode ;; --mode=*) mode="$optarg" ;; --quiet | --silent) show=: ;; -dlopen) prevopt="-dlopen" prev=execute_dlfiles ;; -*) $echo "$modename: unrecognized option \`$arg'" 1>&2 $echo "$help" 1>&2 exit 1 ;; *) nonopt="$arg" break ;; esac done if test -n "$prevopt"; then $echo "$modename: option \`$prevopt' requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then case "$nonopt" in *cc | *++ | gcc* | *-gcc*) mode=link for arg do case "$arg" in -c) mode=compile break ;; esac done ;; *db | *dbx | *strace | *truss) mode=execute ;; *install*|cp|mv) mode=install ;; *rm) mode=uninstall ;; *) # If we have no mode, but dlfiles were specified, then do execute mode. test -n "$execute_dlfiles" && mode=execute # Just use the default operation mode. if test -z "$mode"; then if test -n "$nonopt"; then $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 else $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 fi fi ;; esac fi # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then $echo "$modename: unrecognized option \`-dlopen'" 1>&2 $echo "$help" 1>&2 exit 1 fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$modename --help --mode=$mode' for more information." # These modes are in order of execution frequency so that they run quickly. case "$mode" in # libtool compile mode compile) modename="$modename: compile" # Get the compilation command and the source file. base_compile= lastarg= srcfile="$nonopt" suppress_output= user_target=no for arg do # Accept any command-line options. case "$arg" in -o) if test "$user_target" != "no"; then $echo "$modename: you cannot specify \`-o' more than once" 1>&2 exit 1 fi user_target=next ;; -static) build_old_libs=yes continue ;; esac case "$user_target" in next) # The next one is the -o target name user_target=yes continue ;; yes) # We got the output file user_target=set libobj="$arg" continue ;; esac # Accept the current argument as the source file. lastarg="$srcfile" srcfile="$arg" # Aesthetically quote the previous argument. # Backslashify any backslashes, double quotes, and dollar signs. # These are the only characters that are still specially # interpreted inside of double-quoted scrings. lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly in scan # sets, so we specify it separately. case "$lastarg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) lastarg="\"$lastarg\"" ;; esac # Add the previous argument to base_compile. if test -z "$base_compile"; then base_compile="$lastarg" else base_compile="$base_compile $lastarg" fi done case "$user_target" in set) ;; no) # Get the name of the library object. libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` ;; *) $echo "$modename: you must specify a target with \`-o'" 1>&2 exit 1 ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo xform='[cCFSfmso]' case "$libobj" in *.ada) xform=ada ;; *.adb) xform=adb ;; *.ads) xform=ads ;; *.asm) xform=asm ;; *.c++) xform=c++ ;; *.cc) xform=cc ;; *.cpp) xform=cpp ;; *.cxx) xform=cxx ;; *.f90) xform=f90 ;; *.for) xform=for ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` case "$libobj" in *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; *) $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 exit 1 ;; esac if test -z "$base_compile"; then $echo "$modename: you must specify a compilation command" 1>&2 $echo "$help" 1>&2 exit 1 fi # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $libobj" else removelist="$libobj" fi $run $rm $removelist trap "$run $rm $removelist; exit 1" 1 2 15 # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext} lockfile="$output_obj.lock" removelist="$removelist $output_obj $lockfile" trap "$run $rm $removelist; exit 1" 1 2 15 else need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until ln "$0" "$lockfile" 2>/dev/null; do $show "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then echo "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi echo $srcfile > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile # All platforms use -DPIC, to notify preprocessed assembler code. command="$base_compile $pic_flag -DPIC $srcfile" if test "$build_old_libs" = yes; then lo_libobj="$libobj" dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$libobj"; then dir="$objdir" else dir="$dir/$objdir" fi libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` if test -d "$dir"; then $show "$rm $libobj" $run $rm $libobj else $show "$mkdir $dir" $run $mkdir $dir status=$? if test $status -ne 0 && test ! -d $dir; then exit $status fi fi fi if test "$compiler_o_lo" = yes; then output_obj="$libobj" command="$command -o $output_obj" elif test "$compiler_c_o" = yes; then output_obj="$obj" command="$command -o $output_obj" fi $show "$command" if $run eval "$command"; then : else test -n "$output_obj" && $run $rm $removelist exit 1 fi if test "$need_locks" = warn && test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed, then go on to compile the next one if test x"$output_obj" != x"$libobj"; then $show "$mv $output_obj $libobj" if $run $mv $output_obj $libobj; then : else error=$? $run $rm $removelist exit $error fi fi # If we have no pic_flag, then copy the object into place and finish. if test -z "$pic_flag" && test "$build_old_libs" = yes; then # Rename the .lo from within objdir to obj if test -f $obj; then $show $rm $obj $run $rm $obj fi $show "$mv $libobj $obj" if $run $mv $libobj $obj; then : else error=$? $run $rm $removelist exit $error fi # Now arrange that obj and lo_libobj become the same file $show "$LN_S $obj $lo_libobj" if $run $LN_S $obj $lo_libobj; then exit 0 else error=$? $run $rm $removelist exit $error fi fi # Allow error messages only from the first compilation. suppress_output=' >/dev/null 2>&1' fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then command="$base_compile $srcfile" if test "$compiler_c_o" = yes; then command="$command -o $obj" output_obj="$obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" $show "$command" if $run eval "$command"; then : else $run $rm $removelist exit 1 fi if test "$need_locks" = warn && test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed if test x"$output_obj" != x"$obj"; then $show "$mv $output_obj $obj" if $run $mv $output_obj $obj; then : else error=$? $run $rm $removelist exit $error fi fi # Create an invalid libtool object if no PIC, so that we do not # accidentally link it into a program. if test "$build_libtool_libs" != yes; then $show "echo timestamp > $libobj" $run eval "echo timestamp > \$libobj" || exit $? else # Move the .lo from within objdir $show "$mv $libobj $lo_libobj" if $run $mv $libobj $lo_libobj; then : else error=$? $run $rm $removelist exit $error fi fi fi # Unlock the critical section if it was locked if test "$need_locks" != no; then $rm "$lockfile" fi exit 0 ;; # libtool link mode link) modename="$modename: link" C_compiler="$CC" # save it, to compile generated C sources CC="$nonopt" # CYGNUS LOCAL: tromey/java # Add -B options to link line. for arg do case "$arg" in -B*) CC="$CC $arg" ;; esac done # END CYGNUS LOCAL case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invokation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes # This is a source program that is used to create dlls on Windows # Don't remove nor modify the starting and closing comments # /* ltdll.c starts here */ # #define WIN32_LEAN_AND_MEAN # #include # #undef WIN32_LEAN_AND_MEAN # #include # # BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); # # #include # DECLARE_CYGWIN_DLL( DllMain ); # HINSTANCE __hDllInstance_base; # # BOOL APIENTRY # DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) # { # __hDllInstance_base = hInst; # return TRUE; # } # /* ltdll.c ends here */ # This is a source program that is used to create import libraries # on Windows for dlls which lack them. Don't remove nor modify the # starting and closing comments # /* impgen.c starts here */ # /* Copyright (C) 1999 Free Software Foundation, Inc. # # This file is part of GNU libtool. # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # */ # # #include /* for printf() */ # #include /* for open(), lseek(), read() */ # #include /* for O_RDONLY, O_BINARY */ # #include /* for strdup() */ # # static unsigned int # pe_get16 (fd, offset) # int fd; # int offset; # { # unsigned char b[2]; # lseek (fd, offset, SEEK_SET); # read (fd, b, 2); # return b[0] + (b[1]<<8); # } # # static unsigned int # pe_get32 (fd, offset) # int fd; # int offset; # { # unsigned char b[4]; # lseek (fd, offset, SEEK_SET); # read (fd, b, 4); # return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); # } # # static unsigned int # pe_as32 (ptr) # void *ptr; # { # unsigned char *b = ptr; # return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); # } # # int # main (argc, argv) # int argc; # char *argv[]; # { # int dll; # unsigned long pe_header_offset, opthdr_ofs, num_entries, i; # unsigned long export_rva, export_size, nsections, secptr, expptr; # unsigned long name_rvas, nexp; # unsigned char *expdata, *erva; # char *filename, *dll_name; # # filename = argv[1]; # # dll = open(filename, O_RDONLY|O_BINARY); # if (!dll) # return 1; # # dll_name = filename; # # for (i=0; filename[i]; i++) # if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') # dll_name = filename + i +1; # # pe_header_offset = pe_get32 (dll, 0x3c); # opthdr_ofs = pe_header_offset + 4 + 20; # num_entries = pe_get32 (dll, opthdr_ofs + 92); # # if (num_entries < 1) /* no exports */ # return 1; # # export_rva = pe_get32 (dll, opthdr_ofs + 96); # export_size = pe_get32 (dll, opthdr_ofs + 100); # nsections = pe_get16 (dll, pe_header_offset + 4 +2); # secptr = (pe_header_offset + 4 + 20 + # pe_get16 (dll, pe_header_offset + 4 + 16)); # # expptr = 0; # for (i = 0; i < nsections; i++) # { # char sname[8]; # unsigned long secptr1 = secptr + 40 * i; # unsigned long vaddr = pe_get32 (dll, secptr1 + 12); # unsigned long vsize = pe_get32 (dll, secptr1 + 16); # unsigned long fptr = pe_get32 (dll, secptr1 + 20); # lseek(dll, secptr1, SEEK_SET); # read(dll, sname, 8); # if (vaddr <= export_rva && vaddr+vsize > export_rva) # { # expptr = fptr + (export_rva - vaddr); # if (export_rva + export_size > vaddr + vsize) # export_size = vsize - (export_rva - vaddr); # break; # } # } # # expdata = (unsigned char*)malloc(export_size); # lseek (dll, expptr, SEEK_SET); # read (dll, expdata, export_size); # erva = expdata - export_rva; # # nexp = pe_as32 (expdata+24); # name_rvas = pe_as32 (expdata+32); # # printf ("EXPORTS\n"); # for (i = 0; i&2 fi build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test $# -gt 0; do arg="$1" shift # If the previous option needs an argument, assign it. if test -n "$prev"; then case "$prev" in output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" ;; esac case "$prev" in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. compile_command="$compile_command @SYMFILE@" finalize_command="$finalize_command @SYMFILE@" preload=yes fi case "$arg" in *.la | *.lo) ;; # We handle these cases below. self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes fi prev= continue ;; *) dlprefiles="$dlprefiles $arg" test "$prev" = dlfiles && dlfiles="$dlfiles $arg" prev= ;; esac ;; expsyms) export_symbols="$arg" if test ! -f "$arg"; then $echo "$modename: symbol file \`$arg' does not exist" exit 1 fi prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath) rpath="$rpath $arg" prev= continue ;; xrpath) xrpath="$xrpath $arg" prev= continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi prevarg="$arg" case "$arg" in -all-static) if test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" dlopen_self=$dlopen_self_static fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 continue ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) if test "$export_dynamic" != yes; then export_dynamic=yes if test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" else arg= fi fi ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: cannot have more than one -exported-symbols" exit 1 fi if test "$arg" = "-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -L*) dir=`$echo "X$arg" | $Xsed -e 's%^-L\(.*\)$%\1%'` case "$dir" in /* | [A-Za-z]:[/\\]*) # Add the corresponding hardcode_libdir_flag, if it is not identical. ;; *) $echo "$modename: \`-L$dir' cannot specify a relative directory" 1>&2 exit 1 ;; esac case " $deplibs " in *" $arg "*) ;; *) deplibs="$deplibs $arg";; esac case " $lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir";; esac case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) dllsearchdir=`cd "$dir" && pwd || echo "$dir"` case ":$dllsearchpath:" in ::) dllsearchpath="$dllsearchdir";; *":$dllsearchdir:"*) ;; *) dllsearchpath="$dllsearchpath:$dllsearchdir";; esac ;; esac ;; -l*) deplibs="$deplibs $arg" ;; -module) if test "$module" != yes; then module=yes if test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" else arg= fi fi ;; -no-undefined) allow_undefined=no continue ;; -o) prev=output ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) xrpath="$xrpath "`$echo "X$arg" | $Xsed -e 's/^-R//'` continue ;; -static) # If we have no pic_flag, then this is the same as -all-static. if test -z "$pic_flag" && test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" dlopen_self=$dlopen_self_static fi continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; # Some other compiler flag. -* | +*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac ;; *.o | *.obj | *.a | *.lib) # A standard object. objs="$objs $arg" ;; *.lo) # A library object. if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` prev= fi libobjs="$libobjs $arg" ;; *.la) # A libtool-controlled library. dlname= libdir= library_names= old_library= # Check to see that this really is a libtool archive. if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 exit 1 fi # If the library was installed with an old release of libtool, # it will not redefine variable installed. installed=yes # If there is no directory component, then add one. case "$arg" in */* | *\\*) . $arg ;; *) . ./$arg ;; esac # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 exit 1 fi # Find the relevant object directory and library name. name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` if test "X$installed" = Xyes; then dir="$libdir" else dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$arg"; then dir="$objdir" else dir="$dir/$objdir" fi fi if test -n "$dependency_libs"; then # Extract -R from dependency_libs temp_deplibs= for deplib in $dependency_libs; do case "$deplib" in -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'` case " $rpath $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; -L*) case "$compile_command $temp_deplibs " in *" $deplib "*) ;; *) temp_deplibs="$temp_deplibs $deplib";; esac;; *) temp_deplibs="$temp_deplibs $deplib";; esac done dependency_libs="$temp_deplibs" fi if test -z "$libdir"; then # It is a libtool convenience library, so add in its objects. convenience="$convenience $dir/$old_library" old_convenience="$old_convenience $dir/$old_library" deplibs="$deplibs$dependency_libs" compile_command="$compile_command $dir/$old_library$dependency_libs" finalize_command="$finalize_command $dir/$old_library$dependency_libs" continue fi # This library was specified with -dlopen. if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking statically, # we need to preload. prev=dlprefiles else # We should not create a dependency on this library, but we # may need any libraries it requires. compile_command="$compile_command$dependency_libs" finalize_command="$finalize_command$dependency_libs" prev= continue fi fi # The library was specified with -dlpreopen. if test "$prev" = dlprefiles; then # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then dlprefiles="$dlprefiles $dir/$old_library" else dlprefiles="$dlprefiles $dir/$linklib" fi prev= fi if test "$build_libtool_libs" = yes && test -n "$library_names"; then link_against_libtool_libs="$link_against_libtool_libs $arg" if test -n "$shlibpath_var"; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; *) temp_rpath="$temp_rpath $dir" ;; esac fi # We need an absolute path. case "$dir" in /* | [A-Za-z]:[/\\]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: cannot determine absolute directory name of \`$libdir'" 1>&2 exit 1 fi ;; esac # This is the magic to use -rpath. # Skip directories that are in the system default run-time # search path, unless they have been requested with -R. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac lib_linked=yes case "$hardcode_action" in immediate | unsupported) if test "$hardcode_direct" = no; then compile_command="$compile_command $dir/$linklib" deplibs="$deplibs $dir/$linklib" case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) dllsearchdir=`cd "$dir" && pwd || echo "$dir"` if test -n "$dllsearchpath"; then dllsearchpath="$dllsearchpath:$dllsearchdir" else dllsearchpath="$dllsearchdir" fi ;; esac elif test "$hardcode_minus_L" = no; then case "$host" in *-*-sunos*) compile_shlibpath="$compile_shlibpath$dir:" ;; esac case "$compile_command " in *" -L$dir "*) ;; *) compile_command="$compile_command -L$dir";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -L$dir -l$name" elif test "$hardcode_shlibpath_var" = no; then case ":$compile_shlibpath:" in *":$dir:"*) ;; *) compile_shlibpath="$compile_shlibpath$dir:";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes; then compile_command="$compile_command $absdir/$linklib" deplibs="$deplibs $absdir/$linklib" elif test "$hardcode_minus_L" = yes; then case "$compile_command " in *" -L$absdir "*) ;; *) compile_command="$compile_command -L$absdir";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -L$absdir -l$name" elif test "$hardcode_shlibpath_var" = yes; then case ":$compile_shlibpath:" in *":$absdir:"*) ;; *) compile_shlibpath="$compile_shlibpath$absdir:";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then $echo "$modename: configuration error: unsupported hardcode properties" exit 1 fi # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes; then finalize_command="$finalize_command $libdir/$linklib" elif test "$hardcode_minus_L" = yes; then case "$finalize_command " in *" -L$libdir "*) ;; *) finalize_command="$finalize_command -L$libdir";; esac finalize_command="$finalize_command -l$name" elif test "$hardcode_shlibpath_var" = yes; then case ":$finalize_shlibpath:" in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:";; esac finalize_command="$finalize_command -l$name" else # We cannot seem to hardcode it, guess we'll fake it. case "$finalize_command " in *" -L$dir "*) ;; *) finalize_command="$finalize_command -L$libdir";; esac finalize_command="$finalize_command -l$name" fi else # Transform directly to old archives if we don't build new libraries. if test -n "$pic_flag" && test -z "$old_library"; then $echo "$modename: cannot find static library for \`$arg'" 1>&2 exit 1 fi # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_command="$compile_command $dir/$linklib" finalize_command="$finalize_command $dir/$linklib" else case "$compile_command " in *" -L$dir "*) ;; *) compile_command="$compile_command -L$dir";; esac compile_command="$compile_command -l$name" case "$finalize_command " in *" -L$dir "*) ;; *) finalize_command="$finalize_command -L$dir";; esac finalize_command="$finalize_command -l$name" fi fi # Add in any libraries that this one depends upon. compile_command="$compile_command$dependency_libs" finalize_command="$finalize_command$dependency_libs" continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac ;; esac # Now actually substitute the argument into the commands. if test -n "$arg"; then compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi done if test -n "$prev"; then $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi oldlibs= # calculate the name of the file, without its directory outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` libobjs_save="$libobjs" case "$output" in "") $echo "$modename: you must specify an output file" 1>&2 $echo "$help" 1>&2 exit 1 ;; *.a | *.lib) if test -n "$link_against_libtool_libs"; then $echo "$modename: error: cannot link libtool libraries into archives" 1>&2 exit 1 fi if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 fi if test -n "$dlfiles$dlprefiles"; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 fi if test -n "$export_symbols"; then $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 fi # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" ;; *.la) # Make sure we only generate libraries of the form `libNAME.la'. case "$outputname" in lib*) name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` eval libname=\"$libname_spec\" ;; *) if test "$module" = no; then $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 $echo "$help" 1>&2 exit 1 fi if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` eval libname=\"$libname_spec\" else libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` fi ;; esac output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= if test -n "$objs"; then $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 exit 1 fi # How the heck are we supposed to write a wrapper for a shared library? if test -n "$link_against_libtool_libs"; then $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2 exit 1 fi if test -n "$dlfiles$dlprefiles"; then $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2 fi set dummy $rpath if test $# -gt 2; then $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 fi install_libdir="$2" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. libext=al oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi dependency_libs="$deplibs" if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 fi else # Parse the version information argument. IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 IFS="$save_ifs" if test -n "$8"; then $echo "$modename: too many parameters to \`-version-info'" 1>&2 $echo "$help" 1>&2 exit 1 fi current="$2" revision="$3" age="$4" # Check that each of the things are valid numbers. case "$current" in 0 | [1-9] | [1-9][0-9]*) ;; *) $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case "$revision" in 0 | [1-9] | [1-9][0-9]*) ;; *) $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case "$age" in 0 | [1-9] | [1-9][0-9]*) ;; *) $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac if test $age -gt $current; then $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 fi # Calculate the version variables. major= versuffix= verstring= case "$version_type" in none) ;; irix) major=`expr $current - $age + 1` versuffix="$major.$revision" verstring="sgi$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test $loop != 0; do iface=`expr $revision - $loop` loop=`expr $loop - 1` verstring="sgi$major.$iface:$verstring" done ;; linux) major=.`expr $current - $age` versuffix="$major.$age.$revision" ;; osf) major=`expr $current - $age` versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test $loop != 0; do iface=`expr $current - $loop` loop=`expr $loop - 1` verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current"; ;; windows) # Like Linux, but with '-' rather than '.', since we only # want one extension on Windows 95. major=`expr $current - $age` versuffix="-$major-$age-$revision" ;; *) $echo "$modename: unknown library version type \`$version_type'" 1>&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= verstring="0.0" if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi dependency_libs="$deplibs" case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) # these systems don't actually have a c library (as such)! ;; *) # Add libc to deplibs on all other systems. deplibs="$deplibs -lc" ;; esac fi # Create the output directory, or remove our outputs if we need to. if test -d $output_objdir; then $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* else $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test $status -ne 0 && test ! -d $output_objdir; then exit $status fi fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi if test "$build_libtool_libs" = yes; then # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case "$deplibs_check_method" in pass_all) newdeplibs=$deplibs ;; # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behaviour. test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potlib" 2>/dev/null \ | grep " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | sed 's/.* -> //'` case "$potliblink" in /*) potlib="$potliblink";; *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" \ | sed 10q \ | egrep "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done if test -n "$a_deplib" ; then droppeddeps=yes echo echo "*** Warning: This library needs some functionality provided by $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | grep . >/dev/null; then echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" echo "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi dlname= library_names= else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." fi fi fi # test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then deplibs=$newdeplibs # Done checking deplibs! # Get the real and link names of the library. eval library_names=\"$library_names_spec\" set dummy $library_names realname="$2" shift; shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi lib="$output_objdir/$realname" for link do linknames="$linknames $link" done # Ensure that we have .o objects for linkers which dislike .lo # (e.g. aix) incase we are running --disable-static for obj in $libobjs; do oldobj=`$echo "X$obj" | $Xsed -e "$lo2o"` test -f $oldobj || ${LN_S} $obj $oldobj done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` if test -n "$whole_archive_flag_spec"; then if test -n "$convenience"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" fi else for xlib in $convenience; do # Extract the objects. xdir="$xlib"x generated="$generated $xdir" xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x ../$xlib)" $run eval "(cd \$xdir && $AR x ../\$xlib)" || exit $? libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` done fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linkopts="$linkopts $flag" fi # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then $show "generating symbol list for \`$libname.la'" export_symbols="$objdir/$libname.exp" $run $rm $export_symbols eval cmds=\"$export_symbols_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" if test -n "$export_symbols_regex"; then $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' $show "$mv \"${export_symbols}T\" \"$export_symbols\"" $run eval '$mv "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' fi # Do each of the archive commands. if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval cmds=\"$archive_expsym_cmds\" else eval cmds=\"$archive_cmds\" fi IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; *.lo | *.o | *.obj) if test -n "$link_against_libtool_libs"; then $echo "$modename: error: cannot link libtool libraries into objects" 1>&2 exit 1 fi if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 fi if test -n "$dlfiles$dlprefiles"; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 fi case "$output" in *.lo) if test -n "$objs"; then $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 exit 1 fi libobj="$output" obj=`$echo "X$output" | $Xsed -e "$lo2o"` ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $run $rm $obj $libobj # Create the old-style object. reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` output="$obj" eval cmds=\"$reload_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Exit if we aren't doing a library object file. test -z "$libobj" && exit 0 if test "$build_libtool_libs" != yes; then # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. $show "echo timestamp > $libobj" $run eval "echo timestamp > $libobj" || exit $? exit 0 fi if test -n "$pic_flag"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs" output="$libobj" eval cmds=\"$reload_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" else # Just create a symlink. $show $rm $libobj $run $rm $libobj $show "$LN_S $obj $libobj" $run $LN_S $obj $libobj || exit $? fi exit 0 ;; # Anything else should be a program. *) if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 fi if test "$preload" = yes; then if test "$dlopen" = unknown && test "$dlopen_self" = unknown && test "$dlopen_self_static" = unknown; then $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." fi fi if test "$dlself" = yes && test "$export_dynamic" = no; then $echo "$modename: error: \`-dlopen self' requires \`-export-dynamic'" 1>&2 exit 1 fi if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$compile_rpath " in *" $libdir "*) ;; *) compile_rpath="$compile_rpath $libdir" ;; esac case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" = yes; then if test -n "$NM" && test -n "$global_symbol_pipe"; then dlsyms="${outputname}S.c" else $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 fi fi if test -n "$dlsyms"; then case "$dlsyms" in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$objdir/${output}.nm" if test -d $objdir; then $show "$rm $nlist ${nlist}S ${nlist}T" $run $rm "$nlist" "${nlist}S" "${nlist}T" else $show "$mkdir $objdir" $run $mkdir $objdir status=$? if test $status -ne 0 && test ! -d $objdir; then exit $status fi fi # Parse the name list into a source file. $show "creating $objdir/$dlsyms" $echo > "$objdir/$dlsyms" "\ /* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ /* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ #ifdef __cplusplus extern \"C\" { #endif /* Prevent the only kind of declaration conflicts we can make. */ #define lt_preloaded_symbols some_other_symbol /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then $show "generating symbol list for \`$output'" echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for arg in $progfiles; do $show "extracting global C symbols from \`$arg'" $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi if test -n "$export_symbols_regex"; then $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$objdir/$output.exp" $run $rm $export_symbols $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' else $run $rm $export_symbols $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$objdir/$output.exp"' $run eval 'grep -f "$objdir/$output.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' fi fi for arg in $dlprefiles; do $show "extracting global C symbols from \`$arg'" name=`echo "$arg" | sed -e 's%^.*/%%'` $run eval 'echo ": $name " >> "$nlist"' $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -z "$run"; then # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $mv "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then : else grep -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' else echo '/* NONE */' >> "$output_objdir/$dlsyms" fi $echo >> "$output_objdir/$dlsyms" "\ #undef lt_preloaded_symbols #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = {\ " sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ < "$nlist" >> "$output_objdir/$dlsyms" $echo >> "$output_objdir/$dlsyms" "\ {0, (lt_ptr_t) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " fi pic_flag_for_symtable= case "$host" in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; esac esac # Now compile the dynamic symbol file. $show "(cd $objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" $run eval '(cd $objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? # Transform the symbol file into the correct name. compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$objdir/${output}S.${objext}%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$objdir/${output}S.${objext}%"` ;; *) $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 exit 1 ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then # Replace the output file specification. compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. $show "$link_command" $run eval "$link_command" exit $? fi if test -n "$shlibpath_var"; then # We should set the shlibpath_var rpath= for dir in $temp_rpath; do case "$dir" in /* | [A-Za-z]:[/\\]*) # Absolute path. rpath="$rpath$dir:" ;; *) # Relative path: add a thisdir entry. rpath="$rpath\$thisdir/$dir:" ;; esac done temp_rpath="$rpath" fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" # AGH! Flame the AIX and HP-UX people for me, will ya? $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 $echo "$modename: \`$output' will be relinked during installation" 1>&2 else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Create the binary in the object directory, then wrap it. if test ! -d $output_objdir; then $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test $status -ne 0 && test ! -d $objdir; then exit $status fi fi # Delete the old output file. $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname $show "$link_command" $run eval "$link_command" || exit $? # Now create the wrapper script. $show "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $echo for shipping. if test "X$echo" = "X$SHELL $0 --fallback-echo"; then case "$0" in /* | [A-Za-z]:[/\\]*) qecho="$SHELL $0 --fallback-echo";; *) qecho="$SHELL `pwd`/$0 --fallback-echo";; esac qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if our run command is non-null. if test -z "$run"; then # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) output=`echo $output|sed 's,.exe$,,'` ;; esac $rm $output trap "$rm $output; exit 1" 1 2 15 $echo > $output "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test \"\${CDPATH+set}\" = set; then CDPATH=; export CDPATH; fi relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variable: link_against_libtool_libs='$link_against_libtool_libs' else # When we are sourced in execute mode, \$file and \$echo are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then echo=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then # Yippee, \$echo works! : else # Restart under the correct shell, and then maybe \$echo will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $echo >> $output "\ # Find the directory that this script lives in. thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in /* | [A-Za-z]:[/\\]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` done # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then echo >> $output "\ program=lt-'$outputname' progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || \\ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $mkdir \"\$progdir\" else $rm \"\$progdir/\$file\" fi" echo >> $output "\ # relink executable if necessary if test -n \"\$relink_command\"; then if (cd \"\$thisdir\" && eval \$relink_command); then : else $rm \"\$progdir/\$file\" exit 1 fi fi $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $rm \"\$progdir/\$program\"; $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } $rm \"\$progdir/\$file\" fi" else echo >> $output "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi echo >> $output "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $echo >> $output "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $echo >> $output "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $echo >> $output "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in *-*-cygwin* | *-*-mingw | *-*-os2*) # win32 systems need to use the prog path for dll # lookup to work $echo >> $output "\ exec \$progdir\\\\\$program \${1+\"\$@\"} " ;; *) $echo >> $output "\ # Export the path to the program. PATH=\"\$progdir:\$PATH\" export PATH exec \$program \${1+\"\$@\"} " ;; esac $echo >> $output "\ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" exit 1 fi else # The program doesn't exist. \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 \$echo \"This script is just a wrapper for \$program.\" 1>&2 echo \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " chmod +x $output fi exit 0 ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` fi addlibs="$old_convenience" fi # Add in members from convenience archives. for xlib in $addlibs; do # Extract the objects. xdir="$xlib"x generated="$generated $xdir" xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x ../$xlib)" $run eval "(cd \$xdir && $AR x ../\$xlib)" || exit $? oldobjs="$oldobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` done # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then eval cmds=\"$old_archive_from_new_cmds\" else eval cmds=\"$old_archive_cmds\" fi IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$generated"; then $show "${rm}r$generated" $run ${rm}r$generated fi # Now create the libtool archive. case "$output" in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" $show "creating $output" if test -n "$xrpath"; then temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" done dependency_libs="$temp_xrpath $dependency_libs" fi # Only create the output if not a dry run. if test -z "$run"; then $echo > $output "\ # $output - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # The name that we can dlopen(3). dlname='$dlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=no # Directory that this library needs to be installed in: libdir='$install_libdir'\ " $rm "$output_objdir/$outputname"i sed 's/^installed=no$/installed=yes/' \ < "$output" > "$output_objdir/$outputname"i || exit 1 fi # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $? ;; esac exit 0 ;; # libtool install mode install) modename="$modename: install" # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$arg " arg="$1" shift else install_prog= arg="$nonopt" fi # The real first argument should be the name of the installation program. # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog$arg" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest="$arg" continue fi case "$arg" in -d) isdir=yes ;; -f) prev="-f" ;; -g) prev="-g" ;; -m) prev="-m" ;; -o) prev="-o" ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest="$arg" continue fi ;; esac # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog $arg" done if test -z "$install_prog"; then $echo "$modename: you must specify an install program" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -n "$prev"; then $echo "$modename: the \`$prev' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -z "$files"; then if test -z "$dest"; then $echo "$modename: no file or destination specified" 1>&2 else $echo "$modename: you must specify a destination" 1>&2 fi $echo "$help" 1>&2 exit 1 fi # Strip any trailing slash from the destination. dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` test "X$destdir" = "X$dest" && destdir=. destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` # Not a directory, so check to see that there is only one file specified. set dummy $files if test $# -gt 2; then $echo "$modename: \`$dest' is not a directory" 1>&2 $echo "$help" 1>&2 exit 1 fi fi case "$destdir" in /* | [A-Za-z]:[/\\]*) ;; *) for file in $files; do case "$file" in *.lo) ;; *) $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case "$file" in *.a | *.lib) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi library_names= old_library= # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" test "X$dir" = "X$file/" && dir= dir="$dir$objdir" # See the names of the shared library. set dummy $library_names if test -n "$2"; then realname="$2" shift shift # Install the shared library and build the symlinks. $show "$install_prog $dir/$realname $destdir/$realname" $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? test "X$dlname" = "X$realname" && dlname= if test $# -gt 0; then # Delete the old symlinks, and create new ones. for linkname do test "X$dlname" = "X$linkname" && dlname= if test "$linkname" != "$realname"; then $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" fi done fi if test -n "$dlname"; then # Install the dynamically-loadable library. $show "$install_prog $dir/$dlname $destdir/$dlname" $run eval "$install_prog $dir/$dlname $destdir/$dlname" || exit $? fi # Do each command in the postinstall commands. lib="$destdir/$realname" eval cmds=\"$postinstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Install the pseudo-library for information purposes. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` instname="$dir/$name"i if test ! -f "$instname"; then # Just in case it was removed... $show "Creating $instname" $rm "$instname" sed 's/^installed=no$/installed=yes/' "$file" > "$instname" fi $show "$install_prog $instname $destdir/$name" $run eval "$install_prog $instname $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case "$destfile" in *.lo) staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` ;; *.o | *.obj) staticdest="$destfile" destfile= ;; *) $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` $show "$install_prog $staticobj $staticdest" $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit 0 ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Do a test to see if this is really a libtool program. if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then link_against_libtool_libs= relink_command= # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Check the variables that should have been set. if test -z "$link_against_libtool_libs"; then $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 exit 1 fi finalize=yes for lib in $link_against_libtool_libs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then # If there is no directory component, then add one. case "$lib" in */* | *\\*) . $lib ;; *) . ./$lib ;; esac fi libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" if test -n "$libdir" && test ! -f "$libfile"; then $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 finalize=no fi done outputname= if test "$fast_install" = no && test -n "$relink_command"; then if test "$finalize" = yes; then outputname="/tmp/$$-$file" # Replace the output file specification. relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $echo "$modename: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2 $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 continue fi file="$outputname" else $echo "$modename: warning: cannot relink \`$file' on behalf of your buggy system linker" 1>&2 fi else # Install the binary that we compiled earlier. file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi $show "$install_prog$stripme $file $destfile" $run eval "$install_prog\$stripme \$file \$destfile" || exit $? test -n "$outputname" && $rm $outputname ;; esac done for file in $staticlibs; do name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` # Set up the ranlib parameters. oldlib="$destdir/$name" $show "$install_prog $file $oldlib" $run eval "$install_prog \$file \$oldlib" || exit $? # Do each command in the postinstall commands. eval cmds=\"$old_postinstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$future_libdirs"; then $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 fi if test -n "$current_libdirs"; then # Maybe just do a dry run. test -n "$run" && current_libdirs=" -n$current_libdirs" exec $SHELL $0 --finish$current_libdirs exit 1 fi exit 0 ;; # libtool finish mode finish) modename="$modename: finish" libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. eval cmds=\"$finish_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || admincmds="$admincmds $cmd" done IFS="$save_ifs" fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $run eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. test "$show" = : && exit 0 echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do echo " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" echo " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then echo " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" echo "more information, such as the ld(1) and ld.so(8) manual pages." echo "----------------------------------------------------------------------" exit 0 ;; # libtool execute mode execute) modename="$modename: execute" # The first argument is the command name. cmd="$nonopt" if test -z "$cmd"; then $echo "$modename: you must specify a COMMAND" 1>&2 $echo "$help" exit 1 fi # Handle -dlopen flags immediately. for file in $execute_dlfiles; do if test ! -f "$file"; then $echo "$modename: \`$file' is not a file" 1>&2 $echo "$help" 1>&2 exit 1 fi dir= case "$file" in *.la) # Check to see that this really is a libtool archive. if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi # Read the libtool library. dlname= library_names= # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" continue fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 exit 1 fi ;; *.lo) # Just add the directory containing the .lo file. dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. ;; *) $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case "$file" in -*) ;; *) # Do a test to see if this is really a libtool program. if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` args="$args \"$file\"" done if test -z "$run"; then # Export the shlibpath_var. eval "export $shlibpath_var" # Restore saved enviroment variables if test "${save_LC_ALL+set}" = set; then LC_ALL="$save_LC_ALL"; export LC_ALL fi if test "${save_LANG+set}" = set; then LANG="$save_LANG"; export LANG fi # Now actually exec the command. eval "exec \$cmd$args" $echo "$modename: cannot exec \$cmd$args" exit 1 else # Display what would be done. eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" $echo "export $shlibpath_var" $echo "$cmd$args" exit 0 fi ;; # libtool uninstall mode uninstall) modename="$modename: uninstall" rm="$nonopt" files= for arg do case "$arg" in -*) rm="$rm $arg" ;; *) files="$files $arg" ;; esac done if test -z "$rm"; then $echo "$modename: you must specify an RM program" 1>&2 $echo "$help" 1>&2 exit 1 fi for file in $files; do dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` rmfiles="$file" case "$name" in *.la) # Possibly a libtool archive, so verify it. if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then . $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $dir/$n" test "X$n" = "X$dlname" && dlname= done test -n "$dlname" && rmfiles="$rmfiles $dir/$dlname" test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" $show "$rm $rmfiles" $run $rm $rmfiles if test -n "$library_names"; then # Do each command in the postuninstall commands. eval cmds=\"$postuninstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" done IFS="$save_ifs" fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. eval cmds=\"$old_postuninstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" done IFS="$save_ifs" fi # FIXME: should reinstall the best remaining shared library. fi ;; *.lo) if test "$build_old_libs" = yes; then oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` rmfiles="$rmfiles $dir/$oldobj" fi $show "$rm $rmfiles" $run $rm $rmfiles ;; *) $show "$rm $rmfiles" $run $rm $rmfiles ;; esac done exit 0 ;; "") $echo "$modename: you must specify a MODE" 1>&2 $echo "$generic_help" 1>&2 exit 1 ;; esac $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$generic_help" 1>&2 exit 1 fi # test -z "$show_help" # We need to display help for each of the modes. case "$mode" in "") $echo \ "Usage: $modename [OPTION]... [MODE-ARG]... Provide generalized library-building support services. --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --finish same as \`--mode=finish' --help display this help message and exit --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] --quiet same as \`--silent' --silent don't print informational messages --version print version information MODE must be one of the following: compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for a more detailed description of MODE." exit 0 ;; compile) $echo \ "Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -static always build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $echo \ "Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $echo \ "Usage: $modename [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $echo \ "Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $echo \ "Usage: $modename [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -static do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $echo "Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac echo $echo "Try \`$modename --help' for more information about other modes." exit 0 # Local Variables: # mode:shell-script # sh-indentation:2 # End: gnats-4.1.0/missing0000744000175000017500000001421307005251730014757 0ustar chewiechewie00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. # Copyright (C) 1996, 1997 Free Software Foundation, Inc. # Franc,ois 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi case "$1" in -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch]" ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing - GNU libit 0.0" ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; aclocal) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acinclude.m4' or \`configure.in'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`configure.in'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acconfig.h' or \`configure.in'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and you do not seem to have it handy on your system. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequirements for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 gnats-4.1.0/mkinstalldirs0000744000175000017500000000133206620401137016164 0ustar chewiechewie00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1994-03-25 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? fi if test ! -d "$pathcomp"; then errstatus=$lasterr fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here gnats-4.1.0/move-if-change0000744000175000017500000000156007005251730016074 0ustar chewiechewie00000000000000#!/bin/sh # Copyright (C) 1996 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 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. if test -r $2 then if cmp $1 $2 > /dev/null then echo $2 is unchanged rm -f $1 else mv -f $1 $2 fi else mv -f $1 $2 fi gnats-4.1.0/symlink-tree0000744000175000017500000000172106620401137015731 0ustar chewiechewie00000000000000#!/bin/sh # Create a symlink tree. # # Syntax: symlink-tree srcdir "ignore1 ignore2 ..." # # where srcdir is the directory to create a symlink tree to, # and "ignoreN" is a list of files/directories to ignore. prog=$0 srcdir=$1 ignore="$2" ignore_additional=". .. CVS" # If we were invoked with a relative path name, adjust ${prog} to work # in subdirs. case ${prog} in /*) ;; *) prog=../${prog} ;; esac # Set newsrcdir to something subdirectories can use. case ${srcdir} in /*) newsrcdir=${srcdir} ;; *) newsrcdir=../${srcdir} ;; esac for f in `ls -a ${srcdir}`; do if [ -d ${srcdir}/$f ]; then found= for i in ${ignore} ${ignore_additional}; do if [ "$f" = "$i" ]; then found=yes fi done if [ -z "${found}" ]; then echo "$f ..working in" if [ -d $f ]; then true; else mkdir $f; fi (cd $f; ${prog} ${newsrcdir}/$f "${ignore}") fi else echo "$f ..linked" rm -f $f ln -s ${srcdir}/$f . fi done exit 0 gnats-4.1.0/ylwrap0000744000175000017500000000630407005251730014626 0ustar chewiechewie00000000000000#! /bin/sh # ylwrap - wrapper for lex/yacc invocations. # Copyright (C) 1996, 1997 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Usage: # ylwrap PROGRAM INPUT [OUTPUT DESIRED]... -- [ARGS]... # * PROGRAM is program to run. # * INPUT is the input file # * OUTPUT is file PROG generates # * DESIRED is file we actually want # * ARGS are passed to PROG # Any number of OUTPUT,DESIRED pairs may be used. # The program to run. prog="$1" shift # Make any relative path in $prog absolute. case "$prog" in /* | [A-Za-z]:\\*) ;; */*) prog="`pwd`/$prog" ;; esac # The input. input="$1" shift case "$input" in /* | [A-Za-z]:\\*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. Why? Because otherwise any # debugging info in the generated file will point to the wrong # place. This is really gross. input="`pwd`/$input" ;; esac # We don't want to use the absolute path if the input in the current # directory like when making a tar ball. input_base=`echo $input | sed -e 's|.*/||'` if test -f $input_base && cmp $input_base $input >/dev/null 2>&1; then input=$input_base fi pairlist= while test "$#" -ne 0; do if test "$1" = "--"; then shift break fi pairlist="$pairlist $1" shift done # FIXME: add hostname here for parallel makes that run commands on # other machines. But that might take us over the 14-char limit. dirname=ylwrap$$ trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 mkdir $dirname || exit 1 cd $dirname case "$input" in /* | [A-Za-z]:\\*) # Absolute path; do nothing. ;; *) # Make a symbolic link, hard link or hardcopy. ln -s ../"$input" . > /dev/null 2>&1 || ln ../"$input" . > /dev/null 2>&1 || cp ../"$input" . ;; esac $prog ${1+"$@"} "$input" status=$? if test $status -eq 0; then set X $pairlist shift first=yes while test "$#" -ne 0; do if test -f "$1"; then # If $2 is an absolute path name, then just use that, # otherwise prepend `../'. case "$2" in /* | [A-Za-z]:\\*) target="$2";; *) target="../$2";; esac mv "$1" "$target" || status=$? else # A missing file is only an error for the first file. This # is a blatant hack to let us support using "yacc -d". If -d # is not specified, we don't want an error when the header # file is "missing". if test $first = yes; then status=1 fi fi shift shift first=no done else status=$? fi # Remove the directory. cd .. rm -rf $dirname exit $status gnats-4.1.0/contrib/0000755000175000017500000000000010212665130015016 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/README0000644000175000017500000000074106620401143015700 0ustar chewiechewie00000000000000These files are contributed scripts and programs which have been used for analyzing or investigating data that's stored in a GNATS database. The authors of GNATS disclaim any responsibility for problems or deficiencies with the functionality or usefulness of these files. Please contact the individual authors of the contributed software to inquire about bug fixes, report problems, etc. The files in the contrib directory are not necessarily covered by the GNU Public License. gnats-4.1.0/contrib/prmon0000744000175000017500000002774306620401143016112 0ustar chewiechewie00000000000000#!/usr/unsupported/bin/bash function usage () { if [ $# -gt 0 ]; then echo -e "${progname}: $*\n" 1>&2 fi shcat 1>&2 < /dev/null builtin exit ${exitstat} } # # Time-related functions # # Compute the number of seconds specified by a string of the form # ...y...M...w...d...h...m...s # For years, months, weeks, days, hours, minutes, and seconds. Any given # unit is optional. function timefmt_to_seconds () { local arg="$*" local val local unit local total if [ $# -eq 0 ]; then read arg fi shift $# set -- $(echo ${arg} | sed 's/\([0-9]*\)\([yMwdhms]\)/\1 \2 /g') while [ $# -gt 0 ]; do val="${1}" unit="${2}" shift 2 # `multiple' is number of seconds per unit (year, month, etc.) case "${unit}" in y ) multiple=31536000 ;; M ) multiple=2592000 ;; w ) multiple=604800 ;; "" | d ) multiple=86400 ;; h ) multiple=3600 ;; m ) multiple=60 ;; s ) multiple=1 ;; * ) usage "Invalid time+unit argument: ${val}${unit}" return 1 ;; esac total=$[ total + (val * multiple) ]; done echo "${total}" } function seconds_to_days () { echo $[ ${1:-0} / 86400 ]; } function seconds_to_minutes () { echo $[ ${1:-0} / 60]; } # # Routines which search for locks # function find_locks () { verbose_echo "Searching for locks..." while read file; do verbose_echo "Looking for locks in ${file}" lock_info=$(gnatslocks "${file}") if [ -n "${lock_info}" ]; then file="`echo ${lock_info%%:*} | sed -e s,/gnats/GNATS/,,g`" user="${lock_info#*:\ }" user="${user%%@*}" verbose_echo "*** PR ${file} is locked by ${bq}${user}${eq}" if user_known_p "${user}" ; then echo " ${file}" >> "${tmpdir}/${user}.K" else owner=$(ls -l "${file}" | awk '{print $3}') echo "${file} by ${user}" >> "${tmpdir}/${owner}.U" fi fi done verbose_echo "Done searching for locks." } # Give some info about each lock. function gnatslocks () { local file for file in "$@" ; do filename=`echo ${file} | sed -e s/\.lock//g` echo "${filename}: `cat ${file}`" done } function user_known_p () { local file for file in /etc/passwd ; do if grep -s "^${1}:" "${file}" > /dev/null 2>&1 ; then return 0 fi done return 1 } # # Reporting generating routines # function send_reports () { local file pushd "${tmpdir}" > /dev/null for file in *.[KU] ; do verbose_echo "*** Mailing report to ${file%.[KU]}" generate_mail_message "${file}" | sendmail -oi -t done popd > /dev/null } function generate_mail_message () { local file="$1" local recipient="${file%.[KU]}" local line shcat <<- __EOF__ From: ${progname} (GNATS lock monitor daemon) To: ${recipient} Bcc: ${maintainer} Reply-To: ${maintainer} Subject: old GNATS locks Precedence: bulk This is an automated report generated on ${hostname}. __EOF__ case "${file}" in *.K ) shcat <<- __EOF__ You have had some PRs locked for over $(age_echo ${age} ${age_unit}). If you no longer need the PR locked, just do \'C-x k\' in the buffer to relinquish the lock. However, if the original emacs session you had no longer exists (e.g, emacs crashed, or you did a kill-buffer by hand, you have a couple of options. You can either type: /usr/unsupported/lib/gnats/pr-edit --unlock foo/1234 for each one, or, in emacs, you can do M-x unlock-pr RET foo/1234 RET to unlock them. The PRs in question are: __EOF__ ;; *.U ) shcat <<- __EOF__ The following files are presently locked by unknown users, but you (${recipient}) are the present owner of the PR. These files have been locked over $(age_echo ${age} ${age_unit}). Please look into this. __EOF__ ;; esac echo "" shcat "${file}" echo "" shcat <<- __EOF__ Thanks, Your friendly neighborhood GNATS admin. __EOF__ } function age_echo () { local age="$1" local unit="$2" echo -n "${age} " if [ "${age}" = "1" ]; then echo "${unit}" else echo "${unit}s" fi } function mail_stderr_to_maintainer () { if [ -z "${stderr_file+set}" ]; then return 0; fi if [ -s "${stderr_file}" ]; then sendmail -oi -t <<- __EOF__ From: ${progname} (GNATS lock monitor daemon) To: ${maintainer} Subject: ${progname} stderr output Precedence: bulk This is an automated report from host ${hostname}. With euid ${EUID} (ruid ${UID}), program "${progname}" ran with the following arguments: ${progname_arguments} and generated the following output on stderr: $(cat "${stderr_file}") __EOF__ fi } function shcat () { local IFS="" local line local file local exitstat=0 if [ $# -eq 0 ]; then while read line; do echo "${line}" done return 0 else for file in "$@" ; do if [ -r "${file}" ]; then { while read line; do echo "${line}" done } < "${file}" else # This will cause the error to be printed on stderr < "${file}" exitstat=1 fi done return ${exitstat} fi } function verbose_echo () { test -n "${verbose+set}" && echo "$@" 1>&2 } function exit () { exitstat="$1" builtin exit ${exitstat} } main "$@" # # eof # gnats-4.1.0/contrib/elisp/0000755000175000017500000000000010212665130016132 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/elisp/gnats-admin.el0000644000175000017500000006721006620401144020665 0ustar chewiechewie00000000000000;; gnats administration code ;; display the pr's in a buffer, ;; dired-style commands to edit & view them. ;; this version is known to work in XEmacs. ;; author: Roger Hayes, roger.hayes@sun.com ;; copyright: You are welcome to use this software as you see fit. ;; Neither the author nor his employer make any representation about ;; the suitability of this software for any purpose whatsoever. (defconst gnats-admin-copyright "Copyright (c) 1996 Roger Hayes. Permission to use, copy, modify and distribute this software and documentation for any purpose and without fee is hereby granted in perpetuity, provided that this COPYRIGHT AND LICENSE NOTICE appears in its entirety in all copies of the software and supporting documentation. The names of the author or Sun Microsystems, Inc. shall not be used in advertising or publicity pertaining to distribution of the software and documentation without specific, written prior permission. ANY USE OF THE SOFTWARE AND DOCUMENTATION SHALL BE GOVERNED BY CALIFORNIA LAW. THE AUTHOR AND SUN MICROSYSTEMS, INC. MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE OR DOCUMENTATION FOR ANY PURPOSE. THEY ARE PROVIDED *AS IS* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. THE AUTHOR AND SUN MICROSYSTEMS, INC. SEVERALLY AND INDIVIDUALLY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE AND DOCUMENTATION, INCLUDING THE WARRANTIES OF MERCHANTABILITY, DESIGN, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHOR OR SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN ACTION ARISING OUT OF CONTRACT, NEGLIGENCE, PRODUCT LIABILITY, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE OR DOCUMENTATION." "Copyright and disclaimer notice") ;; magic words are highlighted using font-lock ;; data structures: a pr is represented as an alist ;; the list of known pr's is represented as a vector ;; pr references are often done by number ;; (pr N) takes either a number, and returns the pr assoc list, ;; or the pr assoc list, returning the same. ;; regions are tagged with the number of the pr; the indirection lets ;; updates to pr's happen without disturbing the region. (defvar pr-list nil "Vector of parsed problem reports.") (require 'cl) ;;; (require 'match-string) ;;; inline match-string (if (not (fboundp 'match-string)) (defun match-string (n &optional target) "Return the text of the NTH match in optional TARGET." (let* ((m-data (match-data)) (idx (* 2 n)) (m-beg (elt m-data idx)) (m-end (elt m-data (1+ idx)))) (cond ((markerp m-beg) (buffer-substring m-beg m-end)) ((integerp m-beg) (substring target m-beg m-end)) (t (error "Bad argument N to match-string")))))) ;;; (require 'edit-expr) ;; edit-expr -- pop up a buffer to edit an expression (if (not (fboundp 'edit-expr)) (defun edit-expr (e &optional explain) "Pop up a buffer to edit the EXPRESSION; return the edited value. Buffer gets optional EXPLANATION." (with-output-to-temp-buffer "*expr-buffer*" (let ((buffer standard-output) (val nil) emark) (save-excursion (pop-to-buffer (buffer-name buffer)) (emacs-lisp-mode) (delete-region (point-min) (point-max)) (insert (or explain ";; Edit this value")) (insert "\n") (setq emark (point-marker)) (prin1 e) (goto-char emark) (message "recursive edit -- M-C-c when done") (recursive-edit) (goto-char emark) (setq val (read buffer))) val)))) ;; (require 'regret) ;; creates regression tests in my environment [rh] (provide 'gnats-admin) ;; add stuff for font-lock; harmless if you don't use font-lock. ;; beware -- font-lock uses the first match; hence longer words must ;; precede shorter words, if they both match. (defconst gnats-admin::font-lock-keywords '(;; severity ("non-critical" . non-critical) ("critical" . critical) ("serious" . serious) ;; priority ("high" . high) ("medium" . medium) ("low" . low) ;; state ("open" . open) ("analyzed" . analyzed) ("suspended" . suspended) ("feedback" . feedback) ("closed\\*" . closed*) ("closed\\?" . closed?) ("closed" . closed) ;; class ("sw-bug" . sw-bug) ("doc-bug" . doc-bug) ("support" . support) ("change-request" . change-request) ("mistaken" . mistaken) ("duplicate" . duplicate))) (defvar gnats-admin::popup-menu '("Gnats-Admin" ["Edit" 'gnats-admin:pr-edit t] ["View" 'gnats-admin:pr-view t] ) "Local popup menu.") (defvar gnats-admin-query-hook nil "Hooklist for post-query processing in gnats-admin mode.") (defvar gnats-admin:query-list nil "Results of one query -- may be altered by query hook to change results of query.") (defvar gnats-admin-refresh-hook nil "Hooklist for post-refresh processing in gnats-admin mode. Run after a refresh -- gnats-admin::dirty-list may contain list of re-read pr numbers") (defvar gnats-admin::selector nil "Function of one argument that governs if a PR should be diplayed.") (add-hook 'gnats-admin-refresh-hook (function (lambda () (font-lock-fontify-buffer)))) ;;; ;; first, how do we get & parse the pr's? (defun gnats-admin::run-query () "Run a default query, setting pr-list to the result." (setq pr-list (apply 'vector (gnats-admin::query))) (length pr-list)) (defun trim (s) "trim the leading & trailing blanks from a string" (if (string-match "^\\s-*\\(\\S-.*\\S-\\|\\S-\\)\\s-*$" s) (substring s (match-beginning 1) (match-end 1)) "") ) ;; parse one pr -- moves point. (defun gnats-admin::parse-pr () "parse one pr, moving point" (let ((pr nil)) (let ((flv (make-vector 13 nil)) (lim 0) (bol 0) (index 0)) (end-of-line) (setq lim (point)) (beginning-of-line) (setq bol (point)) (while (and (< (point) lim) (re-search-forward "\\([^|]*\\)|" lim t)) (aset flv index (trim (match-string 1))) (setq index (1+ index))) (if (not (= index 13)) (error "Bad PR inquiry: %s" (buffer-substring bol lim))) (setq pr (gnats-admin::vec->pr flv))) (if (not (bolp)) (forward-line 1)) pr)) (defun gnats-admin::query (&rest args) (let ((prl (list)) (buf (get-buffer-create "**gnats-query*"))) (save-excursion (set-buffer buf) (delete-region (point-min) (point-max)) (message "Running query") (setq args (mapcar (function (lambda (x) (format "%s" x))) args)) (apply 'call-process "query-pr" nil t nil "--sql" args) (message "Query completed") ;; now parse the output (goto-char (point-min)) (while (not (eobp)) (setq prl (cons (gnats-admin::parse-pr) prl))) ) (message "Result parsed") ;; lots of stuff to apply the proper hook (setq gnats-admin:query-list prl) (run-hooks 'gnats-admin-query-hook) (setq prl gnats-admin:query-list) (setq gnats-admin:query-list nil) (nreverse prl))) ;; ;; (defun gnats-admin::vec->pr (v) "massage a 13-element vector into the internal pr representation. fields are as described in query-pr documentation." (if (not (and (vectorp v) (= (length v) 13))) (error "Not a valid PR intermediate form")) ;;; 0 - pr number (aset v 0 (read (aref v 0))) ;;; 1 - category (aset v 1 (read (aref v 1))) ;;; 2 - synopsis ; leave as string ;;; 3 - confidential (aset v 3 (if (equal "no" (aref v 3)) nil (aref v 3))) ;;; 4 - severity (let ((num (read (aref v 4)))) (aset v 4 (aref [null critical serious non-critical] num))) ;;; 5 - priority (let ((num (read (aref v 5)))) (aset v 5 (aref [null high medium low] num))) ;;; 6 - responsible ; leave as string ;;; 7 - state (let ((num (read (aref v 7)))) (aset v 7 (aref [null open analyzed suspended feedback closed] num))) ;;; 8 - class (let ((num (read (aref v 8)))) (aset v 8 (aref [null sw-bug doc-bug support change-request mistaken duplicate] num))) ;;; 9 - submitter-id ; leave as string ;;; 10 - arrival-date ; leave as string ;;; 11 - originator ; leave as string ;;; 12 - release ; leave as string ;; the fields of v have been transformed; now map them into an alist (do ((vx 0 (1+ vx)) ; v index (an ; field names (in order!) (gnats-admin::pr-field-names) (cdr an)) (al nil) ; assoc list ) ((null an) (nreverse al)) ; <- here's where the result comes from (setq al (cons (cons (car an) (aref v vx)) al)) )) (defun gnats-admin::pr-get (pr field) "Get, from PR, value of slot named FIELD (a symbol)." (let ((p (assq field (gnats-admin:pr pr)))) (if p (cdr p) nil))) (defun nset-assq (alist key val) "destructively set key'v association in the alist to val. returns the original list, unless it was null" (let ((p (assq key alist))) (if p (progn (setcdr p val) alist) (nconc alist (list (cons key val)))))) (defun gnats-admin::pr-set! (pr field val) "Set, in PR, slot named FIELD to VAL. Slot name is a symbol." (nset-assq pr field val)) ;; fast version of field name->index mapper ;; also tests if a symbol is a field name present in sql report. (defun gnats-admin::pr-field-index (feild) (case feild (Number 0) (Category 1) (Synopsis 2) (Confidential 3) (Severity 4) (Priority 5) (Responsible 6) (State 7) (Class 8) (Submitter-Id 9) (Arrival-Date 10) (Originator 11) (Release 12))) ;; next is for completing-read ;; order must be the same as indices ;; content is (name index type width) ;; width is field width, not counting space (defconst gnats-admin::pr-field-alist '(("Number" 0 integer 3) ("Category" 1 symbol 15) ("Synopsis" 2 string 80) ("Confidential" 3 boolean 1) ("Severity" 4 symbol 12) ("Priority" 5 symbol 6) ("Responsible" 6 string 7) ("State" 7 symbol 8) ("Class" 8 symbol 14) ("Submitter-Id" 9 string 7) ("Arrival-Date" 10 string 14) ("Originator" 11 string 32) ("Release" 12 string 48)) "Alist that maps field-name->(name index type width)") (defun gnats-admin::pr-field-names () "List of symbols that are field keys in pr. Must be in order." (mapcar (function (lambda (pr) (intern (car pr)))) gnats-admin::pr-field-alist)) ;; format control template for PR display (defconst gnats-admin::pr-long-format '((4 Category Class) (35 Priority Severity) (60 Responsible) (70 State ) nl 4 "Synopsis:" Synopsis )) (defconst gnats-admin::pr-short-format '((4 Category Class) (35 Priority Severity) (60 Responsible) (70 State ))) (defvar gnats-admin::pr-format gnats-admin::pr-short-format "Format list for printing a pr.") ;; hook that sets extent etc for Lucid emacs (defun gnats-admin::pr-display-hook (b e pr buf) "Set extent around pr." (let ((ext (make-extent b e buf))) (set-extent-layout ext 'outside-margin) (set-extent-property ext 'pr pr) (set-extent-property ext 'start-open t) (set-extent-property ext 'end-open t) (set-extent-property ext 'highlight t))) ;; gnats uses one face for each element of the enumerated fields, ;; to give maximum flexibility in display. ;;; symbol->(face foreground background) alist (defvar gnats-admin::face-color '((critical "firebrick" nil) (serious "goldenrod" nil) (non-critical "blue3" nil) (high "firebrick" nil) (medium "goldenrod" nil) (low "blue3" nil) (open "firebrick" nil) (analyzed "goldenrod" nil) (suspended "turquoise" nil) (feedback "blue3" nil) (closed "ForestGreen" nil) (closed* "HotPink" nil) (closed? "blue3" nil) (sw-bug nil nil) (doc-bug nil nil) (support nil nil) (change-request nil nil) (mistaken nil nil) (duplicate nil nil)) "Alist of font properties") (defun gnats-admin::field-display (pr fld buf) "Display value field on specified stream." (let ((fv (gnats-admin::pr-get pr fld))) (princ fv buf))) (defun gnats-admin::pr-print-func (f pr buf) "Printer for pr. Depends on free variable pr-did-indent." (cond ((eq 'nl f) (princ "\n " buf) (setq pr-did-indent t)) ((listp f) (do ((fmt f (cdr fmt))) ((null fmt)) (gnats-admin::pr-print-func (car fmt) pr buf))) ((numberp f) (indent-to-column f 1) (setq pr-did-indent t)) ((symbolp f) (if (not pr-did-indent) (princ " " buf)) (gnats-admin::field-display pr f buf) (setq pr-did-indent nil)) ((stringp f) (if (not pr-did-indent) (princ " " buf)) (princ f buf) (setq pr-did-indent nil)) ) t) (defun gnats-admin::display-pr (pr &optional buf) ;; always print the number first (if (not buf) (setq buf (current-buffer))) (let ((b (point)) (buffer-read-only nil) (pr-did-indent nil)) (princ (gnats-admin::pr-number pr) buf) ;; now print according to the pr-format list (do ((fmt gnats-admin::pr-format (cdr fmt))) ((null fmt)) (gnats-admin::pr-print-func (car fmt) pr buf)) (gnats-admin::pr-display-hook b (point) (gnats-admin::pr-number pr) buf) (newline))) (defun gnats-admin::pr-buffer-extent (pr) "Find the extent for this PR." (extent-at (1+ (gnats-admin::pr-buffer-begin pr)) (gnats-admin::pr-buffer pr) 'pr)) (defun gnats-admin::pr-reread (pr) "Rerun query for one PR in the pr-list." (let ((num (gnats-admin::pr-number pr))) (let ((repl (gnats-admin::query num))) (if (and (listp repl) (= (length repl) 1) (= (gnats-admin::pr-get (car repl) 'Number) num)) (gnats-admin::pr-replace! num (car repl)) (error "Query failed for pr %s" num))) )) (defun gnats-admin::selection (loprs) "Return the elements of LOPRS (list of PR's) which satify PREDicate." (let ((pred gnats-admin::selector)) (if (not pred) loprs ;; else use the common-lisp loop appropriate to the type of loprs (cond ((arrayp loprs) (loop for pr across loprs if (apply pred pr '()) collect pr )) ((listp loprs) (loop for pr in loprs if (apply pred pr '()) collect pr )) (t (error "Bad type for PR collection"))) ))) (defun gnats-admin::selected? (pr) "Test to see if one pr meets the selection criterion." (or (null gnats-admin::selector) (apply gnats-admin::selector pr '()))) (defun gnats-admin::pr-replace! (oldpr newpr) "Replace the old pr with the new one" (if (not (consp newpr)) (error "Replacement pr must be a full PR value")) (let ((pr-num (gnats-admin::pr-number newpr))) (if (not (= (gnats-admin::pr-number oldpr) pr-num)) (error "Cannot replace PR with one of different number")) (if (< (length pr-list) pr-num) (setq pr-list (vconcat pr-list (make-vector (- pr-num (length pr-list)) nil)))) (aset pr-list (1- pr-num) newpr))) (defvar gnats-admin::dirty-list nil "List of PRs which may be out of date and need refreshing.") (defun gnats-admin:reset () "Reset the cached data for gnats-admin." (setq pr-list nil) (setq gnats-admin::dirty-list nil) ; it's everything now ) (defun gnats-admin:regret () "Create or edit the regression test for the current problem report." (interactive) (let* ((pr (gnats-admin::pr-at (point))) (num (gnats-admin::pr-number pr))) (pr-regret num))) (defun gnats-admin:refresh (&optional force) (interactive "P") (if force (gnats-admin:reset)) (if (not pr-list) (progn (gnats-admin::run-query)) (progn (mapc (function (lambda (p) (gnats-admin::pr-reread p))) gnats-admin::dirty-list))) (setq gnats-admin::dirty-list nil) (set-buffer (gnats-admin::buffer)) (let ((standard-output (current-buffer)) (buffer-read-only nil) (this-pr-num (gnats-admin::pr-num-at (point)))) ; is this overkill; could we save our extents unless force? (if nil (map-extents (function (lambda (ext data) (delete-extent ext) nil)) (current-buffer))) (delete-region (point-min) (point-max)) (beginning-of-buffer) (message "Redisplay") (mapc (function (lambda (pr) (if (gnats-admin::selected? pr) (gnats-admin::display-pr pr)))) pr-list) (message nil) ;; catch search errors in case the current pr no longer exists-- ;; if so, go to end of buffer (condition-case err (if (numberp this-pr-num) (gnats-admin:goto-pr this-pr-num)) (search-failed (goto-char (point-max))))) (run-hooks 'gnats-admin-refresh-hook) t) (defun gnats-admin::pr-number (pr) "Get the number of this pr -- which can be either a pr datum or a number." (or (and (numberp pr) pr) (gnats-admin::pr-get pr 'Number))) ;; this must not depend on pr-at, because that depends on this. (defun gnats-admin::pr-num-at (pos) "Find the pr number for the pr at POS" (let* ((ext (extent-at pos nil 'pr)) (pr-prop (and ext (extent-property ext 'pr)))) (if pr-prop (gnats-admin::pr-number pr-prop) (save-excursion (goto-char pos) (if (not (looking-at "^\\s-*[0-9]")) (backward-paragraph)) (if (looking-at "\\s-*[0-9]+[^0-9]") (read (match-string 0)) nil))))) (defun gnats-admin::pr-by-number (num) "Find the pr numbered N." ;; first try the easy way (let ((pr (elt pr-list (1- num)))) (if (and pr (= num (gnats-admin::pr-number pr))) pr ;; easy way didnt work; scan the list (loop for prx across pr-list if (= num (gnats-admin::pr-number prx)) return prx)))) ;; use face alist to set face colors (defun gnats-admin::setup-faces () "Set up the faces for gnats admin mode." (mapc (function (lambda (l) (make-face (car l)))) gnats-admin::face-color) (if (memq (device-class) '(color grayscale)) (mapc (function (lambda (l) (if (cadr l) (set-face-foreground (car l) (cadr l))) (if (caddr l) (set-face-background (car l) (caddr l))))) gnats-admin::face-color)) (setq font-lock-keywords gnats-admin::font-lock-keywords) ;; this is too slow -- instead, do explicit fontification after modify ; (turn-on-font-lock) ) (defvar gnats-admin::pr-mark-glyph nil "Glyph used to mark the current PR in display.") (defun gnats-admin::buffer () "Find or create gnats admin buffer." (or (get-buffer "*gnats*") (let ((buf (get-buffer-create "*gnats*"))) (set-buffer buf) (make-local-variable 'paragraph-start) (make-local-variable 'paragraph-separate) (setq paragraph-start "^\\(\\S-\\|[ \t\n]*$\\)") (setq paragraph-separate "^[ \t\n]*$") (setq buffer-read-only t) (setq buffer-undo-list t) ; disable undo info (setq gnats-admin::pr-mark-glyph (make-pixmap "target")) (gnats-admin::setup-faces) buf) )) (defun gnats-admin:pr (pr-or-num) "If PR-OR-NUM is a pr, return it; if it's a number, return the pr with that number." (cond ((numberp pr-or-num) (gnats-admin::pr-by-number pr-or-num)) ((consp pr-or-num) pr-or-num) (t (error "Not a valid PR: %s" pr-or-num)) )) (defun gnats-admin::pr-at (pos) "PR at POSITION" (or (let ((ext (extent-at pos nil 'pr))) (if ext (extent-property ext 'pr))) (gnats-admin::pr-num-at pos))) ;; next should, ideally, run a 1-pr query then splice that into ;; pr-list to update the current pr. ;; however, there's a race condition with gnats; so put the edited ;; pr on the dirty list to be inquired later. (defun gnats-admin:pr-edit () (interactive) (let* ((pr (gnats-admin::pr-at (point))) (num (gnats-admin::pr-number pr)) (num-str (format "%d" num))) (pr-edit num-str) (setq gnats-admin::dirty-list (cons pr gnats-admin::dirty-list)))) (defun gnats-admin:pr-view () (interactive) (pr-view (format "%d" (gnats-admin::pr-num-at (point))))) (defun gnats-admin:pr-synopsis () (interactive) (let* ((pr (gnats-admin::pr-at (point))) (syn (gnats-admin::pr-get pr 'Synopsis))) (message "Synopsis: %s" syn))) (defun gnats-admin:pr-originator () (interactive) (let* ((pr (gnats-admin::pr-at (point))) (syn (gnats-admin::pr-get pr 'Originator))) (message "Originator: %s" syn))) (defun gnats-admin:pr-field (fld) "Show any pr field FLD of current pr." (interactive (list (completing-read "Field: " gnats-admin::pr-field-alist nil t))) (let* ((pr (gnats-admin::pr-at (point))) (val (gnats-admin::pr-get pr (intern fld)))) (message "%s: %s" fld val))) (defvar gnats-admin::current-pr nil "Current pr") (defun gnats-admin::highlight (pr) "Hilight the current PR -- may unhilight the previous." (condition-case err (progn (if gnats-admin::current-pr (highlight-extent (gnats-admin::pr-buffer-extent gnats-admin::current-pr) nil)) (highlight-extent (gnats-admin::pr-buffer-extent pr) t) (setq gnats-admin::current-pr pr)) (error (setq gnats-admin::current-pr nil)))) (defun gnats-admin::highlight-point () "Highlight the pr at point" ;; make point visible (or (pos-visible-in-window-p) (recenter '(t))) (gnats-admin::highlight (gnats-admin::pr-at (point)))) (defun gnats-admin:next () "Next pr" (interactive) (forward-paragraph) (gnats-admin::highlight-point)) (defun gnats-admin:prev () "Prev pr." (interactive) (backward-paragraph) (gnats-admin::highlight-point)) (defun gnats-admin:this () "Activate pr at point." (interactive) (end-of-line) (backward-paragraph) (gnats-admin::highlight-point)) (defun gnats-admin:mouse-set (ev) (interactive "e") (mouse-set-point ev) (gnats-admin::highlight-point)) (defun gnats-admin:mouse-synopsis (ev) (interactive "e") (gnats-admin:mouse-set ev) (gnats-admin:pr-synopsis)) (defun gnats-admin:mouse-menu (ev) (interactive "e") (gnats-admin:mouse-set ev) (popup-mode-menu)) (defun gnats-admin:refresh-this-pr () "Reread and refresh the display of the current PR." (interactive) (let* ((pr (gnats-admin::pr-at (point))) (buffer-read-only nil) (b (gnats-admin::pr-buffer-begin pr)) (e (gnats-admin::pr-buffer-end pr))) (goto-char b) (save-excursion (gnats-admin::pr-buffer-delete pr) (gnats-admin::pr-reread pr) (gnats-admin::display-pr pr (current-buffer)) ;; had to dive pretty deep into font-lock to get this one... (let ((font-lock-mode t)) (font-lock-after-change-function b e 1))) (gnats-admin::highlight-point))) (defun gnats-admin:goto-pr (n) "Make pr number N the current pr." (interactive "nPR: ") (goto-char (gnats-admin::pr-n-pos n)) (gnats-admin::highlight-point)) (defun gnats-admin::pr-n-pos (n) "Find the buffer position of pr numbered N in current buffer." (save-excursion (goto-char (point-min)) (let ((re (format "^%s\\s-" n))) (re-search-forward re) (point) ))) (defun gnats-admin::pr-buffer-delete (pr) "Delete the display of the PR." (let* ((b (gnats-admin::pr-buffer-begin pr)) (e (gnats-admin::pr-buffer-end pr)) (mbuf (gnats-admin::pr-buffer pr)) (pr-ext (gnats-admin::pr-buffer-extent pr))) (set-buffer mbuf) (let ((buffer-read-only nil)) (delete-region b e) (if (extentp pr-ext) (delete-extent pr-ext))) )) (defun gnats-admin:quit () "Quit out of gnats admin mode." (interactive) (if (get-buffer "**gnats-query*") (kill-buffer "**gnats-query*")) (kill-buffer nil)) (defvar gnats-admin-mode-map nil "Key map for gnats admin mode.") (defun gnats-admin::setup-keymap () (if (not (keymapp gnats-admin-mode-map)) (progn (setq gnats-admin-mode-map (make-keymap)) (suppress-keymap gnats-admin-mode-map) (define-key gnats-admin-mode-map "e" 'gnats-admin:pr-edit) (define-key gnats-admin-mode-map "v" 'gnats-admin:pr-view) (define-key gnats-admin-mode-map "s" 'gnats-admin:pr-synopsis) (define-key gnats-admin-mode-map "o" 'gnats-admin:pr-originator) (define-key gnats-admin-mode-map "f" 'gnats-admin:pr-field) (define-key gnats-admin-mode-map "\C-l" 'gnats-admin:refresh) (define-key gnats-admin-mode-map "n" 'gnats-admin:next) (define-key gnats-admin-mode-map "p" 'gnats-admin:prev) (define-key gnats-admin-mode-map " " 'gnats-admin:this) (define-key gnats-admin-mode-map "q" 'gnats-admin:quit) (define-key gnats-admin-mode-map "g" 'gnats-admin:goto-pr) (define-key gnats-admin-mode-map "r" 'gnats-admin:refresh-this-pr) (define-key gnats-admin-mode-map "S" 'gnats-admin:edit-selection) (define-key gnats-admin-mode-map "R" 'gnats-admin:regret) (define-key gnats-admin-mode-map 'button1 'gnats-admin:mouse-set) (define-key gnats-admin-mode-map 'button2 'gnats-admin:mouse-synopsis) (define-key gnats-admin-mode-map 'button3 'gnats-admin:mouse-menu) )) ) (defun gnats-admin-mode () "Major mode for looking at a summary of gnats reports. Stomps to gnats admin buffer! Commands: \\{gnats-admin-mode-map}." (interactive) (switch-to-buffer (gnats-admin::buffer)) (setq major-mode 'gnats-admin-mode) (setq mode-name "Gnats Admin") (gnats-admin::setup-keymap) (use-local-map gnats-admin-mode-map) (setq mode-popup-menu gnats-admin::popup-menu) (gnats-admin:refresh) ) (put 'gnats-admin-mode 'mode-class 'special) (defvar gnats-admin::pr-mark-glyph nil "marker for current PR.") (defun gnats-admin::pr-buffer (pr) "The buffer in which this pr is displayed." (gnats-admin::buffer)) (defun gnats-admin::pr-buffer-begin (pr) "Return the position of beginning of this PR." (let ((pr-num (gnats-admin::pr-number pr))) (save-excursion (set-buffer (gnats-admin::pr-buffer pr)) ;; first try locally, then thru whole buffer (or (and (progn (backward-paragraph 1) (re-search-forward (format "^%d " pr-num) nil t)) (progn (beginning-of-line 1) (point))) (and (progn (goto-char (point-min)) (re-search-forward (format "^%d " pr-num) nil t)) (progn (beginning-of-line 1) (point))))))) (defun gnats-admin::pr-buffer-end (pr) "Return the position of the end of the PR." (save-excursion (set-buffer (gnats-admin::pr-buffer pr)) (goto-char (gnats-admin::pr-buffer-begin pr)) (forward-paragraph 1) (point))) (defun gnats-admin::unclosed (pr) "A selector that chooses unclosed PR's." (not (eq 'closed (gnats-admin::pr-get pr 'State)))) (defvar gnats-admin:selexpr nil "Selection expression -- see eval-selexpr.") (defun gnats-admin::eval-selexpr (pr) "Evaluate the selection expression, in an environment with pr bound to the pr, and the field names bound to their value." (let ((Number (gnats-admin::pr-get pr 'Number)) (Category (gnats-admin::pr-get pr 'Category)) (Synopsis (gnats-admin::pr-get pr 'Synopsis)) (Confidential (gnats-admin::pr-get pr 'Confidential)) (Severity (gnats-admin::pr-get pr 'Severity)) (Priority (gnats-admin::pr-get pr 'Priority)) (Responsible (gnats-admin::pr-get pr 'Responsible)) (State (gnats-admin::pr-get pr 'State)) (Class (gnats-admin::pr-get pr 'Class)) (Submitter-Id (gnats-admin::pr-get pr 'Submitter-Id)) (Arrival-Date (gnats-admin::pr-get pr 'Arrival-Date)) (Originator (gnats-admin::pr-get pr 'Originator)) (Release (gnats-admin::pr-get pr 'Release))) (or (not gnats-admin:selexpr) (eval gnats-admin:selexpr)))) (defun gnats-admin:edit-selection () "Edit the selection criteria." (interactive) (setq gnats-admin::selector 'gnats-admin::eval-selexpr) (setq gnats-admin:selexpr (edit-expr gnats-admin:selexpr ";; Selection expression. This is evaluated with Number, Category, Synopsis, ;; Confidential, Severity, Priority, Responsible, State, Class, Submitter-Id, ;; Arrival-Date, Originator, and Release set from the PR; if it's a non-null ;; expression that evaluates true, then that record is displayed. Free-form ;; fields are strings, others are symbols or other atoms. " )) (gnats-admin:refresh)) gnats-4.1.0/contrib/juniper-web-reports/0000755000175000017500000000000010212665130020741 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/juniper-web-reports/index.html0000744000175000017500000000404506620401145022744 0ustar chewiechewie00000000000000 Juniper Networks: Bug Tracking System Juniper Networks Bug Tracking System

Submiting/editing problem reports

o Submit a problem report

Problem report summaries

o Construct a custom search
o Summary of active problem reports -- by severity
o Summary of active problem reports -- by priority
o Summary of active problem reports -- by category
o Summary of active problem reports -- by responsible party
o Summary of active problem reports -- by state

Query a specific problem report

Please enter the PR number you wish to query:


Juniper Networks / webmaster@juniper.net
gnats-4.1.0/contrib/juniper-web-reports/README0000644000175000017500000000162606665562177021656 0ustar chewiechewie00000000000000The following code represents a snapshot of the problem report tracking system we use at Juniper. This stuff is based on old code I wrote for FreeBSD, Inc, and has a couple thousand cooks in the kitchen over time. I should really rewrite it from scratch and make it clean and quick, but who has the time? Paul 26/feb/1999 -- this code was rewritten to user perl5 and the standard CGI modules that come with perl5 - index.html - just a list of VERY basic commands to get folks started - query-pr.cgi - perl script to display/pretty-print a particular bug - query-pr-summary.cgi - bimodal perl script, can be run as either a cgi program or will output standard text - submit-pr.cgi - Web based initial problem report submissions this is the meat of the package -- it will give you relatively extensive nice web based reports and link with query-pr.cgi to give you expanded detail on particular bugs. gnats-4.1.0/contrib/juniper-web-reports/bugs0000744000175000017500000000010506620401145021623 0ustar chewiechewie00000000000000#!/bin/sh exec /volume/httpd/cgi-bin/query-pr-summary.cgi --quiet $* gnats-4.1.0/contrib/juniper-web-reports/query-pr-summary.cgi0000744000175000017500000006510706703105746024732 0ustar chewiechewie00000000000000#!/usr/local/bin/perl # $Id: query-pr-summary.cgi,v 1.3 1999/01/19 22:16:50 pst Exp pst $ # # GNATS problem tracking report generator # # This script can be used to generate reports from the GNATS database. # The same tool is used to generate both HTML and ascii reports. # # Copyright (c) 1994-1998, FreeBSD Inc. # All rights reserved. # Copyright (c) 1997-1999, Juniper Networks Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $Id: query-pr-summary.cgi,v 1.3 1999/01/19 22:16:50 pst Exp pst $ # # ----------------------------------------------------------------------- # TODO: # Add back support for sorting on dates once we confirm new gnats # has been installed at FreeBSD Inc. (arrival/modified). # Move the HTML formatting crap out to a separate library ala # the old cgi-style.pl so it can be shared with query-pr.cgi. # ----------------------------------------------------------------------- # # $preformat = 1; use Getopt::Long; use CGI; $html_mode = 1 if $ENV{'DOCUMENT_ROOT'}; $ENV{'PATH'} = '/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin'; $query_pr = '/usr/local/bin/nquery-pr'; # # Customization variables to move things back and forth between # Juniper Networks and FreeBSD, Inc. # $project = "Juniper"; # FreeBSD if ($project eq "Juniper") { $mail_prefix = "bug-"; $mail_unass = "bugs"; $default_submitter = "juniper"; } else { $mail_prefix = "freebsd-"; $mail_unass = "freebsd-bugs"; $default_sumbitter = "current-users"; } #Usage: query-pr [-FGhiPRqVx] [-C confidential] [-c category] [-d directory] # [-e severity] [-m mtext] [-O originator] [-o outfile] [-p priority] # [-L class] [-r responsible] [-S submitter] [-s state] [-t text] # [-b date] [-a date] [-B date] [-M date] [-z date] [-Z date] # [-y synopsis] [-A release] [--full] [--help] [--print-path] [--version] # [--summary] [--sql] [--skip-closed] [--category=category] # [--confidential=yes|no] [--directory=directory] [--output=outfile] # [--originator=name] [--priority=level] [--class=class] # [--responsible=person] [--release=release] [--restricted] # [--quarter=quarter] [--keywords=regexp] # [--required-before=date] [--required-after=date] # [--arrived-before=date] [--arrived-after=date] # [--modified-before=date] [--modified-after=date] # [--closed-before=date] [--closed-after=date] # [--severity=severity] [--state=state] [--submitter=submitter] # [--list-categories] [--list-classes] [--list-responsible] # [--list-states] [--list-submitters] [--list-config] # [--synopsis=synopsis] [--text=text] [--multitext=mtext] [PR] [PR]... @input_fields = ( "confifdential", "originator", "priority", "class", "category", "responsible", "release", "quarter", "keywords", "required-before", "required-after", "arrived-before", "arrived-after", "modified-before", "modified-after", "closed-before", "closed-after", "severity", "state", "submitter", "synopsis", "text", "multitext", # now our special fields ... "closed", "public" ); # #---------------------------------------------------------------------------- # HTML management #---------------------------------------------------------------------------- # # # Convert a line from ascii to HTML-ascii (handle things that are likely # to be displayed incorrectly. # sub html_fixline { my $line = shift; $line =~ s/&/&/g; $line =~ s//>/g; return $line; } # # Print an initial HTML header # Place whatever stylistic data you want right here. # # XXX Project specific data found here (Juniper vs. FreeBSD) # sub html_header { my $title = shift; print $query->header; print $query->start_html('title' => $title, 'author' => 'pst@juniper.net', 'bgcolor' => '#ffffff'); print <

$title



EOM } # # Print project specific HTML footer information here # # XXX Project specific data found here (Juniper vs. FreeBSD) # sub html_footer { print < Juniper Internal Home Page
webmaster\@juniper.net
EOM } # # These self references are attempts to only change a single variable at a time. # If someone does a multiple-variable query they will probably do weird things. # sub html_refs { my $me_ref1 = $self_ref . '?'; $me_ref1 .= "sort=$input{sort}" if $input{sort}; $me_ref1 .= '&' if ($me_ref1 !~/\?$/); my $me_ref2 = $self_ref . '?'; foreach (@input_fields) { if ($input{$_}) { $me_ref2 .= '&' if ($me_ref2 !~/\?$/); $me_ref2 .= $_ . '=' . $input{$_}; } } my $me_ref3 = $me_ref2; $me_ref3 =~ s/&closed=on//g; print < You may view summaries by Severity, State, Category, Priority, Class, or Responsible Party.
You may also sort by Category, Priority, Severity, or Responsible Party.
Or formulate a specific query. EOM if ($input{closed} eq "on") { print <Exclude closed reports.
EOM } else { print <Include closed reports.
EOM } # # The following are Juniper additions, some of our standard weekly # reports for problem tracking meetings. # if ($project eq "Juniper") { $base = "$self_ref?priority=summary&sort=severity"; $b_new = $base . "&state=active&arrived-after=1%20week%20ago"; $b_sw = $base . "&state=active&class=sw-bug"; $b_hw = $base . "&state=active&class=hw-bug"; $b_chg = $base . "&state=active&class=change-request"; print <new this week, software, hardware, change-requests.

EOM } } # # Severities are hardcoded in gnats (ick) # &create_field(\@f_severities, "?error?", "?", 0, ""); &create_field(\@f_severities, "critical", "c", 1, ""); &create_field(\@f_severities, "serious", "s", 2, ""); &create_field(\@f_severities, "non-critical", "n", 3, ""); # # As are priorities # &create_field(\@f_priorities, "?error?", "?", 0, ""); &create_field(\@f_priorities, "high", "h", 1, ""); &create_field(\@f_priorities, "medium", "m", 2, ""); &create_field(\@f_priorities, "low", "l", 3, ""); # # Use the same mechanism for handling our own web script's sorting hacks. # This is overkill, I'm just being lazy. # &create_field(\@f_sort, "category", "", 1, ""); &create_field(\@f_sort, "priority", "", 2, ""); &create_field(\@f_sort, "responsible", "", 3, ""); &create_field(\@f_sort, "severity", "", 4, ""); &create_field(\@f_sort, "last-modified", "", 5, ""); # # Get all dynamic information from GNATS # &get_states; &get_classes; &get_categories; &get_submitters; &get_responsibles; if ($html_mode) { CGI::ReadParse(*input); $query = $input{CGI}; $query->use_named_parameters(1); $self_ref = $query->script_name; ($query_pr_ref = $self_ref) =~ s/-summary//; if ($query->query_string eq 'keywords=query') { &html_header("Query $project problem reports"); &query_form; &html_footer; exit(0); } &html_header("$project problem reports"); &html_refs; } else { %optctl = ( "closed" => \$input{closed}, "quiet" => \$input{quiet}, "public" => \$input{public}, "wide" => \$wide, "releases" => \$releases, "sort" => \$input{sort}, "category" => \$input{category}, "class" => \$input{class}, "priority" => \$input{priority}, "submitter" => \$input{'submitter'}, "responsible" => \$input{responsible}, "severity" => \$input{severity}, "state" => \$input{state}, "release" => \$input{release}, "arrived-before" => \$input{'arrived-before'}, "arrived-after" => \$input{'arrived-after'}, "closed-before" => \$input{'closed-before'}, "closed-after" => \$input{'closed-after'}, "modified-before" => \$input{'modified-before'}, "modified-after" => \$input{'modified-after'}, "synopsis" => \$input{'synopsis'}, ); GetOptions(\%optctl, "closed", "quiet", "public", "wide", "releases", "sort=s", "class=s", "category=s", "priority=s", "submitter=s", "responsible=s", "severity=s", "state=s", "release=s", "arrived-before=s", "arrived-after=s", "closed-before=s", "closed-after=s", "modified-before=s", "modified-after=s", "synopsis=s") || die "usage:\n" . "--closed Include closed reports\n", "--quiet Skip headers\n", "--public Omit confidential reports\n", "--wide Unlimited line length\n", "--releases Print release information\n\n", "--arrived-after= PR arrived after \n", "--arrived-before= PR arrived before \n", "--closed-after= PR closed after \n", "--closed-before= PR closed before \n", "--modified-after= PR modified after \n", "--modified-before= PR modified before \n", "--category=<> summary:\n", "--class=<> summary:", join(':', &field_names(@f_classes)), "\n", "--priority=<> summary:", join(':', &field_names(@f_priorities)), "\n", "--release= Release field contains \n", "--responsible=<> summary:\n", "--severity=<> summary:", join(':', &field_names(@f_severities)), "\n", "--sort=<> ", join(':', &field_names(@f_sort)), "\n", "--submitter=<> ", join(':', &field_names(@f_submitters)), "\n", "--state=<> summary:active:", join(':', &field_names(@f_states)), "\n"; } #------------------------------------------------------------------------ # Build up the query request $query_args = ''; $query_args .= '--skip-closed ' unless $input{closed}; $query_args .= '--restricted ' if $input{public}; foreach (@input_fields) { next if ($_ eq "closed" || $_ eq "public"); if ($input{$_} && $input{$_} ne "summary") { if ($html_mode) { $query_args .= " --${_}=\'" . join("|", $query->param($_)) . "\'"; } else { $query_args .= " --${_}=\'" . $input{$_} . "\'"; } } } # Handle active pseudo-state (can't just change $input{state} because # $input is now a tied variable (sigh).. kludge it). $query_args =~ s/--state='active'/--state='$active_states'/; &query_gnats($query_args); # # Sort reports as necessary # if ($input{sort} eq 'category') { @prs = sort { $a->{category} eq $b->{category} ? $a->{number} <=> $b->{number} : $a->{category} cmp $b->{category} } @prs; } elsif ($input{sort} eq 'responsible') { @prs = sort { $a->{responsible} eq $b->{responsible} ? $a->{number} <=> $b->{number} : $a->{responsible} cmp $b->{responsible} } @prs; } elsif ($input{sort} eq 'last-modified') { @prs = sort { $a->{'last-modified'} eq $b->{'last-modified'} ? $a->{number} <=> $b->{number} : $a->{'last-modified'} cmp $b->{'last-modified'} } @prs; } elsif ($input{sort} eq 'priority') { @prs = sort { ($a->{priority})->{sql} eq ($b->{priority})->{sql} ? $a->{number} <=> $b->{number} : ($a->{priority})->{sql} cmp ($b->{priority})->{sql} } @prs; } elsif ($input{sort} eq 'severity') { @prs = sort { ($a->{severity})->{sql} eq ($b->{severity})->{sql} ? $a->{number} <=> $b->{number} : ($a->{severity})->{sql} cmp ($b->{severity})->{sql} } @prs; } else { $input{sort} = 'none'; } # # Generate the appropriate report(s) # if ($#prs < $[) { print "No matches to your query\n"; } elsif ($input{'responsible'} eq 'summary') { &norm_summary('responsible', @f_responsibles); &gnats_summary("Unassigned problems", '$entry->{responsible} eq ""'); } elsif ($input{'state'} eq 'summary') { &enum_summary('state', @f_states); } elsif ($input{'category'} eq 'summary') { &norm_summary('category', @f_categories); } elsif ($input{'priority'} eq 'summary') { &enum_summary('priority', @f_priorities); } elsif ($input{'severity'} eq '' || $input{'severity'} eq 'summary') { &enum_summary('severity', @f_severities); } else { &gnats_summary("Requested problem reports", 1); } &html_footer if $html_mode; exit(0); #------------------------------------------------------------------------ sub norm_query { my $category = shift; my $field = shift; &gnats_summary("$field $category problems", '$entry->{\'' . $category . '\'} eq "' . $field . '"'); } sub norm_summary { my $category = shift; my %field_type; foreach $field_type (@_) { &norm_query($category, $field_type->{name}); } } sub enum_query { my $category = shift; my $field = shift; &gnats_summary("$field $category problems", '($entry->{\'' . $category . '\'})->{\'name\'} eq "' . $field . '"'); } sub enum_summary { my $category = shift; my %field_type; foreach $field_type (@_) { &enum_query($category, $field_type->{name}); } } sub get_categories { open(Q, "$query_pr --list-categories |") || die "Cannot get categories\n"; my $sql = 0; &create_field(\@f_categories, "?error?", "?", $sql++, ""); while() { chomp; my ($cat, $desc, $responsible, $notify) = split(/:/); &create_field(\@f_categories, $cat, $cat, $sql++, $desc); } close(Q); } # # Get states from gnats # # Add a pseudo-state for reports called 'active' which means anything # not suspended or closed. # sub get_states { open(Q, "$query_pr --list-states |") || die "Cannot get states\n"; my $sql = 0; my @active; &create_field(\@f_states, "?error?", "?", $sql++, ""); while() { chomp; my ($state, $desc) = split(/:/); &create_field(\@f_states, $state, substr($state, 0, 1), $sql++, $desc); push(@active, $state) unless ($state eq "suspended" || $state eq "closed"); } close (Q); $active_states = join('|', @active); } # # Get classes from gnats # sub get_classes { open(Q, "$query_pr --list-classes |") || die "Cannot get classes\n"; my $sql = 0; &create_field(\@f_classes, "?error?", "?", $sql++, ""); while() { chomp; my ($class, $desc) = split(/:/); my ($short) = substr($class, 0, 1); # # Support conflicts with sw-bug # Duplicate conflicts with doc-bug # $short = "S" if $class eq "support"; $short = "D" if $class eq "duplicate"; &create_field(\@f_classes, $class, $short, $sql++, $desc); } close (Q); } # # Get responsible parties from gnats # sub get_responsibles { open(Q, "$query_pr --list-responsible |") || die "Cannot get resposible parties\n"; my $sql = 0; &create_field(\@f_responsibles, "?error?", "?", $sql++, ""); while() { chomp; my ($resp, $desc) = split(/:/); &create_field(\@f_responsibles, $resp, $desc, $sql++, $desc); } close (Q); } # # Get submitter-id's from gnats # sub get_submitters { open(Q, "$query_pr --list-submitters |") || die "Cannot get submitter-id's\n"; my $sql = 0; &create_field(\@f_submitters, "?error?", "?", $sql++); while() { chomp; my ($id, $desc, $other) = split(/:/); &create_field(\@f_submitters, $id, $desc, $sql++); } close (Q); } # # Load up the PR array with all problems matching a given query # sub query_gnats { my $report = shift; print "Report: $report\n"; open(Q, "$query_pr --sql $report|") || die "Cannot query the reports.\n"; while() { chomp; my ($s_number, $s_category, $s_synopsis, $s_confidential, $s_severity, $s_priority, $s_responsible, $s_state, $s_class, $s_submitter, $s_arrival_date, $s_originator, $s_release, $s_last_modified, $s_closed_date, $s_quarter, $s_keywords, $s_anythingelse) = split(/\s*\|/); my %rec = ( 'submitter' => $s_submitter, 'number' => $s_number, 'category' => $s_category, 'synopsis' => $s_synopsis, 'confidential' => $s_confidential, 'severity' => &field_from_sql(\@f_severities, $s_severity), 'priority' => &field_from_sql(\@f_priorities, $s_priority), 'responsible' => $s_responsible, 'state' => &field_from_sql(\@f_states, $s_state), 'class' => &field_from_sql(\@f_classes, $s_class), 'submitter' => $s_submitter, 'arrival' => $s_arrival_date, 'originator' => $s_originator, 'release' => $s_release, 'last-modified' => $s_last_modified, 'closed-date' => $s_closed_date, 'quarter' => $s_quarter, 'keywords' => $s_keywords, ); push(@prs, \%rec); } close(Q); } # # Clean up release field # # At Juniper, for software defects, the relevant releases are # listed as "JUNOS-x.x", we cut this down for display purposes # to just have the relevant version numbers displayed. # sub clean_release { my $release = shift; if ($project eq "Juniper") { $release =~ s/junos-(\d+\.\d+)\S*/\1/gi; $release =~ s/,/ /g; $release =~ s/\s+/ /g; } return $release; } # # Clean up the responsible field # # We have mailing lists for responsible parties, if the bug is # assigned to a list, we consider it pending individual # assignment and just clear the field for display. # sub clean_responsible { my $responsible = shift; $responsible =~ s/@.*//; $responsible =~ tr/A-Z/a-z/; $responsible = "" if ($responsible =~ /^$mail_unass/); $responsible = "" if ($responsible =~ /^$mail_prefix/); $responsible =~ s/^$mail_prefix//; # cut it down to a username's length to keep it narrow $responsible = substr($responsible, 0, 8); return $responsible; } # # Clean up the submitter field # # We use the submitter field for each special submitter, # and have an default submitter field. If a report was # submitted with this default submitter ID, display the # last name of the originator instead. # sub clean_submitter { my $submitter = shift; my $originator = shift; if ($submitter eq $default_submitter) { $originator =~ s/,.*//; $originator =~ s/.*\s+(\S+)/\1/; $originator =~ s/A-Z/a-z/; $submitter = substr(${originator}, 0, 9); } else { $submitter = "${submitter}" if ($html_mode && !$preformat); } return $submitter; } # # Shorten the date entries down to something readable/manageable. # We're deliberately causing a Y2K issue here by shortening the # century down to 2 bytes to leave more room for the synopsis. # Will we never learn? # sub clean_date { my $date = shift; $date =~ s/^\d\d//; # chop off the century $date =~ s/\s+.*//; # chop off the time return $date; } # # Generate a summary of all problem reports matching the current query. # sub gnats_summary { my $header = ucfirst(shift); my $report = shift; my $counter = 0; foreach $entry (@prs) { next if (($report ne '') && (eval($report) == 0)); if ($counter++ == 0) { if ($html_mode) { if ($preformat) { print <${header}

VPSC Release(s)   Arrived  Submitter Tracker            Respons. Description

EOM } else { print < EOM } } else { print "${header}:\n\n" . "VPSC Arrived ID Respons. Description\n". "---- -------- ------------------ -------- -----------" . "--------------------------\n"; } } my $synopsis = $entry->{synopsis}; my $tracker = $entry->{category} . '/' . $entry->{number}; my $title = $tracker; my $severity = ($entry->{severity})->{short}; my $priority = ($entry->{priority})->{short}; my $state = ($entry->{state})->{short}; my $class = ($entry->{class})->{short}; my $responsible = &clean_responsible($entry->{responsible}); $tracker = substr($tracker, length($tracker) - 18, 18) if length($tracker) > 18 && (!$html_mode || $preformat); if ($html_mode) { $synopsis = &html_fixline($synopsis); $title = "{number} . "\">${tracker}"; } if ($html_mode) { if ($preformat) { printf "%s%s%s%s %-12.12s %s %-9.9s %s %-8.8s %s\n", $severity, $priority, $state, $class, &clean_release($entry->{release}), &clean_date($entry->{arrival}), &clean_submitter($entry->{submitter}, $entry->{originator}), $title . ' ' x (18 - length($tracker)), $responsible, $synopsis; } else { printf "" . "" . "" . "" . "" . "" . "" . "\n" , $severity, $priority, $state, $class, &clean_release($entry->{release}), &clean_date($entry->{arrival}), &clean_submitter($entry->{submitter}, $entry->{originator}), $title, $responsible, $synopsis; } } else { # # We don't have as much flexibility with the ascii format, # so ditch the release and submitter fields. # printf "%s%s%s%s %s %s %-8.8s %s\n", $severity, $priority, $state, $class, &clean_date($entry->{arrival}), $title . ' ' x (18 - length($tracker)), $responsible, ($wide ? $synopsis : substr($synopsis, 0, 37)); } } if ($counter) { if ($html_mode) { if ($preformat) { print "

\n"; } else { print "

$header
VPSC Release(s) Arrived Submitter Tracker Respons. Description
%s%s%s%s
%s%s%s%s%s%s

\n"; } } print "\n${counter} problems total.\n\n"; } return $counter; } # --------------------------------------------------------------------------- # Enumerated field management routines # # These are a bunch of "complex as all hell" routines for building # some perl5 hashes. They should be cleaned up. sub create_field { local *table = shift; my $name = shift; my $short = shift; my $sql = shift; my $desc = shift; my %rec = ( name => $name, sql => $sql, short => $short, desc => $desc); push(@table, \%rec); }; sub field_from_sql { local *table = shift; my $sqlval = shift; my $entry; foreach $entry (@table) { return $entry if $entry->{sql} eq $sqlval; } return undef; } sub field_from_name { local *table = shift; my $name = shift; my $entry; foreach $entry (@table) { return $entry if $entry->{name} eq $name; } return undef; } sub field_names { my $field_type; my @result; foreach $field_type (@_) { $_ = $field_type->{name}; next if $_ eq '?error?'; push(@result, $_); } return @result; } sub field_list { my $prefix = shift; my $display = shift; my $name = shift; my @values = &field_names(@_); print $prefix; print "$display:"; print $query->scrolling_list(-name => $name, -values => [ @values ], -size => 5, -multiple => 'true'); print ""; } sub field_boxes { my $prefix = shift; my $display = shift; my $name = shift; my @values = &field_names(@_); print $prefix; print "$display:"; print $query->checkbox_group(-name => $name, -values => [ @values ]); print ""; } sub field_radio { my $prefix = shift; my $display = shift; my $name = shift; my @values = &field_names(@_); print $prefix; print "$display:"; print $query->radio_group(-name => $name, -values => [ @values ]); print ""; } sub field_text { my $prefix = shift; my $display = shift; my $name = shift; print $prefix; print "$display:"; print $query->textfield(-name => $name); print ""; } # --------------------------------------------------------------------------- # Display the "query" form for customer problem report queries. # sub query_form { print qq` Please select the items you wish to search for. Multiple items are AND'ed together.

`; print $query->startform(-method => 'get'), "\n"; &field_boxes("", "States", "state", @f_states); &field_boxes("", "Severity", "severity", @f_severities); &field_boxes("", "Priority", "priority", @f_priorities); &field_radio("", "Sort by", "sort", @f_sort); &field_list("", "Responsible", "responsible", @f_responsibles); &field_list("", "Submitter", "submitter", @f_submitters); &field_list("", "Category", "category", @f_categories); &field_list("", "Classes", "class", @f_classes); &field_text("", "Arrived Before", "arrived-before"); &field_text("", "Arrived After", "arrived-after"); &field_text("", "Closed Before", "closed-before"); &field_text("", "Closed After", "closed-after"); &field_text("", "Modified Before", "modified-before"); &field_text("", "Modified After", "modified-after"); &field_text("", "Release", "release"); &field_text("", "Originator", "originator"); &field_text("", "Target", "quarter"); &field_text("", "Text in multi-line fields", "multitext"); print qq`
Include closed reports: Exclude confidential reports:

`, $query->submit(-value => " Query PR's "), $query->reset, $query->endform(); } gnats-4.1.0/contrib/juniper-web-reports/query-pr.cgi0000744000175000017500000001676606702675504023251 0ustar chewiechewie00000000000000#!/usr/local/bin/perl # # GNATS problem tracking report generator # # This script can be used to generate reports from the GNATS database. # The same tool is used to generate both HTML and ascii reports. # # Copyright (c) 1994-1998, FreeBSD Inc. # All rights reserved. # Copyright (c) 1997-1999, Juniper Networks Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $Id: query-pr.cgi,v 1.2 1999/01/19 22:14:38 pst Exp $ # use CGI; $ENV{'PATH'} = "/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin"; $project = "Juniper"; # FreeBSD if ($project eq "Juniper") { $default_domain = '@juniper.net'; $submit = 'bugs\@juniper.net'; $query_pr = 'nquery-pr'; $cvsweb = 'http://www-in.juniper.net/cgi-bin/cvsweb.cgi/'; } else { $default_domain = '@freebsd.org'; $submit = 'freebsd-gnats-submit\@freebsd.org'; $query_pr = 'query-pr'; $restrict = '--restricted'; $cvsweb = 'http://www.freebsd.org/cgi/cvsweb.cgi/'; } sub html_header { my $title = shift; print $query->header; print $query->start_html('title' => $title, 'author' => 'pst@juniper.net', 'bgcolor'=> '#ffffff'); print <

$title



EOM } sub html_footer { } CGI::ReadParse(*input); $input{pr} = $ENV{'QUERY_STRING'} unless $input{pr}; $query = $input{CGI}; $query->use_named_parameters(1); unless ($input{pr}) { &html_header("PR Query Interface"); print "

Please enter the PR number you wish to query:

\n"; ($scriptname = $ENV{'SCRIPT_NAME'}) =~ s|^/?|/|; $scriptname =~ s|/$||; ($summary = $scriptname) =~ s/query-pr/query-pr-summary/; print "
\n"; print "
\n"; print "

See also the PR summary

\n"; &html_footer; exit 0; } # be tolerant to / queries $input{pr} =~ s%^[a-z]+/([0-9]+)$%$1%; if ($input{pr} < 1 || $input{pr} > 99999) { &html_header("$project Problem Report"); print "

Invalid problem report number: $input{pr}

\n"; &html_footer; exit 0; } unless (open(Q, "$query_pr $restrict -F $input{pr} 2>&1 |")) { &html_header("$project Problem Report"); print "

Unable to open PR database.

\n"; &html_footer; die "Unable to query PR's"; } $multiline = 0; $from = ""; $replyto = ""; $state = "header"; while() { chomp; $html_fixup = 1; # # If we have an error return from query-pr, print it and abort # if (/^${query_pr}: /) { &html_header("$project Problem Report"); print "
$_\n";
	print ;
	print "
\n"; &html_footer; exit 0; } # # Process useful crap out of the e-mail header on the front # if ($state eq "header") { if (/^From:\s*(.*)$/i) { $from = $1; $from =~ s/.*<(.*)>.*/$1/; $from =~ s/\s*\(.*\)\s*//; } if (/^Reply-to:\s*(.*)$/i) { $replyto = $1; $replyto =~ s/.*<(.*)>.*/$1/; $replyto =~ s/\s*\(.*\)\s*//; } # End of e-mail header if (/^$/) { $from = $replyto if ($replyto); $email = $from; if ($default_domain) { $email .= $default_domain unless ($email =~ /@/); } $state = "title"; } } # # Process the one line fields # if ($state eq "title") { if (/^>Number:/) { $number = &getline($_); } elsif (/^>Category:/) { $category = &getline($_); } elsif (/^>Synopsis:/) { $synopsis = &getline($_); $synopsis =~ s/[\t]+/ /g; $synopsis = &fixline($syn); &html_header("$category/$number"); print "
$synopsis\n"; $state = "table"; } } if ($state eq "table") { # # Special case for responsible, fake up the line and add the # e-mail info we sucked in from the header # if (/^>Responsible:/) { $_ = &getline($_); s/\(.*\)//; # remove personal name s/\s+//g; $_ = $_ . $default_domain if !/@/; $_ = '>Responsible:' . $_ . ''; $html_fixup = 0; } # # Ditto with originator line # if (/^>Originator:/ && $from) { $_ .= " " . &fixline($from) . ''; $html_fixup = 0; } # # Organization is the first of the multi-line entry areas, # we're done with the table. # if (/^>Organization:/) { print "
\n
\n"; $state = "multiline"; } else { if (!/^>(\S+):\s*(.*)\s*/) { print "ERROR" . &fixline($_) . "\n"; } else { $line = $html_fixup ? &fixline($2) : $2; print "$1$line\n"; } } } if ($state eq "multiline") { if (/^>(\S+):\s*(.*)/) { print $trailer . "\n" unless ($blank); $trailer = "
$1
\n"; if ($html_fixup) { $trailer .= &fixline($2); } else { $trailer .= $2; } $blank = !($2); $multiline = 0; } else { unless ($multiline) { next if /^\s*$/; print $trailer . "\n
\n";
	    }
	    $multiline = 1;
	    $blank = 0;
	    print $html_fixup ? &fixline($_) : $_ , "\n";
	    $trailer = "
"; } } } close(Q); print "$trailer\n" unless ($blank); print "
"; $syn =~ s/[\?&%"]/"%" . sprintf("%02X", unpack(C, $&))/eg; $email =~ s/[\?&%]/"%" . sprintf("%02X", unpack(C, $&))/eg; print "Submit Followup\n"; &html_footer; exit 0; sub getline { local($_) = @_; ($tag,$remainder) = split(/[ \t]+/, $_, 2); return $remainder; } sub cvsweb { local($file) = shift; $file =~ s/[,.;]$//; return $cvsweb . $file; } sub srcref { local($_) = shift; local($rev) = '(rev\.?|revision):?\s+[0-9]\.[0-9.]+(\s+of)?'; local($src) = '((src|www|doc|ports)/[^\s]+)'; if (m%$rev\s*$src%oi || m%$src\s*$ref%) { s#$src#sprintf("%s", 34, &cvsweb($1), 34, $1)#ge; } return $_; } sub fixline { local($line) = shift; $line =~ s/&/&/g; $line =~ s//>/g; $line =~ s%((http|ftp)://[^\s"\)\>,;]+)%$1%gi; $line =~ s%(\WPR[:s# \t]+)([a-z0-9-]+\/)?([0-9]+)%$1$2$3%ig; if ($cvsweb) { return &srcref($line); } else { return $line; } } gnats-4.1.0/contrib/juniper-web-reports/submit-pr.cgi0000744000175000017500000004172406702675432023377 0ustar chewiechewie00000000000000#!/usr/local/bin/perl # $Id: submit-pr.cgi,v 1.2 1999/04/07 15:34:50 pst Exp $ use CGI qw( :standard ); use CGI qw( shortcuts ); use CGI::Carp qw(fatalsToBrowser); $NAME = 'jnx-wwwgnats'; $VERSION = 'v1.0'; $error_mail = 'dwinters'; ################################################################ # # This script can be called in 3 main ways: # # 1) with no params (from the web) # a) run make to create new form if needed # b) cat the form to the browser # # 2) with parameters (from the web) # a) get possible lists from query-pr # b) check for errors # c) if errors, print error message & form # else, pront finished form & submit pr # # NOT IMPLEMENTED - form is built with each script invocation # 3) with parameter mode=makeform (from UNIX command line) # a) get possible lists from query-pr # b) create a blank form, print to STDOUT # ################################################################ ################################################################ # # Main Loop # # branch to function based on path in calling URL # ################################################################ my $q = new CGI; if ($q->param) { # script re-entry submit_pr ($q); } else { # run for the first time $q->param('mode', 'make_form'); submit_pr ($q); } exit 0; ################################################################ # # Define a hash of lists. # These lists are the possible values for fields in the form. # # If values are passed from a form for processing, this list is used # to verify that the passed value is valid. # # These lists are also used to create scrolling lists on the form # # $possible{'class' }[ lists of all class values ] # $possible{'categories'}[ lists of all category values ] # $possible{'submitter'}[ lists of all submitters values ] # ################################################################ sub get_possible_values { my $q = shift @_; $rh_possible = shift @_; # Hard coded values # $$rh_possible{'confidential'} = [ 'yes', 'no' ]; $$rh_possible{'severity'} = [ 'non-critical', 'serious', 'critical' ]; $$rh_possible{'priority'} = [ 'low', 'medium', 'high' ]; # Obtained dynamic values from query-pr # if ($q->server_name() eq 'www-in.juniper.net') { @categories = map { (split ':', $_)[0] } `/usr/local/bin/query-pr --list-categories`; @classes = map { (split ':', $_)[0] } `/usr/local/bin/query-pr --list-classes`; @submitters = map { (split ':', $_)[0] } `/usr/local/bin/query-pr --list-submitters`; } else { @categories = map { (split ':', $_)[0] } `/usr/local/bin/nquery-pr --list-categories`; @classes = map { (split ':', $_)[0] } `/usr/local/bin/nquery-pr --list-classes`; @submitters = map { (split ':', $_)[0] } `/usr/local/bin/nquery-pr --list-submitters`; } # # assign filtered values to "possible" hash # if ($q->server_name() eq 'www-in.juniper.net') { $category_filter = '(pending)'; $class_filter = '(mistaken|duplicate|unreproducible)'; } else { $category_filter = '((hw|esw|rom)-.*|gnats|pending)'; $class_filter = '(mistaken|duplicate|unreproducible)'; } @f_categories = grep !/^$category_filter$/, @categories; $$rh_possible{'category'} = \@f_categories; @f_classes = grep !/^$class_filter$/, @classes; $$rh_possible{'class'} = \@f_classes; push @submitters, 'unknown'; $$rh_possible{'submitter'} = \@submitters; } ################################################################ # # Define the default values for some of the fields # ################################################################ sub get_default_values { my $q = shift @_; my $rh_default = shift @_; $$rh_default{'confidential'} = 'yes'; $$rh_default{'class'} = 'sw-bug'; $$rh_default{'submitter'} = 'juniper'; } ################################################################ # # submit_pr actions # # 1) get hash of possible values using gnats query-pr command # 2) if passed values, check values # A) if error, define error message # 3) print form # ################################################################ # Variables # (cli NOT IMPLEMENTED # $if 'cli' script called from cli (else assume http server) # # $mode 'make_form' used to make the form only # 'error' error detected in processing form # 'ok' all checks passed, pr will be e-mailed # sub submit_pr { my $q = shift @_; my $if = ($q->param('if')) ? $q->param('if') : 'http'; my $mode = ($q->param('mode')) ? $q->param('mode') : 'ok'; # 1) # get_possible_values ($q, \%possible); get_default_values ($q, \%default); my @fields = ('email', 'originator', 'organization', 'synopsis', 'submitter', 'confidential', 'category', 'severity', 'priority', 'class', 'release', ); my @wide_fields = ('environment', 'description', 'howtorepeat', 'fix' ); my %field_label; foreach (@fields, @wide_fields) { $field_label{$_} = ucfirst $_; } $field_label{'email'} = 'Your Electronic Mail Address'; $field_label{'originator'} = 'Your name'; $field_label{'organization'} = 'Your Organization or Company'; $field_label{'submitter'} = 'Submitter ID'; $field_label{'synopsis'} = 'One line summary of the problem'; $field_label{'release'} = 'Which software release are you using'; $field_label{'environment'} = 'Environment (output of "show version" on the problem machine)'; $field_label{'description'} = 'Full Description'; $field_label{'howtorepeat'} = 'How to repeat the problem'; $field_label{'fix'} = 'Fix/workaround to the problem (if known)'; # 2) check form values or assign defaults # my ($error, $message, %error_message); if ($mode eq 'ok') { # A form has been submitted, check it # Read in values from the form into 'Q' name space # $q->import_names('Q'); # Data checking # 1) Check that email has some characters # ($temp = $Q::email) =~ s/\s//g; if ($temp eq '') { $error = 'email_req'; $mode = 'error'; } # 2) Check that synopsys has some characters # unless ($error) { ($temp = $Q::synopsis) =~ s/\s//g; if ($temp eq '') { $error = 'synopsis_req'; $mode = 'error'; } } # 3) Check that each parameter is in the list of possible values # ${Q::submitter} =~ s/\s*//g; # remove spaces ${Q::submitter} = lc ${Q::submitter}; # normalized (lower case) submitter IS my ($pat, $temp); unless ($error) { foreach $list ('submitter', 'confidential', 'category', 'severity', 'priority', 'class', ) { $pat = ${'Q::' . $list}; if ($pat =~ /^\s*$/) { $error = $list . '_unselected'; $mode = 'error'; last; } unless (grep { m/^$pat$/ } @{$possible{$list}}) { $error = $list; $mode = 'error'; last; } } } # 4) If the bug is 'sw-bug', release field must contain something # unless ($error) { if ($Q::class eq 'sw-bug') { ($temp = $Q::release) =~ s/\s//g; if ($temp eq '') { $error = 'release_req'; $mode = 'error'; } } } # 5) If the bug is 'sw-bug', howtorepeat field must contain something # unless ($error) { if ($Q::class eq 'sw-bug') { ($temp = $Q::howtorepeat) =~ s/\s//g; if ($temp eq '') { $error = 'howtorepeat_req'; $mode = 'error'; } } } # # End of Form data checking # # remove
 and 
tags for wide_fields foreach (@wide_fields) { ${'Q::' . $_} =~ s/^
//;
	    ${'Q::' . $_} =~ s/<\/pre>$//;
	}


    } else {                             # Set defaults for a new form
	foreach (keys %default) {
	    ${'Q::' . $_} = $default{$_};
	}
    }

    # 3) if form data okay, email the pr

    my ($resp, $pr);

    if ($mode eq 'ok') {

        push @header, "To: bugs\n";
        push @header, "Subject: $Q::synopsis\n";
        push @header, "From: $Q::email\n";
        push @header, "Reply-To:\n";
        push @header, "Bcc: dwinters\n";
        push @header, "X-send-pr: $NAME $VERSION\n";

        my @records = ('submitter', 
	   	       'originator',
		       'organization',
		       'confidential',		      
		       'synopsis',
		       'severity',
		       'priority',
		       'category',
		       'class',
		       'release',
		       'environment',
		       'description',
		       'howtorepeat',
		       'fix'
		      );

	foreach (@records) {
	    $record_key{$_} = ucfirst $_;
	}
	$record_key{'submitter'} = 'Submitter-Id';
	$record_key{'howtorepeat'} = 'How-To-Repeat';

	my @body;
	foreach (@records) {
	    push @body, ">$record_key{$_}:\t\t${'Q::' .$_}\n";
	}

        my $tmpfile = "/tmp/file-pr.log.$$";

        open MAIL, "|/usr/local/libexec/gnats/file-pr --debug 1>&2 2>$tmpfile";
 	print MAIL @header;
        print MAIL "\n\n";
	print MAIL @body;
        close MAIL;

        open FILE_PR_LOG, "$tmpfile";

	$submit = 'failed';
        while (chomp($line1 = )) {
	    if ($line1 =~ /^file-pr: responsible person is:\s*(\S+)\s*$/) {
		$resp = $1;
		undef $submit;
		last;
	    }
	}

        chomp($line2 = );
	if ($line2 =~ /^file-pr: PR written out:\s*(\S+)\s*$/) {
            my @path_rev = reverse(split '/', (split ':', $line2)[2]);
            $pr = "$path_rev[1]/$path_rev[0]";
        } else {
	    $submit = 'failed';
        }

	if ($submit eq 'failed') {
 	    @file_pr_error = ;
	    $file_pr_error = join "
", $line1, $line2, @file_pr_error; @header[0] =~ s/bugs/gnats-admin/; @header[1] =~ s/(Subject: )/$1(ERROR) submit-pr.cgi failed: /; open MAIL, "| /usr/sbin/sendmail -oi -t"; print MAIL @header; print MAIL "\n\n"; print MAIL @body; print MAIL "\n\n*** Error from file-pr ***\n"; print MAIL join "\n", $line1, $line2, @file_pr_error; close MAIL; } else { # `rm $tmpfile`; } close FILE_PR_LOG; } # Define the message unless ($mode eq 'make_form') { if ($mode eq 'ok') { if ($submit eq 'failed') { $message = "ERROR: An error was detected during the PR submission process.
"; $message .= "ERROR: Your PR has NOT been submitted.

"; $message .= "$file_pr_error"; } else { $message = "Your problem report (PR) has been submitted as: $pr
"; $message .= "The responsible person for this PR is: $resp
"; $message .= "An e-mail acknowledgement will be sent to: $Q::email"; } } else { # Non-standard error messages $error_message{'email_req'} = 'Electronic Mail Address is a required field.'; $error_message{'synopsis_req'} = 'Problem Synopsis is a required field.'; $error_message{'release_req'} = "For $Q::class problems, you must enter the software release data."; $error_message{'howtorepeat_req'} = "For $Q::class problems, you must enter a description of how to repeat the problem."; $error_message{'submitter'} = q/Invalid name for Submitter ID
use "unknown" if you don't know your Submitter ID./; # Standard error messages my $err; ($err = $error) =~ s/_.*//g; $message = ($error =~ /_unselected/) ? "You must select a value for $field_label{$err}" : "Invalid value for $field_label{$err}"; $message = (exists $error_message{$error}) ? $error_message{$error} : $message; $message = 'Error: ' . $message; } } # 4) print out the HTML form # unless ($if eq 'cli') { print $q->header; } # generate the HTML form # my ($bgcolor, $color, $errcolor); $bgcolor = '#ffffff'; $errcolor = 'mistyrose'; print $q->start_html(-title=>'Submit a Juniper problem report', -author=>'webmaster@juniper.net', -BGCOLOR=>$bgcolor, -text=>'#000033', -link=>'#2244cc', -vlink=>'#112288', ); print img { -src=>'/images/juniper-logo-official-mag0-trans.gif', -alt=>'Juniper Networks', -align=>'left', -hspace=>'5', -vspace=>'5' }; print h1 ( {-align=>'right'}, 'Submit a problem report' ); print br { -clear=>'all' }; print hr; print 'Thank you for taking the time to let us know about a problem with a Juniper product. Please fill out the form as completely as possible. Make sure you fill in the "Environment" field as requested with the output from the machine on which problem occurred.'; if ($message) { $color = ($error) ? $errcolor : $bgcolor; print $q->h1($message); print $q->hr; $error =~ s/_.*//g; } # print Form # print $q->start_form(-method=>'POST', -action=>'submit-pr.cgi' ); my %elem_type = ('email' => 'textfield 40', 'originator' => 'textfield 40', 'organization' => 'textfield 40', 'submitter' => 'textfield 40', 'synopsis' => 'textfield 72', 'confidential' => 'scrollist 2', 'category' => 'scrollist 3', 'severity' => 'scrollist 3', 'priority' => 'scrollist 3', 'class' => 'scrollist 3', 'release' => 'textfield 40', 'environment' => 'textarea 6 72', 'description' => 'textarea 6 72', 'howtorepeat' => 'textarea 6 72', 'fix' => 'textarea 6 72', ); print "\n"; my @type; foreach (@fields) { $color = ($error eq $_) ? $errcolor : $bgcolor; print "\n"; } print "
"; print b ("$field_label{$_}"); print ""; if ($mode eq 'ok') { if (${'Q::'.$_}) { print "${'Q::'.$_}"; } else { print ' '; } } else { @type = split " ", $elem_type{$_}; if ($type[0] eq 'textfield') { print $q->textfield(-name=>$_, -default=>${'Q::'.$_}, -size=>$type[1], -maxlength=>$type[1] ); } if ($type[0] eq 'scrollist') { print $q->scrolling_list(-name=>$_, -values=>$possible{$_}, -default=>${'Q::'.$_}, -size=>$type[1], ); } if ($type[0] eq 'textarea') { # -default=>"
${'Q::'.$_}
", print $q->textarea(-name=>$_, -default=>"${'Q::'.$_}", -rows=>$type[1], -columns=>$type[2], -wrap=>'physical' ); } } print "
"; foreach (@wide_fields) { $color = ($error eq $_) ? $errcolor : $bgcolor; print ""; print "\n"; } print "
"; print b ("$field_label{$_}"); print "
"; if ($mode eq 'ok') { if (${'Q::'.$_}) { print "${'Q::'.$_}"; } else { print ' '; } } else { @type = split " ", $elem_type{$_}; if ($type[0] eq 'textfield') { print $q->textfield(-name=>$_, -default=>${'Q::'.$_}, -size=>$type[1], -maxlength=>$type[1] ); } if ($type[0] eq 'scrollist') { print $q->scrolling_list(-name=>$_, -values=>$possible{$_}, -default=>${'Q::'.$_}, -size=>$type[1], ); } if ($type[0] eq 'textarea') { # -default=>"
${'Q::'.$_}
", print $q->textarea(-name=>$_, -default=>${'Q::'.$_}, -rows=>$type[1], -columns=>$type[2], -wrap=>'physical' ); } } print "
"; unless ($mode eq 'ok') { print $q->submit(-name=>'Submit'); print $q->reset; } print address ('Juniper Networks / ', $q->a({href=>'mailto:webmaster@juniper.net'}, 'webmaster@juniper.net' ), ); print $q->end_form(); print $q->end_html(); } gnats-4.1.0/contrib/scripts/0000755000175000017500000000000010212665130016505 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/scripts/cross-check0000744000175000017500000000512706620401144020643 0ustar chewiechewie00000000000000#!/bin/ksh # # cross-check # # This program performs cross checks between the category, responsible, # and submitters files. It will not make changes to these files. # # # First, insure that the categories file holds valid directories # errors=0 echo Checking for valid directories for each category. echo GNATS_ROOT=~gnats cd $GNATS_ROOT/gnats-adm for files in `egrep -v '#' categories|cut -d":" -f1 | egrep -v "^\$"` do if [ ! -d $GNATS_ROOT/$files ] then echo $files is not a valid category. There is no corresponding echo directory in $GNATS_ROOT. let errors=1 echo fi done # # Second, insure that the responsible party in all of the files matches. # tmp1=`mktemp` tmp2=`mktemp` tmp3=`mktemp` tmp4=`mktemp` egrep -v '#' categories|cut -d":" -f3 | egrep -v "^\$" | sort -u >$tmp1 egrep -v '#' responsible|cut -d":" -f3 | egrep -v "^\$" | sort -u >$tmp2 egrep -v '#' submitters|cut -d":" -f5 | egrep -v "^\$" | sort -u >$tmp3 # Insure that there are no submitters in the categories file that aren't # in the responsible file. echo Cross checking responsible parties between the categories file, echo and the responsible file. echo diff $tmp1 $tmp2 | egrep '^<' | cut -c3- | egrep -v 'gnats-admin' > $tmp4 results=`cat $tmp4 | wc -l` if (( results )) then echo The following responsible parties are in the categories file, echo but have no corresponding entry in the 'responsible' file. cat $tmp4 let errors=1 echo fi # Perform the same check against the submitters file. echo Cross checking responsible parties between the categories file, echo and the submitters file. echo diff $tmp3 $tmp1 | egrep '^<' | cut -c3- | egrep -v 'gnats-admin' > $tmp4 results=`cat $tmp4 | wc -l` if (( results )) then echo The following responsible parties are in the categories file, echo but have no corresponding entry in the 'responsible' file. cat $tmp4 let errors=1 echo fi # Now look at ALL of the responsible parties, and verify that they are # either valid users, or a mail alias. echo Finally, checking all responsible parties to insure that they are echo either a valid userid, or an e-mail alias. echo for id in `cat $tmp2` do homedir=~$id eval homedir=$homedir if [ ! -d $homedir ] then alias=`praliases $id | egrep -v 'No such key'` if [ "$alias" = "" ] then echo $id is in the responsible file, but it is not an ID or alias. let errors=1 fi fi done echo echo Checking complete. \\c if [ $errors -ne 0 ] then echo Errors were found. else echo No errors were found. fi rm $tmp1 $tmp2 $tmp3 $tmp4 gnats-4.1.0/contrib/scripts/README0000644000175000017500000000543006620401144017370 0ustar chewiechewie00000000000000Brian Abernathy check-categories - This script does several functions. They are: - Pending check. It will look in the 'pending' directory, displaying a message if it finds any files. - Category check. Each PR in every active category is examined, looking at the '>Category' line, verifying that the category matches the actual directory name. If there is a mismatch, the script attempts to move the PR to the proper category (directory). Note: If the category does not exist, the PR is moved to the GNATS_ROOT directory. - Unresolved check. The gnats-queue directory is examined, and if files are found that have a prefix of a period, then a message is displayed. cross-check - This script performs cross-checks between the category, responsible and submitters files. This is the sequence of events: - First, it examines the categories file, and compares any uncommented lines against directories in GNATS_ROOT. It is considered an error if a live category appears in the file with no corresponding directory in GNATS_ROOT. - Next, it insures that any submitters appearing in the categories file are also in the categories file. - After that, it performs the same check against the responsible file. - Finally, it gathers a list of all responsible parties, and insures that they are either a valid userid on the system, or they are a valid e-mail alias. (This check might not be possible on some systems.) display-config - The display-config script decodes the config file into a more readable format. Each line of the config file is displayed, followed by the decoded explaination. Several lines may be grouped together if it makes sense. For example, the following partial explaination is displayed for my configuration: 7:NOTIFY=1 Automatic reminders are enabled. (default) This means that if a call is not changed out of the 'open' state after a predefined period of time, a reminder is e-mailed to the maintainer(s) of the PR. 11:BDAY_START=8 12:BDAY_END=17 13:BWEEK_START=1 14:BWEEK_END=5 Business hours are: Monday through Friday 8 am to 5 pm Since Automatic reminders are enabled, the start/stop of the business week is needed, so all those lines are displayed, and decoded. reset-gnats - This script should be used with extreme caution! In fact, I put several queries into it, to make sure the user knew what they were asking for. Basically, this is what it does: - It asks twice if the user really wants to go through with it. - Locks the database - Write a zero into the $GNATS_ROOT/gnats-adm/current file. - Cycles through all of the categories, erasing all files in each directory. - Regenerates the index. - Unlocks the database. gnats-4.1.0/contrib/scripts/check-categories0000744000175000017500000000252206620401144021633 0ustar chewiechewie00000000000000#!/bin/sh # # check-categories A script to verify that all PRs are filed in the # proper directories. # # GNATS_ROOT=/usr/local/lib/gnats/gnats-db # Move to the directory where all the categories lie. cd $GNATS_ROOT # Now, go into each category directory in turn, and examine *each* Pr. for dirs in `query-pr --list-categories| cut -d":" -f1` do # Move to directory cd $dirs echo Checking $dirs for files in `ls` do if [ "$dirs" = "pending" -a "`ls`" != "" ] then echo Warning! There are pending PRs. This must be corrected. else catline=`egrep '>Category' $files|line|cut -d':' -f2-|cut -c8-` if [ "$catline" != "$dirs" ] then # Use pr-edit to check to see if this is a PR. If not, then what # is it doing here? echo \\n$files is not in the correct directory. Attempting to move echo to proper directory, $catline. if [ -d ../$catline ] then mv $files ../$catline else echo Error! Directory $catline does not exist. Please correct. echo $files not moved. fi fi fi done cd .. done # # Now, see if there are any unresolved files in the queue. # unresolved=`ls gnats-queue/.gnats\* 2>/dev/null` if [ "$unresolved" ] then echo There are unresolved problems in gnats-queue fi gnats-4.1.0/contrib/scripts/display-config0000744000175000017500000001004306620401144021340 0ustar chewiechewie00000000000000#!/bin/sh # # display-config # # This shell reads the GNATS configuration file, and displays the results # in a more humane format. # GNATS_ROOT=/usr/local/lib/gnats/gnats-db # # First, we grab the file. # . $GNATS_ROOT/gnats-adm/config # # Clear the screen # tput clear # # Now, display each value, accompanied by some descriptive text. # echo This is a display of the information inside the config file, decoded echo into a more \'user-friendly\' format. The actual lines from the echo config file are displayed prior to the explaination. The config echo lines are preceeded by the record number for each line, to make echo identification easier. echo echo grep -in '^GNATS_ADDR' $GNATS_ROOT/gnats-adm/config grep -in '^GNATS_ADMIN' $GNATS_ROOT/gnats-adm/config grep -in '^GNATS_SITE' $GNATS_ROOT/gnats-adm/config echo \'$GNATS_ADDR\' is the userid on \'$GNATS_SITE\' which receives bug reports. echo echo The Gnats administrator\'s e-mail id is: \'$GNATS_ADMIN\' echo grep -in '^SUBMITTER' $GNATS_ROOT/gnats-adm/config echo The name for this local GNATS submission site is \'$SUBMITTER\' echo grep -in '^DEFAULT_RELEASE' $GNATS_ROOT/gnats-adm/config echo If GNATS problems are submitted with no release number they will echo default to \'$DEFAULT_RELEASE\' echo grep -in '^DEFAULT_ORGANIZATION' $GNATS_ROOT/gnats-adm/config echo The default organization is \'$DEFAULT_ORGANIZATION\' echo grep -in '^DEFAULT_SUBMITTER' $GNATS_ROOT/gnats-adm/config echo The default submitter is\: \'$DEFAULT_SUBMITTER\' echo # # Process the booleans. # grep -in '^NOTIFY' $GNATS_ROOT/gnats-adm/config if [ $NOTIFY ] then echo Automatic reminders are enabled. \(default\) echo This means that if a call is not changed out of the \'open\' state echo after a predefined period of time, a reminder is e-mailed to the echo maintainer\(s\) of the PR. # Decode the business hours. grep -in '^BDAY_START' $GNATS_ROOT/gnats-adm/config grep -in '^BDAY_END' $GNATS_ROOT/gnats-adm/config grep -in '^BWEEK_START' $GNATS_ROOT/gnats-adm/config grep -in '^BWEEK_END' $GNATS_ROOT/gnats-adm/config if [ $BDAY_START -gt 12 ] then BDAY_START=`echo $BDAY_START - 12 | bc` BDAY_START=$BDAY_START" pm" else BDAY_START=$BDAY_START" am" fi if [ $BDAY_END -gt 12 ] then BDAY_END=`echo $BDAY_END - 12 | bc` BDAY_END=$BDAY_END" pm" else BDAY_END=$BDAY_END" am" fi case $BWEEK_START in 0) WEEK_START="Sunday";; 1) WEEK_START="Monday";; 2) WEEK_START="Tuesday";; 3) WEEK_START="Wednesday";; 4) WEEK_START="Thursday";; 5) WEEK_START="Friday";; 6) WEEK_START="Saturday";; esac case $BWEEK_END in 0) WEEK_END="Sunday";; 1) WEEK_END="Monday";; 2) WEEK_END="Tuesday";; 3) WEEK_END="Wednesday";; 4) WEEK_END="Thursday";; 5) WEEK_END="Friday";; 6) WEEK_END="Saturday";; esac echo Business hours are\: echo \ \ \ \ \ $WEEK_START through $WEEK_END $BDAY_START to $BDAY_END else echo Automatic reminders are disabled. echo No reminders are sent to maintainer\(s\) of PRs. fi echo grep -in '^ACKNOWLEDGE' $GNATS_ROOT/gnats-adm/config if [ $ACKNOWLEDGE ] then echo Automatic acknowledgements are enabled. \(default\) echo This option will tell GNATS to send an acknowledgement to the echo originator of a PR when the PR is filed in the database. else echo Automatic acknowledgements are disabled. echo When a PR is submitted, an acknowledgement will not be sent to echo the originator. fi echo grep -in '^KEEP_RECEIVED_HEADERS' $GNATS_ROOT/gnats-adm/config if [ $KEEP_RECEIVED_HEADERS ] then echo GNATS is configured to keep mail headers. \(default\) echo Please note that this takes up a lot of space in your database, echo and is seldom used. It is useful for debugging. else echo GNATS is configured to remove mail headers before filing the PR. fi echo grep -in '\^DEBUG_MODE' $GNATS_ROOT/gnats-adm/config if [ $DEBUG_MODE ] then echo Debug mode is set. This means that ALL mail will be forwarded to \\c echo \'$GNATS_ADMIN\'. else echo Debug mode is not set. \(default\) fi gnats-4.1.0/contrib/scripts/reset-gnats0000744000175000017500000000215006620401144020664 0ustar chewiechewie00000000000000#!/bin/ksh # Program to reset GNATS to a pristine condition. # Use with CAUTION! # Written by Brian Abernathy. GNATS_ROOT=/usr/local/lib/gnats/gnats-db PATH=$PATH:$GNATS_ROOT/gnats-bin echo Warning! This script will empty the GNATS database of echo ALL PRs. echo echo Do you want to do this? \(Y/N\) read ans if [ "$ans" != "Y" ] then echo exiting. exit fi echo echo Are you REALLY SURE? \(Y/N\) read ans if [ "$ans" != "Y" ] then echo I didn\'t think so.\ \ Bye! exit fi CATEGORIES=`grep -v '^#' $GNATS_ROOT/gnats-adm/categories | sed -e 's/:.*//g'` # Obtain a database lock. pr-edit --lockdb if [ $? -ne 0 ] then echo Sorry - cannot obtain a database lock. Try later. exit 1 fi # Reset the 'current' number. echo 0 >$GNATS_ROOT/gnats-adm/current # Clear out all the waiting PRs. for files in `echo $CATEGORIES` do rm $GNATS_ROOT/$files/* 2>/dev/null done # Regenerate the index. rm $GNATS_ROOT/gnats-adm/index touch $GNATS_ROOT/gnats-adm/index gen-index # Release database lock. pr-edit --unlockdb echo Done! # Release lock. pr-edit --unlockdb echo The GNATS database has been reset. gnats-4.1.0/contrib/sql/0000755000175000017500000000000010212665130015615 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/sql/Iprms.cust0000744000175000017500000000130506620401144017610 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin #------------------------------------------------------------------------ # run customer report and cut off the informix header # before putting into the correctly named file #------------------------------------------------------------------------ for cust in customer1 customer2 customer3 do CUSTABBR=`echo $cust | cut -c1-3` $INFX/sacego bcust $cust | sed -n '7,$p' > $BUGDIR/$CUSTABBR`date +%y%m%d` done gnats-4.1.0/contrib/sql/Iprms.setup0000744000175000017500000000167706620401144020006 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin #--------------------------------------------------------------- # query the GNATS db for derivative data #--------------------------------------------------------------- query_pr -sql > $BUGDIR/gnats`date +%y%m%d` cp $BUGDIR/gnats`date +%y%m%d` $BUGDIR/gnats.curr #--------------------------------------------------------------- # load into informix database #--------------------------------------------------------------- $INFX/isql engdb loadGNATS.sql #--------------------------------------------------------------- # calculate age of non-closed bugs and update db #--------------------------------------------------------------- cd $DBPATH $INFX/fglgo calc_age gnats-4.1.0/contrib/sql/Iprms.summdy0000744000175000017500000000111006620401144020142 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp MAIL=/usr/ucb/mail export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin # ------------------------------------------------------------------------ # select critical bug data for day # ------------------------------------------------------------------------ cd $DBPATH $INFX/isql engdb cat_rev.sql | $MAIL -s "Open + Analyzed Critical Bugs" staff gnats-4.1.0/contrib/sql/Iprms.summmn0000744000175000017500000000124706620401144020153 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin # ------------------------------------------------------------------------ # report on # history of bugs in different states by count and by % # ------------------------------------------------------------------------ FN=$BUGDIR/history`date +%y%m%d` cat $DBTEMP/tmp1 > $FN for rept in history historyPC do $INFX/sacego $rept | sed -n '7,$p' >> $FN cat $DBTEMP/tmp1 >> $FN done gnats-4.1.0/contrib/sql/Iprms.summwk0000744000175000017500000000117006620401144020155 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp MAIL=/usr/ucb/mail export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin # ------------------------------------------------------------------------ # select summary data for week and update history # ------------------------------------------------------------------------ cd $DBPATH $INFX/fglgo summ_wk $INFX/isql engdb cust_rev.sql | $MAIL manager $INFX/isql engdb engr_rev.sql | $MAIL manager gnats-4.1.0/contrib/sql/Iprms.wkbuffs0000744000175000017500000000104506620401144020302 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin # ------------------------------------------------------------------------ # move buffer into table for last monday # and copy today's table into buffer # ------------------------------------------------------------------------ $INFX/isql engdb loadOGNATS.sql gnats-4.1.0/contrib/sql/Iprms.wkchng0000744000175000017500000000204306620401144020113 0ustar chewiechewie00000000000000#!/bin/sh # set up PATH=.:/bin:/usr/bin:/usr/unsupported/bin:/usr/unsupported/informix/bin INFORMIXDIR=/usr/unsupported/informix DBPATH=/users/db/infx DBTEMP=/tmp export PATH export INFORMIXDIR export DBPATH export DBTEMP BUGDIR=/users/db/reports INFX=/usr/unsupported/informix/bin # ------------------------------------------------------------------------ # report on # changes in bug statistics, new opens, and state changes for week # ------------------------------------------------------------------------ for rept in wk_delta wk_open wk_st_chng do FN=$BUGDIR/$rept`date +%y%m%d` $INFX/sacego $rept | sed -n '7,$p' > $FN cat $FN >> $DBTEMP/tmp done # ------------------------------------------------------------------------ # report on # open bugs and open enhancement requests # ------------------------------------------------------------------------ for rept in open enhreq do cat $DBTEMP/tmp1 >> $DBTEMP/tmp FN=$BUGDIR/$rept`date +%y%m%d` $INFX/sacego $rept | sed -n '7,$p' > $FN cat $FN >> $DBTEMP/tmp done gnats-4.1.0/contrib/sql/README0000644000175000017500000001367606620401144016513 0ustar chewiechewie00000000000000 Overview GNATS data can be extracted and uploaded into a relational database. The advantages for doing this include 1. Interfacing the problem report information with other information, e.g., a customer database 2. Take advantage of report writers to generate production reports or more sophisticated report generation capabilities not present in GNATS 3. Perform complex queries available in SQL but not supported in GNATS This directory includes a set of scripts that interfaces GNATS to an Informix relational database application. There are four types of script in the current directory: Ignats.* Unix shell scripts *.sql SQL (Structured Query Language) scripts, *.ace Informix report generator source code *.4gl Informix 4GL source code A sample set of crontab entries has also been providedi in the file crontab. An index to the files is provided in the file fileList. This code is unsupported, and is provided only as an example of how you could use GNATS in conjunction with a relational database management system (rdbms). Application Structure In this example, GNATS is main working database for the developers. Extracted data are upload daily into the relational database for generation of management reports, overview statistics, and special queries. Once the database has been created, most of the interactions are driven by shell scripts scheduled through the Unix cron utility. Two Unix system users are assumed: "manager", who creates the database, and "staff", who receives some of the output reports via email. See the GNATS and Informix manuals for more details on the specifics of the software. Database Creation The main database consists of 5 tables, one for the problem reports and one each for the severity, priority, class, and state codes. An additional table is used to hold a history of weekly summary statistics. The 3 script files used to create these tables, their indices, and access permissions, are as follows. crGNATS.sql crCodes.sql crHist.sql Permissions are set to read/write permission for the creator, "manager", and read only for the rest of the world. These scripts are run manually once to create the database, and are not in the cron table. Two additional tables can be created to hold previous week's data in order to report on which problem reports have been updated in the last week. These tables are created in crOGNATS.sql with the same access permissions. Scheduled Activities and Reports Regular activities and reports by scheduled through cron. (See appendix A.) Daily: 1. Extract data from GNATS by running query-pr. 2. Upload data in database 3. Calculate the age of each problem report at the time of the upload. 4. Report on the problem reports that are of severity "critical" that have not yet been fixed, i.e., in either the "open" or "analyzed" states. Weekly: 1. Manage the buffering of data from the last 2 weeks. 2. Generate summary statistics on the number of problem reports in each of the known states, and store into history table. 3. Generate the following management reports: - summary statistics on the problem reports in each of the known states for the last two weeks - list of problem reports that have changed state in the past week - list of new problem reports for the past week - list of problem reports that are still not closed - list of change requests that are still not closed - statistics on "critical" and "serious" problem reports that have not been fixed, grouped by customer - statistics on "critical" and "serious" problem reports that have not been fixed, grouped by responsible person 4. Generate customer-specific lists of problem reports Monthly: 1. Generate historical record of the problem report statistics, in absolute counts and as a percentage of total problem reports. Additional Scripts A number of additional SQL scripts and report scripts not scheduled through cron are provided as examples. These can be customized to your specific needs. Customization and Use The scripts mentioned above have been tested on a Sun 4 workstation running Sun OS 4.1.x and Informix SE 5.x and Informix ISQL 4.1. You will need an Informix Development licence to compile and use the report generator sources. Shell scripts should be reviewed for the correct pathnames where programs and reports are to be located. Some of the scripts send email, or use parameterized reports that need local customization. The SQL scripts should be easily portable to other relational database systems supporting SQL. Informix report generator sources are not portable, but can serve as examples for report generators from other database vendors. APPENDIX A -------------------------------------------------------------------------- Shell script Informix Program* Informix Script -------------------------------------------------------------------------- Daily: Ignats.setup query-pr --sql isql engdb loadGNATS.sql fglgo calc_age Ignats.summdy isql engdb cat_rev.sql Weekly: Ignats.summwk fglgo summ_wk.4gl isql engdb cust_rev.sql isql engdb engr_rev.sql Ignats.wkbuffs isql engdb loadOGNATS.sql Ignats.wkchng sacego wk_delta sacego wk_open sacego wk_st_chng sacego open sacego enhreq Ignats.cust sacego bcust (custname) Monthly: Ignats.summmn sacego history sacego historyPC -------------------------------------------------------------------------- * isql - SQL interpreter sacego - report generator fglgo - 4GL gnats-4.1.0/contrib/sql/bcust.ace0000644000175000017500000000241306620401144017410 0ustar chewiechewie00000000000000database engdb end {xxx customize here xxx} define param [1] cust_id char(16) end output page length 66 top margin 5 bottom margin 3 left margin 0 {xxx customize here xxx} {report to "/s1/users/smlieu/chron/bugs/reports/cust.infx"} end select {xxx customize here xxx} arrival, gnatsid, category, synopsis, severity, gnatsstate, gnatsclass, sevnum, sevstr, statenum, statestr from gnats, statecode, severitycode {xxx customize here xxx} where customer = $cust_id and severity=sevnum and gnatsstate=statenum order by category, gnatsstate, severity end format page header {xxx customize here xxx} print column 1, "*** GNATS SUMMARY for ", cust_id clipped, " as of ", date, " ***", column 100, "Page", pageno skip 2 lines print column 3, "Date", column 13, "PR #", column 25, "Program", column 37, "State", column 49, "Severity", column 63, "Synopsis" skip 1 line on every row print column 3, date(arrival) using "yy-mm-dd", column 13, gnatsid clipped, column 25, category clipped, column 37, statestr clipped, column 49, sevstr clipped, column 63, synopsis end gnats-4.1.0/contrib/sql/byCat.sql0000644000175000017500000000023406620401144017400 0ustar chewiechewie00000000000000select category, count(*) from gnats where gnatsclass < 4 and arrival > "92-05-01 00:00" and gnatsstate < 5 group by category order by category gnats-4.1.0/contrib/sql/calc_age.4gl0000644000175000017500000000173406620401144017751 0ustar chewiechewie00000000000000 DATABASE engdb #----------------------------------------------------------------------------- # globals definition #----------------------------------------------------------------------------- GLOBALS DEFINE arr_date DATETIME year to minute, t_date DATETIME year to hour, p_age interval day(5) to hour, p_tag CHAR(8) END GLOBALS #----------------------------------------------------------------------------- # main #----------------------------------------------------------------------------- MAIN declare p_curs CURSOR for select arrival from gnats where gnatsstate <5 for update let t_date = extend (today, year to hour) + interval (8) hour to hour {let p_tag = "TAGGED-4"} {display t_date, p_tag} foreach p_curs into arr_date let p_age = t_date - arr_date {display arr_date} {display p_age} update gnats {set (age, tag) = (p_age, p_tag)} set (age) = (p_age) where current of p_curs whenever error stop end foreach END MAIN gnats-4.1.0/contrib/sql/cat_rev.sql0000644000175000017500000000060106620401144017757 0ustar chewiechewie00000000000000select category, count(*) count, avg(age) avg_age, max(age) max_age ,min(age) min_age from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 1 group by category order by category; select category, respengr, gnatsid, age, customer from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 1 order by category, respengr, age; gnats-4.1.0/contrib/sql/crCodes.sql0000644000175000017500000000321706620401144017724 0ustar chewiechewie00000000000000drop table severityCode; create table severityCode ( sevNum integer, sevStr char ( 16) ); revoke insert, delete, update, references, index, alter on severityCode from public; insert into severityCode values (0, "unspecified"); insert into severityCode values (1, "critical"); insert into severityCode values (2, "serious"); insert into severityCode values (3, "non-critical"); drop table priorityCode; create table priorityCode ( priNum integer, priStr char ( 16) ); revoke insert, delete, update, references, index, alter on priorityCode from public; insert into priorityCode values (1, "high"); insert into priorityCode values (2, "medium"); insert into priorityCode values (3, "low"); drop table stateCode; create table stateCode ( stateNum integer, stateStr char ( 16) ); revoke insert, delete, update, references, index, alter on stateCode from public; insert into stateCode values (1, "open"); insert into stateCode values (2, "analyzed"); insert into stateCode values (3, "suspended"); insert into stateCode values (4, "feedback"); insert into stateCode values (5, "closed"); drop table classCode; create table classCode ( classNum integer, classStr char ( 16) ); revoke insert, delete, update, references, index, alter on classCode from public; insert into classCode values (1, "sw-bug"); insert into classCode values (2, "doc-bug"); insert into classCode values (3, "support"); insert into classCode values (4, "change-request"); insert into classCode values (5, "mistake"); insert into classCode values (6, "duplicate"); gnats-4.1.0/contrib/sql/crHist.sql0000644000175000017500000000045406620401144017576 0ustar chewiechewie00000000000000 create table history ( asof date, open integer, analyzed integer, suspended integer, feedback integer, closed integer, total integer ); revoke insert, delete, update, references, index, alter on history from public; gnats-4.1.0/contrib/sql/crOPRMS.sql0000644000175000017500000000322706620401144017570 0ustar chewiechewie00000000000000 drop table o_gnats; create table o_gnats ( gnatsid char(8), category char(16), synopsis char(128), confidential char(3), severity integer, priority integer, respengr char(16), gnatsstate integer, gnatsclass integer, customer char(16), arrival datetime year to minute, age interval day(5) to hour, custcontact char(64), release char(64) ); create unique index o_gnats_prid on o_gnats(gnatsid); create index o_gnats_cat on o_gnats(category); create index o_gnats_resp on o_gnats(respengr); create index o_gnats_cust o_gnats(customer); revoke insert, delete, update, references, index, alter on o_gnats from public; drop table buf_gnats; create table buf_gnats ( gnatsid char(8), category char(16), synopsis char(128), confidential char(3), severity integer, priority integer, respengr char(16), gnatsstate integer, gnatsclass integer, customer char(16), arrival datetime year to minute, age interval day(5) to hour, custcontact char(64), release char(64) ); create unique index buf_gnats_prid on buf_gnats(gnatsid); create index buf_gnats_cat on buf_gnats(category); create index buf_gnats_resp on buf_gnats(respengr); create index buf_gnats_cust buf_gnats(customer); revoke insert, delete, update, references, index, alter on buf_gnats from public; gnats-4.1.0/contrib/sql/crPRMS.sql0000644000175000017500000000153006620401144017444 0ustar chewiechewie00000000000000grant dba to creator; grant connect to public; drop table GNATS; create table gnats ( gnatsid char(8), category char(16), synopsis char(128), confidential char(3), severity integer, priority integer, respengr char(16), gnatsstate integer, gnatsclass integer, customer char(16), arrival datetime year to minute, age interval day(5) to hour, custcontact char(64), release char(64) ); create unique index gnats_prid on gnats(gnatsid); create index gnats_cat on gnats(category); create index gnats_resp on gnats(respengr); create index gnats_cust gnats(customer); revoke insert, delete, update, references, index, alter on gnats from public; gnats-4.1.0/contrib/sql/crontab0000644000175000017500000000155106620401144017173 0ustar chewiechewie00000000000000# # ------------------------------------------------------- # I-gnats (informix gnats) -------------------------------- # ------------------------------------------------------- # --every day ------------------------------------------- # 40 5 * * * /usr/unsupported/bin/Ignats.setup 58 5 * * * /usr/unsupported/bin/Ignats.summdy # # --every monday, must be in sequence ------------------- # # summarize state totals and write to history table 0 6 * * 1 /usr/unsupported/bin/Ignats.summwk # # update buffered records for this week and last week 1 6 * * 1 /usr/unsupported/bin/Ignats.wkbuffs # # report new bugs and state changes for past week 3 6 * * 1 /usr/unsupported/bin/Ignats.wkchng # # reports for customers 5 6 * * 1 /usr/unsupported/bin/Ignats.cust # # --every first of month -------------------------------- # 7 6 1 * * /usr/unsupported/bin/Ignats.summmn # gnats-4.1.0/contrib/sql/cust_p_rev.ace0000644000175000017500000000312506620401145020443 0ustar chewiechewie00000000000000 database engdb end {xxx customize here xxx} define param [1] cust_id char(16) variable javg interval day(4) to day variable jmax interval day(4) to day variable jmin interval day(4) to day end output page length 66 top margin 5 bottom margin 3 left margin 0 {xxx customize here xxx} {report to "/s1/users/smlieu/chron/bugs/reports/cust.infx"} end select severity, count(*) icount, avg(age) iavg, max(age) imax, min(age) imin, sevstr from gnats, severitycode {xxx customize here xxx} where customer = $cust_id and gnatsstate < 3 and gnatsclass < 4 and severity < 3 and severity = sevnum group by severity, sevstr order by severity, sevstr end format page header {xxx customize here xxx} print column 1, "*** AGE OF OPEN AND ANALYZED PROBLEM REPORTS ", column 60, "Page", pageno print column 1, "*** FOR ", cust_id clipped, " as of ", date skip 2 lines print column 28, "Average", column 38, "Maximum", column 48, "Minimum" print column 3, "Severity", column 19, "Total", column 28, " (days)", column 38, " (days)", column 48, " (days)" skip 1 line on every row let javg = iavg + interval (12) hour to hour let jmax = imax + interval (12) hour to hour let jmin = imin + interval (12) hour to hour print column 3, sevstr clipped, column 15, icount using "###,###", column 30, javg, column 40, jmax, column 50, jmin skip 1 line end gnats-4.1.0/contrib/sql/cust_rev.sql0000644000175000017500000000100106620401145020162 0ustar chewiechewie00000000000000select customer, count(*), avg(age), max(age), min(age) from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 1 group by customer order by customer; select customer, gnatsid, age from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 1 order by customer, age; select customer, count(*), avg(age), max(age), min(age) from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 2 group by customer order by customer; gnats-4.1.0/contrib/sql/engr_rev.sql0000644000175000017500000000100106620401145020137 0ustar chewiechewie00000000000000select respengr, count(*), avg(age), max(age), min(age) from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 1 group by respengr order by respengr; select respengr, gnatsid, age from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 1 order by respengr, age; select respengr, count(*), avg(age), max(age), min(age) from gnats where gnatsstate < 3 and gnatsclass < 4 and severity = 2 group by respengr order by respengr; gnats-4.1.0/contrib/sql/enhreq.ace0000644000175000017500000000212106620401145017547 0ustar chewiechewie00000000000000database engdb end output page length 66 top margin 5 bottom margin 3 left margin 0 {xxx customize here xxx} {report to "/s1/users/smlieu/chron/bugs/reports/enhR.infx"} end select gnatsid, category, synopsis, severity, gnatsstate, gnatsclass, sevnum, sevstr, statenum, statestr from gnats, statecode, severitycode {xxx customize here xxx} where gnatsclass = 4 and gnatsstate < 5 and severity=sevnum and gnatsstate=statenum order by category, gnatsstate, severity end format page header {xxx customize here xxx} print column 1, "*** GNATS SUMMARY - CHANGE REQUESTS NOT CLOSED as of ", date, " ***", column 100, "Page", pageno skip 2 lines print column 3, "PR #", column 15, "Program", column 27, "State", column 39, "Severity", column 53, "Synopsis" skip 1 line on every row print column 3, gnatsid clipped, column 15, category clipped, column 27, statestr clipped, column 39, sevstr clipped, column 53, synopsis end gnats-4.1.0/contrib/sql/fileList0000644000175000017500000000457106620401145017324 0ustar chewiechewie00000000000000 -------------------------------------------------------------------------- Informix SQL Script Files -------------------------------------------------------------------------- Name Function byCat.sql problem reports by program category cat_rev.sql critical problem reports by category crCodes.sql create severity and state code tables crHist.sql create statistical history table crGNATS.sql create main problem reports table crOGNATS.sql create problem reports buffer tables cust_rev.sql critical problem reports by customer engr_rev.sql critical problem reports by responsible person loadOGNATS.sql manage data from previous weeks loadGNATS.sql upload current data monthly.sql generate cumulative problem report graph by month pick_id.sql list details for selected problem reports statesumm.sql problem report statistics by report state -------------------------------------------------------------------------- Informix ACE Report Generator Source Files -------------------------------------------------------------------------- Name Function bcust.ace customer problem reports cust_p_rev.ace customer summary statistics enhreq.ace change requests not closed history.ace historical statistics in absolute count historyPC.ace historical statistics as percentage of total reports open.ace problem reports not closed wk_delta.ace change statistics wk_open.ace new problem reports not closed wk_st_chng.ace state changes for problem reports -------------------------------------------------------------------------- Informix 4GL Source Files -------------------------------------------------------------------------- Name Function calc_age.4gl calculate age of problem reports summ_wk.4gl calculate summary statistics -------------------------------------------------------------------------- Unix Shell Scripts -------------------------------------------------------------------------- Name Function Ignats.cust generate customer reports Ignats.setup extract data from GNATS and load into database Ignats.summdy generate list of critical problem reports not closed Ignats.summmn generate historical data Ignats.summwk generate weekly statistics report Ignats.wkbuffs manage data from previous weeks Ignats.wkchng generate report of changes in past week gnats-4.1.0/contrib/sql/history.ace0000644000175000017500000000155706620401145020002 0ustar chewiechewie00000000000000 database engdb end output page length 100 top margin 5 bottom margin 0 left margin 0 end select asof, open, analyzed, suspended, feedback, closed, total mytotal from history order by asof end format page header print column 1, "*** GNATS HISTORY as of ", date, " ***" skip 2 lines print column 1, "Date", column 13, "Open", column 21, "Analzd", column 29, "Fdback", column 37, "Closed", column 45, "Suspnd", column 53, "Total" skip 1 line on every row print column 1, asof using "mm/dd/yy", column 13, open using "#####", column 21, analyzed using "#####", column 29, feedback using "#####", column 37, closed using "#####", column 45, suspended using "#####", column 53, mytotal using "#####" end gnats-4.1.0/contrib/sql/historyPC.ace0000644000175000017500000000245706620401145020225 0ustar chewiechewie00000000000000 database engdb end define variable i1 float variable i2 float variable i3 float variable i4 float variable i5 float end output page length 100 top margin 5 bottom margin 0 left margin 0 end select asof, open, analyzed, suspended, feedback, closed, total mytotal from history order by asof end format page header print column 1, "*** GNATS HISTORY as of ", date, " ***" skip 2 lines print column 13, " %", column 21, " %", column 29, " %", column 37, " %", column 45, " %" print column 1, "Date", column 13, "Open", column 21, "Analzd", column 29, "Fdback", column 37, "Closed", column 45, "Suspnd", column 53, "Total" skip 1 line on every row let i1 = open * 100 / mytotal let i2 = analyzed * 100 / mytotal let i3 = feedback * 100 / mytotal let i4 = closed * 100 / mytotal let i5 = suspended * 100 / mytotal print column 1, asof using "mm/dd/yy", column 13, i1 using "###.#", column 21, i2 using "###.#", column 29, i3 using "###.#", column 37, i4 using "###.#", column 45, i5 using "###.#", column 53, mytotal using "#####" end gnats-4.1.0/contrib/sql/loadOPRMS.sql0000644000175000017500000000021406620401145020075 0ustar chewiechewie00000000000000delete from o_gnats; insert into o_gnats select * from buf_gnats; delete from buf_gnats; insert into buf_gnats select * from gnats; gnats-4.1.0/contrib/sql/loadPRMS.sql0000644000175000017500000000046706620401145017770 0ustar chewiechewie00000000000000 delete from gnats; load from "/s1/users/smlieu/chron/bugs/reports/gnats.curr" insert into gnats ( gnatsID, category, synopsis, confidential, severity, priority, respEngr, gnatsState, gnatsClass, customer, arrival, custContact, release ); gnats-4.1.0/contrib/sql/monthly.sql0000644000175000017500000000254106620401145020034 0ustar chewiechewie00000000000000select count(*) from gnats where category ="gcc" and arrival < "91-05-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-06-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-07-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-08-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-09-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-10-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-11-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "91-12-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-01-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-02-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-03-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-04-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-05-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-06-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-07-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-08-01 00:00"; select count(*) from gnats where category ="gcc" and arrival < "92-09-01 00:00"; gnats-4.1.0/contrib/sql/open.ace0000644000175000017500000000215506620401145017235 0ustar chewiechewie00000000000000database engdb end output page length 66 top margin 5 bottom margin 3 left margin 0 {xxx customize here xxx} {report to "/s1/users/smlieu/chron/bugs/reports/open.infx"} end select gnatsid, category, synopsis, severity, gnatsstate, gnatsclass, sevnum, sevstr, statenum, statestr from gnats, statecode, severitycode {xxx customize here xxx} where gnatsclass < 3 and gnatsstate < 5 and severity=sevnum and gnatsstate=statenum order by category, gnatsstate, severity end format page header {xxx customize here xxx} print column 1, "*** GNATS SUMMARY - PR'S NOT CLOSED as of", column 42, date, column 55, " ***", column 100, "Page", pageno skip 2 lines print column 3, "PR #", column 15, "Program", column 27, "State", column 39, "Severity", column 53, "Synopsis" skip 1 line on every row print column 3, gnatsid clipped, column 15, category clipped, column 27, statestr clipped, column 39, sevstr clipped, column 53, synopsis end gnats-4.1.0/contrib/sql/pick_id.sql0000644000175000017500000000035506620401145017745 0ustar chewiechewie00000000000000select gnatsid, severity, age, customer, synopsis from gnats where gnatsid = "p0000355" or gnatsid = "p0000383" or gnatsid = "p0000389" or gnatsid = "p0000553" or gnatsid = "p0001048" order by gnatsid gnats-4.1.0/contrib/sql/statesumm.sql0000644000175000017500000000036106620401145020362 0ustar chewiechewie00000000000000 select statenum, statestr, count(*) from gnats, statecode where gnatsstate=statenum and gnatsclass < 5 group by statestr, statenum order by statenum; select " ", "Total", count(*) from gnats where gnatsclass <5; gnats-4.1.0/contrib/sql/summ_wk.4gl0000644000175000017500000000154006620401145017711 0ustar chewiechewie00000000000000DATABASE engdb #----------------------------------------------------------------------------- # globals definition #----------------------------------------------------------------------------- GLOBALS DEFINE hist RECORD asof DATE, state ARRAY [5] of INTEGER, total INTEGER END RECORD, i INTEGER END GLOBALS #----------------------------------------------------------------------------- # main #----------------------------------------------------------------------------- MAIN let hist.asof=today let hist.total=0 for i = 1 to 5 select count(*) into hist.state[i] from gnats where gnatsclass < 5 and gnatsstate = i let hist.total=hist.total+hist.state[i] end for insert into history values (hist.asof, hist.state[1], hist.state[2], hist.state[3], hist.state[4], hist.state[5], hist.total) END MAIN gnats-4.1.0/contrib/sql/wk_delta.ace0000644000175000017500000000471106620401145020066 0ustar chewiechewie00000000000000database engdb end define variable open_old integer variable open_new integer variable analz_old integer variable analz_new integer variable fdbck_old integer variable fdbck_new integer variable suspd_old integer variable suspd_new integer variable closed_old integer variable closed_new integer variable total_old integer variable total_new integer variable week_str char(9) end output page length 66 top margin 5 bottom margin 3 left margin 0 end select asof, open, analyzed, suspended, feedback, closed, total ptotal from history where asof >= (today - interval (13) day to day) order by asof end format page header print column 1, "*** GNATS SUMMARY as of ", date, " ***", column 56, "Page", pageno skip 2 lines print column 1, "Date", column 15, "Open", column 25, "Analyzed", column 35, "Feedback", column 45, "Closed", column 55, "Suspended", column 65, "Total" skip 1 line let open_new = 0 let analz_new = 0 let fdbck_new = 0 let suspd_new = 0 let closed_new = 0 let total_new = 0 on every row let week_str="Change " let open_old = open_new let analz_old = analz_new let fdbck_old = fdbck_new let closed_old = closed_new let suspd_old = suspd_new let total_old = total_new let open_new = open let analz_new = analyzed let fdbck_new = feedback let closed_new = closed let suspd_new = suspended let total_new = ptotal print column 1, asof using "yy-mm-dd", column 13, open using "###,###", column 23, analyzed using "###,###", column 33, feedback using "###,###", column 43, closed using "###,###", column 53, suspended using "###,###", column 63, ptotal using "###,###" on last row let open_old = open_new - open_old let analz_old = analz_new - analz_old let fdbck_old = fdbck_new - fdbck_old let closed_old = closed_new - closed_old let suspd_old = suspd_new - suspd_old let total_old = total_new - total_old skip 2 lines print "Change", column 13, open_old using "----###", column 23, analz_old using "----###", column 33, fdbck_old using "----###", column 43, closed_old using "----###", column 53, suspd_old using "----###", column 63, total_old using "----###" end gnats-4.1.0/contrib/sql/wk_open.ace0000644000175000017500000000240106620401145017730 0ustar chewiechewie00000000000000database engdb end output page length 66 top margin 5 bottom margin 3 left margin 0 {xxx customize here xxx} {report to "/s1/users/smlieu/chron/bugs/reports/open.infx"} end select gnatsid, category, synopsis, severity, gnatsstate, gnatsclass, sevnum, sevstr, statenum, statestr from gnats, statecode, severitycode {select for those that arrived (after midnight) a week ago} {all states from open - closed } where gnatsclass < 3 and gnatsstate < 6 and severity=sevnum and gnatsstate=statenum and arrival > (today - interval (7) day to day) order by category, gnatsstate, severity end format page header {xxx customize here xxx} print column 1, "*** GNATS SUMMARY - NEW PR'S for week ending ", column 42, date, column 55, " ***", column 100, "Page", pageno skip 2 lines print column 3, "PR #", column 15, "Program", column 27, "State", column 39, "Severity", column 53, "Synopsis" skip 1 line on every row print column 3, gnatsid clipped, column 15, category clipped, column 27, statestr clipped, column 39, sevstr clipped, column 53, synopsis end gnats-4.1.0/contrib/sql/wk_st_chng.ace0000644000175000017500000000272506620401145020425 0ustar chewiechewie00000000000000 database engdb end output page length 66 top margin 5 bottom margin 3 left margin 0 {xxx customize here xxx} {report to "/s1/users/smlieu/chron/bugs/reports/open.infx"} end select gnats.gnatsid pid, gnats.category pcat, gnats.synopsis psyn, gnats.severity psev, o_gnats.gnatsstate ostate, old.stateStr oldstr, new.stateStr newstr, sevstr from gnats, o_gnats, stateCode old, stateCode new, severityCode where (o_gnats.gnatsid = gnats.gnatsid and o_gnats.gnatsstate <> gnats.gnatsstate) and o_gnats.gnatsstate = old.stateNum and gnats.gnatsstate = new.stateNum and gnats.severity = severityCode.sevNum order by pcat, ostate end format page header {xxx customize here xxx} print column 1, "*** GNATS SUMMARY - STATE CHANGES for week ending ", column 42, date, column 55, " ***", column 100, "Page", pageno skip 2 lines print column 3, "PR #", column 15, "Program", column 27, "Severity", column 43, "From State", column 55, "To State", column 67, "Synopsis" skip 1 line on every row print column 3, pid clipped, column 15, pcat clipped, column 27, sevstr clipped, column 43, oldstr clipped, column 55, newstr clipped, column 67, psyn end gnats-4.1.0/contrib/tkgnats/0000755000175000017500000000000010212665130016471 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/tkgnats/print/0000755000175000017500000000000010212665130017625 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/tkgnats/print/Description_Summary0000644000175000017500000000346306665615034023575 0ustar chewiechewie00000000000000proc Description_Summary {prid ln} { global Print ##workingMsg headingMsg "Doing $prid..." set fout $Print(fout) print_parsepr $prid flds if {$Print(first_time) == 1} { # title section set dat "[clock format [clock seconds] -format "%a %b %e %H:%M %Y"]" putlines $fout { {.po 0.375i} {.ll 7.75i} } putlines $fout { {.TS} {expand, tab(%);} } putlines $fout [list {Cbp12w(7.75i).} "Problem Report Description Summary -- $dat" {.TE}] puts $fout ".sp" # format section putlines $fout { {.\" format section} {.ds CF " \\n(yr / \\n(mo / \\n(dy} {.TS H} {box;} {Lb|Lbw(7.0i)} {Lb|^} {Lb S} } for {set n 0} {$n < [expr $Print(num_ids) - 1]} {incr n} { putlines $fout { {L|L} {L|^} {L S} } } putlines $fout { {L|L} {L|^} {L S.} {.\" table heading} {Id Synopsis} {_} {State} {_} {Description} {=} {.TH} {.sp .5} } } ################################### putfldvalbold $fout flds {>Number} puts $fout "\t" nonewline putfldval2 $fout flds {>Synopsis} puts $fout "_" putfldval1 $fout flds {>State} puts $fout "\n_" # putfldval2 $fout flds {>Description} freeform_text2 $fout flds {>Description} puts $fout "=" ################################### if {$Print(last_time) == 1} { # trailer puts $fout ".TE" } { puts $fout ".sp .5" } return 0 } gnats-4.1.0/contrib/tkgnats/print/Synopsis_Summary0000644000175000017500000000421306665615034023133 0ustar chewiechewie00000000000000proc Synopsis_Summary {prid ln} { global Print ##workingMsg headingMsg "Doing $prid..." set fout $Print(fout) print_parsepr_medium $prid flds if {$Print(first_time) == 1} { # title section set dat "[clock format [clock seconds] -format "%a %b %e %H:%M %Y"]" putlines $fout { {.po 0.375i} {.ll 7.75i} } putlines $fout { {.TS} {expand, tab(%);} } putlines $fout [list {Cbp12w(7.75i).} "Problem Report Synopsis Summary -- $dat" {.TE}] puts $fout ".sp" # format section putlines $fout { {.\" format section} {.ds CF " \\n(yr / \\n(mo / \\n(dy} {.TS H} {box;} {Cb|Lb|Lb|Lb|Lb|Lbw(2.6i)} {^|Lb|Lb|Lb|Lb|^} {N|L|L|L|L|L.} {.\" table heading} {Id Arrival Date Responsible Category Priority Synopsis} { Last Modified Originator State Severity} {=} {.TH} } } ################################### putfldvalbold $fout flds {>Number} puts $fout "\t" nonewline putfldval1 $fout flds {>Arrival-Date} puts $fout "\t" nonewline putfldval1 $fout flds {>Responsible} puts $fout "\t" nonewline putfldval1 $fout flds {>Category} puts $fout "\t" nonewline putfldval1 $fout flds {>Priority} puts $fout "\t" nonewline putfldval2 $fout flds {>Synopsis} puts $fout "\\^\t" nonewline putfldval1 $fout flds {>Last-Modified} puts $fout "\t" nonewline ## putfldval1 $fout flds {>Originator} puts $fout [lrange [split [ftrim $flds(>Originator)]] 0 0] nonewline puts $fout "\t" nonewline putfldval1 $fout flds {>State} puts $fout "\t" nonewline putfldval1 $fout flds {>Severity} # putfldval1 $fout flds {>Class} # putfldval1 $fout flds {>Submitter-Id} puts $fout "\t\\^\n_" ################################### if {$Print(last_time) == 1} { # trailer puts $fout ".TE" } return 0 } gnats-4.1.0/contrib/tkgnats/CHANGES0000644000175000017500000012600407005513656017502 0ustar chewiechewie00000000000000 ================= Changes in 3.0.14 ================= TkGnats 3.0.14 requires at least gnats-3.112-beta. TkGnats requires TclTk 8.0 or newer on UNIX and Windows 95/98/NT. A few Windows users have reported socket communication problems with Windows version 8.0p2 which were fixed in Tcl/Tk 8.0.3. 20OCT1999 o Set the minimum version of GNATS required to 3.112. o Fixed broken query for Submitter-Id when TkGnats is configured for batch mode ([n]query-pr, etc, instead of gnatsd). 20SEP1999 o Changed index separator in "DELETE PERMANENTLY" from ":" to "|". 03SEP1999 o People were entering "now" for Date-Required. This is valid, but when check-db is run, "now" evaluates to a different time so the gnats index appears to be in error. TkGnats now converts Date-Required to the YY-MM-DD format to ensure that this doesn't happen. now, today, yesterday and tomorrow are all valid dates where this could occur. ================= Changes in 3.0.13 ================= TkGnats 3.0.13 requires at least gnats-3.111-beta. TkGnats requires TclTk 8.0 or newer on UNIX and Windows 95/98/NT. It no longer runs with Tcl/Tk 7.6/4.2. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 29AUG1999 o Set the minimum version of GNATS required to 3.111. This should have also been set in TkGnats-3.0.12 but I forgot to do it. :-( o Improved error handling when filing edited PRs. Email isn't sent until after the PR has been successfully filed. o Added Cancel buttons to a few text entry dialogs (Edit Reasons, Saved Query commands, etc). o Removed two files that shouldn't be included in the distribution: NEWCONFIGOPTS and TKGNATSPATCH2. ================= Changes in 3.0.12 ================= TkGnats 3.0.12 requires at least gnats-3.111-beta. TkGnats requires TclTk 8.0 or newer on UNIX and Windows 95/98/NT. It no longer runs with Tcl/Tk 7.6/4.2. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 06AUG1999 o Added bindings for Cut/Copy/Paste operations and the Query listbox for upper case characters so these functions all work when the CapsLock is on. o Changed the default of SUPPRESSED_EDIT_FIELDS to "none" instead of "Audit-Trail(admin)". 24JUL1999 o Fixed handling email address of the form "Rick Macdonald" . o MS email sometimes has addresses (in Reply-To, IE the Originator) with commas. eg: "Macdonald, Rick" . TkGnats internally parses and changes this to "Rick Macdonald" because TkGnats can't handle the comma. This change is _not_ saved in the PR even when the PR is editted and saved. 06JUL1999 o New config variable TkGnats(QueryDefaultAction) defaults to "view" but can be set to "edit" to control the action for double-clicking and pressing Enter in the Query listbox. 02JUL1999 o Added FIELD_ALIASES to the client hints. You can now "rename" any field in the PR! o Reinstated the TkGnats(Quarter) config variable for Paul Triana. o Fixed some background colours under Windows. o Added Delete to the Cut/Copy/Paste popup menu, and disabled functions when inappropriate such as Cut/Copy when there is no selection. o Fixed SendPr when Responsible is blank but not mandatory. o Fixed missing domain name in Send Email. 30JUN99 o Query listbox now takes input focus and has these bindings: - PageUp, PageDown, UpArrow, DownArrow, LeftArrow, RightArrow - e: Edit Pr (if authorized) - d: Delete Pr (if authorized) - v,Enter: View Pr - r: View Raw Data - h: Hide from List - m: Send Email o Improved busy stopwatch cursor setting and clearing. o New configuration variable TkGnats(DefaultDomainName). If specified, this will be added to all email addresses without a domain name. o New configuration variables for the default setting of fields in SendPr. Any field can be set with: set TkGnats(CreateDefault${field}) value where $field is any field such as Release. For example: set TkGnats(CreateDefaultRelease) "1.00 99" 24JUN99 o Added pop-up right mouse menu for Clipboard Cut/Copy/Paste operations in all text and entry widgets. Cut/Copy/Paste operations are also bound to the ^x, ^c and ^v keys respectively. Details are in the new Help/Cut,Copy,Paste menu item. 21JUN99 o Added support for multiple databases when UNIX platforms have direct disk access. See README.config and README.unix. The "ServerDir" is was a poor name choice and should have been called the DatabaseDir, but I'm leaving it as ServerDir in the README and CONFIG files for now. 18JUN99 o The File/EditReport menu item of the ViewPr dialog wasn't being disabled if the user didn't have edit permission. (Thanks to Richard McGowen ) 31MAY99 o TkGnats now searches the GNATS config file (--list-config|LCFG) for these "client hint" parameters. See README.config for details and defaults. REQUIRE_AUDIT_TRAIL_ENTRY REQUIRE_AUDIT_TRAIL_REASON REQUIRE_AUDIT_TRAIL_EMAIL SUPPRESSED_FIELDS SUPPRESSED_SEND_FIELDS SUPPRESSED_EDIT_FIELDS MANDATORY_FIELDS FIELD_ALIASES o TkGnats now searches the GNATS config file (--list-config|LCFG) for TKGNATS_MIN_VERSION, in which case it will abort if you are running a version of TkGnats older than that specified. The numbers are compared as strings, so 3.0.2 is greater than 3.0.19. I'll have to make sure that all future TkGnats versions are compatable with this check. This is documented in README.config. o Changed Reply-To to Notify-List, which now internally uses the email header X-GNATS-Notify instead of Reply-To. When parsing a PR, the following occurs: - if X-GNATS-Notify doesn't exist but Reply-To does, Reply-To is copied to X-GNATS-Notify and Reply-To is set to From. o Changed references to "ServerKey" to GNATSDatabaseAlias in the various README and CONFIG files. o Added sample server (gnatsd) passwords to CONFIG-user.ini and CONFIG-single-user.ini. ================= Changes in 3.0.11 ================= TkGnats 3.0.11 requires at least gnats-3.108-beta. This release was never used outside of my office. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0 or newer is recommended for performance and font handling. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 29MAY99 o Fixed bug where the continuation lines of long Reply-To headers were not being parsed, and therefore lost. 28APR99 o Fixed Help menus when using local disk access to GNATS. It was failing with the error: can't read "TkGnats(UserAccess)": no such element in array. (thanks to "Kitchener, Steve" ) o The Query window no longer resizes with the Query listbox xscroll. (thanks to "Kitchener, Steve" ) 21APR99 o The Create New PR dialog now removes "pending" from the category list. o Added an example TkGnats(CreateDefaultCategory) to tkgnats.config. 19APR99 o Added support for NIS+ to get the user's full name from the password file. (thanks to morgan.boklund@dynamics.saab.se) 25MAR99 o Positioned EditPr "reason for change" dialogs closer to the center of the EditPr window. Same with the entry dialog called when saving and renaming saved sorts and queries. 22MAR99 o If you pressed return or clicked OK without entering a reason after editing a PR, the entry dialog wasn't being raised again after a message dialog informed you that you must enter something. Now it is raised. (thanks to Matthew.Rice@ftlsol.com) 16MAR99 o Added the "Changes" file to all Help menus. The Makefile now installs the CHANGES file to TKGNATSLIB. 07MAR99 o Added validity check for release-based "Date-Required" field in tksend-pr and tkeditpr. ================= Changes in 3.0.10 ================= TkGnats 3.0.10 requires at least gnats-3.108-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0 or newer is recommended for performance and font handling. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 25FEB99 o The column headings of the main Query listbox now scroll (sideways) with the listbox contents. 21DEC98 o Removed a restriction from the Environment field that disallowed the "|" character (in tksendpr). 15DEC98 o Added the GNATS "Organization" field to the send, view and edit windows. ================ Changes in 3.0.9 ================ TkGnats 3.0.9 requires at least gnats-3.108-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0 or newer is recommended for performance and font handling. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 20NOV98 o Makefile now uses "cp -p" to retain dates of all files when installing. 19NOV98 o Print preview and print-to-file of "ascii" and "latin1" formats now have overstrikes removed by passing the "-b" flag to the groff post-processor (grotty). 09NOV98 o Changes to support fixes in GNATS-3.108: gnatsd no longer unlocks PRs under any circumstances, like pr-edit, so we have to. pr-edit now returns the full text of a PR when locking, like npr-edit does, so we don't need a separate call to get the full text. pr-edit no longer locks the entire GNATS database when locking an individual PR (gnatsd never did) so we don't have to check for the error condition of gnats being locked when we lock a PR. gnatsd LOCK now properly terminates with \r\n.\r\n so this had to be handled. gnatsd and npr-edit now properly escape single dots on send and un-escape on receive so this had to be handled. ================ Changes in 3.0.8 ================ TkGnats 3.0.8 requires at least gnats-3.107-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0 or newer is recommended for performance and font handling. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 26OCT98 o TkGnats was including the entire GECOS field from NIS or the /etc/passwd entry for fullname. It now only reads up to the first comma. (Thanks to Paul Traina ) o Added still more support for release-based keywords. o Added configuration variable TkGnats(Quarter) that defines an alternate name for the release-based Quarter field. 25OCT98 o Added configuration variable TkGnats(AutoUpdateCheck). If set non-zero, this causes TkGnats to check if TkGnats has been recently updated when certain buttons are pressed (query, view, edit, etc). The method is to store and check the file modification time of the file $TkGnats(lib)/VERSION. When an update is detected, TkGnats refuses most operations and asks the user to quit and restart. You can use this to force users to quit and restart to get updated local configuration changes by simply "touch"ing this file. 24OCT98 o Added configuration variable TkGnats(MainMenu) which is code executed in the main menu just prior to adding the buttons to the window. This can be used to add custom buttons to, for example, provide a shortcut to a SendPr window. The following adds such a button for the first server in your server list: set TkGnats(MainMenu) { set s [lindex [lsort [array names TkGnats server,*]] 0] set l [list $TkGnats($s)] set b s_[lindex [split $s ,] 1] button .top.n$b -relief raised -text "Send New Bug Report" \ -command "TkGnats_exec {$TkGnats(WISHPATH)} $TkGnats(lib)/tksendpr.tcl \ -server $l &; schedule_reap" pack .top.n$b -side top -fill x } 23OCT98 o Added configuration variables TkGnats(ClassAbbreviations) and TkGnats(StateAbbreviations) that are lists of values and their abbreviations for the Query listbox. These override any default abbreviations provided by TkGnats. Currently, Class and State names are given 5 and 9 characters in the listbox respectively. If your custom Classes or States are longer, use these variables to supply abbreviations. For example, if you have custom Classes called "installation" and "management", place this is a tkgnatsrc file: set TkGnats(ClassAbbreviations) "installation ins management mgmt" o Added example Class and State abbreviations to tkgnats.config. 17OCT98 o UNIX commands such as "groups" and "id" are no longer executed under Windows. o Multiple database support. o UserID and password supported for network access. See new configuration variable TkGnats(ServerPasswords) in the README.config file. o Variables TkGnats(edit_autorized_groups) and TkGnats(edit_authorized_users) are now used only when accessing gnats by local disk. Otherwise, GNATS database access is controlled by gnatsd directly. 16OCT98 o Added configuration variable TkGnats(FocusStyle). The default is "mouse" for focus-follows-mouse. Set to "click" for click to focus. ================ Changes in 3.0.7 ================ TkGnats 3.0.7 requires at least gnats-3.106-beta. That's not a misprint; I really do mean gnats-3.106. It's just coincidence that the version numbers of TkGnats and GNATS have been similar for awhile. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0 or newer is recommended for performance and font handling. A few Windows users have reported socket communication problems with Windows version 8.0p2 which are fixed in Tcl/Tk 8.0.3. 05OCT98 o Corrected the order of "Group A" config files in README.config. It's: Group A: user-specified "INI" file (command line or env variable) "TKGNATSLIB"/tkgnatsini "TKGNATSLIB"/servers 01OCT98 o Added yet another optional configuration file, TkGnats(TKGNATSLIB)/tkgnatsini. It's read if it's there. See README.config. o Added the ViewConfigurationVariables menu item to the Help menu of the View Raw Data and Send Email dialogs. 30SEP98 o Somewhere between gnats-3.105 and gnats-3.107 a bug was fixed in gnatsd where it used to not precede the final "dot" terminator with \r\n. Now that it does, the get_pr_full_text_socket procedure in tkpr_library.tcl needed changing. I had originally prgrammed around this bug and fixing the bug broke TkGnats. The problem only showed up in the Print/Full and Print/DescriptionSummary functions in the Query dialog, and then only when there was more than one PR being printed. 29SEP98 o Added to some of the Help text that searching on Text-Fields can be slow (all other fields are in the GNATS index as of GNATS-3.107). 24SEP98 o TkGnats now checks the GNATS version and refuses to run if it is not compatable. o Removed a restriction from the Environment field that disallowed the "|" character (in tkeditpr). o The configuration variable TkGnats(QueryMode) is now obsolete. The Days-Idle query-field now gets the Last-Modified date from the SQLF/SQL2 format and no longer needs to do the slower "medium" query (which isn't so slow as of GNATS 3.106 anyway). o The Help for State and Class is now dynamic: it comes from the description fields of the states and classes files. 20SEP98 o Added Query options for all date fields, including a pop-up date selector. o Added full support for the release-based fields Quarter and Date-Required (send, query, view and edit). Previously, only Keywords was supported. o tkeditpr - improved handling of missing PR fields. o Added a "Save to file" button to the Help windows. This is mainly for Windows users where you can't copy/paste the Help/ConfigurationVariables text into another window such as a mail program. 17SEP98 o In the Query listbox, the right mouse button now pops up the "Actions" menu for the PR under the mouse. 08SEP98 o Changed from gnatsd command SQLF to SQL2, which has the blanks squished out to reduce the data transfer size. 03SEP98 o Fixed bug in tksendpr when the CreateDefaultClass wasn't set. The error message was: Error in startup script: invalid command name ".eflds.lb.bars.class._$TkGnats(ClassesList)" ================ Changes in 3.0.6 ================ TkGnats 3.0.6 requires at least gnats-3.106-beta. This is an interim release in that new feature support is not totally complete (see below). It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. Customizable classes and states is not quite complete. See the TO-DO file for details of any remaining issues. 24AUG98 o Added the new Release-Note field to help, view and edit. 27JUL98 o The status area of the Query window now shows the number of PRs found in the query. o Fixed double spacing in the Audit-Trail when more than one change was made at once. ================ Changes in 3.0.5 ================ TkGnats 3.0.5 was a development version that was never released. 27JUL98 o Added the Closed-Date field to the View and Edit dialogs (read-only). New queries for Closed-Date are not done yet. o Customizable classes and states is not quite complete. See the TO-DO file for details of any remaining issues. o Priority and Severity Audit-Trail change notices are now separate and they both prompt for comments. 07JUL98 o * INCOMPATIBILITY ISSUE * Audit-Trail logs use "->" to separate change notices instead of just "-". GNATS was inconsistant (and TkGnats too), using "->" for Responsible changes but "-" for state changes. EG: Responsible-Changed-From-To: rickm->atoyota GNATS 3.105 and newer have this same change. A conversion script for existing PRs was provided in GNATS 3.106 and newer. ================ Changes in 3.0.4 ================ TkGnats 3.0.4 requires at least gnats-3.104-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. 26JUN98 o Unlike GNATS edit-pr, TkGnats now sends email notification and makes an entry into the Audit-Trail when the Priority and/or Severity are changed. I've added this fact to the tkgnats.doc file. 23JUN98 o Added GNATS_ADDR to the title bar of the New Problem Report window (tksendpr.tcl). 06JUN98 o Fixed TkGnats_sendmail_smtp (tcl_library.tcl) to work with newer versions of sendmail (8.x). It seems sendmail is more strict than it used to be. The SMTP commands MAIL FROM: and RCPT TO: no longer accept email addresses in the form: Rick Macdonald (this used to work in v5.x). Since the full email addresses are in the email headers (To:, From:, etc), there is no visible change to any email sent by TkGnats. 27MAY98 o Made colour settings variable. These variables defaults have been added to tkgnats.config: set TkGnats(ReadOnlyBackground) green set TkGnats(EditFieldBackground) grey95 This is temporary. Someday I'll add a colour configuration dialog. o Fixed spelling of variable in tkviewpr: TkGnats(mtextbackground). 11MAY98 o Fixed Query from Selection. It was broken. o Fixed hang when the Number field or Selection contained a non-existent PR. 07MAY98 o Fixed a problem in Summary print when a PR had no Synopsis or some other blank field or blanks within a field (such as Release or Originator). The error was "m0: no such variable", or, field data would be in the wrong cells of the generated report. o Made the Query listbox selection stickier. As you do new queries, the selection will warp to the last PR selected, if possible. 29APR98 o Improved error handling in lock_pr. 20APR98 o Renamed README.first to README. o Fixed the backspace and Ctrl-h keys in the quickfill entry widgets (send and edit dialogs). 18APR98 o Fixed a problem with category names ending with "++", such as "ospic++". 27FEB98 o Changed exec wish "$0" "$@" to be exec wish "$0" ${1+"$@"}. The old form (recommended in the wish man page!) apparently caused problems for DEC UNIX users. This apparently still doesn't work for DEC UNIX, but it seems it's the proper syntax anyway. o Added instructions to README.unix for executing TkGnats programs directly (bypassing the TkGnats Main Menu). (requested by "Wolfgang S. Kechel" ). o Added experimental user authentification with gnatsd. This is for a test version of gnatsd that a TkGnats user built. Perhaps a similar method can be defined universally and added to the mainstream gnatsd. ================ Changes in 3.0.3 ================ TkGnats 3.0.3 requires at least gnats-3.104-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. 09JAN98 o TkGnats(GroupName) under UNIX is now set to the list of groups from the 'groups' command. The edit_authorized and delete_authorized groups are now searched for in this list. The list can still be a single group. (Thanks to Martin Schwenke ) o New variable TkGnats(GNATS_BINDIR) can be set if the GNATS programs query-pr and nquery-pr aren't in your path. (Thanks to Martin Schwenke ) 06JAN98 o A new variable TkGnats(ENVIRONMENT) may be set as the initial value of the Environment text when creating new problem reports. (Thanks to Dan Wilder ) 05JAN98 o Fixed bug in TkGnats_sendmail_smtp where a trailing comma in the address list (unusual) would cause a null string to be sent as SMPT RCPT TO: and cause the connection to the SMTP daemon to hang until it timed out. o Pressing Return in any entry field of the Query window executes the "Do Query" command. o The cursor in the Query entry fields now changes to a stopwatch when the Query window is busy (previously all widgets _but_ the entry fields got the cursor change). 23DEC97 o Reworked the Makefile somewhat. A new variable helps control installation for local or network GNATS access. Set GNATS=local or GNATS=network. The default is local. Variables can be set on the make command line: make GNATS=network In the case of GNATS=local, the Makefile looks at the file $(GNATS_ROOT)/gnats-adm/config for the following variables: GNATS_ADDR, GNATS_USER, SUBMITTER In the case of GNATS=network, GNATS_USER isn't required, GNATS_ADDR is in the "servers" file, and SUBMITTER is typically in the server-specific tkgnatsrc file. o Modified README.unix to reflect the Makefile changes above. o Re-worded parts of README.windows. o Added mention of the GNATS mailing list to the README.first file. o Changed the subject of the email sent when editing the State or Responsible fields to be recognizable by GNATS as follow-up mail. Before, a reply to such mail copied to "bugs" (a rare non-sensible thing to do!) would be misinterpreted as a new report. 22DEC97 o Put the server title (the one that goes on the TkGnats main menu) into the iconname for the main Query window. o By default, the Query listbox now shows as many characters of the Originator's name as will fit into the space allotted. If you want the first name only, set TkGnats(QueryOriginatorFormat) to "short". ================ Changes in 3.0.2 ================ TkGnats 3.0.2 requires at least gnats-3.104-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. 16DEC97 o Fixed bug where GNATS_ADDR was hardwired to "bugs" in the UNIX case where the GNATS daemon was _not_ being used. o Various improvements to the README files. ================ Changes in 3.0.1 ================ TkGnats 3.0.1 requires at least gnats-3.104-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. 15DEC97 o Fixed bug in tkeditpr. When not using gnatsd, it would not unlock the PR after it was updated. o Improved comments in the Makefile. o Added $(MAKEPATH) $(MANDIR)/man1 to makefile. o Got rid of the `which $(WISHPROG)` in the Makefile. It just caused too many problems. WISHPROG is still a variable, and can be given to make on the command line: make WISHPROG=wish8.0. Note that the tkgnats executable now has the following, directly from the wish man page: #!/bin/sh # the next line restarts using wish \ exec wish "$0" "$@" This means that WISHPROG may be set to the executable only, such as "wish8.0" or to a full path such as /usr/local/bin/wish8.0. The Makefile replaces "exec wish" with "exec $WISHPROG". ================ Changes in 3.0.0 ================ TkGnats 3.0.0 requires at least gnats-3.104-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. 08DEC97 o Consolidated the man files into one, tkgnats.1. o Finished rewriting the README and CONFIG files. o Removed the shell script execution line (first line) from tkeditpr, tkquerypr, tksendpr and tkviewpr and renamed with .tcl extensions. o Renamed to version 3.0.0 and released. ================ Changes in 2.0b8 ================ TkGnats 2.0b8 requires at least gnats-3.104-beta. It runs with Tcl/Tk 7.6/4.2 on UNIX, and TclTk 8.0 on UNIX and Win95/NT. Version 8.0p2 has also been tested. Version 8.0 or newer is recommended for performance and font handling. 03DEC97 o Improved email error handling when using smtp sockets. On error, the socket is closed and the email dialog is not destoyed. o Added the wish path and patchlevel to the Help windows. o The "Send Email..." dialog now disallows a blank message body (GNATS won't process mail if the body is blank). 02DEC97 o Fixed bug in font selector where resetting to the previous font didn't load the corresponding font sizes into the size listbox. o Made the TkGnats(HOME) variable optional, but either TkGnats(HOME) or TkGnats(UserDir) must be specified. o Removed the TkGnats(HOME) variable from CONFIG-user.ini and CONFIG-single-user.ini. TkGnats(UserDir), TkGnats(UserSubdir) and env(HOME) are now set automatically in WIN-tkgnats.tcl from the path name of the tkgnats.tcl script (this applies only to Windows). 10NOV97 o In TkGnats(TKGNATSLIB) the contents of the print/query/sort directories are merged with the contents of the TkGnats(TKGNATSLIB)/'ServerDir'/ print/query/sort directories when building the print/query/sort menus of the Query dialog. All directories and files are optional. o In TkGnats(UserDir) the contents of the print/query/sort directories are merged with the contents of the TkGnats(UserDir)/'ServerDir'/ print/query/sort directories when building the print/query/sort menus of the Query dialog. All directories and files are optional. 08NOV97 o Saving of the Query startup (default) sort order and fields is now explicit in the Sort and Fields menus rather than hidden side effects. o Saved queries now include the sort order and selected fields. o Cascaded parts of the Query, Sort and Fields menus. 07NOV97 o The regexp in saved queries are now enclosed in braces instead of quotes to preserve escaped characters. o The UserDir still defaults to ".tkgnats" for unix, but non-unix defaults to "tkgnats". 06NOV97 o Various tweaks to configurations issues. o Updated TECHNOTES, FILES, README, etc. o Audit-trail messages changed from: Responsible-Changed-By: rickm to: Responsible-Changed-By: Rick Macdonald IE: from $TkGnats(LogName) to $TkGnats(FullName) <$TkGnats(EmailAddr)> o Fixed error message when trying to edit a PR that is locked. 02NOV97 o Lots of minor changes but I couldn't keep up with this changelog. o Added a font editor. o Moved buttons and menus around to be a bit more standard. 27OCT97 o The category in the TkSendpr dialog may be pre-set with the variable TkGnats(CreateDefaultCategory). This used to be TkGnats(TksendprCategory). 16OCT97 o Added font control variables: TkGnats(DialogFont), TkGnats(TextFont) and TkGnats(HelpFont). 07OCT97 o Added a new item to the Print menu, "Dump Listbox Data...". This saves the SQL-formatted data for the PRs in the Query listbox to a file. This might be useful to feed external scripts until TkGnats gets some report-generating options. Even then, I doubt that TkGnats could ever support _all_ of the reports that one might want to glean from the GNATS database. 06OCT97 o More portability improvements, such as using [info hostname] and $tcl_platform instead of external unix programs like hostname and uname. o The Days-Idle query requires the Last-Modified field, which isn't part of the -i (--sql or SQLF) query. I've coded around this by doing a "medium" query (QURY) and parsing this to build data similar to the SQLF output. This runs a bit slower when the query has lots of hits but I only do it when a value is given for the Days-Idle field. It should run better on Tcl/Tk 8.0 due to the byte compiler. You can force this behaviour for all queries by setting TkGnats(QueryMode) to medium. The default is sql, except when a value is given for the Days-Idle field as explained above. Previously, TkGnats looked at the time-stamp of the PR file itself, but of course this wouldn't work in the network case, or from Windows95/NT. I'll ask Brendan for a new query option that adds this field to the sql output. It probably should be a new option or flag so existing scripts don't break. 04OCT97 o Added internal sorting of the Query listbox. This elimates the use of the external sort program (necessary for Win95/NT port). o Sort and Field menu items now operate on the current listbox contents, rather than running the query again. This improves performance. 02OCT97 o proc Tkgnats_config sets new variable TkGnats(HOSTNAME) which checks [info hostname] to get the hostname. This is still overridden by the environment variable HOSTNAME. lock_pr now uses this variable. o Cleaned up proc TkGnats_config somewhat. 29SEP97 o Removed temporary file use when updating PRs in favour of writing directly to the program (or socket) through a pipe. o Removed use of the UNIX "cat" command from perform_print_cmd. 26SEP97 o Gathered up all the TkGnats configuration code into proc TkGnats_config. o Added direct SMTP mail sending, controlled by new variables TkGnats(MailMethod) (mailer or smtp) and TkGnats(SMTP_SERVER) and TkGnats(SMTP_PORT). o Added direct gnatsd socket communication, controlled by new variables TkGnats(GNATS_SERVER) and TkGnats(GNATS_PORT). Network access to gnatsd can be batch (nquery-pr/npr-edit) or direct socket connections and is controlled by the variable TkGnats(GNATS_ACCESS_METHOD) (batch or socket). "socket" is recommended. Don't bother with the batch method. o Changed internal variable Tksendpr(Organization) to TkGnats(ORGANIZATION). o Added lots of configuration info to the Help/About menu item. ================ Changes in 2.0b7 ================ TkGnats 2.0b7 requires at least gnats-3.104-beta. This release was never used outside of my office. 25SEP97 o In preparation for direct communication with SMTP, the mail sending code has been rearranged. Mail is built into a string instead of written to a temporaty file and piped directly to TkGnats(Mailer). o Made the determination of ReleaseBased automatic, and removed the variable from tkgnats.config (which would now be overridden). o Changed the GNATS config variable of GNATS_SITE to SUBMITTER in the TkGnats Makefile as the value that needs to be set. GNATS_SITE is no longer used by TkGnats. o Changed the grep in the Makefile of the GNATS config file to be anchored at the beginning of lines so it finds SUBMITTER, not DEFAULT_SUBMITTER. o The internal variable TkGnats(Submitter-Id) is now TkGnats(SUBMITTER). This is the value of SUBMITTER from the GNATS config file. 22SEP97 o The category in the TkSendpr dialog may be pre-set with the variable TkGnats(TksendprCategory). o The pr mail header field "X-send-pr-version" is now set to the TkGnats version rather than the send-pr version, since we don't use send-pr. example: X-send-pr-version: tkgnats-2.0b7 I don't know that anybody uses this for anything other than debugging. o The "About" item in the "Help" menu now shows if you're accessing a local or network GNATS database. The GNATS server hostname is given, if known. o The variables GNATS_ROOT and LIBEXECDIR are now passed around TkGnats as TkGnats(GNATS_ROOT) and TkGnats(GNATS_LIBEXECDIR) respectively. o Added the variable CHECK_CFG to the Makefile. You can make TkGnats even if GNATS isn't installed with: make CHECK_CFG=no o The run-time configuration, which checks for certain environment variables, now happens after $TKGNATSLIB/tkgnats.config and any and all of the optional "tkgnatsrc" files have been read. 13SEP97 o Network support for the GNATS gnatsd daemon! o Added variables TkGnats(GNATS_ACCESS) and TkGnats(GNATS_SERVER) to tkgnats.config to set "local" GNATS database or "network" daemon access. o The Query action "Delete PERMANENTLY" is limited to local GNATS databases. o The command line arguments to the various executables in TkGnats (tksendpr, tkquerypr, tkeditpr and tkviewpr) have changed to improve performance (especially for network access) by passing along more information. o Fixed a bug where the Save Query option would fail if GNATS was _not_ configured --with-release-based. o TkGnats now uses query-pr to get the GNATS categories, submitters and responsible lists. Therefore, the following variables have been removed from tkgnats.config: TkGnats(CategoriesFile), TkGnats(SubmittersFile), TkGnats(ResponsibleFile), GNATS_BASE TkGnats(ResponsibleFile) is a variable used for a different purpose now. o Removed the TkGnats(pr_editor) variable from tkgnats.config. This is hardwired and shouldn't have been a variable. o Removed the TkGnats(pr-addr) variable from tkgnats.config. This simple function is now implemented internally in TkGnats. o The format of the Saved Queries has changed greatly (much simpler and not so dependent on TkGnats internal code) but the old format can still be read. o Fixed highlighting around active entry and text widgets. o Generally removed various bits of dead code. o Improved the quick-fill entry fields slightly. It's now impossible to erase the value in the field once it contains a value from the listbox. ================ Changes in 2.0b6 ================ TkGnats 2.0b6 requires at least gnats-3.104-beta. 20AUG97 o No visible changes or fixes. Only the installation configuration has changed to match and be consistent with the latest GNATS beta 3.104. o The Makefile now matches the new GNATS "LIBEXECDIR". The default is /usr/local/libexec to match GNATS beta 3.104. o The TkGnats files that go into TKGNATSLIB are platform-independent and have been moved from /usr/local/lib/tkgnats to /usr/local/share/tkgnats. This matches the default location for the GNATS platform-independent files, which is /usr/local/share/gnats. If you have been using the old location you should move or copy all the files and subdirectories to the new location _before_ installing TkGnats 2.0b6. This will preserve your old settings and any global queries, sorts and print functions. If you installed the new release first, then simply copy the old files then run "make install" again. Please make sure that you do _not_ have any set statements for TkGnats(lib) in tkgnats.config or any of the optional "tkgnatsrc" files. The setting of this variable now only occurs in the main executables (such as tkgnats, tksendpr, etc) and is configured by the Makefile. o Changed tksendpr to get the send-pr version dynamically by executing "send-pr --version". o This change was made in 2.0b5 but I forgot to add it to the Changes: Several values in $TKGNATSLIB/tkgnats.config can be overridden at runtime. At runtime, TkGnats checks for the environment variable "GNATS_ROOT". If it exists, the GNATS config file $GNATS_ROOT/gnats-adm/config is scanned for the following values: GNATS_ADDR, GNATS_USER, GNATS_SITE, Submitter-Id which reset the following TkGnats variables: TkGnats(GNATS_ADDR), TkGnats(GNATS_USER), GNATS_ROOT, GNATS_BASE, TkGnats(GNATS_SITE), TkGnats(Submitter-Id) GNATS_ROOT also gives TkGnats the locations of the following GNATS files: categories, submitters, responsible by resetting the following TkGnats variables: TkGnats(CategoriesFile), TkGnats(SubmittersFile), TkGnats(ResponsibleFile) This happens _after_ $TKGNATSLIB/tkgnats.config is read but _before_ any of the following optional files are read: $TKGNATSLIB/tkgnatsrc $TKGNATSLIB/tkgnatsrc. ~/.tkgnats/tkgnatsrc ~/.tkgnats/tkgnatsrc. The is the result from the command "uname -s". For example, tkgnatsrc.SunOS, or tkgnatsrc.Linux. ================ Changes in 2.0b5 ================ TkGnats 2.0b5 is compatable only with gnats-3.102-beta. It was in the contrib directory of gnats-3.103, but gnats-3.103 was short-lived due to errors in its Makefile. It was also in the contrib directory of gnats-3.103, but it's Makefile was not compatable with GNATS's Makefile. 31JUL97 o Fixed tkeditpr to handle categories longer than 16 characters. 30JUL97 All of the following fixes were provided by Jonathan I. Kamens: o Don't delete the VERSION file in the "clean" rule, since it's part of the distribution and therefore shouldn't be deleted when the user just wants to remove derived objects. o Support the "Keywords" PR field with the new configuration option TkGnats(ReleaseBased) is true. o Rename default_sort to default_sort.old when renaming ~/TkGnats to ~/.tkgnats, since the old format of default_sort isn't compatible with the new one. o Put back the functionality for doing a query from the current X selection, using a "Query Selection" item on the "Query" menu, and augment it by allowing the selection to contain multiple PR numbers rather than just one. o Don't truncate search patterns when doing queries. o When doing queries, don't fail if a field we're querying doesn't actually exist in the queried PR. This is necessary because not all fields are present in all PRs. o Added TkGnats(MsMacroSet) to tkgnats.config. This sets the name of the macros for groff, typically "-ms" or "-mgs". 29JUL97 o Added Category to subject line of email sent from tkeditpr. 14JUL97 o Fixed bug in tkeditpr where it would incorrectly form the subject line when clicking "Send Email...". It used "Re: nnn:" instead of "Re: category/nnn:". o Added an "About" item to all of the Help menus to show the TkGnats version number. 11JUL97 o Improved TkGnats(LogName) determination throughout. 08JUL97 o Replaced several physical temporary files with internal Tcl variables in tkeditpr. 06JUL97 o Replaced internal Tcl code with calls to query-pr for the new gnats-3.102 options --synopsis and --release. REGEXP searches are now always done by query-pr and work properly. The regexp's are passed directly to query-pr and do not require quoting. For example, this is OK in the Synopsis field: this error|that error 04JUL97 o Added synopsys to the Subject line of created bug reports. Nobody usually sees this anyway, since GNATS does this too. o Changed the default for TkGnats(TextWrap) in tkgnats.config from "none" to "word". o Added TkGnats(delete_authorized_groups), TkGnats(GNATS_USER) and TkGnats(delete_authorized_users) to tkgnats.config. These turn on a new "Delete PERMANENTLY" option in the Actions menu of the Query dialog. Since GNATS_ROOT/gnats-adm/index and the PR files are usually writable only by the GNATS_USER, GNATS_USER is the default for TkGnats(delete_authorized_users). ================ Changes in 2.0b4 ================ TkGnats 2.0b4 is compatable with gnats beta releases up to gnats-3.102-beta. 06MAY97 o Tweaked Makefile again to work on Solaris, IRIX64 and Linux. o Fixed chmod in Makefile. o Added missing help for Last-Modified. o Removed call to old workingMsg (busy symbol) in synopsis_summary. o Removed "exec date" in synopsis_summary. o Renamed tkgnats.cf.t to tkgnats.config. 04MAY97 o Updated manpages and added them to Makefile install/uninstall. o Renamed sortDialog.tcl to tkprsort.tcl. o Renamed reports.tcl to tkprprint.tcl. o Fixed valid filename checking when saving and renaming queries and sorts. o Added TO-DO list. 03MAY97 o Makefile improvements. o Added the GNU COPYING file for copyright. o Removed "exec date" in favour of built-in Tcl "clock" command. o Removed "exec rm/mv/cp" in favour of built-in Tcl "file" commands. o Removed "exec cat" in favour of built-in open/read/close commnads. o Removed "exec grep" and "exec sed" in favour of built-in commnads. 01MAY97 o Makefile improvements. o Removed all old files that were no longer used. o Updated README and FILES. o Converted tkeditpr from sh script to tcl. o Combined tkeditpr and tkeditpr.tcl. Deleted tkeditpr.tcl. o Got rid of msgDialog. Use tk_dialog instead. o Got rid of the "busy" symbol on the status line in tkquerypr. ================ Changes in 2.0b3 ================ 24APR97 o Reworked email handling to support these email address formats: # 01: "Rick Macdonald" and Rick Macdonald # 02: rickm@vsl.com (Rick Macdonald) # 03: rickm@vsl.com o Added TkGnats Documentation button to the TkGnats main menu. It currently only describes the flow of email. 23APR97 o Originator field changed back to be just the real name of the actual submitter. It's no longer used as an email address. o Added Reply-To field to Create, View and Edit windows. This is a comma-separated list of email addresses and should include the Originator's email address. This was to maintain compatibility with other gnats front-ends (emacs, www). o Send Email can toggle off individuals fom the Reply-To field. o Send Email can now toggle off GNATS_ADDR (eg bugs) if desired. ================ Changes in 2.0b2 ================ 15MAY97 o User rc dir changed from ~/TkGnats to ~/.tkgnatsrc. Previous dir, if any, will get renamed. o Other changes, but I wasn't keeping track yet. ============== Changes in 2.0 ============== o Complete overhaul of TkGnats interface. o This was the first TkGnats that I sent out. It got onto the Debian 1.3 release. It should have been numbered 2.0b1. gnats-4.1.0/contrib/tkgnats/CONFIG-server.tkgnatsrc0000644000175000017500000000132207005513656022675 0ustar chewiechewie00000000000000# Server-specific TkGnats rc file for Win95/98/NT. # Use globally for all users at a site. # Copy this file to "$TkGnats(TKGNATSLIB)/'ServerDir'/tkgnatsrc" # 'ServerDir' is the 5th field from the TkGnats(Servers) entry. # # Tell TkGnats what the GNATS server wants to know about your Site # set TkGnats(SUBMITTER) calgary set TkGnats(ORGANIZATION) "VSL Calgary" # # These set defaults in the "Create Problem Report" dialog and are optional # #set TkGnats(CreateDefaultCategory) Chores set TkGnats(CreateDefaultClass) support #set TkGnats(CreateDefaultClass) sw-bug #set TkGnats(CreateDefaultPriority) medium #set TkGnats(CreateDefaultSeverity) serious #set TkGnats(CreateDefaultConfidential) no gnats-4.1.0/contrib/tkgnats/CONFIG-servers0000644000175000017500000000050707005513656021065 0ustar chewiechewie00000000000000# Server list for TkGnats # Copy this file to "$TkGnats(TKGNATSLIB)/servers" # # Tell TkGnats about the GNATS Servers # # server fields: Title GNATS_SERVER GNATS_PORT GNATS_ADDR ServerDir GNATSDatabaseAlias set TkGnats(Servers) { "Widget Bugs" srv.widget.com 1529 bugs@widget.com bugs.srv.widget.com bugs.srv.widget.com } gnats-4.1.0/contrib/tkgnats/CONFIG-single-user.ini0000644000175000017500000000434107005513656022407 0ustar chewiechewie00000000000000# ALTERNATE Single-User TkGnats ini file for Win95/98/NT. # This file simply contains all the information from the servers file, # CONFIG-user.ini, CONFIG-site.tkgnatsrc and CONFIG-server.tkgnatsrc. # Copy it to $TkGnats(UserDir)/tkgnats.ini # Windows: TkGnats(UserDir) is {home}/tkgnats # where {home} is any directory that belongs to an individual. # UNIX: TkGnats(UserDir) is $HOME/.tkgnats ######################################################### ######## This is the CONFIG-servers file section ######## ######################################################### # # Tell TkGnats about the GNATS Servers # # server fields: Title GNATS_SERVER GNATS_PORT GNATS_ADDR ServerDir GNATSDatabaseAlias set TkGnats(Servers) { "Widget Bugs" srv.widget.com 1529 bugs@widget.com bugs.srv.widget.com bugs.srv.widget.com } ##################################################### ######## This is the CONFIG-user.ini section ######## ##################################################### # # Tell TkGnats about yourself # set TkGnats(LogName) myname set TkGnats(GroupName) mygroup set TkGnats(FullName) "My Name" set TkGnats(EmailAddr) myname@widget.com # server password fields: GNATS_ADDR userid password set TkGnats(ServerPasswords) { bugs@widget.com rickm sickm } ########################################################### ######## This is the CONFIG-site.tkgnatsrc section ######## ########################################################### # # Tell TkGnats about your mail server # set TkGnats(SMTP_SERVER) mail.widget.com set TkGnats(SMTP_PORT) 25 ############################################################# ######## This is the CONFIG-server.tkgnatsrc section ######## ############################################################# # # Tell TkGnats what the GNATS server wants to know about your Site # set TkGnats(SUBMITTER) calgary set TkGnats(ORGANIZATION) "VSL Calgary" # These set defaults in the "Create Problem Report" dialog and are optional #set TkGnats(CreateDefaultCategory) Chores set TkGnats(CreateDefaultClass) support #set TkGnats(CreateDefaultClass) sw-bug #set TkGnats(CreateDefaultPriority) medium #set TkGnats(CreateDefaultSeverity) serious #set TkGnats(CreateDefaultConfidential) no gnats-4.1.0/contrib/tkgnats/CONFIG-site.tkgnatsrc0000644000175000017500000000036607005513656022342 0ustar chewiechewie00000000000000# Site-specific TkGnats rc file for Win95/98/NT. # Use globally at a site. # Copy this file to "$TkGnats(TKGNATSLIB)/tkgnatsrc". # # Tell TkGnats about your mail server # set TkGnats(SMTP_SERVER) comsrv1.vsl.com set TkGnats(SMTP_PORT) 25 gnats-4.1.0/contrib/tkgnats/CONFIG-user.ini0000644000175000017500000000121207005513656021122 0ustar chewiechewie00000000000000# User TkGnats ini file for Win95/98/NT. # Each individual user gets a copy of this file. # Copy it to $TkGnats(UserDir)/tkgnats.ini # Windows: TkGnats(UserDir) is {home}/tkgnats # where {home} is any directory that belongs to an individual. # UNIX: TkGnats(UserDir) is $HOME/.tkgnats # # Tell TkGnats about yourself # set TkGnats(LogName) myname set TkGnats(GroupName) mygroup set TkGnats(FullName) "My Name" set TkGnats(EmailAddr) myname@widget.com # # Tell TkGnats about the GNATS Server passwords # # server password fields: GNATS_ADDR userid password set TkGnats(ServerPasswords) { bugs@widget.com rickm sickm } gnats-4.1.0/contrib/tkgnats/COPYING0000644000175000017500000004307606665615034017555 0ustar chewiechewie00000000000000 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. gnats-4.1.0/contrib/tkgnats/FILES0000644000175000017500000000463007005513656017274 0ustar chewiechewie00000000000000CHANGES - Update history. CONFIG-server.tkgnatsrc CONFIG-single-user.ini CONFIG-site.tkgnatsrc CONFIG-user.ini - These are sample configuration files for Windows 95/98/NT, but can be used for UNIX installations as well. CONFIG-servers - Example servers file. COPYING - GNU GENERAL PUBLIC LICENSE, Version 2 FILES - This file. Makefile - Make file to build and install tkgnats on UNIX systems. Note: it needs 'which' and 'sed' to work right. README.config - Installation and configuration notes. README.first - General TkGnats information. README.unix - UNIX specific notes. README.windows - Windows 95/98/NT specific notes. TECHNOTES - I made this list for myself to help sort out design and configuration issues. TO-DO - To Do list of things that might get done someday. VERSION - Holds the version number and date when this release was made. This gets put into the menu items Help/About. WIN-tkgnats.tcl - This is the file that is executed by the Windows Shortcut. print/* - Some print formaters used in the 'Print' menu of tkquerypr. query/* - Some saved query settings used in the 'Query' menu of tkquerypr. sort/* - Some saved sort settings used in the 'Sort' menu of tkquerypr. tkeditpr - Tk version of edit-pr, called from tkquerypr. tkeditpr.xbm - tkeditpr's icon. tkgnats - tkgnats main menu. Calls tkquerypr. tkgnats.1 - Man page for tkviewpr. tkgnats.config - Site dependent configuration. tkgnats.doc - A tkgnats document accessible from the main menu. tkgnats.xbm - An icon for the tkgnats script. tkprdatesel.tcl - Tcl/Tk code for the date selector dialog. tkpr_library.tcl - Tcl procs shared by all of the tkgnats scripts. tkprfolder.tcl - Tk code to handle saved queries and sorts. Used by tkquerypr. tkprfont.tcl - A font selector for the Edit/Fonts menus. tkprhelp.tcl - Help file for the Help menus. tkprprint.tcl - Where most of the printed report formatting is done. Used by tkquerypr. tkprsort.tcl - A tk script to select the sort order for the Query listbox. Used by tkquerypr. tkquerypr - Submit, query, view, print and edit bug reports. tkquerypr.xbm - tkquerypr's icon. tksendpr - Create and send new problem reports. Called by tkquerypr. tksendpr.xbm - tksendpr's icon. tkviewpr - Tk problem report viewer. gnats-4.1.0/contrib/tkgnats/Makefile0000644000175000017500000002601607642176774020166 0ustar chewiechewie00000000000000################################################# ################################################# #### Section 1. Manual Configuration section #### ################################################# ################################################# # WISHPROG can be a full path or just program name. WISHPROG = wish # Set GNATS=network if you _are_ using the GNATS daemon "gnatsd". # Set GNATS=local if you're going to access disk files directly. GNATS = network # Set CHECK_CFG=no if GNATS=local but GNATS is not actually installed yet. CHECK_CFG = yes ########## TkGnats installation locations prefix = /usr/local ########## tkgnats executable location BINDIR = $(prefix)/bin ########## tkgnats.1 man directory MANDIR = $(prefix)/man ########## TkGnats is installed here TKGNATSLIB = $(prefix)/share/tkgnats4 ########## Existing GNATS installation locations (required if _not_ using GNATS daemon) ########## location of GNATS pr-edit/npr-edit programs LIBEXECDIR = $(prefix)/libexec ########## location of GNATS database GNATS_ROOT = $(prefix)/share/gnats/gnats-db ################################################################################ ### If GNATS=network, the following variables are not used. ### ################################################################################ #SUBMITTER = YourSubmitterSite #GNATS_ADDR = bugs@bugsrus.com #GNATS_USER = gnats # include local overrides so that CVS stays pure. -include Makefile.local ######################################################################### ######################################################################### ### Section 2. You shouldn't have to change anything below this point ### ######################################################################### ######################################################################### VERSION = tkgnats-4.0-beta1 MAKEPATH = mkdir -p SED = sed GNATS_ROOT_REPL =set TkGnats(GNATS_ROOT) $(GNATS_ROOT); \#\#GNATS_ROOT\#\# GNATS_ROOT_SED =-e "s,^.*\#\#GNATS_ROOT\#\#,$(GNATS_ROOT_REPL)," SUBMITTER_REPL =set TkGnats(SUBMITTER) $(SUBMITTER); \#\#SUBMITTER\#\# SUBMITTER_SED =-e "s,^.*\#\#SUBMITTER\#\#,$(SUBMITTER_REPL)," GNATS_ADDR_REPL =set TkGnats(GNATS_ADDR) $(GNATS_ADDR); \#\#GNATS_ADDR\#\# GNATS_ADDR_SED =-e "s,^.*\#\#GNATS_ADDR\#\#,$(GNATS_ADDR_REPL)," GNATS_USER_REPL =set TkGnats(GNATS_USER) $(GNATS_USER); \#\#GNATS_USER\#\# GNATS_USER_SED =-e "s,^.*\#\#GNATS_USER\#\#,$(GNATS_USER_REPL)," LIBEXECDIR_REPL =set TkGnats(GNATS_LIBEXECDIR) $(LIBEXECDIR); \#\#LIBEXECDIR\#\# LIBEXECDIR_SED =-e "s,^.*\#\#LIBEXECDIR\#\#,$(LIBEXECDIR_REPL)," TKGNATSLIB_REPL =set TkGnats(lib) $(TKGNATSLIB); \#\#TKGNATSLIB\#\# TKGNATSLIB_SED =-e "s,^.*\#\#TKGNATSLIB\#\#,$(TKGNATSLIB_REPL)," WISH_SED =-e "3s,^exec wish ,exec $(WISHPROG) ," T_LIB = _tlib T_BIN = _tbin tkgnatsbin= \ $(T_BIN)/tkgnats xbmfiles= \ $(T_LIB)/tkeditpr.xbm \ $(T_LIB)/tkgnats.xbm \ $(T_LIB)/tkquerypr.xbm \ $(T_LIB)/tksendpr.xbm tkgnatslib= \ $(T_LIB)/tkgnats.config \ $(T_LIB)/tkeditpr.tcl \ $(T_LIB)/tkgnats.doc \ $(T_LIB)/tkprdatesel.tcl \ $(T_LIB)/tkpr_library.tcl \ $(T_LIB)/tkprfolder.tcl \ $(T_LIB)/tkprfont.tcl \ $(T_LIB)/tkprhelp.tcl \ $(T_LIB)/tkprprint.tcl \ $(T_LIB)/tkprsort.tcl \ $(T_LIB)/tkquerypr.tcl \ $(T_LIB)/tksendpr.tcl \ $(T_LIB)/tkviewpr.tcl \ $(T_LIB)/CHANGES \ $(T_LIB)/VERSION \ $(xbmfiles) manfiles= tkgnats.1 all: check_cfg dirs $(tkgnatslib) $(tkgnatsbin) # WARNING: the tests below involving GNATS_ADDR and SUBMITTER # are very sensitive to having quotes (or not) with various # bourne/bash shells. Don't mess with them unless they # fail. They are the way they are to make it work for # /bin/sh on Solaris 2.5 and IRIX64 6.2 and bash on Linux. # This is all due to the nested backticks and single and double quotes. check_cfg: @echo " " @cat VERSION @echo " " @if [ ! $(GNATS) = network -a $(CHECK_CFG) = yes ]; then \ rm -f /tmp/tkgnats.errors; \ echo "Checking the Makefile configuration variables for your GNATS setup..."; \ echo "---------------------------------------------------------------------"; \ echo " "; \ if [ ! -d $(LIBEXECDIR)/gnats ]; then \ echo "*** Error: Cannot find '$(LIBEXECDIR)/gnats'."; \ touch /tmp/tkgnats.errors; \ else \ echo \'$(LIBEXECDIR)\' is the configured path for GNATS LIBEXECDIR.; \ fi; \ if [ x$(SUBMITTER) = "x" ]; then \ echo " Set SUBMITTER in this file to the name of your site. "; \ echo " GNATS and TkGnats use it as your Submitter-Id."; \ touch /tmp/tkgnats.errors; \ else \ echo \'$(SUBMITTER)\' is the configured name for SUBMITTER.; \ fi; \ if [ x$(GNATS_ADDR) = "x" ]; then \ echo " Set GNATS_ADDR in this file to the email address that gnats"; \ echo " bugs are supposed to be sent to. It's probably missing due to"; \ echo " an old bug in the GNATS installation Makefile."; \ touch /tmp/tkgnats.errors; \ else \ echo \'$(GNATS_ADDR)\' is the configured mail address for GNATS_ADDR.; \ fi; \ if [ x$(GNATS_USER) = "x" ]; then \ echo " Set GNATS_USER in this file to the gnats administrator user id."; \ touch /tmp/tkgnats.errors; \ else \ echo \'$(GNATS_USER)\' is the configured user id for GNATS_USER.; \ fi; \ if [ -f /tmp/tkgnats.errors ]; then \ echo "*** Errors have been detected. Make aborted."; \ echo "*** If you don't have GNATS installed locally, run make with CHECK_CFG=no."; \ rm -f /tmp/tkgnats.errors; \ exit 1; \ fi; \ echo " "; \ echo "Done checking GNATS configuration."; \ echo "----------------------------------"; \ echo " "; \ elif [ ! $(GNATS) = network ]; then \ echo "By-passed checking GNATS configuration."; \ echo "---------------------------------------"; \ echo " "; \ echo \'$(LIBEXECDIR)\' is the configured path for GNATS LIBEXECDIR.; \ echo \'$(SUBMITTER)\' is the configured name for SUBMITTER.; \ echo \'$(GNATS_ADDR)\' is the configured mail address for GNATS_ADDR.; \ echo \'$(GNATS_USER)\' is the configured user id for GNATS_USER.; \ echo " "; \ fi uninstall: uninstall_tkgnatsbin uninstall_tkgnatslib uninstall_man uninstall_tkgnatsbin: for f in $(tkgnatsbin); do \ rm -if "$(BINDIR)/`basename $$f`"; \ done uninstall_tkgnatslib: for f in $(tkgnatslib); do \ rm -if "$(TKGNATSLIB)/`basename $$f`"; \ done uninstall_man: for f in $(manfiles); do \ rm -if $(MANDIR)/man1/$$f; \ done clean: rm -rf $(T_LIB) $(T_BIN) *~ dirs: @-$(MAKEPATH) $(T_LIB) @-$(MAKEPATH) $(T_BIN) install: all install_tkgnatsbin install_tkgnatslib install_tkgnatsbin: -$(MAKEPATH) $(BINDIR) cp -p $(T_BIN)/* $(BINDIR)/ install_tkgnatslib: -$(MAKEPATH) $(TKGNATSLIB) cp -p $(T_LIB)/* $(TKGNATSLIB)/ -$(MAKEPATH) $(TKGNATSLIB)/print -$(MAKEPATH) $(TKGNATSLIB)/query -$(MAKEPATH) $(TKGNATSLIB)/sort cp -p `find print \( -type f -print \) -or \( -name CVS -prune \)` $(TKGNATSLIB)/print/ cp -p `find query \( -type f -print \) -or \( -name CVS -prune \)` $(TKGNATSLIB)/query/ cp -p `find sort \( -type f -print \) -or \( -name CVS -prune \)` $(TKGNATSLIB)/sort/ install_man: -$(MAKEPATH) $(MANDIR) -$(MAKEPATH) $(MANDIR)/man1 @chmod 664 $(manfiles) for f in $(manfiles); do \ cp -p $$f $(MANDIR)/man1/$$f; \ done $(T_BIN)/tkgnats: tkgnats Makefile $(SED) $(WISH_SED) $(TKGNATSLIB_SED) $@ @chmod 775 $@ $(T_LIB)/CHANGES: CHANGES cp -p CHANGES $@ @chmod 664 $@ $(T_LIB)/VERSION: VERSION cp -p VERSION $@ @chmod 664 $@ $(T_LIB)/tkeditpr.tcl: tkeditpr.tcl Makefile cp -p tkeditpr.tcl $@ @chmod 664 $@ $(T_LIB)/tkviewpr.tcl: tkviewpr.tcl Makefile cp -p tkviewpr.tcl $@ @chmod 664 $@ $(T_LIB)/tksendpr.tcl: tksendpr.tcl Makefile cp -p tksendpr.tcl $@ @chmod 664 $@ $(T_LIB)/tkquerypr.tcl: tkquerypr.tcl Makefile cp -p tkquerypr.tcl $@ @chmod 664 $@ $(T_LIB)/tkprdatesel.tcl: tkprdatesel.tcl Makefile cp -p tkprdatesel.tcl $@ @chmod 664 $@ $(T_LIB)/tkprfolder.tcl: tkprfolder.tcl Makefile cp -p tkprfolder.tcl $@ @chmod 664 $@ $(T_LIB)/tkprfont.tcl: tkprfont.tcl Makefile cp -p tkprfont.tcl $@ @chmod 664 $@ $(T_LIB)/tkpr_library.tcl: tkpr_library.tcl Makefile cp -p tkpr_library.tcl $@ @chmod 664 $@ $(T_LIB)/tkprprint.tcl: tkprprint.tcl Makefile cp -p tkprprint.tcl $@ @chmod 664 $@ $(T_LIB)/tkprsort.tcl: tkprsort.tcl Makefile cp -p tkprsort.tcl $@ @chmod 664 $@ $(T_LIB)/tkprhelp.tcl: tkprhelp.tcl Makefile cp -p tkprhelp.tcl $@ @chmod 664 $@ $(T_LIB)/tkgnats.doc: tkgnats.doc Makefile cp -p tkgnats.doc $@ @chmod 664 $@ # Again, the following ugliness is intentional and works on Linux, Solaris 2.5 and IRIX64 6.2. $(T_LIB)/tkgnats.config: tkgnats.config Makefile @if [ ! $(GNATS) = network ]; then \ tempsubm=$(SUBMITTER); \ tempsubmrepl="set TkGnats(SUBMITTER) $$tempsubm; \#\#SUBMITTER\#\#"; \ tempsubmsed='s,^.*\#\#SUBMITTER\#\#,'$$tempsubmrepl,; \ tempaddr=$(GNATS_ADDR); \ tempaddrrepl="set TkGnats(GNATS_ADDR) $$tempaddr; \#\#GNATS_ADDR\#\#"; \ tempaddrsed='s,^.*\#\#GNATS_ADDR\#\#,'$$tempaddrrepl,; \ tempuser=$(GNATS_USER); \ tempuserrepl="set TkGnats(GNATS_USER) $$tempuser; \#\#GNATS_USER\#\#"; \ tempusersed='s,^.*\#\#GNATS_USER\#\#,'$$tempuserrepl,; \ $(SED) $(LIBEXECDIR_SED) \ $(GNATS_ROOT_SED) \ -e "$$tempsubmsed" \ -e "$$tempaddrsed" \ -e "$$tempusersed" \ $@; \ echo $(SED) $(LIBEXECDIR_SED) \ $(GNATS_ROOT_SED) \ -e "$$tempsubmsed" \ -e "$$tempaddrsed" \ -e "$$tempusersed" \ \$@; \ else \ echo cp -p tkgnats.config $@; \ cp -p tkgnats.config $@; \ fi; @chmod 664 $@ # The following was OK on my Linux system but failed on Solaris and IRIX64. #$(T_LIB)/tkgnats.config: tkgnats.config Makefile # $(SED) $(LIBEXECDIR_SED) \ # $(GNATS_ROOT_SED) \ # $(SUBMITTER_SED) \ # $(GNATS_ADDR_SED) \ # $(GNATS_USER_SED) \ # $@ $(T_LIB)/tkgnats.xbm: tkgnats.xbm Makefile cp -p tkgnats.xbm $@ @chmod 664 $@ $(T_LIB)/tkquerypr.xbm: tkquerypr.xbm Makefile cp -p tkquerypr.xbm $@ @chmod 664 $@ $(T_LIB)/tksendpr.xbm: tksendpr.xbm Makefile cp -p tksendpr.xbm $@ @chmod 664 $@ $(T_LIB)/tkeditpr.xbm: tkeditpr.xbm Makefile cp -p tkeditpr.xbm $@ @chmod 664 $@ package: clean rm -f VERSION echo "This is version ${VERSION} and was made by $$LOGNAME@`hostname` on" > VERSION date >> VERSION echo untarit > /tmp/tkgnpkg.exclude dir=`pwd | sed -e "s:.*/::g"`; \ fil=$$dir.tar.gz; \ rm -f $$fil; \ rm -rf _tbin _tlib $$dir.zip; \ cd ..; \ tar -cvf - -X /tmp/tkgnpkg.exclude $$dir | gzip -9c > $$fil; \ rm -rf /tmp/tkgnpkg.exclude; \ mv $$fil $$dir; \ cd $$dir; \ zip -rl9 $$dir.zip * -x *.gz untarit; \ ls -l $$fil $$dir.zip sed_check: (cd $(T_BIN); fgrep usr *) >/tmp/cfg_check.bin (cd $(T_LIB); fgrep usr *) >/tmp/cfg_check.lib more /tmp/cfg_check.bin /tmp/cfg_check.lib # # do not use these rules !!! these are for tkgnats development only !! # __all: make 'SUBMITTER=calgary' 'GNATS_ADDR=bugs' all __check: make 'SUBMITTER=calgary' 'GNATS_ADDR=bugs' check_cfg __install: make 'SUBMITTER=calgary' 'GNATS_ADDR=bugs' install gnats-4.1.0/contrib/tkgnats/README0000644000175000017500000000751107005513656017370 0ustar chewiechewie00000000000000 QuickStart ========== Read all the README files. ;-) (They're not that long.) What is TkGnats? ================ TkGnats is Tcl/Tk-based front end for the GNATS bug management system. While GNATS itself only runs on UNIX platforms, TkGnats runs on UNIX and Windows 95/98/NT (as of version 3.0.0). It could probably be fixed to run on the Mac, but I'm not able to work on this myself. On UNIX systems, TkGnats can access the GNATS database from local or nfs-mounted disk. UNIX and Windows 95/98/NT systems can access the GNATS database through the GNATS network daemon "gnatsd". I highly recommend UNIX users use the GNATS daemon instead of accessing the GNATS files directly from disk. Performance is often better through gnatsd, especially if the GNATS database is NFS mounted. Screenshots, the latest version of TkGnats and other GNATS resources are available at the TkGnats Home Page: http://www.cuug.ab.ca/~macdonal/tkgnats What is GNATS? ============== You can get the latest GNATS from ftp://sourceware.cygnus.com/pub/gnats/snapshots or an ftp site near you that mirrors the GNU software. It will be called something like gnats-3.110-beta.tar.gz. Do not use the very old and obsolete gnats-3.2 that is on many web archives. Here is a fragment from the GNATS info file that describes GNATS in a nutshell... This manual documents a suite of utilities called `GNATS', the GNU Problem Report Management System. `GNATS' is a bug-tracking tool designed for use at a central support site. Software users who experience problems use electronic mail to communicate these problems to the maintainers of that software; `GNATS' partially automates the tracking of these problem reports ("PR"s) by: * organizing problem reports into a database and notifying responsible parties of suspected bugs; * allowing support personnel and their managers to edit and query accumulated bugs; and * providing a reliable archive of problems with a given program and a history of the life of the program by preserving its reported problems and their subsequent solutions. What is Tcl/Tk? =============== Tk is an X toolkit that uses a interpreted language called Tcl. If you want to know more about Tk/Tcl check out the Tcl/Tk website http://www.scriptics.com and the FAQ for the comp.lang.tcl newsgroup. This version of TkGnats uses Tcl/Tk8.0 or newer. It will not work with anything older. You can get Tcl and Tk from http://www.scriptics.com/download. The Author ========== This version of TkGnats was created by Rick Macdonald from the original version 1.3 by Mike Hoegeman. When I asked Mike if I could release my version to the world he said: From Mike Hoegeman , 26 Oct 1996: "You can do whatever you like contribution-wise as far as I'm concerned, although I would like you to explicitly indicate that I am not responsible/associated with your version of TkGnats in any way." TkGnats Support =============== TkGnats discussions are welcome on the GNATS mailing list. Send a subscription request to bug-gnats-request@gnu.org. Once subscribed, send posts to bug-gnats@gnu.org. I will be happy to answer all questions. Any bug fixes will be gratefully accepted. If you have some enhancements or ideas for enhancements I'm receptive to those too. When sending problems to me, please paste in the contents of the Help/ViewConfigurationVariables menu item that appears in the major TkGnats windows. This helps me answer your questions right away. My email address might change someday. If "rickm@vsl.com" bounces try "rick_macdonald@veritasdgc.com". Be sure to put TKGNATS in the subject line. gnats-4.1.0/contrib/tkgnats/README.config0000644000175000017500000003761307005513656020642 0ustar chewiechewie00000000000000 Configuring TkGnats =================== Configuration Files =================== TkGnats searches for several configuration files. Not one of them is mandatory, but obviously it will need to find at least one in order to run properly in your environment. The only file supplied with TkGnats is "TKGNATSLIB"/tkgnats.config. Never edit this file directly because it will just get overwritten when you install new versions of TkGnats. Group A: user-specified "INI" file (command line or env variable) "TKGNATSLIB"/tkgnatsini "TKGNATSLIB"/servers Group B: "TKGNATSLIB"/tkgnats.config "TKGNATSLIB"/tkgnatsrc "TKGNATSLIB"/tkgnatsrc."operating_system_name" "UserDir"/tkgnatsrc "UserDir"/tkgnatsrc."operating_system_name" "TKGNATSLIB"/"ServerDir"/tkgnatsrc "UserDir"/"ServerDir"/tkgnatsrc Within Group A, each file overrides the previous Group A files. Nothing in Group B overrides Group A. Within Group B, each file overrides the previous Group B files. Configuration file format ========================= The config files are in Tcl, but it should be fairly obvious what you have to do. The only trick is that you need quotes around values that contain spaces: set TkGnats(ORGANIZATION) BugsRUs set TkGnats(ORGANIZATION) "BugsRUs Calgary" TkGnats command line arguments ============================== TkGnats has three command line arguments, which are probably rarely used. -lib This is "TKGNATSLIB". In UNIX, this is patched into the tkgnats script by the Makefile. In Windows, this is set by the command Shortcut. This can also be specified with the environment variable "TKGNATSLIB". -ini This is the "INI" file. Not normally used by UNIX users, and assumed to be "UserDir"/tkgnats.ini in Windows. This can also be specified with the environment variable "TKGNATSINI". -servers This is the servers file. "TKGNATSLIB"/servers by default. This can also be specified with the environment variable "TKGNATSSERVERS". Definitions =========== o "TKGNATSLIB" This is the directory where TkGnats resides. For Windows platforms, this is where the distribution was unzipped. For UNIX platforms, this is where the Makefile installed TkGnats. o "UserDir" This is where an individual user's configuration is stored. This can include fonts, saved queries, etc. For UNIX users, this is typically ~/.tkgnats; for Windows, it's usually a directory called tkgnats in the users directory tree. o "operating_system_name" This comes from the tcl variable tcl_platform(os). This is equivalent to the UNIX "uname -s" command. For example, tkgnatsrc.SunOS, or tkgnatsrc.Linux. o "ServerDir" This only applies if you are accessing a network GNATS daemon, or if you have multiple databases. The 5th field of the "servers" file is a subdirectory name for specific GNATS server or database information. TkGnats creates the directory "UserDir"/"ServerDir". TkGnats servers file ==================== The servers file contains everything TkGnats needs to know to communicate with a GNATS daemon. In the absence of a servers file, TkGnats on UNIX platforms assumes direct access to the GNATS database on local disk. The servers information is also used in the case of multiple databases on a UNIX system with direct disk access to the databases. The servers file normally just contains a Tcl set statement for the TkGnats(Servers) variable. It has one line of six fields for each server that you communicate with. The fields are: 1) TkGnats main menu title - this text string appears on the TkGnats main menu. 2) GNATS_SERVER, the GNATS server hostname (set to {} for local UNIX disk) 3) GNATS_PORT, the GNATS server port number (set to {} for local UNIX disk) 4) GNATS_ADDR, the GNATS server email address - The administrator of the GNATS database will give you this info. 5) "ServerDir" This is used as the subdirectory name for server-specific or database-specific info for TkGnats. You might create the directory "TKGNATSLIB"/"ServerDir" for global server-dependent configuration (ser examples below). TkGnats creates "UserDir"/"ServerDir" for you; that's where it puts your saved queries. - I use a directory name made from the GNATS_ADDR email address up to the "@" symbol followed by a dot followed by the GNATS_SERVER. For example, If GNATS_ADDR is bugs@support.com and the server is gnatssrv.support.com, "ServerDir" would be bugs.gnatssrv.support.com. 6) GNATS Database Alias - The administrator of the GNATS database will give you this info. It's an alias that GNATS relates to its database and is stored in the file /etc/gnats-db.conf on the gnatsd server host. - For multiple databases on UNIX with direct disk access, this is the GNATS_ROOT directory. Here is an example showing two GNATS servers: set TkGnats(Servers) { "Widget Bugs" srv.widget.com 1529 bugs@widget.com bugs.srv.widget.com widget "FooBar bugs" srv.foobar.com 1529 bugs@foobar.com bugs.srv.foobar.com foobar } The server entry for UNIX users to tell TkGnats to access GNATS from local disk files is shown below. I use this so I can easily test both configurations at once. Also, the GNATS_USER (usually gnats) may want direct disk access to enable the menu item Actions/DeletePermanently. This is the only way to delete PR's from within TkGnats. Otherwise, I highly recommend using the gnatsd over direct disk access. Note the "2nd Database" entry with the "ServerDir" and "GNATSDatabaseAlias" entries: set TkGnats(Servers) { "Create/Query Problem Reports" {} {} {} {} {} "2nd Database For Testing" {} {} {} test-db /usr/local/share/gnats/test-db "Widget Bugs" srv.widget.com 1529 bugs@widget.com bugs.srv.widget.com widget } The most direct way for an individual to override a site-wide "servers" file is to use the tkgnats command line "-servers" argument, giving it the file name of your personal server file. GNATS Security ============== As of gnats-3.107-beta, a userid/password scheme is available to control access to the GNATS database. If required, you can configure TkGnats to send your userid and password: set TkGnats(ServerPasswords) { bugs@widget.com rickm sickm bugs@foobar.com foo bar } The first field of ServerPasswords is from the fourth field of the Servers information above. It's the GNATS_ADDR (gnats bugs email address) of the server. The next two fields are your userid and password. Why so many configuration files? ================================ Well, here are some examples. o "TKGNATSLIB"/tkgnatsini I found I needed one global file that was read in before any others, and that didn't need to be specified explicitly on the command line or an environment variable. I actually use code in this file that detects which of our sites TkGnats is being run on and then sources a separate site-specific file. o "TKGNATSLIB"/tkgnats.config This is the one that comes with TkGnats. Don't edit it directly. If you do, it will get overwritten the next time you update TkGnats unless you're careful to make a copy of it first. I suggest copying the required bits to "TKGNATSLIB"/tkgnatsrc and editing that. o "TKGNATSLIB"/tkgnatsrc."operating_system_name" In my office we have SUN and SGI workstations. For postscript viewers, we use "pageview" on the SUNs and "xpsview" on the SGIs. Thus, "TKGNATSLIB"/tkgnatsrc.SunOS contains: set TkGnats(psPreviewer) "pageview %s" and "TKGNATSLIB"/tkgnatsrc.IRIX64 contains: set TkGnats(psPreviewer) "xpsview %s" o "TKGNATSLIB"/"ServerDir"/tkgnatsrc For one of our GNATS databases, we want the default "Class" to be "support" when creating a new problem report. In another, it's set to "change-request". TkGnats Configuration controlled by GNATS ========================================= The following GNATS configuration parameters are called "client hints" because front-end GNATS programs such as gnatsweb and TkGnats are free to support any and all of these configuration options. These options help give GNATS some degree of user-customizable fields until such time as the core GNATS code is modified for complete support. In the absence of the client hints, the default behaviour of any particular front-end client is up to the discretion of the client. The format is comma-separated field names. For example: MANDATORY_FIELDS="Category,Originator,Synopsis,Description" These optional parameters may be placed in the GNATS configuration file gnats-db/gnatas-adm/config. GNATS itself ignores these options. Where defaults are suggested, they are just a guideline to get the same behaviour as the gnats clients send-pr and edit-pr. Please note that GNATS currently has a limit of 255 characters per line in the config file, including the parameter name. FIELD_ALIASES: You can effectively rename any GNATS field with these aliases. The alias only affects the client interface. Behind the scenes, the GNATS PR field still has the original name. Blanks are not allowed in field names. Field names longer than 13 characters will overflow the space alotted for them. Format: field(alias) Example: Release(Source),Quarter(Cost) REQUIRE_AUDIT_TRAIL_ENTRY: Edits to these fields trigger entries in the Audit-Trail. "none" signals no fields. "all" signals all fields. REQUIRE_AUDIT_TRAIL_REASON: Edits to one or more of these fields triggers the prompt of one reason for all changes for the Audit-Trail. "none" signals no fields. "all" signals all fields. REQUIRE_AUDIT_TRAIL_EMAIL: Edits to one or more of these fields trigger the sending of email notification. "none" signals no fields. "all" signals all fields. MANDATORY_FIELDS: SendPR will insist that new PRs have values for these fields. EditPR will insist that editied PRs have values for these fields. "none" signals no fields. "all" signals all fields, but doesn't include Audit-Trail, Unformatted or Release-Note in EditPR because these fields are usually added by GNATS and are often blank for the first part of a PRs life. You can always add these fields if you wish. SUPPRESSED_FIELDS: Fields to suppress from view in all front-end views. SUPPRESSED_FIELDS override MANDATORY_FIELDS if a field appears in both lists. SUPPRESSED_SEND_FIELDS: See "unless" options below. Fields not to present in SendPR. Format: field[(unless)] Default: State,Responsible,Release-Note,Unformatted,Audit-Trail Example: State,Responsible(edit),Release-Note,Audit-Trail SUPPRESSED_EDIT_FIELDS: See "unless" options below. Fields not to present, or to present read-only, in EditPR. It is suggested that front-ends do not allow editing Arrival-Date, Last-Modified and Closed-Date, since these are maintained by GNATS. Format: field[(unless)] Example: Audit-Trail(admin) SUPPRESS "unless" options: Finer control over the showing of fields in SendPR and EditPR. In SendPR, the field is suppressed. In EditPR, the field is suppressed or shown read-only, at the discression or configuration of the front-end. Suppress fields: user - unless the user of the front-end asks for it. edit - unless the user has edit access. edituser - unless the user has edit access and the user of the the front-end asks for it. admin - unless the user has admin access. adminuser - unless the user has admin access and the user of the the front-end asks for it. TkGnats searches the GNATS config file (--list-config|LCFG) for parameters with these names. User specification for not suppressing fields are supplied in TkGnats config files in the format: set TkGnats(${field}In${app}Pr) 1 where $field is any field such as State or Responsible, and $app is Send or Edit. For example: set TkGnats(StateInSendPr) 1 The TkGnats defaults for these parameters are: FIELD_ALIASES "" REQUIRE_AUDIT_TRAIL_ENTRY "Responsible,State,Priority,Severity,Date-Required" REQUIRE_AUDIT_TRAIL_REASON "Responsible,State,Priority,Severity,Date-Required" REQUIRE_AUDIT_TRAIL_EMAIL "Responsible,State,Priority,Severity,Date-Required" SUPPRESSED_FIELDS "none" SUPPRESSED_SEND_FIELDS "State,Responsible,Release-Note,Unformatted,Audit-Trail" SUPPRESSED_EDIT_FIELDS "none" MANDATORY_FIELDS "Class,State,Priority,Severity,Confidential,Category, Submitter-Id,Originator,Synopsis,Description" All field names are the original GNATS field names, not any aliases that you may have specified in FIELD_ALIASES. When creating a new PR, suppressed fields are either sent with CreateDefault{FIELD} values that TkGnats is configured to use or not sent at all, in which case GNATS itself will load blanks or default values. The fields are actually still seen and parsed by TkGnats when viewing and editing, but they just are left off the various windows. There are no default fields that are ignored. "Number" and "Text-Fields" (in the query window) can't be ignored, and at least one multitext field has to be not ignored. Run time Configuration ====================== TkGnats automatically detects if GNATS is configured "release-based" and adds a query fields for the GNATS release-based fields. Some TkGnats values can be set at runtime by setting environment variables. o Instead of command line arguments, you can control tkgnats with the environment variables: TKGNATSLIB TKGNATSINI TKGNATSSERVERS o TkGnats checks for the environment variable REPLYTO. If it exists, TkGnats(EmailAddr) is set to this value rather than TkGnats(LogName). o TkGnats searches the GNATS config file (--list-config|LCFG) for TKGNATS_MIN_VERSION, in which case it will abort if you are running a version of TkGnats older than that specified. The numbers are compared as strings, so 3.0.2 is greater than 3.0.19. I'll have to make sure that all future TkGnats versions are compatable with this check. o This just applies to UNIX users with a local GNATS database: TkGnats checks for the environment variable "GNATS_ROOT". If it exists, the GNATS config file $GNATS_ROOT/gnats-adm/config is scanned for the following values: GNATS_ADDR, GNATS_USER, SUBMITTER which reset the following TkGnats variables: TkGnats(GNATS_ADDR), TkGnats(GNATS_USER), TkGnats(GNATS_ROOT), TkGnats(SUBMITTER) This happens _after_ "TKGNATSLIB"/tkgnats.config and any and all of the next four optional "tkgnatsrc" files (see Groub B above) have been read, but before the two optional "ServerDir"/tkgnatsrc files are read. gnats-4.1.0/contrib/tkgnats/README.unix0000644000175000017500000001257107005513656020354 0ustar chewiechewie00000000000000 Distribution Files ================== The 'Files' file contains a short description of each file in this distribution. Install GNATS ============= If you will have a local GNATS database, you need to first install the latest GNATS (see README.first for more information). Once you get it running and you can send a few bug reports to the 'test' bug category to make sure it's working properly. If you're only accessing a GNATS daemon, just continue and install TkGnats. Install TkGnats =============== o If you are updating a previous TkGnats installation, you should clean up the old files first. Along the way, I have deleted, renamed and moved several TkGnats files. - If you have modified the tkgnats.config file, save a copy as a guide when modifying the new tkgnats.config file. - In the old TkGnats distribution directory, run: make uninstall As of TkGnats version 2.0b6, the TKGNATSLIB moved from /usr/local/lib/tkgnats to /usr/local/share/tkgnats to be consistant with GNATS itself. If you have been using this old location you should move or copy all the remaining files and subdirectories to the new location _after_ running "make uninstall" from the old TkGnats distribution. This will preserve your old settings and any global queries, sorts and print functions. o Edit "Section 1" of the Makefile. Follow the instructions in the Makefile, especially: Set GNATS=network if you _are_ using the GNATS daemon "gnatsd". Set GNATS=local if you're going to access disk files directly. Set CHECK_CFG=no if GNATS=local but GNATS is not actually installed yet. Alternatively, these can be set on the 'make' command line. o Look at "Section 2" of the tkgnats.config file. (The first section is configured by the Makefile.) This sets up things needed by the TkGnats scripts like what postscript viewer to use. There are options described in this file that are not documented elsewhere. I highly recommend copying the interesting bits of the second section of tkgnats.config to "TKGNATSLIB"/tkgnatsrc and editing that. This way, the file won't get overwritten the next time that you update TkGnats. o Run 'make' to configure all the files into two temporary directories (./_tbin and ./_tdir). If you chose to use command line args instead of editing the Makefile: Local GNATS: run 'make' if GNATS is already installed. : run 'make CHECK_CFG=no' if GNATS is not installed yet. Network GNATS: run 'make GNATS=network' Check for any error messages. o Run 'make' again to copy the files in _tbin and _tdir to wherever you defined previously in the first section of the Makefile. If you chose to use command line args instead of editing the Makefile: Local GNATS: run 'make install' if GNATS is already installed. : run 'make CHECK_CFG=no install' if GNATS is not installed. Network GNATS: run 'make GNATS=network install' Check for any error messages. o Optionally execute 'make install_man'. This will install the TkGnats man file to wherever you defined previously in the first section of the Makefile. However, the man file isn't very useful. TkGnats doc exists only in the Help menus. o See the file README.config for more configuration information. o I've had problems with the default colors of CDE on Solaris overriding the Tk color defaults. The following in TKGNATSLIB/tkgnatsrc fixes it up for me: . config -bg grey85 option add *foreground black user option add *background grey85 user option add *highlightBackground grey85 user o TkGnats assumes the following programs are present somewhere within the user's search $PATH: - (g)tbl - For producing PostScript format printed reports. - (g)roff - For producing PostScript format printed reports. - ghostview - For previewing PostScript format printed reports. o You can execute any of the TkGnats dialogs directly by supplying the necessary command line arguments directly or in a wrapper script. The following can all go on one command line for bourne/bash shells: TKGNATSLIB=/usr/local/share/tkgnats ; export TKGNATSLIB ; wish $TKGNATSLIB/tkeditpr.tcl -server "{} {} {} {} {} {}" -prid 1234 or csh: setenv TKGNATSLIB /usr/local/share/tkgnats ; wish $TKGNATSLIB/tkeditpr.tcl -server "{} {} {} {} {} {}" -prid 1234 You could make a script called tkeditpr (and similar ones for tkviewpr, tksendpr and tkquerypr if required): #!/bin/sh TKGNATSLIB=/usr/local/share/tkgnats export TKGNATSLIB wish $TKGNATSLIB/tkeditpr.tcl -server "{} {} {} {} {} {}" -prid $1 For multiple database access, give the "ServerDir" and "GNATSDatabaseAlias" fields: -server "{} {} {} test-db /usr/local/share/gnats/test-db The above are for direct disk access of the GNATS database. If you're accessing the GNATS network daemon, use the proper server argument (note that the first field is for the main menu, which is being bypassed and therefore not required here): -server "{} srv.widget.com 1529 bugs@widget.com bugs.srv.widget.com widget" gnats-4.1.0/contrib/tkgnats/README.windows0000644000175000017500000000661207005513656021062 0ustar chewiechewie00000000000000 Distribution Files ================== The 'Files' file contains a short description of each file in this distribution. Install Tcl/Tk ============== Install Tcl/Tk 8.0 or newer. I haven't tested anything older. A few Windows users have reported socket communication problems with Windows version 8.0(p2). These problems are fixed in TclTk 8.0.3. Printing from Windows not yet supported ======================================= The report generation and printing in TkGnats still depends on UNIX programs, and is therefore not yet available to Windows users. DISCLAIMER ========== I don't use Windows. Suggestions for improvements to the Windows installation and configuration would be welcome. Install TkGnats =============== UnZip the TkGnats distribution file directly into its final location, such as c:\tkgnats. I call this "TKGNATSLIB". TkGnats (Tcl) doesn't like spaces in the pathname, so not _not_ install into c:\Program Files\. Configure for Single-user on a single PC ======================================== o Create a directory for yourself. I called mine C:\home\rickm\tkgnats but it can be anything. Your personal config will be stored here. I call this the "UserDir". o Copy the WIN-tkgnats.tcl file to "UserDir"\tkgnats.tcl. Make a shortcut to it and edit the Properties StartIn directory to be the "TKGNATSLIB" directory where you unzipped TkGnats. You don't need to edit this file. o Copy the CONFIG-single-user.ini file to "UserDir"\tkgnats.ini. Edit it as required, giving your specific user, site and server information. o Have a look at the tkgnats.config file. Anything that you'd like to change, copy those lines into a new file "TKGNATSLIB"/tkgnatsrc. If you edit the tkgnats.config directly, it can get overwritten the next time that you update TKGnats (if you use the same directory). o Place the shortcut on the desktop or in a menu, and you're all done! Configure for Multi-users on one or more PCs ============================================ o Each individual needs the "WIN-tkgnats.tcl file" copied to "UserDir"\tkgnats.tcl and a shortcut created, as explained above in the "Single-user" section. o The CONFIG-single-user.ini file contains the combined information from the actual CONFIG-servers, CONFIG-user.ini, CONFIG-site.tkgnatsrc and CONFIG-server.tkgnatsrc files. For multi-users accessing one or more GNATS servers, you would use the actual configuration files as follows: CONFIG-servers: Server list for TkGnats Copy to "$TKGNATSLIB"/servers CONFIG-site.tkgnatsrc: Site-specific TkGnats rc file Copy to "TKGNATSLIB"/tkgnatsrc CONFIG-server.tkgnatsrc: Server-specific TkGnats rc file Copy to "TKGNATSLIB"/"ServerDir"/tkgnatsrc CONFIG-user.ini: User TkGnats ini file Copy to "UserDir"/tkgnats.ini o Have a look at the tkgnats.config file. There are options described in this file that are not documented elsewhere. If you find anything that you'd like to change, copy those lines into the file "TKGNATSLIB"/tkgnatsrc (which came from CONFIG-site.tkgnatsrc). If you edit the tkgnats.config directly, it can get overwritten the next time that you update TKGnats (if you use the same directory). gnats-4.1.0/contrib/tkgnats/TECHNOTES0000644000175000017500000003252007005513656017765 0ustar chewiechewie00000000000000I made this list for myself to help sort out design and configuration issues as I was adding support for the GNATS newtork daemon (gnatsd). I haven't clearly marked what applies to local disk access or network daemon access. GNATS programs executed by TkGnats ================================== o query-pr (local GNATS) / nquery-pr (network GNATS) - tkpr_library.tcl (check_release_based_batch) to determine if GNATS is Release Based - tkpr_library.tcl (get_gnats_config) calls check_release_based - called by tkeditpr, tkgnats, tkquerypr, tksendpr, tkviewpr - tkpr_library.tcl (get_gnats_list_batch) to get lists from GNATS - tkpr_library.tcl (get_gnats_list) - get_categories / get_submitters / get_responsible - tkeditpr, tkgnats, tkquerypr, tksendpr, tkviewpr - tkpr_library.tcl (get_pr_medium_text_batch) to get medium list of PR - tkpr_library.tcl (delete_pr_local) to get Category and State only - tkquery-pr (selection_Delete_cmd) to delete PRs - tkprintpr.tcl (Medium) to get medium listing of PRs for printing - tkpr_library.tcl (get_pr_medium_text_batch) to get medium list of PR - tkprintpr.tcl (print_parsepr_medium) to get medium listing of PRs for printing - print/Synopsis_Summary to get Number,Arrival-Date,Responsible,Category, Priority,Synopsis,Last-Modified,Originator, State,Severity. - tkpr_library.tcl (get_pr_full_text_batch) to get full list of PR - tkpr_library.tcl (lock_pr) to get full list of PR for editing when GNATS_ACCESS=local - see npr-edit below for callers of lock-pr - tkprintpr.tcl (Raw_Data) to get full listing of PRs for printing - tkprintpr.tcl (print_parsepr) to get full listing of PRs for printing - tkprintpr.tcl (Full) to get full listing of PRs for printing - print/Description_Summary to get Number,Synopsis,State,Description (Can't use medium) - tkquerypr (selection_Email_cmd) to get Reply-To,Responsible,From,Category,Synopsis (Can't use medium) - tkviewpr (main) to get full list of PR for viewing Raw or Formatted - tkquerypr (query_cmd_batch) to perform actual database queries o pr-edit (local GNATS) / npr-edit (network GNATS) - tkpr_library.tcl (lock_pr_batch) to lock PR for editing and to get full list of PR for editing (npr-edit) - tkeditpr (edit_window) to lock PR for editing - tkeditpr (real_file_report) to re-lock PR: this is a get-around for a bug in gnatsd that unlocks a pr when the update fails - tkpr_library.tcl (delete_pr_local) to lock PR for deleting - tkeditpr (real_file_report_batch) to send edited PR back to GNATS - tkpr_library.tcl (unlock_pr_batch) to unlock PR - tkeditpr (edit_window) to unlock the PR after updating - tkpr_library.tcl (delete_pr_local) to unlock the PR after deleting External programs executed by TkGnats ===================================== o TkGnats(Mailer) - sendmail, if TkGnats(MailMethod)=mailer o TkGnats(InfoReader) - tkinfo, xinfo, etc; optional in tkgnats main menu o TkGnats(MailReader) - pine, etc; optional in tkgnats main menu o groups in tkpr_library.tcl (TkGnats_config) - to get GROUP list o id in tkpr_library.tcl (TkGnats_config) - to get USER and GROUP o whoami optionally in tkgnats.config, if id fails and env(USER) and env(LOGNAME) don't exist o true in tkpr_library.tcl (do_reap) (protected by catch) o ypcat|grep|cut in tkpr_library.tcl (fullname_from_logname) (protected with catch) - tkpr_library.tcl (TkGnats_config) calls fullname_from_logname to set TkGnats(FullName) - tksendpr uses TkGnats(FullName) as the default for Originator o /bin/sh -c in tkquery_pr (perform_print_cmd) to execute Print(Previewer,*) - can this be just directly exec'd? No, because it's chained to rm tempfile in background o uname, arch, xdpyinfo|fgrep in tksendpr to get Environment defaults (optional) - tcl_platform and [info hostname] values are used if uname fails o sort, if TkGnats(QuerySortMethod)=external, to sort queries for the query listbox o groff in tkprintpr.tcl is the input to Print(Printspooler,*) GNATS configuration details needed by TkGnats ============================================= o GNATS_ROOT: TkGnats(GNATS_ROOT) - set in tkgnats.config by the Makefile - used in Makefile to read $(GNATS_ROOT)/gnats-adm/config which in turn sets GNATS_ADDR, GNATS_USER and SUBMITTER in tkgnats.config - tkpr_library.tcl (TkGnats_config) looks for env variable GNATS_ROOT and resets GNATS_ADDR, GNATS_USER, SUBMITTER and GNATS_ROOT itself - tkpr_library.tcl (delete_pr_local) gets the GNATS index from $TkGnats(GNATS_ROOT)/gnats-adm/index and the PR pathname from $TkGnats(GNATS_ROOT)/$full_id for deletion o GNATS_SITE: TkGnats(GNATS_SITE) - REMOVED. No longer used. See SUBMITTER. o GNATS_USER: TkGnats(GNATS_USER) - set in tkgnats.config by the Makefile - tkpr_library.tcl (TkGnats_config) looks for env variable GNATS_ROOT and resets this from the GNATS config file - this is used for the default TkGnats(delete_authorized_users) in tkgnats.config which is only required for GNATS_ACCESS=local. o GNATS_ADDR: TkGnats(GNATS_ADDR) - set in tkgnats.config by the Makefile or gotten from the "servers" file info - tkpr_library.tcl (TkGnats_config) looks for env variable GNATS_ROOT and resets this from the GNATS config file - tkpr_library.tcl (email_originator) as the recipient of the follow-up email - tksendpr (send_report) as the recipient of the email bug report o LIBEXECDIR: TkGnats(GNATS_LIBEXECDIR) - set in tkgnats.config by the Makefile - tkpr_library.tcl (TkGnats_config) as $TkGnats(GNATS_LIBEXECDIR)/gnats/pr-edit and npr-edit to get the path for the GNATS (n)pr-edit program o SUBMITTER - set in tkgnats.config by the Makefile - tkpr_library.tcl (TkGnats_config) looks for env variable GNATS_ROOT and resets this from the GNATS config file - tkpr_library.tcl (TkGnats_config) uses this as the default Organization if nothing else is found - tksendpr uses this to set the default Submitter in the dialog o GNATS category list - TkGnats(CategoryList) in tkpr_library.tcl (get_category_list) - got from (n)query-pr or direct socket call o GNATS submitter list - TkGnats(SubmitterList) in tkpr_library.tcl (get_submitter_list) - got from (n)query-pr or direct socket call o GNATS responsible list - TkGnats(ResponsibleList) in tkpr_library.tcl (get_responsible_list) - got from (n)query-pr or direct socket call o TkGnats(ReleaseBased) - set automatically in tkpr_library.tcl (get_gnats_config / check_release_based) - used throughout to determine if the Keywords field is used o TkGnats(GNATS_ACCESS) - set in tkpr_library.tcl(TkGnats_config_rc) to local if GNATS_SERVER is blank, otherwise set to network - tkeditpr (real_file_report) to know to do the get-around for a bug in gnatsd that unlocks a pr when the update fails - tkpr_library.tcl (TkGnats_config) to inhibit TkGnats(delete_authorized) if not a local GNATS system - tkpr_library.tcl (lock_pr) to know if pr-edit is meant to return the full text of the PR or not o TkGnats(GNATS_ACCESS_METHOD) (where used/how set/etc) - defaults to socket if GNATS_ACCESS is network, but can be set to batch to force usage of nquery-pr and npr-edit (not recommended) o TkGnats(GNATS_SERVER) - set from the "servers" file info - if GNATS_ACCESS=network: used as the --host argument to nquery-pr and npr-edit (GNATS_ACCESS_METHOD=batch) or gnatsd socket (GNATS_ACCESS_METHOD=socket) o TkGnats(GNATS_PORT) - set from the "servers" file info - if GNATS_ACCESS=network: used as the --port argument to nquery-pr and npr-edit (GNATS_ACCESS_METHOD=batch) or gnatsd socket (GNATS_ACCESS_METHOD=socket) Other TkGnats configuration issues ================================== o tkgnats.config - this file is sourced in tkpr_library.tcl (TkGnats_config), where only TkGnats and env are declared global. o TkGnats(EmailAddr) - tkpr_library.tcl (TkGnats_config) checks for the environment variable REPLYTO. If it exists, TkGnats(EmailAddr) is set to this value rather than TkGnats(LogName) - tkeditpr (real_file_report) to know who is doing the edit so that name can be omitted from receiving notification of the edit - tkeditpr (real_file_report) as the name in the Audit Trail "Responsible-Changed-By:" and "State-Changed-By:" entries, along with TkGnats(FullName) - tkeditpr (real_file_report) as the From and Reply-To mail headers of the mail being sent - tkpr_library.tcl (email_send) as the From and Reply-To mail headers of the mail being sent - tkpr_library.tcl (email_send) to know who is sending the mail so that name can be omitted from receiving notification of the edit o TkGnats(ENVIRONMENT) - tksendpr.tcl will use this to set the initial value of the Environment text when creating new problem reports. Otherwise, the output of the UNIX command "uname -a" (or the tcl_platform Tcl variables) is used. o TkGnats(LogName) - tkpr_library.tcl (TkGnats_config) sets by searching in this order: - check the first output field of the id command - then check USER environment variable - then try LOGNAME environment variable - then try running whoami - tkpr_library.tcl (TkGnats_config) to set TkGnats(EmailAddr) if the environment variable REPLYTO isn't available - tkeditpr (main) to make sure root doesn't edit PRs - tkpr_library.tcl (TkGnats_config) to compare against TkGnats(edit_authorized) - tkpr_library.tcl (TkGnats_config) to compare against TkGnats(delete_authorized) - tkpr_library.tcl (fullname_from_logname) to search "ypcat passwd" or /etc/passwd - tkpr_library.tcl (lock_pr_batch) as the --lock argument to (n)pr-edit or for the LOCK command when calling the gnatsd socket (lock_pr_socket) - tksendpr (main) to make sure root doesn't send PRs - used in the filename of various temporary files - used in iconnames o TkGnats(GroupName) - tkpr_library.tcl (TkGnats_config) sets by searching in this order: - first check the output of the groups command for a list of groups - then check the second output field of the id command for a primary group - then check GROUP environment variable - tkpr_library.tcl (TkGnats_config) to compare against TkGnats(edit_authorized) - tkpr_library.tcl (TkGnats_config) to compare against TkGnats(delete_authorized) o TkGnats(ORGANIZATION) - tkpr_library.tcl (TkGnats_config) sets by searching in this order: - environment variable ORGANIZATION, which is either a filename whose contents is used or else a string to use - $env(HOME)/.signature, which is a filename whose contents is used - if the above aren't found then $TkGnats(SUBMITTER) is used o TkGnats(CreateDefaultCategory) - tksendpr (main) to use as a pre-selected category default o TkGnats(QuerySortMethod) - tkpr_library.tcl (TkGnats_config) sets or overrides TkGnats(QuerySortMethod) (internal or external) - determines if Query listbox will be sorted by Tcl code (internal) or the unix "sort" program (external). The internal sort runs as fast or faster than the external sort in Tcl/Tk 8.0 due to the byte compiler. The internal sort is mandatory for Win95/98/NT. - tkpr_library.tcl (build_sort_cmd) to build sort keys - tkquerypr (perform_sort_cmd) to sort listbox o TkGnats(SMTP_SERVER) - MailMethod is either mailer (like sendmail) or smtp to connect directly to an smtp server when sending mail. smtp is mandatory for Win95/98/NT. o TkGnats(SMTP_PORT) - defaults to the standard 25. o TkGnats(GNATS_BINDIR) - This can be set if the GNATS programs query-pr and nquery-pr aren't in your path. Full list of TkGnats array variables ==================================== o This list can be viewed from the Help menu on any TkGnats window. Full list of environment variables checked by TkGnats ===================================================== environment variable sets TkGnats variable -------------------- --------------------- env(GNATS_ROOT) TkGnats(GNATS_ROOT), TkGnats(GNATS_ADDR), TkGnats(GNATS_USER), TkGnats(SUBMITTER) env(GROUP) TkGnats(GroupName) (if unix 'groups' and 'id' cmds not available) env(HOME) TkGnats(HOME) env(HOSTNAME) TkGnats(HOSTNAME) env(LOGNAME) TkGnats(LogName) (if env(USER) not found) env(ORGANIZATION) TkGnats(ORGANIZATION) env(REPLYTO) TkGnats(EmailAddr) (otherwise use TkGnats(LogName)) env(TKGNATSINI) TkGnats(TKGNATSINI) env(TKGNATSLIB) TkGnats(TKGNATSLIB) (and TkGnats(lib), which is actually used) env(TKGNATSSERVERS) TkGnats(TKGNATSLIB) (and TkGnats(lib), which is actually used) env(USER) TkGnats(LogName) (if unix 'id' cmd not available) gnats-4.1.0/contrib/tkgnats/TO-DO0000644000175000017500000000421407005513656017252 0ustar chewiechewie00000000000000In no particular order: o Code get-around for the 255 character line limit in gnatsd? o Save size and position of all windows. $TkGnats(UserDir)/wgeometry o Fix tkpr_library.tcl proc delete_pr_local. It hasn't kept up with the changes. o Allow editing of raw data (Jens Krinke ). o Show responsible for each category? (Daniel Quinlan ). o Add delayed mail sending to allow off-line creation of new bug reports? o Add instructions/support for tksendpr stand-alone without gnatsd access. o Add a dialog to edit/set configuration parameters? (Paul Traina ). o Find a volunteer to test TkGnats on the Macintosh. - Mac doesn't use slashes in file names; have to convert path manipulation to use Tcl file commands (such as [file join]). o Add SUBMITTER as a new field in the servers file? o Color configuration - short-term: make variable (DONE in TkGnats-3.0.4) - long-term: interactive control similar to the font selector. o Option to add the Description field to the edit change notice email. (for just certain field changes? Add to client hints system?) o > It would be real useful if tkgnats would use the DBLA command and get > all the databases on a given host. A servers entry like: > > "Gnats" gnats 1529 bugs@gnats /var/lib/gnats normal > > would work as present, but an entry like: > > "*" gnats 1529 > > Would connect to gnats on port 1529 and do a DBLA to get the list of > databases there, then fill in all the entries as buttons. I'm surprised that nobody asked for this sooner. TkGnats can get the email address (GNAST_ADDR) from gnats, and make the button text something like "Host:gnats DB: normal" (for your example), but what should it do for the 5th field? Your example above doesn't look right: the 5th field is simply a subdirectory for a user's config files (saved queries, etc) for a particular server. I could assume host.alias, which would be gnats.normal in your case. This might end up as ~/.tkgnatsrc/gnats.normal., for example. > Also can tkgnats be configured to prompt for a username/password on > CHDB? Somebody asked for this recently. It's on my list. gnats-4.1.0/contrib/tkgnats/VERSION0000644000175000017500000000013507642176774017570 0ustar chewiechewie00000000000000This is version tkgnats-4.0-beta1 and was made by mcr@gnu.org on Mon Mar 31 21:47:57 EST 2003gnats-4.1.0/contrib/tkgnats/WIN-tkgnats.tcl0000644000175000017500000000131207005513656021313 0ustar chewiechewie00000000000000# TkGnats startup file for Win95/98/NT. # Don't use this for UNIX; it only makes sense for Windows ShortCuts. # Each individual user gets a copy of this file. # Copy it to $TkGnats(UserDir)/tkgnats.tcl # Windows: TkGnats(UserDir) is {home}/tkgnats # where {home} is any directory that belongs to an individual. # Make a shortcut to this file and set the "Start In:" field to # the directory where TkGnats itself resides. # No need to edit anything in this file. set TkGnats(UserDir) [file dirname [info script]] set TkGnats(UserSubdir) [file tail $TkGnats(UserDir)] set env(HOME) [file dirname $TkGnats(UserDir)] set TkGnats(TKGNATSINI) $TkGnats(UserDir)/tkgnats.ini source tkgnats gnats-4.1.0/contrib/tkgnats/tkeditpr.tcl0000644000175000017500000011010607642466237021046 0ustar chewiechewie00000000000000proc tkeditpr_usage {{str ""}} { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "${str}usage: tkeditpr -prid nnnn -server 'ServerInfo' \[-categories 'list'\] \ \[-classes 'list'\] \[-states 'list'\] \ \[-submitters 'list'\] \[-responsible 'list'\]" "error" 0 "OK" exit } proc tkeditpr_process_args {} { global TkGnats Tkeditpr argc argv env set TkGnats(CurrentProgram) tkeditpr if {$argc != 0} { if {$argc%2 != 0} { tkeditpr_usage } for {set x 0} {$x<$argc} {incr x 2} { set opt [lindex $argv $x] set val [lindex $argv [expr $x+1]] switch -exact -- $opt -server { set TkGnats(ServerInfo) $val } -categories { set TkGnats(CategoryList) $val } -submitters { set TkGnats(SubmitterList) $val } -responsible { set TkGnats(ResponsibleFile) $val } -classes { set TkGnats(ClassesFile) $val } -states { set TkGnats(StatesFile) $val } -prid { set Tkeditpr(prid) $val } default { tkeditpr_usage "Illegal option pair:\n'$opt $val'\n\n" } } } if {![info exists TkGnats(ServerInfo)]} { tkeditpr_usage "No -server argument given.\n\n" } foreach var {TKGNATSLIB TKGNATSINI} { if {[info exists env($var)]} { set TkGnats($var) $env($var) } } set TkGnats(lib) $TkGnats(TKGNATSLIB) if {[info exists TkGnats(TKGNATSINI)]} { if {[file readable $TkGnats(TKGNATSINI)]} { source $TkGnats(TKGNATSINI) } { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "TkGnats INI file '$TkGnats(TKGNATSINI)' not readable" "error" 0 "OK" exit } } if {[file exists $TkGnats(lib)/tkgnatsini]} { source $TkGnats(lib)/tkgnatsini } } proc headingMsg {a {flash 1}} { .action.msg configure -text $a update idletasks if {$flash} { foreach rep {1 2 3 4 5} { foreach r {raised sunken flat} { .action.msg configure -relief $r; update idletasks after 50 } } } } proc merge_into_list {lname new_value {omit_value {}}} { upvar 1 $lname l set omit_addr [lindex [extract_email_address $omit_value] 0] # set omit_name [lindex [extract_email_address $omit_value] 1] set adds [split $new_value ,] set nadds [llength $adds] for {set i 0} {$i < $nadds} {incr i} { set add [string trim [lindex $adds $i]] set new_addr [lindex [extract_email_address $add] 0] # set new_name [lindex [extract_email_address $add] 1] if {"$new_addr" != "$omit_addr"} { if {[lsearch $l $new_addr] < 0} { lappend l $new_addr } } } } proc file_report {} { global TkGnats Tkeditpr flds set stat [real_file_report] if {$stat == 1} { headingMsg "" 0 return } if {$stat == -1} { #headingMsg "Error filing report!" headingMsg "" 0 return } bind . "" unlock_pr $Tkeditpr(prid) exit } proc real_file_report_batch {rep} { global TkGnats Tkeditpr upvar 1 $rep errs if {[catch {set fout [eval open \"|$TkGnats(pr-edit) $TkGnats(UseridPassword)\" w]} errs]} { Msg "Error executing \"$TkGnats(pr-edit)\" to update PRID $Tkeditpr(prid):\n" "$errs" return -1 } write_pr $fout return [catch {close $fout} errs] } proc real_file_report_socket {rep} { global TkGnats Tkeditpr upvar 1 $rep errs set errs "" if {[set s [open_socket_gnatsd]] == "-1"} { return -2 } gnatsd_send $s "EDIT $Tkeditpr(prid)" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { set errs "GNATSD error sending EDIT command for PRID $Tkeditpr(prid):\n[join $rep \n]" return -1 } write_pr $s #write_pr stdout puts $s "." set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { set errs "GNATSD error updating PRID $Tkeditpr(prid): [join $rep \n]" return -1 } return 0 } proc real_file_report {} { global TkGnats Tkeditpr flds frm errorCode whyText flush_singletext $Tkeditpr(singletextflds) flush_singletext $Tkeditpr(shorttextflds) .eboxs.shortones flush_multitext # # do some local field checking.. # headingMsg "Checking fields..." 0 # Check mandatory fields for non-blank input foreach f [concat $Tkeditpr(radioflds) $Tkeditpr(listboxflds) $Tkeditpr(singletextflds) $Tkeditpr(multitextflds) $Tkeditpr(shorttextflds)] { if {[check_suppressed_field $f]} { continue } if {![check_mandatory_field $f]} { continue } set val [string trim $frm($f) " \n\t\f!:~-#_?"] if {$val == ""} { Msg "You must supply a value for '[get_field_alias $f]'." return -1 } } # Check listbox fields foreach {field list} {Category Category Submitter-Id Submitter Responsible Responsible} { if {$frm(>$field) != "" && [lsearch -exact $TkGnats(${list}List) $frm(>$field)] < 0} { Msg "You have specified an invalid [get_field_alias $field]: $frm(>$field)" return -1 } } # Check Date-Required field... if {$TkGnats(ReleaseBased)} { if {[check_date_invalid $frm(>Date-Required) "Invalid [get_field_alias Date-Required]:"]} { return -1 } set frm(>Date-Required) [normalize_date $frm(>Date-Required)] } set requireAudit 0 set requireEmail 0 set requireReason 0 set Audit_text "Changed-When:\t[clock format [clock seconds]]\n" append Audit_text "Changed-By:\t$TkGnats(LogName) \"$TkGnats(FullName)\" <[lindex [extract_email_address $TkGnats(EmailAddr)] 0]>\n" set Email_text $Audit_text # # now see if any fields changed that trigger notifiers or audit records # set mail_list "" set changedfields "" set responsible_addr [get_responsible_addr $frm(>Responsible)] set old_responsible_addr [get_responsible_addr $flds(>Responsible)] foreach t [concat $Tkeditpr(listboxflds) $Tkeditpr(radioflds)] { #dputs "Comparing frm($t) and flds($t): $frm($t) vs $flds($t)" if {$frm($t) != $flds($t)} { foreach require {Audit Email Reason} { if {[check_audit_trail_opts $require $t]} { set require$require 1 append changedfields "$t " dputs "Field changed: $changedfields" if {$require != "Reason"} { append ${require}_text "$t-Changed-[get_field_alias $t]-From-To:\t$flds($t)->$frm($t)\n" } } } } } foreach f [concat $Tkeditpr(singletextflds) $Tkeditpr(shorttextflds)] { # Check that singletext text fields do not have a | char. (not allowed in gnats index) if {[string first "|" $frm($f)] >= 0} { Msg " '|' is an illegal character for the '[get_field_alias $f]' field!" return -1 } dputs "Comparing frm($f) and flds($f): $frm($f) vs $flds($f)" if {$frm($f) != $flds($f)} { foreach require {Audit Email Reason} { if {[check_audit_trail_opts $require $f]} { set require$require 1 append changedfields "$f " dputs "Field changed: $changedfields" if {$require != "Reason"} { set tmptag [get_field_alias $f] append ${require}_text "$f-Changed-$tmptag-From:\t$flds($f)\n" append ${require}_text "$f-Changed-$tmptag-To: \t$frm($f)\n" } } } } } foreach t $Tkeditpr(multitextflds) { #dputs "Comparing frm($t) and flds($t): $frm($t) vs $flds($t)" if {[string trim $frm($t)] != [string trim $flds($t)]} { foreach require {Audit Email Reason} { if {[check_audit_trail_opts $require $t]} { set require$require 1 append changedfields "$t " dputs "Field changed: $changedfields" if {$require != "Reason"} { append ${require}_text "$t-Changed-[get_field_alias $t]\n" } } } } } headingMsg "" 0 if {$requireReason} { if {[catch {textEntryDialog "Enter reason for changes" "Return to Edit" $whyText 0 .} whyText]} { return 1 } foreach f $changedfields { #dputs "Field changed $f" append frm($f-Changed-Why) "\n[string trim $whyText]\n" append Email_text "$f-Changed-Why:\t[string trim $whyText]\n" } } if {$requireAudit} { set dash "------------------------------------------------------------------\n" append frm(>Audit-Trail) "\n$dash$Audit_text$dash" } headingMsg "Filing report..." 0 set done 0 while {!$done} { set stat [real_file_report_$TkGnats(GNATS_ACCESS_METHOD) errs] #puts "stat=$stat errs=$errs" if {$stat == 0} { set done 1 } { # If the failure is opening gnatsd socket, stat= -2 if {$stat != -2} { # The first message is returned by gnatsd directly; # the second by the batch [n]pr-edit. if {[string first "currently locked" $errs] >= 0 || [string first "lock file exists" $errs] >= 0} { set errs "The GNATS database is presently locked.\nPlease try again in a moment." } } set msg "Error filing $frm(>Category)/$Tkeditpr(prid):\n\n$errs" bell set rep [tk_dialog .tkquerypr_delete "Error Filing PR Changes" $msg \ "warning" 0 "Try Again" "Return to Edit"] if {$rep == "1"} { return -1 } } } headingMsg "Done" 0 # # Did any notifiable changes take place ?? # if {$requireEmail} { # Send to the responsible person, original sender and the X-GNATS-Notify list merge_into_list mail_list $responsible_addr $TkGnats(EmailAddr) merge_into_list mail_list $flds(Reply-To) $TkGnats(EmailAddr) if {[info exists $frm(X-GNATS-Notify)]} { merge_into_list mail_list $frm(X-GNATS-Notify) $TkGnats(EmailAddr) } if {$frm(>Responsible) != $flds(>Responsible)} { # Mail to the old responsible person too merge_into_list mail_list $old_responsible_addr $TkGnats(EmailAddr) } ##puts "maillist=$mail_list" if {"$mail_list" != ""} { headingMsg "Changes saved. Sending mail..." 0 set addrs [add_email_domainname [join $mail_list ", "]] ##puts "maillist=$addrs" set mailtxt "" append mailtxt "From: $TkGnats(EmailAddr)\n" append mailtxt "Reply-To: $TkGnats(EmailAddr)\n" append mailtxt "To: $addrs\n" append mailtxt "Subject: Re: $frm(>Category)/$Tkeditpr(prid): Changed information\n\n" #TTD: add database name here! foreach f {Synopsis Priority Severity} { if {[check_suppressed_field $f]} { continue } set alias [get_field_alias $f] append mailtxt "[get_field_alias $f]: $frm(>$f)\n" } #append mailtxt "Synopsis: $frm(>Synopsis)\n\n" #append mailtxt "Priority: $frm(>Priority)\n" #append mailtxt "Severity: $frm(>Severity)\n" append mailtxt \n$Email_text if {[TkGnats_sendmail $addrs $mailtxt] == "-1"} { Msg "Error sending mail notification.\n\nPR changes were saved." } } } set whyText "" return 0 } proc TTDescape_dots_gnatsd {txt} { set txttmp [split $txt \n] set len [llength $txttmp] for {set l 0} {$l < $len} {incr l} { set line [lindex $txttmp $l] # TTD: This is what RFC821 uses for SMTP, but we can't use this since gnatsd # doesn't remove the extra dot and you'd get another dot every time the PR is edited. # When gnatsd is fixed this proc goes away and we just need escape_dots. #if {[string match .* $line]} if {$line == "."} { #puts "escaping this line: $line" set txttmp [lreplace $txttmp $l $l .$line] } } set newlen [llength $txttmp] if {$len != $newlen} { Msg "Internal programming error escaping .'s in message body.\n" \ "Lines in=$len; lines out=$newlen" return $txt } return [join $txttmp \n] } proc write_multitextfld {fout flds tag} { global TkGnats upvar 1 $flds f #set txt [string trimleft "$tag: \n[string trim $f($tag) "\n"]" "\n"] set txt [string trim "$tag: \n[string trim $f($tag) "\n"]" "\n"] if {$TkGnats(GNATS_ACCESS_METHOD) == "batch"} { puts $fout $txt } { puts $fout [escape_dots $txt] } } proc write_pr {fout} { global Tkeditpr flds frm foreach tag [array names frm] { set still_left($tag) $tag } # # for each parsed field from the PR form... # #puts "tags:$Tkeditpr(parsed_flds)" foreach tag $Tkeditpr(parsed_flds) { case $tag {_prefix_} { # # The mail header, stored under the _prefix_ tag, is written out # unadulterated, except for the edited X-GNATS-Notify field. # #puts "prefix before:$flds($tag)" set lines [split $flds($tag) \n] set idx [lsearch -regexp $lines "^X-GNATS-Notify:"] if {[info exists frm(X-GNATS-Notify)]} { set repto "X-GNATS-Notify: [lindex [split $frm(X-GNATS-Notify) ,] 0]" foreach addr [lrange [split $frm(X-GNATS-Notify) ,] 1 end] { append repto ", [string trim $addr]" } set lines [lreplace $lines $idx [expr $idx + $flds(_prefix_len_X-GNATS-Notify) - 1] $repto\n] } #set frm($tag) "[string trim [join $lines \n]]\n" set frm($tag) [join $lines \n] #puts "prefix after:$flds($tag)" puts -nonewline $fout $frm($tag) } {X-GNATS-Notify} { # # Taken care of above with the mail header # if {[info exists still_left($tag)]} { unset still_left($tag) } } {>Unformatted} { # # Taken care of later in the function... # unset still_left($tag) } {>*} { # When writing out the fields # first check for data present in the form (the frm bag) # If not present use data read from the PR file (the flds bag) # if {[info exists frm($tag)]} { set data $frm($tag) unset still_left($tag) } { set data $flds($tag) } # # Write out fields # # Multi line fields are newline trimmed to a single leading # and trailing newline # # Single line text fields are whitespace trimmed to a leading # tab and a trailing newline # case $tag $Tkeditpr(singletextflds) { #puts $fout "$tag:\t[string trim [textget $tag] "\t\n "]" puts $fout "$tag:\t[string trim $frm($tag) "\t\n "]" } $Tkeditpr(shorttextflds) { puts $fout "$tag:\t[string trim $frm($tag) "\t\n "]" } [concat >Category >Responsible >Submitter-Id $Tkeditpr(radioflds)] { puts $fout "$tag:\t$frm($tag)" } $Tkeditpr(multitextflds) { write_multitextfld $fout frm $tag } default { puts -nonewline $fout "$tag:$data" } } } # # now write any fields in the form that were not in the parsed report # foreach tag [array names still_left] { write_multitextfld $fout frm $tag } # # Finally, write the >Unformatted field # (BUG: >Unformatted should not really be stripped) # write_multitextfld $fout frm ">Unformatted" } proc cancel_report {} { global Tkeditpr bind . "" unlock_pr $Tkeditpr(prid) exit } proc get_tkeditpr_listbox_height {} { global TkGnats Tkeditpr set ch [llength $TkGnats(CategoryList)] set sh [llength $TkGnats(SubmitterList)] set rh [llength $TkGnats(ResponsibleList)] set h $ch if {$h < $sh } { set h $sh } if {$h < $rh } { set h $rh } if {$h > 6 } { set h 6 } set Tkeditpr(listbox_height) $h } proc edit_category_listbox {p {pat *}} { global TkGnats Tkeditpr flds frm set wid [expr 2 + [get_max_strlen $TkGnats(CategoryList)]] set alias [get_field_alias Category] frame $p.cat -relief flat pack $p.cat -side top -anchor w button $p.cat.lab -text "${alias}: " -width 14 -anchor w -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 -highlightthickness 1 frame $p.cat.msg -relief flat label $p.cat.msg.val -text "[ftrim $flds(>Category)]" -relief groove -anchor w \ -width $wid -background $TkGnats(ReadOnlyBackground) pack $p.cat.msg.val -side top -fill both -expand true -anchor center pack $p.cat.lab $p.cat.msg -side left -anchor n if {[check_suppressed_field Category] == 2} { return "" } set ew [entry $p.cat.msg.ent -width $wid -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground) -highlightthickness 2 \ -textvariable frm(>Category)] lappend Tkeditpr(tlist) $ew set_focus_style $ew bind $ew { tkEntrySetCursor %W [%W index insert] } bind $ew { tkEntrySetCursor %W [%W index insert] } scrollbar $p.cat.msg.sb -command "$p.cat.msg.list yview" -borderwidth 2 -relief sunken listbox $p.cat.msg.list -yscroll "$p.cat.msg.sb set" -setgrid 1 -relief sunken -borderwidth 2 \ -width $wid -height $Tkeditpr(listbox_height) -exportselection false pack $p.cat.msg.ent -side top -fill both -expand true -anchor w pack $p.cat.msg.list -side left -fill both -expand true pack $p.cat.msg.sb -side right -fill y eval $p.cat.msg.list insert end $TkGnats(CategoryList) trace variable frm(>Category) w set_edit_category_ew bind $p.cat.msg.list "set_edit_category $p.cat.msg %W %y" return $p.cat.msg.list } proc edit_responsible_listbox {p {pat *}} { global TkGnats Tkeditpr flds frm set wid [expr 2 + [get_max_strlen $TkGnats(ResponsibleList)]] set alias [get_field_alias Responsible] frame $p.res -relief flat pack $p.res -side top -anchor w button $p.res.lab -text "${alias}: " -width 14 -anchor w -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 -highlightthickness 1 frame $p.res.msg -relief flat label $p.res.msg.val -text "[ftrim $flds(>Responsible)]" -relief groove -anchor w \ -width $wid -background $TkGnats(ReadOnlyBackground) pack $p.res.msg.val -side top -fill both -expand true -anchor center pack $p.res.lab $p.res.msg -side left -anchor n if {[check_suppressed_field Responsible] == 2} { return "" } set ew [entry $p.res.msg.ent -width $wid -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground) -highlightthickness 2 \ -textvariable frm(>Responsible)] lappend Tkeditpr(tlist) $ew set_focus_style $ew bind $ew { tkEntrySetCursor %W [%W index insert] } bind $ew { tkEntrySetCursor %W [%W index insert] } scrollbar $p.res.msg.sb -command "$p.res.msg.list yview" -borderwidth 2 -relief sunken set height [llength $TkGnats(ResponsibleList)] if {$height > 6 } { set height 6 } listbox $p.res.msg.list -yscroll "$p.res.msg.sb set" -setgrid 1 -relief sunken \ -borderwidth 2 -width $wid -height $Tkeditpr(listbox_height) -exportselection false pack $p.res.msg.ent -side top -fill both -expand true -anchor w pack $p.res.msg.list -side left -fill both -expand true pack $p.res.msg.sb -side right -fill y eval $p.res.msg.list insert end $TkGnats(ResponsibleList) trace variable frm(>Responsible) w set_edit_responsible_ew bind $p.res.msg.list "set_edit_responsible $p.res.msg %W %y" return $p.res.msg.list } proc edit_submitter-id_listbox {p {pat *}} { global TkGnats Tkeditpr flds frm set wid [expr 2 + [get_max_strlen $TkGnats(SubmitterList)]] set alias [get_field_alias Submitter-Id] frame $p.sub -relief flat pack $p.sub -side top -anchor w button $p.sub.lab -text "${alias}: " -width 14 -anchor w -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 -highlightthickness 1 frame $p.sub.msg -relief flat label $p.sub.msg.val -text "[ftrim $flds(>Submitter-Id)]" -relief groove -anchor w \ -width $wid -background $TkGnats(ReadOnlyBackground) pack $p.sub.msg.val -side top -fill both -expand true -anchor center pack $p.sub.lab $p.sub.msg -side left -anchor n if {[check_suppressed_field Submitter-Id] == 2} { return "" } set ew [entry $p.sub.msg.ent -width $wid -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground) \ -highlightthickness 2 -textvariable frm(>Submitter-Id)] lappend Tkeditpr(tlist) $ew set_focus_style $ew bind $ew { tkEntrySetCursor %W [%W index insert] } bind $ew { tkEntrySetCursor %W [%W index insert] } scrollbar $p.sub.msg.sb -command "$p.sub.msg.list yview" -borderwidth 2 -relief sunken set height [llength $TkGnats(SubmitterList)] if {$height > 6 } { set height 6 } listbox $p.sub.msg.list -yscroll "$p.sub.msg.sb set" -setgrid 1 -relief sunken \ -borderwidth 2 -width $wid -height $Tkeditpr(listbox_height) -exportselection false pack $p.sub.msg.ent -side top -fill both -expand true -anchor w pack $p.sub.msg.list -side left -fill both -expand true pack $p.sub.msg.sb -side right -fill y eval $p.sub.msg.list insert end $TkGnats(SubmitterList) trace variable frm(>Submitter-Id) w set_edit_submitter-id_ew bind $p.sub.msg.list "set_edit_submitter-id $p.sub.msg %W %y" return $p.sub.msg.list } proc set_edit_category_ew {a b c} { upvar #0 $a f global TkGnats quickfill_entry_from_listbox f($b) .eboxs.clb.cat.msg.ent .eboxs.clb.cat.msg.list \ $TkGnats(CategoryList) } proc set_edit_submitter-id_ew {a b c} { upvar #0 $a f global TkGnats quickfill_entry_from_listbox f($b) .eboxs.slb.sub.msg.ent .eboxs.slb.sub.msg.list \ $TkGnats(SubmitterList) } proc set_edit_responsible_ew {a b c} { upvar #0 $a f global TkGnats quickfill_entry_from_listbox f($b) .eboxs.rlb.res.msg.ent .eboxs.rlb.res.msg.list \ $TkGnats(ResponsibleList) } proc set_edit_category {msg w y} { global frm trace vdelete frm(>Category) w set_edit_category_ew $msg.ent delete 0 end set idx [$w nearest $y] set frm(>Category) [$w get $idx] trace variable frm(>Category) w set_edit_category_ew } proc set_edit_responsible {msg w y} { global frm trace vdelete frm(>Responsible) w set_edit_responsible_ew $msg.ent delete 0 end set idx [$w nearest $y] set frm(>Responsible) [$w get $idx] trace variable frm(>Responsible) w set_edit_responsible_ew } proc set_edit_submitter-id {msg w y} { global frm trace vdelete frm(>Submitter-Id) w set_edit_submitter-id_ew $msg.ent delete 0 end set idx [$w nearest $y] set frm(>Submitter-Id) [$w get $idx] trace variable frm(>Submitter-Id) w set_edit_submitter-id_ew } proc fillfrm {} { global TkGnats Tkeditpr flds frm ### re-set editable PR values to values currently in the PR # clear listbox entry widgets trace vdelete frm(>Category) w set_edit_category_ew trace vdelete frm(>Submitter-Id) w set_edit_submitter-id_ew trace vdelete frm(>Responsible) w set_edit_responsible_ew catch {.eboxs.clb.cat.msg.ent delete 0 end} catch {.eboxs.slb.sub.msg.ent delete 0 end} catch {.eboxs.rlb.res.msg.ent delete 0 end} trace variable frm(>Category) w set_edit_category_ew trace variable frm(>Submitter-Id) w set_edit_submitter-id_ew trace variable frm(>Responsible) w set_edit_responsible_ew # listboxes and radio (enumerated) fields foreach tag [concat $Tkeditpr(listboxflds) $Tkeditpr(radioflds)] { if {[info exists flds($tag)]} { set flds($tag) [string trim $flds($tag) "\t\n "] } { set flds($tag) "" } #unset frm($tag) catch {set frm($tag) $flds($tag)} } # now the 1 line textual flds foreach tag $Tkeditpr(singletextflds) { if {[info exists flds($tag)]} { set flds($tag) [string trim $flds($tag) "\t\n "] } { set flds($tag) "" } textset $tag $flds($tag) } # now the 1 line textual flds foreach tag $Tkeditpr(shorttextflds) { if {[info exists flds($tag)]} { set flds($tag) [string trim $flds($tag) "\t\n "] } { set flds($tag) "" } #puts stderr "Setting $tag to $flds($tag)" textset $tag $flds($tag) .eboxs.shortones } # now the multi line textual flds foreach tag $Tkeditpr(multitextflds) { if {[info exists flds($tag)]} { set flds($tag) [string trim $flds($tag) "\t\n "] set frm($tag) $flds($tag)\n } { set frm($tag) "\n" set flds($tag) "\n" } } switch_txt $TkGnats(first_multitext) $Tkeditpr(multitextflds) } proc reset_report {} { global Tkeditpr flds current_multi_text # load the current text widget with the original text .multiline.text delete 1.0 end .multiline.text insert 1.0 $flds($current_multi_text) # reset everything set current $current_multi_text fillfrm switch_txt $current $Tkeditpr(multitextflds) } proc edit_email_originator {} { global Tkeditpr flds frm flush_singletext $Tkeditpr(singletextflds) flush_singletext $Tkeditpr(shorttextflds) set gn "" if {[info exists $frm(X-GNATS-Notify)]} { set gn [ftrim $frm(X-GNATS-Notify)] } email_originator $gn \ [ftrim $frm(>Responsible)] [ftrim $flds(Reply-To)] \ [ftrim $frm(>Category)]/$Tkeditpr(prid) [ftrim $frm(>Synopsis)] } proc edit_cleanup {} { global Tkeditpr bind . "" unlock_pr $Tkeditpr(prid) exit } proc edit_window {} { global TkGnats Tkeditpr flds frm env current_multi_text set prid $Tkeditpr(prid) set prtxt [lock_pr $prid] # if {$prtxt == ""} { # exit 1 # } # Unlock the PR if the user nukes the window bind . edit_cleanup get_tkeditpr_listbox_height set Tkeditpr(radioflds) { >State >Confidential >Severity >Priority >Class } set Tkeditpr(listboxflds) { >Category >Submitter-Id >Responsible } set Tkeditpr(shorttextflds) { >Release >Cost >XrefPR } set Tkeditpr(singletextflds) { >Originator >Synopsis >IPsec-barf-location } if {$TkGnats(ReleaseBased)} { lappend Tkeditpr(singletextflds) >Keywords >$TkGnats(Quarter) >Date-Required } set Tkeditpr(multitextflds) { >Description >How-To-Repeat >Environment >IPsec-look >Fix >Audit-Trail >Organization >Unformatted >Release-Note } # List of entry widgets for traverse key binding set Tkeditpr(tlist) {} set current_multi_text "" # load a bunch of defaults into flds. set Tkeditpr(parsed_flds) [parsepr_txt $prtxt flds] set missing_list [load_field_defaults flds] frame .mframe -borderwidth 1 -relief raised pack .mframe -side top -fill x menubutton .mframe.file -text "File" -menu .mframe.file.m -underline 0 menu .mframe.file.m .mframe.file.m add command -label "Save Changes" -command file_report .mframe.file.m add command -label "Reset to Starting Values" -command reset_report # .mframe.file.m add command -label "Send Email..." -command \ # "email_originator [list [ftrim $flds(X-GNATS-Notify)]] \ # [list [ftrim $flds(>Responsible)]] [list [ftrim $flds(Reply-To)]] \ # [ftrim $flds(>Category)]/$Tkeditpr(prid) [list [ftrim $flds(>Synopsis)]]" .mframe.file.m add command -label "Send Email..." -command edit_email_originator .mframe.file.m add separator .mframe.file.m add command -label "Cancel" -command cancel_report menubutton .mframe.edit -text "Edit" -menu .mframe.edit.m -underline 0 menu .mframe.edit.m .mframe.edit.m configure -disabledforeground [.mframe.edit.m cget -foreground] .mframe.edit.m add command -label "Use right mouse button for Cut/Copy/Paste" -state disabled .mframe.edit.m add separator .mframe.edit.m add command -label "Fonts..." -command "edit_fonts" pack .mframe.file .mframe.edit -side left menubutton .mframe.help -text "Help" -menu .mframe.help.m -underline 0 menu .mframe.help.m .mframe.help.m add command -label "Overview" \ -command "helpMsg Edit_Overview" .mframe.help.m add separator .mframe.help.m add command -label "Cut, Copy, Paste Operations" \ -command "helpMsg Cut_Copy_Paste" .mframe.help.m add separator .mframe.help.m add command -label "Field Definitions" \ -command "helpMsg Field_Definitions" .mframe.help.m add separator .mframe.help.m add command -label "Radio Buttons (Class, etc)" \ -command "helpMsg Edit_Radio_Buttons" .mframe.help.m add command -label "Listbox Selectors (Category, etc)" \ -command "helpMsg Edit_Listbox_Selectors" .mframe.help.m add command -label "Entry Fields (Originator, etc)" \ -command "helpMsg Edit_Entry_Fields" .mframe.help.m add command -label "Text Fields (Description, etc)" \ -command "helpMsg Edit_Text_Fields" .mframe.help.m add separator .mframe.help.m add command -label "View Configuration Variables" \ -command "helpMsg TkGnats_Variables" .mframe.help.m add separator .mframe.help.m add command -label "Changes" \ -command "helpMsg Changes" .mframe.help.m add command -label "About" \ -command "helpMsg TkGnats_About" pack .mframe.help -side right frame .action -borderwidth 1 -relief raised pack .action -side top -fill x -anchor w button .action.send -borderwidth 1 -text "Save Changes" -command file_report #button .action.cancel -borderwidth 1 -text "Cancel" -command cancel_report button .action.reset -borderwidth 1 -text "Reset to Starting Values" -command reset_report button .action.email -borderwidth 1 -text "Send Email..." -command edit_email_originator # button .action.email -borderwidth 1 -text "Send Email..." -command \ # "email_originator [list [ftrim $flds(X-GNATS-Notify)]] \ # [list [ftrim $flds(>Responsible)]] [list [ftrim $flds(Reply-To)]] \ # [ftrim $flds(>Category)]/$Tkeditpr(prid) [list [ftrim $flds(>Synopsis)]]" #pack .action.send .action.reset .action.email .action.cancel -side left -padx 0 pack .action.send .action.reset .action.email -side left -padx 0 message .action.msg -aspect 10000 -relief sunken -bd 1 -text "" pack .action.msg -side left -fill x -expand 1 # Get the maximum width of the value fields for the bagged_radiobar set Tkeditpr(value_width) 0 foreach tag $Tkeditpr(radioflds) { set f [ftrim $flds($tag)] if {[string length $f] > $Tkeditpr(value_width)} { set Tkeditpr(value_width) [string length $f] } } # Get the maximum width of the value fields for the readonly_singletext fields set Tkeditpr(singletextvalue_width) 0 set flist {>Last-Modified >Arrival-Date >Closed-Date} foreach tag $flist { set f [ftrim $flds($tag)] if {[string length $f] > $Tkeditpr(singletextvalue_width)} { set Tkeditpr(singletextvalue_width) [string length $f] } } foreach efield [list Arrival-Date Last-Modified Closed-Date] { if {[check_suppressed_field $efield] != 1} { # We don't want to support editing these for now. readonly_singletext $efield [ftrim $flds(>$efield)] 14 $Tkeditpr(singletextvalue_width) } } frame .eflds radiobar_frame .eflds .eflds.lb set panelnum 0 foreach {efield elist} [list Class $TkGnats(ClassesList) State $TkGnats(StatesList) Priority {low medium high} Severity {non-critical serious critical} Confidential {no yes}] { if {[check_suppressed_field $efield] != 1} { bagged_radiobar .eflds.lb [string tolower $efield] $efield \ $elist None frm $Tkeditpr(value_width) $panelnum incr panelnum } } pack .eflds.lb -side left -pady 0 pack .eflds -side top -pady 0 -fill x -anchor w #puts stderr [concat "This is fun: " [grid slaves .eflds.lb]] frame .eboxs set nboxes 1 array set xpad {1 0 2 20 3 0} foreach {efield eframe} {Category clb Submitter-Id slb Responsible rlb} { if {[check_suppressed_field $efield] != 1} { frame .eboxs.$eframe -relief groove -borderwidth 2 edit_[string tolower $efield]_listbox .eboxs.$eframe * pack .eboxs.$eframe -side left -anchor nw -pady 2 -padx $xpad($nboxes) -fill y incr nboxes } } frame .eboxs.shortones -relief groove -borderwidth 2 foreach f $Tkeditpr(shorttextflds) { if {[check_suppressed_field $f] == 1} { continue } lappend Tkeditpr(tlist) [singletext .eboxs.shortones $f 20 "" 14] } pack .eboxs.shortones -side left if {$nboxes > 1} { pack .eboxs -side top -anchor w -pady 2 -padx 0 -fill x } foreach f $Tkeditpr(singletextflds) { if {[check_suppressed_field $f] == 1} { continue } lappend Tkeditpr(tlist) [singletext . $f 80 "" 14] } lappend Tkeditpr(tlist) [make_txt_mb $Tkeditpr(multitextflds)] set_text_traversal $Tkeditpr(tlist) wm title . "TkGnats - [lindex $TkGnats(ServerInfo) 0] - Edit Problem Report: [ftrim $flds(>Category)]/[ftrim $flds(>Number)]" wm iconbitmap . @$TkGnats(lib)/tkeditpr.xbm wm iconname . "$TkGnats(LogName)'s tkeditpr [ftrim $flds(>Number)]" fillfrm tkwait visibility . if {"$missing_list" != ""} { Msg "The following fields were missing from the report but will be added when you Save Changes:\n" [join $missing_list \n] set Tkeditpr(parsed_flds) [concat $Tkeditpr(parsed_flds) $missing_list] } } ################################################################## set whyText "" set Tkeditpr(prid) "" tkeditpr_process_args foreach f { tkpr_library.tcl tkprhelp.tcl tkprfont.tcl tkprdatesel.tcl } { source $TkGnats(lib)/$f } # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing if {[open_socket_gnatsd 1] == "-1"} { exit } if {[get_gnats_config] == "-1"} { exit } #TTD remove me after testing #set TkGnats(ReleaseBased) 1 set numerrs 0 if {$Tkeditpr(prid) == ""} { wm withdraw . Msg "No problem report id supplied!\n" "Usage: tkeditpr -prid=nnnn" incr numerrs } if {"$TkGnats(LogName)" == "root"} { wm withdraw . Msg "You cannot edit problem reports as root.\n" "Please use your own login." incr numerrs } if {$numerrs > 0} { close_socket_gnatsd 1 exit 1 } edit_window # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing close_socket_gnatsd 1 gnats-4.1.0/contrib/tkgnats/tkeditpr.xbm0000644000175000017500000000634306665615034021054 0ustar chewiechewie00000000000000#define tkeditpr.xbm_width 64 #define tkeditpr.xbm_height 64 static char tkeditpr.xbm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0x98, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x02, 0x44, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x03, 0x37, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8, 0x81, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x22, 0xe0, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 0x0c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; gnats-4.1.0/contrib/tkgnats/tkgnats0000744000175000017500000001162507005513656020110 0ustar chewiechewie00000000000000#!/bin/sh # the next line restarts using wish \ exec wish "$0" ${1+"$@"} proc tkgnats_error {msg} { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" "$msg" "error" 0 "OK" exit } proc tkgnats_usage {{str ""}} { tkgnats_error "${str}usage: tkgnats \[-lib 'tkgnatslib'\] \[-ini 'inifile'\] \ \[-servers 'serversfile'\]" } proc tkgnats_process_args {} { global TkGnats argc argv env set TkGnats(CurrentProgram) tkgnats if {$argc != 0} { if {$argc%2 != 0} { tkgnats_usage } for {set x 0} {$x<$argc} {incr x 2} { set opt [lindex $argv $x] set val [lindex $argv [expr $x+1]] switch -exact -- $opt -lib { set TkGnats(TKGNATSLIB) $val } -ini { set TkGnats(TKGNATSINI) $val } -servers { set TkGnats(TKGNATSSERVERS) $val } default { tkgnats_usage "Illegal option pair:\n'$opt $val'\n\n" } } } foreach var {TKGNATSLIB TKGNATSINI TKGNATSSERVERS} { if {![info exists TkGnats($var)]} { if {[info exists env($var)]} { set TkGnats($var) $env($var) } } } if {[info exists TkGnats(TKGNATSINI)]} { if {[file readable $TkGnats(TKGNATSINI)]} { source $TkGnats(TKGNATSINI) } { tkgnats_error "TkGnats INI file '$TkGnats(TKGNATSINI)' not readable" } } if {[info exists TkGnats(TKGNATSLIB)]} { set TkGnats(lib) $TkGnats(TKGNATSLIB) } if {![info exists TkGnats(lib)]} { set TkGnats(lib) [pwd]; ##TKGNATSLIB## } set TkGnats(TKGNATSLIB) $TkGnats(lib) if {[file readable $TkGnats(lib)/tkgnatsini]} { source $TkGnats(lib)/tkgnatsini } if {![info exists TkGnats(TKGNATSSERVERS)]} { set TkGnats(TKGNATSSERVERS) $TkGnats(lib)/servers } { if {![file readable $TkGnats(TKGNATSSERVERS)]} { tkgnats_error "TkGnats servers file '$TkGnats(TKGNATSSERVERS)' not readable" } } foreach var {TKGNATSLIB TKGNATSINI TKGNATSSERVERS} { if {[info exists TkGnats($var)]} { set env($var) $TkGnats($var) } } } proc tkgnats_get_servers {} { global TkGnats catch {source $TkGnats(TKGNATSSERVERS)} if {![info exists TkGnats(Servers)]} { set TkGnats(Servers) {} } if {$TkGnats(Servers) == {}} { set TkGnats(Servers) [list "Create/Query Problem Reports" {} {} {} {} {}] } set n 0 foreach s [split $TkGnats(Servers) \n] { if {[llength $s] < 2} { continue } if {[llength $s] != 6} { tkgnats_error "TkGnats servers file '$TkGnats(TKGNATSSERVERS)' has incorrect entries: $s\n\nFields: Title GNATS_SERVER GNATS_PORT GNATS_ADDR ServerDir GNATSDatabaseAlias" } set TkGnats(server,[format "%04d" $n]) $s incr n } } tkgnats_process_args foreach f { tkpr_library.tcl tkprhelp.tcl } { source $TkGnats(lib)/$f } tkgnats_get_servers frame .top pack .top # Add optional buttons to the top of the main menu if {[info exists TkGnats(MainMenu)]} { eval $TkGnats(MainMenu) } foreach s [lsort [array names TkGnats server,*]] { set b s_[lindex [split $s ,] 1] button .top.$b -relief raised -text [lindex $TkGnats($s) 0] \ -command "TkGnats_exec {$TkGnats(WISHPATH)} $TkGnats(lib)/tkquerypr.tcl \ -server [list $TkGnats($s)] &; schedule_reap" pack .top.$b -side top -fill x } button .top.about -relief raised -text "About TkGnats" \ -command {helpMsg TkGnats_Version} button .top.quit -relief raised -text "Quit" -command {destroy .} pack [frame .top.space1] -side top -fill x -pady 5 if {[info exists TkGnats(SiteReadMeFile)]} { regsub -all " " $TkGnats(SiteReadMeTitle) "_" Title button .top.readme -relief raised -text "$TkGnats(SiteReadMeTitle)" \ -command {show_help $Title "[file_get_text $TkGnats(SiteReadMeFile)]"} pack .top.readme -side top -fill x } if {[info exists TkGnats(TkGnatsDocFile)]} { regsub -all " " $TkGnats(TkGnatsDocTitle) "_" Title button .top.doc -relief raised -text "$TkGnats(TkGnatsDocTitle)" \ -command {show_help $Title "[file_get_text $TkGnats(TkGnatsDocFile)]"} pack .top.doc -side top -fill x } if {[info exists TkGnats(InfoReader)]} { button .top.info -relief raised -text "GNATS Info" \ -command "TkGnats_exec $TkGnats(InfoReader) &; schedule_reap" pack .top.info -side top -fill x } if {[info exists TkGnats(MailReader)]} { button .top.mail -relief raised -text "Mail System" \ -command "TkGnats_exec $TkGnats(MailReader) &; schedule_reap" pack .top.mail -side top -fill x } pack [frame .top.space2] -side top -fill x -pady 5 pack .top.about .top.quit -side top -fill x wm title . "TkGnats - Main Menu" wm iconbitmap . @$TkGnats(lib)/tkgnats.xbm wm iconname . "$TkGnats(LogName)'s TkGnats" gnats-4.1.0/contrib/tkgnats/tkgnats.10000644000175000017500000000450206665615034020246 0ustar chewiechewie00000000000000.TH tkgnats .SH NAME tkgnats \- X Window interface to the GNATS problem report database .SH SYNOPSIS \fBtkgnats\fP .SH DESCRIPTION \fBtkgnats\fP is a GUI interface to the \fBGNATS\fP problem report database. It should run on any platform supported by Tcl/Tk. It allows you to: .PP - Query the \fBGNATS\fP database. .PP - View and Edit items returned from a query. .PP - Print problem reports and summaries. .PP - Send followup-email regarding problem reports. The \fBtkgnats\fP command is the main menu for the system. It has these items: One or more GNATS database items .RS .in .5in .PP Send, query and edit problem reports. .PP .RE TkGnats Site README (optional) .RS .in .5in .PP Show special README file customized for your site. .PP .RE TkGnats Documentation (optional) .RS .in .5in .PP Show TkGnats documentation file. .PP .RE Gnats Info (optional) .RS .in .5in .PP Show Gnats GNU Info file. .PP .RE Mail System (optional) .RS .in .5in .PP Execute your mail reader. .RE .SH OPTIONS \fB-lib\fP \fITkGnats Library\fP .PP This is the directory where TkGnats is installed. \fB-ini\fP \fITkGnats initialization file\fP .PP This is meant for Windows users as an easy way for an individual to specify configuration parameters. \fB-servers\fP \fITkGnats servers file\fP .PP This overrides the default servers file TKGNATSLIB/servers. See the README.config file for details of this file. .SH REQUIREMENTS \fBtkgnats\fP assumes the following programs are present somewhere within the users search \fB$PATH\fP. .PP \fB(g)tbl\fP - For producing PostScript format printed reports. .PP \fB(g)roff\fP - For producing PostScript format printed reports. .PP \fBghostview\fP - For previewing PostScript format printed reports. .PP Many of these required programs can be redefined to something functionally similar by editing the \fBtkgnats.config\fP configuration file that is part of the tkgnats release. .SH USER INTERFACE NOTES See the on-line help with the \fIHelp\fP button. .SH SEE ALSO The various README files that come with TkGnats, and the GNATS Info file. .SH BUGS Please send mail to the author if you have a bug to report. .SH AUTHOR This version of tkgnats was created by Rick Macdonald from the original version 1.3 by Mike Hoegeman. .SH CORRESPONDENCE Email can be sent to the author at the following address. .PP \fIrickm@vsl.com\fP gnats-4.1.0/contrib/tkgnats/tkgnats.config0000644000175000017500000002241007005513656021345 0ustar chewiechewie00000000000000# # The site configuration file for TkGnats. # # This file is sourced by the TkGnats scripts # to obtain various configuration variables. # # Normally, only "Section 2" should need changing. # # You may want to copy your settings from "Section 2" into # $TkGnats(lib)/tkgnatsrc so they don't get overwritten every # time you update or re-install TkGnats. # ######################################################################## ### SECTION 1. ### ### This section is configured by the Makefile. ### ### You should change this via the Makefile. Do not edit it directly ### ######################################################################## set TkGnats(GNATS_ADDR) NOT-CONFIGURED; ##GNATS_ADDR## # The default mail address for # PR submissions to go to. set TkGnats(GNATS_USER) gnats; ##GNATS_USER## # The gnats administrator user id. set TkGnats(SUBMITTER) NOT-CONFIGURED; ##SUBMITTER## # GNATS Submitter-Id for your site; the ID # for arriving reports at TkGnats(GNATS_ADDR) set TkGnats(GNATS_ROOT) /usr/local/gnats/gnats-db; ##GNATS_ROOT## set TkGnats(GNATS_LIBEXECDIR) /usr/local/libexec; ##LIBEXECDIR## ######################################################################## ### SECTION 2. ### ### This section may be configured manually for your site. ### ######################################################################## #set TkGnats(GNATS_BINDIR) /dir/not/in/my/path # Set this if the GNATS programs query-pr # and nquery-pr aren't in your path. #set TkGnats(MailMethod) mailer #set TkGnats(MailMethod) smtp #set TkGnats(SMTP_SERVER) localhost #set TkGnats(SMTP_PORT) 25 ### ### Defaults for Creating new problem reports ### ### Any field may be set: set TkGnats(CreateDefault${field}) #set TkGnats(CreateDefaultState) open #set TkGnats(CreateDefaultCategory) test #set TkGnats(CreateDefaultClass) sw-bug #set TkGnats(CreateDefaultPriority) medium #set TkGnats(CreateDefaultSeverity) serious #set TkGnats(CreateDefaultConfidential) no #set TkGnats(CreateDefaultResponsible) gnats-admin #set TkGnats(StateInSendPr) 1 # See README.config for these parameters. #set TkGnats(ResponsibleInSendPr) 1 # See README.config for these parameters. ### ### Custom Class and State abbreviations for the Query window ### # Currently, Class and State names are given 5 and 9 characters in # the listbox respectively. If your custom Classes or States are # longer, use these variables to supply abbreviations. #set TkGnats(ClassAbbreviations) "installation ins management mgmt" #set TkGnats(StateAbbreviations) "lostinspace lost" ### ### Definitions for various support programs used by tkgnats ### ### Print spoolers and previewers # Comment out or use "" for unsupported Print spoolers. # Note: spaces must be put in between # pipe characters if you use pipes set TkGnats(psPrintSpooler) "lpr -P laser" # PostScript print spooler (from stdin) set TkGnats(dviPrintSpooler) "" # dvi print spooler (from stdin) set TkGnats(asciiPrintSpooler) "fmt -s -75 | prt" set TkGnats(latin1PrintSpooler) "fmt -s -75 | prt" set TkGnats(troffPrintSpooler) "fmt -s -75 | prt" # Plain text print spoolers (from stdin) # ms Macros for groff ("-ms" or "-mgs") set TkGnats(MsMacroSet) "-ms" # Comment out or use "" for unsupported Print previewers. set TkGnats(asciiPreviewer) "xterm -e pico %s" set TkGnats(latin1Previewer) "xterm -e pico %s" set TkGnats(dviPreviewer) "xdvi %s" set TkGnats(troffPreviewer) "xterm -e pico %s" set TkGnats(psPreviewer) "ghostview %s" # PostScript previewer for printed reports set TkGnats(Mailer) "/usr/lib/sendmail -em -oi -t" # Mailer to use for send prs, etc.. # Like GNATS, it must read headers from file. ### ### Fonts ### # Unix #set TkGnats(DialogFont) {fixed} #set TkGnats(TextFont) {fixed} #set TkGnats(HelpFont) {10x20} # Unix or Windows with Tcl 8.0 or newer #set TkGnats(DialogFont) {"ms sans serif" 8} #set TkGnats(TextFont) {"courier new" 8} #set TkGnats(HelpFont) {"courier new" 12} ### ### Focus Style ### set TkGnats(FocusStyle) mouse ### ### Colours ### set TkGnats(ReadOnlyBackground) green set TkGnats(EditFieldBackground) grey95 ### ### Optional Main Menu items ### #set TkGnats(MailReader) "xterm -font 10x20 -bg black -fg grey -T \"mail : tkgnats\" -sl 120 -geometry 80x25+0+0 -e pine" # Mail reader used by tkgnats Main Menu. # Commenting this out will cause the # 'Mail System' button to be omitted # from the tkgnats window. #set TkGnats(InfoReader) "xinfo"; # usable but not as nice #set TkGnats(InfoReader) "tkinfo -infofile gnats"; # Info Reader to use. # Get tkinfo v1.3 or newer. # Commenting this out will cause the # 'Gnats Info' button to be omitted # from the tkgnats window. set TkGnats(TkGnatsDocFile) "$TkGnats(lib)/tkgnats.doc" set TkGnats(TkGnatsDocTitle) "TkGnats Documentation" # These two items can be used to add a TkGnats # documentation button to the TkGnats Main Menu. # The "TkGnatsDocTitle" is the text that shows # on the button, and the "TkGnatsDocFile" is # file that is shown in a pop-up window. # Commenting these out will cause the # button to be omitted from the tkgnats window. #set TkGnats(SiteReadMeFile) "$TkGnats(lib)/Veritas_README" #set TkGnats(SiteReadMeTitle) "TkGnats Usage at Veritas" # These two items can be used to add a site # "readme" button to the TkGnats Main Menu. # The SiteReadMeTitle is the text that shows # on the button, and the "SiteReadMeFile" is # file that is shown in a pop-up window. # Commenting these out will cause the # button to be omitted from the tkgnats window. ### ### Other settings ### # This only applies to local disk access to the GNATS database #set TkGnats(edit_authorized_groups) {test prg} #set TkGnats(edit_authorized_users) $TkGnats(GNATS_USER) # List of users and/or groups that are # authorized to edit problem reports. # Other users will see the edit options # disabled in the various menus and dialogs. #set TkGnats(delete_authorized_groups) {} set TkGnats(delete_authorized_users) $TkGnats(GNATS_USER) # List of users and/or groups that are # authorized to delete problem reports. # These users must have write permissions # in $TkGnats(GNATS_ROOT)/gnats-adm. # Other users won't see the delete option # in the Query Actions menu at all. set TkGnats(TextWrap) word # # Type of wrapping to use on multiline # text fields when creating or editing PR's. # Note that no LF's are actually inserted into # the text. This does not affect the Email # dialog, which is set to wrap none. #set TkGnats(QueryOriginatorFormat) short # By default the Query listbox shows as many # characters of the Originator's name as will # fit into the space alloted. If you want the # first name only, set this to "short". #set TkGnats(QueryDefaultAction) view # By default the Query listbox views a PR when # you double click the left mouse button or press Enter. # You can optionally set this to "edit". #set TkGnats(ENVIRONMENT) "Something better than the hostname of your workstation" # This presets the Environment text in new problem # reports. #set TkGnats(ORGANIZATION) "Something good" # This presets the Organization text in new problem # reports. Defaults to the ORGANIZATION environment # variable, which could be a filename or some actual # text. If no env variable, defaults to the users # ~/.signature file. Otherwise defaults to the Submitter-Id. set TkGnats(AutoUpdateCheck) 1 # Check for TkGnats updates (when certain buttons are clicked) # Set to 0 to disable this check. set TkGnats(Quarter) Quarter # This is temporary. It allows you to give a different # name to the release-based GNATS field "Quarter". ### ### End ### gnats-4.1.0/contrib/tkgnats/tkgnats.doc0000644000175000017500000000703107005513656020647 0ustar chewiechewie00000000000000 This document covers features peculiar to TkGnats. See the GNATS documentation for general GNATS information. Last Modified: 26 Jun 1998 (TkGnats-3.0.4) ======== Contents ======== o Email Flow ========== ========== ========== Email Flow ========== ========== ========== ================================================= Email is sent by GNATS and TkGnats in these cases ================================================= 1) create new problem report (sent by GNATS only). 2) change State with Edit (sent by TkGnats only). 3) change Responsible with Edit (sent by TkGnats only). 3) change Priority or Severity with Edit (sent by TkGnats only). 4) the "Send Email..." option in Query, View and Edit (GNATS and TkGnats). ======================================= TkGnats knows of these email recipients ======================================= - the "actual sender" of the original problem report. - the name(s) in the "Notify-List" field. - the current "Responsible". - the "old and new Responsible" when Responsible changed by Edit. GNATS itself knows of these and many others, but I won't go into that here. =========================================== Email sent by GNATS and TkGnats now goes to =========================================== 1) create new problem report (sent by GNATS only). - bugs (GNATS itself). - gnats sends confirmation to the actual sender. - gnats sends a copy of the problem report to: - the default responsible person. - others that we configure. - note that TkGnats can't very well send a copy directly to anyone since GNATS has to get it first to add the problem report number, and other fields. 2) change State with Edit (note: _any_ State change) (TkGnats only); change Priority or Severity with Edit (TkGnats only). - the Responsible, the actual sender, and the Notify-List. - any of these that are the same as the person doing the Edit are removed from the address list. - this could be modified to be only certain State changes, like when the bug is closed, but let's try it like this for awhile. - note that GNATS's edit-pr does not do notification when the Priority or Severity is changed. 3) change Responsible with Edit (sent by TkGnats only). - the old and new Responsible, the actual sender, and the Notify-List. - any of these that are the same as the person doing the Edit are removed from the address list. 4) the "Send Email..." option in Query, View and Edit (GNATS and TkGnats). - bugs (GNATS itself). - GNATS sends one copy to the Responsible person, even if it was this person who sent the email. - optionally the Responsible, actual sender, and the Notify-List. - any of these that are the same as the person sending the email are removed (gray'ed out) from the address list. - note that the Responsible gets two copies: the copy from GNATS is the undesirable copy; I'm looking at inhibiting this copy. This copy doesn't have "bugs" in the address list like the copy sent by TkGnats, so the mailtool "Reply-to-All" option doesn't offer "bugs" as a recipient and some replies don't get into the Audit-Trail. gnats-4.1.0/contrib/tkgnats/tkgnats.xbm0000644000175000017500000000634006665615034020676 0ustar chewiechewie00000000000000#define tkgnats.xbm_width 64 #define tkgnats.xbm_height 64 static char tkgnats.xbm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe1, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x70, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x50, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; gnats-4.1.0/contrib/tkgnats/tkpr_library.tcl0000644000175000017500000031412607656616407021735 0ustar chewiechewie00000000000000proc dputs {text} { global env tcl_platform if {$tcl_platform(platform) == "unix"} { if {[info exists env(TKGNATSDEBUG)]} { if {$env(TKGNATSDEBUG) == "debug"} { puts $text } } } } proc TkGnats_config_platform {} { global TkGnats tcl_platform if {$tcl_platform(platform) != "unix"} { set TkGnats(GNATS_ACCESS) network set TkGnats(GNATS_ACCESS_METHOD) socket set TkGnats(MailMethod) smtp set TkGnats(UserSubdir) tkgnats } { set TkGnats(UserSubdir) .tkgnats # This resets control-v to be Paste instead of scrolling. bind Text {} } } proc TkGnats_config {} { global TkGnats TkGnats_config_platform # This file is optional if {[info exists TkGnats(ServerInfo)]} { if {[llength $TkGnats(ServerInfo)] != 6} { wm withdraw . Msg "Invalid ServerInfo: $TkGnats(ServerInfo)\n\nPlease completely exit TkGnats and start again. If it still fails, contact your TkGnats administrator." exit 1 } if {[lindex $TkGnats(ServerInfo) 1] != {}} { set TkGnats(GNATS_SERVER) [lindex $TkGnats(ServerInfo) 1] } if {[lindex $TkGnats(ServerInfo) 2] != {}} { set TkGnats(GNATS_PORT) [lindex $TkGnats(ServerInfo) 2] } if {[lindex $TkGnats(ServerInfo) 3] != {}} { set TkGnats(GNATS_ADDR) [lindex $TkGnats(ServerInfo) 3] } if {[lindex $TkGnats(ServerInfo) 4] != {}} { set TkGnats(GNATS_DB) [lindex $TkGnats(ServerInfo) 4] } if {[lindex $TkGnats(ServerInfo) 5] != {}} { set TkGnats(GNATS_DBALIAS) [lindex $TkGnats(ServerInfo) 5] } } foreach l [array names TkGnats] { set tmpvars($l) $TkGnats($l) } TkGnats_config_rc tmpvars foreach l [array names tmpvars] { if {![info exists TkGnats($l)]} { set TkGnats($l) $tmpvars($l) } } set TkGnats(EmailAddr) [add_email_domainname $TkGnats(EmailAddr)] if {[info tclversion] < 8.0} { foreach F {DialogFont TextFont HelpFont} { set f [string tolower $F] set TkGnats($f) $TkGnats($F) } } { foreach F {DialogFont TextFont HelpFont} { set f [string tolower $F] set TkGnats($f) $f eval font create $f [font actual $TkGnats($F)] } } option add *font $TkGnats(dialogfont) 100 set TkGnats(WISHPATH) [info nameofexecutable] # Automatic check for TkGnats updates TkGnats_UpdateCheck # Clipboard popup memu clipboard_create } proc TkGnats_exec {args} { global TkGnats if {[TkGnats_UpdateCheck]} { return } eval exec $args } proc TkGnats_UpdateCheck {} { global TkGnats if {$TkGnats(AutoUpdateCheck)} { if {![info exists TkGnats(UpdateCheckTime)]} { set TkGnats(UpdateCheckTime) [file mtime $TkGnats(lib)/VERSION] } { if {$TkGnats(UpdateCheckTime) != [file mtime $TkGnats(lib)/VERSION]} { TkGnats_UpdateRequired return 1 } } } return 0 } proc TkGnats_UpdateRequired {} { global TkGnats Msg "TkGnats has detected that some of its components have been recently updated.\n\nYou must quit all TkGnats windows and restart TkGnats." } proc TkGnats_config_rc {tmparr} { global env tcl_platform help_text upvar $tmparr TkGnats # We need to protect a previously set GNATS_ADDR from the value in tkgnats.config catch {set tempaddr $TkGnats(GNATS_ADDR)} catch {source $TkGnats(lib)/tkgnats.config} catch {set TkGnats(GNATS_ADDR) $tempaddr} ### This section tries to determine the users login, home directory, ### ### group and email address. If it fails for you, please let me know ### ### what you had to do to fix it. ### # TkGnats(LogName) # The login name for the user. # - first check the first output field of the id command # - then check USER env var # - then try LOGNAME # - then try running whoami # # TkGnats(GroupName) # The group name for the user. # - first check the output of the groups command for a list of groups # - then check the second output field of the id command for a primary group # - then check GROUP env var set user "" set group "" set x "" set y "" if {$tcl_platform(platform) == "unix"} { if {![catch {exec groups} result]} { set group $result } if {![catch {exec id} result]} { regexp \\(\[a-zA-Z0-9\]+\\) [lindex [split $result " "] 0] x regexp \\(\[a-zA-Z0-9\]+\\) [lindex [split $result " "] 1] y set user [string trim $x "()"] if {$group == ""} { set group [string trim $y "()"] } } } if {![info exists TkGnats(LogName)]} { if {"$user" != ""} { set TkGnats(LogName) $user } { if {[info exists env(USER)] && $env(USER) != "nouser"} { set TkGnats(LogName) $env(USER) } { if {[info exists env(LOGNAME)]} { set TkGnats(LogName) $env(LOGNAME) } { if {$tcl_platform(platform) == "unix" && ![catch {exec whoami} x]} { set TkGnats(LogName) $x } } } } } if {![info exists TkGnats(LogName)]} { wm withdraw . Msg "No user name found!\nPlease set USER or LOGNAME in environment." exit 1 } set TkGnats(FullName) [fullname_from_logname $TkGnats(LogName)] if {![info exists TkGnats(GroupName)]} { if {$group != ""} { set TkGnats(GroupName) $group } { if {[info exists env(GROUP)]} { set TkGnats(GroupName) $env(GROUP) } { set TkGnats(GroupName) "" } } } if {![info exists TkGnats(EmailAddr)]} { if {[info exists env(REPLYTO)]} { set TkGnats(EmailAddr) $env(REPLYTO) } { set TkGnats(EmailAddr) $TkGnats(LogName) } } if {![info exists TkGnats(HOME)]} { if {[info exists env(HOME)]} { set TkGnats(HOME) $env(HOME) } } if {![info exists TkGnats(CategoryList)]} { set TkGnats(CategoryList) "" } if {![info exists TkGnats(SubmitterList)]} { set TkGnats(SubmitterList) "" } if {![info exists TkGnats(ResponsibleList)]} { set TkGnats(ResponsibleList) "" } if {![info exists TkGnats(ResponsibleFile)]} { set TkGnats(ResponsibleFile) "" } if {![info exists TkGnats(ClassesList)]} { set TkGnats(ClassesList) "" } if {![info exists TkGnats(ClassesFile)]} { set TkGnats(ClassesFile) "" } if {![info exists TkGnats(StatesList)]} { set TkGnats(StatesList) "" } if {![info exists TkGnats(StatesFile)]} { set TkGnats(StatesFile) "" } # # Read in any and all tkgnatsrc files # set system $tcl_platform(os) if {[file readable $TkGnats(lib)/tkgnatsrc]} { source $TkGnats(lib)/tkgnatsrc } if {[file readable $TkGnats(lib)/tkgnatsrc.$system]} { source $TkGnats(lib)/tkgnatsrc.$system } set TkGnats(tkgnats_version) [file_get_text $TkGnats(lib)/VERSION] if {![info exists TkGnats(UserDir)]} { if {![info exists TkGnats(HOME)]} { wm withdraw . Msg "No home directory found!\n\nPlease set HOME in environment or TkGnats(UserDir) in the ini file.." exit 1 } set TkGnats(UserDir) $TkGnats(HOME)/$TkGnats(UserSubdir) } set TkGnats(UserDir) [string trimright $TkGnats(UserDir) /] check_tkgnats_userdir $TkGnats(UserDir) if {[file readable $TkGnats(UserDir)/tkgnatsrc]} { source $TkGnats(UserDir)/tkgnatsrc } if {[file readable $TkGnats(UserDir)/tkgnatsrc.$system]} { source $TkGnats(UserDir)/tkgnatsrc.$system } # # Get environment variable overrides # if {[info exists env(GNATS_ROOT)]} { set config [file_get_text $env(GNATS_ROOT)/gnats-adm/config] if {"$config" != ""} { set TkGnats(GNATS_ADDR) \ [string trim [lindex [split [lindex $config [lsearch -regexp $config GNATS_ADDR]] =] 1] \"] set TkGnats(GNATS_USER) \ [string trim [lindex [split [lindex $config [lsearch -regexp $config GNATS_USER]] =] 1] \"] set TkGnats(SUBMITTER) \ [string trim [lindex [split [lindex $config [lsearch -regexp $config SUBMITTER]] =] 1] \"] set TkGnats(GNATS_ROOT) $env(GNATS_ROOT) } } if {![info exists TkGnats(ORGANIZATION)]} { set TkGnats(ORGANIZATION) $TkGnats(SUBMITTER) if {[info exists env(ORGANIZATION)]} { if {[file readable $env(ORGANIZATION)]} { set TkGnats(ORGANIZATION) [file_get_text $env(ORGANIZATION)] } { set TkGnats(ORGANIZATION) $env(ORGANIZATION) } } { if {[info exists TkGnats(HOME)]} { if {[file readable $TkGnats(HOME)/.signature]} { set TkGnats(ORGANIZATION) [file_get_text $TkGnats(HOME)/.signature] } } } } set TkGnats(HOSTNAME) [info hostname] if {[info exists env(HOSTNAME)]} { set TkGnats(HOSTNAME) $env(HOSTNAME) } if {$tcl_platform(platform) == "unix" && $TkGnats(HOSTNAME) == ""} { if {[catch {exec /bin/hostname} TkGnats(HOSTNAME)]} { if {[catch {exec /usr/bin/hostname} TkGnats(HOSTNAME)]} { if {[catch {exec /usr/ucb/hostname} TkGnats(HOSTNAME)]} { if {[catch {exec /usr/bsd/hostname} TkGnats(HOSTNAME)]} { set TkGnats(HOSTNAME) "" } } } } } # # Make sure some required variables are set # if {![info exists TkGnats(GNATS_SERVER)]} { set TkGnats(GNATS_SERVER) "" } if {$TkGnats(GNATS_SERVER) == ""} { set TkGnats(GNATS_ACCESS) local set TkGnats(GNATS_ACCESS_METHOD) batch } { set TkGnats(GNATS_ACCESS) network if {![info exists TkGnats(GNATS_ACCESS_METHOD)]} { set TkGnats(GNATS_ACCESS_METHOD) socket } if {$TkGnats(GNATS_ACCESS_METHOD) != "batch"} { set TkGnats(GNATS_ACCESS_METHOD) socket } } if {![info exists TkGnats(GNATS_PORT)]} { set TkGnats(GNATS_PORT) 1529 } if {![info exists TkGnats(QuerySortMethod)]} { set TkGnats(QuerySortMethod) internal } catch {source $TkGnats(UserDir)/fonts} label .l set TkGnats(TkDialogFont) [.l cget -font] destroy .l if {![info exists TkGnats(DialogFont)]} { if {$tcl_platform(platform) == "unix"} { set TkGnats(DialogFont) $TkGnats(TkDialogFont) } { if {[info tclversion] < 8.0} { set TkGnats(DialogFont) $TkGnats(TkDialogFont) } { set TkGnats(DialogFont) {"ms sans serif" 8} } } } if {![info exists TkGnats(TextFont)]} { if {[info tclversion] < 8.0} { set font fixed } { if {[font metrics [list [lindex $TkGnats(DialogFont) 0]] -fixed]} { set font $TkGnats(DialogFont) } { set font fixed } } if {$tcl_platform(platform) == "unix"} { set TkGnats(TextFont) $font } { if {[info tclversion] < 8.0} { set TkGnats(TextFont) $font } { set TkGnats(TextFont) {"courier new" 8} } } } if {![info exists TkGnats(HelpFont)]} { if {$tcl_platform(platform) == "unix"} { set TkGnats(HelpFont) $TkGnats(TextFont) } { if {[info tclversion] < 8.0} { set TkGnats(HelpFont) $TkGnats(TextFont) } { set TkGnats(HelpFont) {"courier new" 10} } } } # # Set up for local or network access # if {![info exists TkGnats(GNATS_BINDIR)]} { set TkGnats(GNATS_BINDIR) "" } { set TkGnats(GNATS_BINDIR) [string trim $TkGnats(GNATS_BINDIR)] } if {$TkGnats(GNATS_BINDIR) != ""} { set bindir $TkGnats(GNATS_BINDIR)/ } { set bindir "" } if {[info exists TkGnats(GNATS_DBALIAS)] && $TkGnats(GNATS_DBALIAS) != ""} { set parms " -d $TkGnats(GNATS_DBALIAS)" } { set parms "" } if {$TkGnats(GNATS_ACCESS) == "local"} { set TkGnats(pr-edit) $TkGnats(GNATS_LIBEXECDIR)/gnats/pr-edit$parms set TkGnats(query-pr) ${bindir}query-pr$parms } { if {$TkGnats(GNATS_SERVER) != ""} { append parms " --host $TkGnats(GNATS_SERVER)" } if {$TkGnats(GNATS_PORT) != ""} { append parms " --port $TkGnats(GNATS_PORT)" } set TkGnats(pr-edit) $TkGnats(GNATS_LIBEXECDIR)/gnats/npr-edit$parms set TkGnats(query-pr) ${bindir}nquery-pr$parms } # # Now get any SERVER based tkgnatsrc # set TkGnats(SiteServerDir) $TkGnats(lib) set TkGnats(UserServerDir) $TkGnats(UserDir) set db "" if {[info exists TkGnats(ServerInfo)]} { set db [lindex $TkGnats(ServerInfo) 4] } if {$db != ""} { set TkGnats(SiteServerDir) $TkGnats(SiteServerDir)/$db if {[file readable $TkGnats(SiteServerDir)/tkgnatsrc]} { source $TkGnats(SiteServerDir)/tkgnatsrc } if {[file isdirectory $TkGnats(UserDir)/$TkGnats(GNATS_SERVER)]} { catch {file rename $TkGnats(UserDir)/$TkGnats(GNATS_SERVER) $TkGnats(UserDir)/$db} } set TkGnats(UserServerDir) $TkGnats(UserServerDir)/$db check_tkgnats_userdir $TkGnats(UserServerDir) if {[file readable $TkGnats(UserServerDir)/tkgnatsrc]} { source $TkGnats(UserServerDir)/tkgnatsrc } } # This checks for the query and sort subdirectories check_tkgnats_usersubdir $TkGnats(UserServerDir) # # Set up user id and password # if {$TkGnats(GNATS_ACCESS) == "local"} { set TkGnats(UseridPassword) "" } { set userid "" if {[info exists TkGnats(ServerPasswords)]} { foreach pwd [split $TkGnats(ServerPasswords) \n] { if {[lindex $pwd 0] == $TkGnats(GNATS_ADDR)} { set userid [lindex $pwd 1] set passwd [lindex $pwd 2] break } } } if {$userid == ""} { # Might as well see if there's a default access that's higher than the host access set userid "anonymous" set passwd "guest" } if {$TkGnats(GNATS_ACCESS_METHOD) == "socket"} { set TkGnats(UseridPassword) "$userid $passwd" } { set TkGnats(UseridPassword) "--user $userid --passwd $passwd" } } # # Set up mail method # if {![info exists TkGnats(SMTP_SERVER)]} { set TkGnats(SMTP_SERVER) "" } if {$TkGnats(SMTP_SERVER) == ""} { set TkGnats(MailMethod) mailer } { set TkGnats(MailMethod) smtp } if {![info exists TkGnats(SMTP_PORT)]} { set TkGnats(SMTP_PORT) 25 } # # Determine if this user is authorized to edit problem reports # This only applies to local disk access to the GNATS database. # Network access is controlled (later) by gnatsd. # if {$TkGnats(GNATS_ACCESS) == "local"} { set glist {} set ulist {} if {[info exists TkGnats(edit_authorized_groups)]} { set glist $TkGnats(edit_authorized_groups) } if {[info exists TkGnats(edit_authorized_users)]} { set ulist $TkGnats(edit_authorized_users) } set TkGnats(edit_authorized) 0 if {$ulist == {} && $glist == {}} { set TkGnats(edit_authorized) 1 } if {[lsearch -exact $ulist $TkGnats(LogName)] > -1} { set TkGnats(edit_authorized) 1 } foreach group $glist { if {[lsearch -exact $TkGnats(GroupName) $group] > -1} { set TkGnats(edit_authorized) 1 } } } # # Determine if this user is authorized to delete problem reports # set glist {} set ulist {} if {[info exists TkGnats(delete_authorized_groups)]} { set glist $TkGnats(delete_authorized_groups) } if {[info exists TkGnats(delete_authorized_users)]} { set ulist $TkGnats(delete_authorized_users) } set TkGnats(delete_authorized) 0 if {[lsearch -exact $ulist $TkGnats(LogName)] > -1} { set TkGnats(delete_authorized) 1 } foreach group $glist { if {[lsearch -exact $TkGnats(GroupName) $group] > -1} { set TkGnats(delete_authorized) 1 } } # The delete function only works on local GNATS systems. if {$TkGnats(GNATS_ACCESS) != "local"} { set TkGnats(delete_authorized) 0 } } proc get_gnats_config {} { global TkGnats # # Determine if GNATS is Release Based, and get GNATS lists # # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing if {[info exists TkGnats(socket,$TkGnats(GNATS_SERVER),$TkGnats(GNATS_PORT),keepopen)]} { set keepopen "" } { set keepopen 1 } if {[open_socket_gnatsd $keepopen] == "-1"} { return -1 } get_gnats_version set mingnats 4.0 if {$TkGnats(GNATS_Version) < $mingnats || $TkGnats(GNATS_Version) == 3.2} { wm withdraw . Msg "Sorry, you're trying to talk to a GNATS $TkGnats(GNATS_Version) database but this version of TkGnats requires GNATS $mingnats or newer.\n\nTry ftp://sourceware.cygnus.com/pub/gnats/snapshots" return -1 } get_gnats_access check_release_based get_gnats_server_config if {[info exists TkGnats(SERVER-TKGNATS_MIN_VERSION)]} { set ver (unknown) regexp "tkgnats-(\[^ \]*)" $TkGnats(tkgnats_version) match ver if {[string compare $ver $TkGnats(SERVER-TKGNATS_MIN_VERSION)] < 0} { wm withdraw . Msg "Sorry, you're trying to talk to a GNATS $TkGnats(GNATS_Version) database that requires TkGnats version $TkGnats(SERVER-TKGNATS_MIN_VERSION) or newer, but you're only running TkGnats version $ver.\n\nTry http://www.cuug.ab.ca/~macdonal/tkgnats" return -1 } } if {![info exists TkGnats(QueryMode)]} { set TkGnats(QueryMode) sql2 } get_category_list get_submitter_list get_responsible_list get_classes_list get_states_list # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing close_socket_gnatsd $keepopen return "" } proc set_edit_authorized {} { global TkGnats if {$TkGnats(UserAccess) == "edit" || $TkGnats(UserAccess) == "admin"} { set TkGnats(edit_authorized) 1 } { set TkGnats(edit_authorized) 0 } } proc get_gnats_access {} { global TkGnats get_gnats_access_$TkGnats(GNATS_ACCESS_METHOD) } proc get_gnats_access_batch {} { global TkGnats if {![info exists TkGnats(UserAccess)]} { set TkGnats(UserAccess) unknown if {$TkGnats(GNATS_ACCESS) == "network"} { catch {eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) --closed-before=1970-01-01 -D} rep foreach l [split $rep \n] { if {[string first "received 520" $l] > 0} { Msg "GNATSD access error:\n\n$l'" Exit 1 } if {[string first "access level set" $l] > 0} { set TkGnats(UserAccess) [lindex $l end] break } } set_edit_authorized } } } proc get_gnats_access_socket {} { global TkGnats # The access level is saved when the socket is opened if {![info exists TkGnats(UserAccess)]} { set TkGnats(UserAccess) unknown } } proc get_gnats_version {} { global TkGnats get_gnats_version_$TkGnats(GNATS_ACCESS_METHOD) } proc get_gnats_version_batch {} { global TkGnats if {![info exists TkGnats(GNATS_Version)]} { if {[catch {eval exec $TkGnats(query-pr) --version} rep]} { set TkGnats(GNATS_Version) 0.0 } { set TkGnats(GNATS_Version) [lindex $rep end] } } } proc get_gnats_version_socket {} { global TkGnats # The version number is saved when the socket is opened if {![info exists TkGnats(GNATS_Version)]} { set TkGnats(GNATS_Version) 0.0 } } proc check_tkgnats_userdir {userdir} { global TkGnats if {$TkGnats(CurrentProgram) == "tkgnats"} { return } if {![file isdirectory $userdir]} { file mkdir $userdir } } proc check_tkgnats_usersubdir {userdir} { global TkGnats if {$TkGnats(CurrentProgram) == "tkgnats"} { return } if {![file isdirectory $userdir/query]} { file mkdir $userdir/query catch {eval file copy [glob [file dirname $userdir]/query/*] $userdir/query} } if {![file isdirectory $userdir/sort]} { file mkdir $userdir/sort catch {eval file copy [glob [file dirname $userdir]/sort/*] $userdir/sort} } if {![file exists $userdir/default-sort]} { catch {eval file copy [glob [file dirname $userdir]/default-sort] $userdir} } if {![file exists $userdir/default-view]} { catch {eval file copy [glob [file dirname $userdir]/default-view] $userdir} } } # # Procedures # proc Msg {args} { set msg "" set nargs [expr [llength $args] - 1] for {set i 0} {$i < $nargs} {incr i} { append msg "[lindex $args $i]\n" } append msg "[lindex $args $nargs]" bell tk_dialog .tkerr "TkGnats Error" $msg "error" 0 "OK" } proc Notice {args} { set msg "" set nargs [expr [llength $args] - 1] for {set i 0} {$i < $nargs} {incr i} { append msg "[lindex $args $i]\n" } append msg "[lindex $args $nargs]" tk_dialog .tknotice "TkGnats Notice" $msg "info" 0 "OK" } # reap any zombied exec's set TkGnats(reap_scheduled) 0 proc do_reap {} { global TkGnats catch {exec true} set TkGnats(reap_scheduled) 0 } proc schedule_reap {} { global TkGnats if {!$TkGnats(reap_scheduled)} { set TkGnats(reap_scheduled) 1 after 5000 do_reap } } proc Exit {x} { #destroy .; # use if before tk3.3 exit $x } proc get_responsible_addr {name} { global TkGnats # strip off whitespace and then take out the first word. # we assume the rest is a (Full Name) type comment set name [string trim $name "\t\n "] set name [lindex [split $name "\t\n "] 0] set addr $name foreach n $TkGnats(ResponsibleFile) { set res [split $n :] if {$name == [lindex $res 0]} { if {[lindex $res 2] != ""} { set addr [lindex $res 2] break } } } return $addr } # # trim pr field data whitespace # proc ftrim {s} { return [string trim $s "\t\n "] } proc gnatsd_send {s msg} { global TkGnats #puts stderr "gnatsd_send $s $msg" if { [catch {puts $s $msg} errstr] } { Msg "Failure writing to socket, assuming it was closed. Error: $errstr" unset -nocomplain TkGnats(socket,$TkGnats(GNATS_SERVER),$TkGnats(GNATS_PORT)) set s [open_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) $keepopen] gnatsd_chdb $s puts $s $msg } } proc gnatsd_chdb {s} { global TkGnats # intentionally, this does not use gnatsd_send to avoid a loop puts $s "CHDB $TkGnats(GNATS_DBALIAS)" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { Msg "GNATSD error setting GNATS database:\n" "[join $rep \n]" return -1 } return $s } proc open_socket_gnatsd {{keepopen {}}} { global TkGnats if {$TkGnats(GNATS_ACCESS_METHOD) == "socket"} { if {[info exists TkGnats(socket,$TkGnats(GNATS_SERVER),$TkGnats(GNATS_PORT))]} { return $TkGnats(socket,$TkGnats(GNATS_SERVER),$TkGnats(GNATS_PORT)) } set s [open_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) $keepopen] if {$s == -1} { return -1 } if {[gnatsd_chdb $s] != $s} { return -1 } set cmd [subst "USER $TkGnats(UseridPassword)"] gnatsd_send $s $cmd set rep [get_socket_reply $s] if {[string match 2* [lindex $rep 0]]} { set accesslevelstr [lindex [lindex $rep 1] end] set accesslevel [string range $accesslevelstr 1 end-1] dputs "access level: $accesslevel" set TkGnats(UserAccess) $accesslevel set_edit_authorized return $s } { # gnatsd closes the connection when this happens unset TkGnats(socket,$TkGnats(GNATS_SERVER),$TkGnats(GNATS_PORT)) catch {unset TkGnats(socket,$TkGnats(GNATS_SERVER),$TkGnats(GNATS_PORT),keepopen)} Msg "GNATSD error sending USER command:\n" "[join $rep \n]" return -1 } } return "" } proc close_socket_gnatsd {{force {}}} { global TkGnats if {$TkGnats(GNATS_ACCESS_METHOD) == "socket"} { return [close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) $force] } return "" } proc open_socket {server port {keepopen {}}} { global TkGnats if {[info exists TkGnats(socket,$server,$port)]} { return $TkGnats(socket,$server,$port) } if {[catch {set s [socket $server $port]} rep]} { Msg "Error-1 opening socket/port $server $port:\n\n$rep" return "-1" } fconfigure $s -buffering line -translation crlf -buffersize 102400 set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 2* [lindex $rep 0]]} { Msg "Error-2 opening socket/port $server $port:\n" "[join $rep \n]" return "-1" } set TkGnats(socket,$server,$port) $s set rep [lindex $rep 0] if {[lsearch $rep GNATS] >= 0} { set TkGnats(GNATS_Version) [lindex $rep [expr [llength $rep] - 2]] } if {$keepopen != ""} { set TkGnats(socket,$server,$port,keepopen) $keepopen } dputs "opened socket $server $port $keepopen" return $s } proc close_socket {server port {force {}}} { global TkGnats if {![info exists TkGnats(socket,$server,$port)]} { dputs "non-exist return" return "" } #puts "force=$force exists=[info exists TkGnats(socket,$server,$port,keepopen)]" if {$force != "" || ![info exists TkGnats(socket,$server,$port,keepopen)]} { set s $TkGnats(socket,$server,$port) puts $s "QUIT" set rep [get_socket_reply $s] #puts "rep=$rep" close $s unset TkGnats(socket,$server,$port) catch {unset TkGnats(socket,$server,$port,keepopen)} dputs "closed socket $server $port $force" } { dputs "non-close return" } return "" } proc get_gnats_list {type} { global TkGnats return [get_gnats_list_$TkGnats(GNATS_ACCESS_METHOD) $type] } proc get_gnats_list_batch {type} { global TkGnats return [eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) --list-$type] } proc get_gnats_list_socket {type} { global TkGnats if {[set s [open_socket_gnatsd]] == "-1"} { return -1 } case $type categories { set cmd {LIST Categories} } submitters { set cmd {LIST Submitters} } responsible { set cmd {LIST Responsible} } gnatsd_send $s $cmd set rep [get_socket_reply $s] if {![string match 301* [lindex $rep 0]]} { Msg "GNATSD error getting GNATS $type list:\n" "[join $rep \n]" return -1 } set glist [join [get_gnatsd_reply_dot_ended $s] \n] # dputs $glist close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) return $glist } # # Get the valid values for a non-built-in field. # proc get_gnats_fieldvalue {type} { global TkGnats return [get_gnats_fieldvalue_$TkGnats(GNATS_ACCESS_METHOD) $type] } proc get_gnats_fieldvalue_batch {type} { global TkGnats return [eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) --list-$type] } proc get_gnats_fieldvalue_socket {type} { global TkGnats if {[set s [open_socket_gnatsd]] == "-1"} { return -1 } gnatsd_send $s "FVLD $type" set rep [get_socket_reply $s] if {![string match 301* [lindex $rep 0]]} { Msg "GNATSD error getting GNATS $type list:\n" "[join $rep \n]" return -1 } set glist [join [get_gnatsd_reply_dot_ended $s] \n] #puts $glist close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) return $glist } # # get a list of valid gnats categories # proc get_categories {{pat "*"}} { global TkGnats set catlist {} set clist [get_gnats_list categories] foreach c [split $clist "\n"] { # ignore lines with leading hash or underscore case $c "#*" { } "_*" { } $pat { lappend catlist [lindex [split $c ":"] 0] } } if {$catlist == ""} { Msg "Cannot get GNATS categories" return "" } return [lsort $catlist] } # # get a list of valid gnats submitters # proc get_submitters {{pat "*"}} { global TkGnats set sublist {} set slist [get_gnats_list submitters] foreach s [split $slist "\n"] { # ignore lines with leading hash or underscore case $s "#*" { } "_*" { } $pat { lappend sublist [lindex [split $s ":"] 0] } } if {$sublist == ""} { Msg "Cannot get GNATS submitters" return "" } return [lsort $sublist] } # # get a list of valid gnats responsibles # proc get_responsibles {{pat "*"}} { global TkGnats set reslist {} set TkGnats(ResponsibleFile) {} set rlist [get_gnats_list responsible] foreach r [split $rlist "\n"] { # ignore lines with leading hash or underscore case $r "#*" { } "_*" { } $pat { lappend reslist [lindex [split $r ":"] 0] lappend TkGnats(ResponsibleFile) $r } } if {$reslist == ""} { Msg "Cannot get GNATS responsibles" return "" } return [lsort $reslist] } # # get a list of valid gnats classes # proc get_classes {} { global TkGnats set reslist {} set TkGnats(ClassesFile) {} set classeslist {} set rlist [get_gnats_fieldvalue class] dputs "Classlist: $rlist" foreach r [split $rlist "\r\n"] { lappend classeslist $r lappend TkGnats(ClassesFile) $r } if {$classeslist == ""} { Msg "Cannot get GNATS classes" return "" } return $classeslist } # # get a list of valid gnats states # proc get_states {} { global TkGnats set reslist {} set TkGnats(StatesFile) {} set rlist [get_gnats_fieldvalue state] foreach r [split $rlist "\r\n"] { lappend stateslist $r lappend TkGnats(StatesFile) $r } if {$stateslist == ""} { Msg "Cannot get GNATS states" return "" } return $stateslist } proc get_classes_list {} { global TkGnats if {$TkGnats(ClassesList) == ""} { if {$TkGnats(ClassesFile) == ""} { set TkGnats(ClassesList) [get_classes] if {$TkGnats(ClassesList) == ""} { Msg "The classes list is empty!" Exit 1 } } { set clist "" foreach c $TkGnats(ClassesFile) { lappend clist [lindex [split $c ":"] 0] } set TkGnats(ClassesList) $clist } } } proc get_states_list {} { global TkGnats if {$TkGnats(StatesList) == ""} { if {$TkGnats(StatesFile) == ""} { set TkGnats(StatesList) [get_states] if {$TkGnats(StatesList) == ""} { Msg "The states list is empty!" Exit 1 } } { set slist "" foreach s $TkGnats(StatesFile) { lappend slist [lindex [split $s ":"] 0] } set TkGnats(StatesList) $slist } } } proc get_category_list {} { global TkGnats if {$TkGnats(CategoryList) == ""} { set TkGnats(CategoryList) [get_categories] if {$TkGnats(CategoryList) == ""} { Msg "The categories list is empty!" Exit 1 } } } proc get_submitter_list {} { global TkGnats if {$TkGnats(SubmitterList) == ""} { set TkGnats(SubmitterList) [get_submitters] if {$TkGnats(SubmitterList) == ""} { Msg "The submitters list is empty!" Exit 1 } } } proc get_responsible_list {} { global TkGnats if {$TkGnats(ResponsibleList) == ""} { if {$TkGnats(ResponsibleFile) == ""} { set TkGnats(ResponsibleList) [get_responsibles] if {$TkGnats(ResponsibleList) == ""} { Msg "The responsibles list is empty!" Exit 1 } } { set reslist "" foreach r $TkGnats(ResponsibleFile) { lappend reslist [lindex [split $r ":"] 0] } set TkGnats(ResponsibleList) [lsort $reslist] } } } proc get_audittrail_state {field} { global TkGnats if {[set s [open_socket_gnatsd]] == "-1"} { return -1 } gnatsd_send $s "FIELDFLAGS $field" set rep [get_socket_reply $s] dputs "gnatsd FIELDFLAGS $field says $rep" if {![string match 350* [lindex $rep 0]]} { Msg "GNATSD error determining FIELDFLAGS $field: \n" "[join $rep \n]" return -1 } if {[lsearch [lindex $rep 0] "requireChangeReason"] >= 0} { set TkGnats(Require-Reason-$field) 1 } { set TkGnats(Require-Reason-$field) 0 } dputs "gnatsd FIELDFLAGS $field results in $TkGnats(Require-Reason-$field)" return $TkGnats(Require-Reason-$field) } proc fullname_from_logname {{lname ""}} { global TkGnats if {"$lname" == ""} { set lname $TkGnats(LogName) } set fullname "" # Get the users name from the passwd file given their logname. # First try NIS, then try the regular passwd file... if {[catch {set fullname [exec niscat passwd.org_dir | grep ^${lname}: | cut -f5 -d:]}]} { if {[catch {set fullname [exec ypcat passwd | grep ^${lname}: | cut -f5 -d:]}]} { set fullname [lindex [split [file_search_string /etc/passwd ^${lname}:] :] 4] } } return [lindex [split $fullname ,] 0] } proc radiobar_frame {parent frname} { frame $frname frame $frname.labels frame $frname.values frame $frname.bars grid columnconfigure $frname 0 -weight 0 grid columnconfigure $frname 1 -weight 0 grid columnconfigure $frname 2 -weight 1 } # text field related procs proc textset {l t {p ""} {e text}} { # a label if {[winfo exists ${p}._${l}.textlabel]} { ${p}._${l}.textlabel configure -text $t return } # text widget if {[winfo exists ${p}._${l}_fr.text]} { ${p}._${l}_fr.text delete 1.0 end ${p}._${l}_fr.text insert 1.0 $t return } # entry widget (text and date) if {[winfo exists ${p}._${l}.$e]} { set state [${p}._${l}.$e cget -state] ${p}._${l}.$e config -state normal ${p}._${l}.$e delete 0 end ${p}._${l}.$e insert 0 $t ${p}._${l}.$e config -state $state return } #error "no such window for $l" } proc textget {l {p ""} {e text}} { if {[catch {set x [lindex [${p}._${l}.textlabel configure -text] 4]} ]} { if {[catch {set x [${p}._${l}_fr.text get 1.0 end]}]} { #return [string trim [${p}._${l}.$e get] "\n"] if {[catch {string trim [${p}._${l}.$e get] "\n"} x]} { return "" } { return $x } } } return "\n$x" } proc readonly_singletext {l {t ""} {labwid 12} {valwid 0}} { global TkGnats if {$valwid == 0} { set valwid [string length "$t"] } set alias [get_field_alias $l] set f [frame ._${l}] set lw [button $f.label -anchor w -width $labwid -text "${alias}: " -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 -highlightthickness 0] set ew [label $f.textlabel -anchor w -width $valwid -text "$t" -relief groove \ -highlightthickness 0 -borderwidth 2 -background $TkGnats(ReadOnlyBackground) -padx 2 -pady 0] pack $lw -side left -anchor w -pady 0 -padx 2 -ipady 0 pack $ew -side left -anchor w -pady 0 -ipady 0 pack $f -side top -anchor w -pady 0 -fill x -ipady 0 return $ew } bind Entry " " proc check_date_invalid {date {msg {Invalid date string:}}} { if {[regexp {^[0-9][0-9]?[0-9]?[0-9]?-[0-9][0-9]?-[0-9][0-9]?([ \t]?[0-9][0-9]?:[0-9][0-9]?)?$} $date]} { # convert yy-mm-dd format coming in set t [convert_date_format $date] } { set t $date } if {[catch {clock scan $t} err]} { Msg "$msg $date" return 1 } return 0 } proc normalize_date {date} { # Return date in YY-MM-DD format if {[regexp {^[0-9][0-9]?[0-9]?[0-9]?-[0-9][0-9]?-[0-9][0-9]?([ \t]?[0-9][0-9]?:[0-9][0-9]?)?$} $date]} { # convert yy-mm-dd format coming in set t [convert_date_format $date] } { set t $date } return [clock format [clock scan $t] -format "%Y-%m-%d"] } proc convert_date_format {date} { # convert from query-pr "yy-mm-dd hh:mm" format to "mm/dd/yy hh:mm" for Tcl clock command set dt [split $date] set d [split [lindex $dt 0] -] return "[lindex $d 1]/[lindex $d 2]/[lindex $d 0] [lindex $dt 1]" } proc get_datesel {w title} { global TkGnats set date [datesel [$w get] $title $TkGnats(textfont)] if {$date != ""} { $w delete 0 end $w insert 0 $date } } proc daterange {parent l w {t1 ""} {t2 ""} {labwid 12}} { global TkGnats set f [frame $parent._${l}] set alias [get_field_alias $l] set lw [button $f.label -anchor w -width $labwid -text "${alias}: " \ -command "helpMsg $alias" -relief flat -padx 0 -pady 0 -borderwidth 0] pack $lw -side left -anchor w set lw1 [button $f.label1 -anchor center -width 4 -text from \ -command "get_datesel $f.after \"$alias - from\"" \ -relief raised -padx 0 -pady 0 -borderwidth 1] set ew1 [entry $f.after -width 11 \ -insertwidth 1 -insertofftime 400 -highlightthickness 2 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground)] set_focus_style $ew1 $ew1 insert end $t1 pack $lw1 -side left -anchor w pack $ew1 -side left -anchor w -fill none -expand 0 set lw2 [button $f.label2 -anchor c -width 2 -text to \ -command "get_datesel $f.before \"$alias - to\"" \ -relief raised -padx 0 -pady 0 -borderwidth 1] set ew2 [entry $f.before -width 11 \ -insertwidth 1 -insertofftime 400 -highlightthickness 2 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground)] set_focus_style $ew2 $ew2 insert end $t2 bind $ew1 <3> "clipboard_post $ew1 %X %Y" bind $ew2 <3> "clipboard_post $ew2 %X %Y" pack $lw2 -side left -anchor w pack $ew2 -side left -anchor w -fill none -expand 0 pack $f -side top -anchor w -fill x -pady 2 return "$ew1 $ew2" } proc singletext {parent l w {t ""} {labwid 12}} { global TkGnats set alias [get_field_alias $l] set f [frame $parent._${l}] # trim off any leading >'s for the label text set lw [button $f.label -anchor w -width $labwid -text "${alias}: " \ -command "helpMsg $alias" -relief flat -padx 0 -pady 0 -borderwidth 0] set ew [entry $f.text -width $w \ -insertwidth 1 -insertofftime 400 -highlightthickness 2 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground)] set_focus_style $ew $ew insert end $t bind $ew <3> "clipboard_post $ew %X %Y" if {[check_suppressed_field [string trimleft $l >]] == 2} { $ew configure -state disabled -background $TkGnats(ReadOnlyBackground) -highlightcolor grey85 } pack $lw -side left -anchor w pack $ew -side left -anchor w -fill x -expand true if {[string first "Date-Required" $l] >= 0} { set cw [button $f.cal -anchor c -width 13 -text "Calendar..." \ -command "get_datesel $f.text $l" \ -relief raised -padx 0 -pady 0 -borderwidth 2] pack $cw -side left -anchor w -padx 1 } pack $f -side top -anchor w -fill x -pady 2 return $ew } proc bagged_singletext {l w bagname {prefix ""} {t ""}} { global TkGnats upvar #0 $bagname bag set f [frame ._${l}] set lw [label $f.label -anchor w -text "$l: "] set ew [entry $f.text -width 80 \ -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground)] set_focus_style $ew $ew insert end $t pack $lw -side left -anchor w -fill x -expand true pack $ew -side right -anchor e pack $f -side top -anchor w -fill x -pady 2 set bag($prefix$l) [format {[string trim [%s get]]} $lw] return $ew } proc multitext {lbl h} { global TkGnats set l _$lbl set f [frame .${l}_fr] button $f.label -anchor w -text "[string trimleft $lbl >]: " \ -command "helpMsg [string trimleft $lbl >]" \ -relief flat -padx 0 -pady 0 -borderwidth 0 text $f.text \ -wrap $TkGnats(TextWrap) \ -yscrollcommand "$f.sb set" \ -height $h -width 80 -relief sunken -padx 4 -insertwidth 1 \ -insertofftime 400 -borderwidth 2 -background $TkGnats(EditFieldBackground) set_focus_style $f.text scrollbar $f.sb -command "$f.text yview" -relief sunken pack $f.label -side top -anchor w pack $f.sb -side left -fill y pack $f.text -side right -fill both -expand true pack $f -side top -fill both -expand true -padx 16 -pady 2 return $f.text } proc set_focus_style {w} { global TkGnats if {$TkGnats(FocusStyle) == "mouse"} { bind $w "+focus $w" } } proc set_text_traversal {tlist} { set ll [llength $tlist] if {$ll < 2} { return } for {set x 1} {$x<$ll} {incr x} { set w [lindex $tlist $x] set prevw [lindex $tlist [expr $x-1]] bind $prevw "focus $w break" bind $prevw "focus $w" } bind [lindex $tlist [expr $ll-1]] "focus [lindex $tlist 0] break" bind [lindex $tlist [expr $ll-1]] "focus [lindex $tlist 0]" bind [lindex $tlist 0] "focus [lindex $tlist [expr $ll-1]] break" bind [lindex $tlist 0] "focus [lindex $tlist [expr $ll-1]]" for {set x 0} {$x < [expr $ll-1]} {incr x} { set w [lindex $tlist $x] set nextw [lindex $tlist [expr $x+1]] bind $nextw "focus $w break" bind $nextw "focus $w" } } proc bagged_radiobar {fr n labeltext blist offLabel dstbag {valwid 0} {rownum 0}} { radiobar $fr $n $labeltext $blist $offLabel > $dstbag $valwid $rownum } # make one in a list a radiobutton bar proc radiobar {fr n labeltext blist offLabel {varprefix ""} {aname ""} {valwid 0} {rownum 0}} { global TkGnats flds tcl_platform if {$tcl_platform(platform) == "unix"} { set buttonbd 2 } { set buttonbd 0 } if {"$aname" != ""} { set vname [set aname]($varprefix$labeltext) } { set vname $varprefix$labeltext } global $vname # alternate the colours so one can see the seperations if {($rownum & 1) == 1} { set panelbg "lightblue" } { set panelbg "grey" } set alias [get_field_alias $labeltext] set $vname "" button $fr.labels_$n -text "${alias}: " -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 -width 14 -anchor w \ -highlightthickness 0 -borderwidth 0 grid $fr.labels_$n -in $fr -column 0 -row $rownum -sticky w -padx 0 -pady 0 -ipady 0 if {$valwid != 0} { label $fr.values_$n -text "[string trim $flds($varprefix$labeltext) " \n\t"]" \ -relief groove -anchor w -width $valwid -background $TkGnats(ReadOnlyBackground) \ -padx 2 -pady 0 -highlightthickness 0 -borderwidth 2 grid $fr.values_$n -in $fr -column 1 -row $rownum -sticky {w n s} -padx 0 -pady 0 -ipady 0 } if {[check_suppressed_field $labeltext] == 2} { set state disabled } { set state normal } frame $fr.bars_$n -bg $panelbg set bcount 0 set bframe 0 frame $fr.bars_$n.$bframe -bg $panelbg pack $fr.bars_$n.$bframe -side top -anchor nw -fill x foreach b $blist { radiobutton $fr.bars_$n._$b -bg $panelbg \ -text $b -relief flat -variable $vname -pady 0 \ -highlightthickness 0 -borderwidth $buttonbd -state $state # Buttons that say None should set variable to the empty # string... if {"$b" == "$offLabel"} { $fr.bars_$n._$b configure -value "" } { $fr.bars_$n._$b configure -value $b } pack $fr.bars_$n._$b -in $fr.bars_$n.$bframe -side left -anchor w -padx 8 -pady 0 -fill none -expand 0 -ipady 0 incr bcount if {$bcount > 7} { set bcount 0 incr bframe frame $fr.bars_$n.$bframe -bg $panelbg pack $fr.bars_$n.$bframe -side top -anchor nw -fill x } } grid $fr.bars_$n -in $fr -column 3 -row $rownum -sticky {w e} -padx 0 -pady 0 } proc radiobar_set {fr n b} { $fr.bars_$n._$b invoke } # make one in a list a radiobutton bar proc checkbar {fr n labeltext blist offLabel {rownum 0}} { global tcl_platform if {$tcl_platform(platform) == "unix"} { set buttonbd 2 } { set buttonbd 0 } upvar #0 gbag ${labeltext} # alternate the colours so one can see the seperations if {($rownum & 1) == 1} { set panelbg "lightblue" } { set panelbg "grey" } set alias [get_field_alias $labeltext] button $fr.labels_$n -text "${alias}: " -command "helpMsg $alias" \ -relief flat -width 14 -padx 0 -pady 0 -borderwidth 0 -anchor w -highlightthickness 0 grid $fr.labels_$n -in $fr -column 0 -row $rownum -sticky w -padx 0 -pady 0 -ipady 0 frame $fr.bars_$n -bg $panelbg set bcount 0 set bframe 0 frame $fr.bars_$n.$bframe -bg $panelbg pack $fr.bars_$n.$bframe -side top -anchor nw -fill x foreach b $blist { checkbutton $fr.bars_$n._$b -bg $panelbg \ -offvalue "" \ -text $b -relief flat -highlightthickness 0 -borderwidth $buttonbd \ -variable [format "%s(%s)" ${labeltext} ${b}] -pady 0 # Buttons that say None should set variable to the empty string... if {"$b" == "$offLabel"} { $fr.bars_$n._$b configure -onvalue "_ALL_" -offvalue "" } { $fr.bars_$n._$b configure -onvalue $b -offvalue "" } set gbag($b) "" pack $fr.bars_$n._$b -in $fr.bars_$n.$bframe -side left -anchor w -padx 8 -pady 0 -fill none -expand 0 -ipady 0 incr bcount if {$bcount > 7} { set bcount 0 incr bframe frame $fr.bars_$n.$bframe -bg $panelbg pack $fr.bars_$n.$bframe -side top -anchor nw -fill x } } # set active [lindex $blist 0] # $fr.bars_$n.$active select grid $fr.bars_$n -in $fr -column 3 -row $rownum -sticky {w e} -padx 0 -pady 0 } # # convert some numeric fields in a 'query-pr --sql2' # record named 'f' in the caller to mnemonic strings # proc convertsqlflds {f} { upvar 1 $f flds foreach a [array names flds] { set n $flds($a) case $a Severity { case $n 1 { } 2 { } 3 { } } Priority { case $n 1 { } 2 { } 3 { } } } } # # split a pr stream into a tcl array named v # # A special array index called _prefix_ contains all the text prior to # to the first gnats field # proc parsepr_txt {txt varname} { upvar 1 $varname fields set gnats_tag_exp {^(>[^:]+):(.*)} set mail_tag_exp {^([A-Z][^:]+):[ ]*(.*)} set no_gnats_tags_yet 1 set fields(_prefix_) "" set fldtags {_prefix_} set leftoverln "" set prtxt [split $txt "\n"] set prlen [llength $prtxt] set pridx 0 while {1} { if {"$leftoverln" == ""} { if {$pridx >= $prlen} { break } set ln [lindex $prtxt $pridx] incr pridx } { set ln $leftoverln set leftoverln "" } set tag "" set val "" regexp $gnats_tag_exp $ln matched tag val if {"$tag" != ""} { set no_gnats_tags_yet 0 # a gnats tag # gnats tags can be multiline so now get all the lines 'till the next gnats tag lappend fldtags $tag set fields($tag) "$val\n" while {$pridx < $prlen} { set ln [lindex $prtxt $pridx] incr pridx set tag2 "" regexp $gnats_tag_exp $ln matched tag2 val if {"$tag2" != ""} { # a new gnats tag so we have hit the end of the # current one.. leave the line we just read in # leftoverln and continue on in the loop set leftoverln $ln break; } append fields($tag) "$ln\n" } continue } # If we get here the current line is not part of a gnats tag value pair if {$no_gnats_tags_yet} { append fields(_prefix_) "$ln\n" } set tag "" set val "" # Here is where we split out regular mail headers if needed. regexp $mail_tag_exp $ln matched tag val if {"$tag" != ""} { # mail header tags can be multiline so now # get all the lines 'till the next gnats or mail tag lappend fldtags $tag set fields($tag) "[string trim $val]\n" # _prefix_len_ is used in writepr to know how many lines to replace (ie Reply-To). set fields(_prefix_len_$tag) 1 while {$pridx < $prlen} { set ln [lindex $prtxt $pridx] incr pridx set tag2 "" set tag3 "" regexp $gnats_tag_exp $ln matched tag2 val regexp $mail_tag_exp $ln matched tag3 val if {"$tag2$tag3" != ""} { # a new gnats or mail tag so we have hit the end of the # current one.. leave the line we just read in # leftoverln and continue on in the loop set leftoverln $ln break; } append fields(_prefix_) "$ln\n" set fields($tag) "[string trim "[string trim $fields($tag)] [string trim $ln]"]\n" incr fields(_prefix_len_$tag) } } { # This is a header line that doesn't match the mail_tag_exp, such as the first "From ". } } return $fldtags } proc write_listbox {lbname fname} { set fout [open $fname w] set sz [$lbname size] for {set x 0} {$x < $sz} {incr x 1} { puts $fout [$lbname get $x] } close $fout } proc write_listbox_selection {lbname fname} { set fout [open $fname w] puts $fout [$lbname get [$lbname curselection]] close $fout } proc foreach_listbox {lbname procname} { set sz [$lbname size] for {set x 0} {$x < $sz} {incr x 1} { if {[$procname [$lbname get $x]] != 0} { return } } } proc get_max_strlen { l } { set maxlen 0 foreach e $l { if {[string length $e] > $maxlen} { set maxlen [string length $e] } } return $maxlen } proc build_sort_cmd {fieldnames fieldflgs sortfields} { global TkGnats return [build_sort_cmd_$TkGnats(QuerySortMethod) $fieldnames $fieldflgs $sortfields] } proc build_sort_cmd_external {fieldnames fieldflgs sortfields} { set rval "-fb -t|" foreach fname $sortfields { set idx [lsearch $fieldnames $fname] set flgs [lindex $fieldflgs $idx] append rval [format " +%d%s -%d" $idx $flgs [expr $idx+1]] } return "$rval" } proc build_sort_cmd_internal {fieldnames fieldflgs sortfields} { set rval "" foreach fname $sortfields { append rval " [lsearch $fieldnames $fname]" } return "$rval" } proc sort_listbox {lb} { set vals [lsort [$lb get 0 end]] $lb delete 0 end eval $lb insert end $vals } proc clipboard_create {} { event add <> event add <> event add <> set m .clipboardmenu menu $m -tearoff 0 $m add command -label "Cut" -accel "Ctrl+X" $m add command -label "Copy" -accel "Ctrl+C" $m add command -label "Paste" -accel "Ctrl+V" $m add command -label "Delete" -accel "Delete" $m add separator $m add command -label "Select All" -accel "Ctrl+/" } proc clipboard_post {w x y} { set m .clipboardmenu if {[winfo class $w] == "Text"} { set sel [$w tag ranges sel] } { if {[$w selection present]} { set sel "1" } { set sel "" } } if {$sel == ""} { set selstate disabled } { set selstate normal } set editstate [$w cget -state] if {$editstate == "disabled"} { set cutstate $editstate } { set cutstate $selstate } if {[catch {selection get -displayof $w -selection CLIPBOARD} sel] || $sel == ""} { set pastestate disabled } { set pastestate $editstate } $m entryconfig "Cut" -command "clipboard_doit $w " -state $cutstate $m entryconfig "Copy" -command "clipboard_doit $w " -state $selstate $m entryconfig "Paste" -command "clipboard_doit $w " -state $pastestate $m entryconfig "Delete" -command "clipboard_doit $w Delete" -state $cutstate $m entryconfig "Select All" -command "clipboard_doit $w Control-slash" tk_popup $m $x $y } proc clipboard_doit {w opt} { event generate $w <$opt> } proc make_txt_mb {multitextflds} { global TkGnats global flds set f [frame .multiline -relief groove -borderwidth 2] frame .mb button .mb.lab -text "Text Fields =>" -width 14 -anchor w -command "helpMsg Text-Fields" \ -relief flat -padx 0 -pady 0 -borderwidth 0 pack .mb.lab -side left -anchor w set count 0 set num 0 foreach field $multitextflds { if {[check_suppressed_field $field] != 1} { if {[info exists flds($field)]} { set tlength [string length $flds($field)] #puts stderr "field $field ($flds($field) has length: $tlength" } { set tlength 0 } if {$tlength < 2} { set buttonbackground "grey" } { set buttonbackground "lightblue" } set alias [get_field_alias $field] button .mb.b$num -text "${alias}:" -command "switch_txt $field {$multitextflds}" -bg $buttonbackground pack .mb.b$num -side left -anchor w incr count if {$count == 1} { set TkGnats(first_multitext) $field } } incr num } if {$count == 0} { wm withdraw . Msg "GNATS config error: at least one Multitext field must be included but all have been suppressed in the gnats-adm/config file." exit 1 } button .mb.insert -text "Insert File..." -command "insert_file .multiline.text" pack .mb.insert -side right -anchor e pack .mb -side top -anchor w -fill x -in $f text $f.text -height 12 -width 80 -relief sunken -padx 4 -insertwidth 1 \ -wrap $TkGnats(TextWrap) -yscrollcommand "$f.sby set" -xscrollcommand "$f.sbx set" \ -highlightthickness 2 -insertofftime 400 -borderwidth 2 -font $TkGnats(TextFont) #set TkGnats(mtextbackground) [$f.text cget -background] set TkGnats(mtextbackground) [.mb.insert cget -background] $f.text configure -background $TkGnats(EditFieldBackground) set_focus_style $f.text bind $f.text "" bind $f.text <3> "clipboard_post $f.text %X %Y" scrollbar $f.sby -command "$f.text yview" -relief sunken # Create padding based on the y scrollbar width and border frame $f.bottom scrollbar $f.sbx -command "$f.text xview" -borderwidth 2 -orient horizontal set pad [expr [$f.sby cget -width] + 2 * \ ([$f.sby cget -bd] + [$f.sby cget -highlightthickness])] frame $f.pad -width $pad -height $pad pack $f.pad -in $f.bottom -side left pack $f.sbx -in $f.bottom -side bottom -fill x pack $f.bottom -side bottom -fill x pack $f.sby -side left -fill y pack $f.text -side right -fill both -expand true pack $f -side top -fill both -expand true -pady 4 return "$f.text" } proc flush_multitext {} { global current_multi_text frm set f .multiline if {"$current_multi_text" != ""} { set frm($current_multi_text) "[string trim [$f.text get 1.0 end] "\t\n "]\n" } } proc flush_singletext {lst {p ""}} { global frm #set frm($tag) [string trim [textget $tag] "\t\n "] foreach tag $lst { if {[catch {string trim [textget $tag $p] "\t\n "} frm($tag)]} { set frm($tag) "" } } if {[info exists frm(X-GNATS-Notify)]} { set frm(X-GNATS-Notify) [fix_email_addresses $frm(X-GNATS-Notify)] } } proc switch_txt {name multitextflds} { global TkGnats current_multi_text frm set f .multiline # write the current text out back into the frm bag flush_multitext # reset the currently selected button relief and command set num [lsearch $multitextflds $current_multi_text] if {$num >= 0} { .mb.b$num configure -relief raised \ -command "switch_txt $current_multi_text {$multitextflds}" } # load the text widget with the new text if {[$f.text cget -state] == "disabled"} { $f.text configure -state normal -background $TkGnats(EditFieldBackground) \ -highlightcolor black catch {.mb.insert configure -state normal} } $f.text delete 1.0 end $f.text insert 1.0 $frm($name) if {[check_suppressed_field [string trimleft $name >]] == 2} { $f.text configure -state disabled -background $TkGnats(mtextbackground) \ -highlightcolor grey85 catch {.mb.insert configure -state disabled} } # set the newly selected button relief and command set current_multi_text $name set num [lsearch $multitextflds $current_multi_text] .mb.b$num configure -relief sunken -command "helpMsg [get_field_alias $current_multi_text]" } proc save_sort_fields {sortfile sortfields} { if {$sortfile != ""} { set fout [open $sortfile "w"] puts $fout "set Query(user_sort_flds) \{$sortfields\}" close $fout } } proc insert_file {w} { global TkGnats tk_strictMotif set initialdir "" if {[info exists TkGnats(InsertFileDir)]} { if {[file isdirectory $TkGnats(InsertFileDir)]} { set initialdir $TkGnats(InsertFileDir) } } if {$initialdir == ""} { if {[info exists TkGnats(HOME)]} { set initialdir $TkGnats(HOME) } { set initialdir [pwd] } } set tk_strictMotif 1 set file [tk_getOpenFile -initialdir $initialdir -title "Enter filename to insert"] set tk_strictMotif 0 if {$file != ""} { set fin [open $file r] $w insert insert [read $fin] close $fin } } proc busy_cursor {opt} { global BusyCursor switch $opt { set { set BusyCursor [list {. left_ptr}] set list [winfo children .] while {$list != ""} { set next {} foreach w $list { set cursor [lindex [$w config -cursor] 4] set class [winfo class $w] if {$class == "Toplevel" || $cursor != ""} { lappend BusyCursor [list $w $cursor] } set next [concat $next [winfo children $w]] } set list $next } foreach w $BusyCursor { catch {[lindex $w 0] config -cursor watch} } update idletasks } clear { foreach w $BusyCursor { catch {[lindex $w 0] config -cursor [lindex $w 1]} } } } } proc file_search_string {file string} { if {[catch {open $file r} fin]} { return "" } set text [split [read $fin] "\n"] close $fin return [lindex $text [lsearch -regexp $text $string]] } proc file_get_text {file} { if {[catch {open $file r} fin]} { return "" } set text [read $fin] close $fin return [string trimright $text "\n"] } proc file_put_text {file text} { if {[catch {open $file w} fout]} { return "" } puts $fout $text close $fout return $file } proc get_socket_reply {s} { set rep [gets $s] while {[regexp {^[0-9]+-} $rep]} { lappend reply $rep set rep [gets $s] } lappend reply $rep return $reply } proc check_release_based_batch {} { global TkGnats catch {eval exec $TkGnats(query-pr) --keywords} rep if {[string first "unrecognized option" $rep] < 0} { set TkGnats(ReleaseBased) 1 } { set TkGnats(ReleaseBased) 0 } } proc check_release_based_socket {} { global TkGnats set TkGnats(ReleaseBased) 0 if {[set s [open_socket_gnatsd]] == "-1"} { return -1 } gnatsd_send $s "KYWD" set rep [get_socket_reply $s] #puts "rep=$rep" if {[string first "Unrecognized command" [lindex $rep 0]] < 0} { set TkGnats(ReleaseBased) 1 } { set TkGnats(ReleaseBased) 0 } close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) } proc check_release_based {} { global TkGnats check_release_based_$TkGnats(GNATS_ACCESS_METHOD) } #proc get_gnats_server_config_batch {} { # global TkGnats # if {[catch {eval exec $TkGnats(query-pr) --list-config} config] != 0 || \ # [string first "unrecognized option" $config] >= 0} { # Msg "Error getting server CONFIG list:\n" "[lindex [split $config \n] 0]" # return -1 # } # return $config #} # #proc get_gnats_server_config_socket {} { # global TkGnats # if {[set s [open_socket_gnatsd]] == "-1"} { # return -1 # } # # gnatsd_send $s "LCFG" # set rep [get_socket_reply $s] # #puts "rep=$rep" # if {![string match 2* [lindex $rep 0]]} { # Msg "GNATSD error getting server CONFIG list:\n" "[join $rep \n]" # return -1 # } # # set config [join [get_gnatsd_reply_dot_ended $s] \n] # # close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) # return $config #} proc get_gnats_server_config {} { global TkGnats # set config [get_gnats_server_config_$TkGnats(GNATS_ACCESS_METHOD)] # if {$config == "-1"} { # return # } # foreach option [split $config \n] { # set val [split [string trim $option "{} \t\n\r"] "="] # set TkGnats(SERVER-[lindex $val 0]) [string trim [lindex $val 1] {\\"}] # } if {![info exists TkGnats(SERVER-REQUIRE_AUDIT_TRAIL_ENTRY)]} { set TkGnats(SERVER-REQUIRE_AUDIT_TRAIL_ENTRY) "Responsible,State,Priority,Severity,Date-Required" } if {![info exists TkGnats(SERVER-REQUIRE_AUDIT_TRAIL_REASON)]} { set TkGnats(SERVER-REQUIRE_AUDIT_TRAIL_REASON) "Responsible,State,Priority,Severity,Date-Required" } if {![info exists TkGnats(SERVER-REQUIRE_AUDIT_TRAIL_EMAIL)]} { set TkGnats(SERVER-REQUIRE_AUDIT_TRAIL_EMAIL) "Responsible,State,Priority,Severity,Date-Required" } if !{[info exists TkGnats(SERVER-SUPPRESSED_FIELDS)]} { set TkGnats(SERVER-SUPPRESSED_FIELDS) {} } if {![info exists TkGnats(SERVER-SUPPRESSED_SEND_FIELDS)]} { set TkGnats(SERVER-SUPPRESSED_SEND_FIELDS) {State,Responsible,Release-Note,Unformatted,Audit-Trail} } if {![info exists TkGnats(SERVER-SUPPRESSED_EDIT_FIELDS)]} { set TkGnats(SERVER-SUPPRESSED_EDIT_FIELDS) {} } if {![info exists TkGnats(SERVER-MANDATORY_FIELDS)]} { # Responsible, even if TkGnats(ResponsibleInSendPr)=1, still doesn't need to be mandatory by default. set TkGnats(SERVER-MANDATORY_FIELDS) "Class,State,Priority,Severity,Confidential,Category,Submitter-Id,Originator,Synopsis,Description" } if {![info exists TkGnats(SERVER-FIELD_ALIASES)]} { set TkGnats(SERVER-FIELD_ALIASES) {} } set TkGnats(SuppressedFields) "" foreach suppressed [split $TkGnats(SERVER-SUPPRESSED_FIELDS) ,] { if {[lsearch -exact "Text-Fields Number" $suppressed] < 0} { lappend TkGnats(SuppressedFields) [string trim $suppressed] } } set TkGnats(MandatoryFields) "" set mandatory [split $TkGnats(SERVER-MANDATORY_FIELDS) ,] foreach field $mandatory { set field [string trim $field] if {[lsearch -exact $TkGnats(SuppressedFields) $field] < 0} { lappend TkGnats(MandatoryFields) $field } } foreach {var parm} {RequireAudit REQUIRE_AUDIT_TRAIL_ENTRY RequireReason REQUIRE_AUDIT_TRAIL_REASON RequireEmail REQUIRE_AUDIT_TRAIL_EMAIL} { set TkGnats($var) "" foreach val [split $TkGnats(SERVER-$parm) ,] { lappend TkGnats($var) [string trim $val] } } foreach {var1 var2 parm} {SuppressedSendFields SuppressedSendFieldsUnless SUPPRESSED_SEND_FIELDS SuppressedEditFields SuppressedEditFieldsUnless SUPPRESSED_EDIT_FIELDS} { set TkGnats($var1) "" set TkGnats($var2) "" foreach val [split $TkGnats(SERVER-$parm) ,] { foreach {field unless junk} [split $val ()] {break} lappend TkGnats($var1) [string trim $field] lappend TkGnats($var2) [string trim $unless] } } set TkGnats(FieldAliases) "" set TkGnats(FieldAliasesReverse) "" foreach val [split $TkGnats(SERVER-FIELD_ALIASES) ,] { foreach {field alias junk} [split $val ()] {break} if {$alias == ""} { set alias $field } lappend TkGnats(FieldAliases) [string trim $field] [string trim $alias] lappend TkGnats(FieldAliasesReverse) [string trim $alias] [string trim $field] } } proc check_audit_trail_opts {requirement field} { global TkGnats set field [string trimleft $field >] # if we have to do this for every field, then it is a no brainer. #if {[lsearch -exact $TkGnats(Require$requirement) "all"] >= 0} { # return 1 #} # if we found out that we needed to do it for this field, do it if {[info exists TkGnats(Require-$requirement-$field)]} { dputs "Reason trail for $requirement $field $TkGnats(Require-$requirement-$field)" return $TkGnats(Require-$requirement-$field) } if {$requirement == "Reason"} { dputs "Reason audit trail for $requirement $field unknown, asking." return [get_audittrail_state $field] } # no way to check the other kinds yet. return 0 } proc get_field_alias {f} { global TkGnats set field [string trimleft $f >] array set aliases $TkGnats(FieldAliases) if {[info exists aliases($field)]} { set field $aliases($field) } if {$field == "X-GNATS-Notify"} { set alias Notify-List } { set alias $field } return $alias } proc get_field_alias_reverse {field} { global TkGnats array set aliases $TkGnats(FieldAliasesReverse) if {[info exists aliases($field)]} { return $aliases($field) } return $field } proc check_mandatory_field {f} { global TkGnats # Return flags: # 0 not mandatory # 1 mandatory set field [string trimleft $f >] if {([lsearch -exact $TkGnats(MandatoryFields) "all"] >= 0 && \ [lsearch -exact "Audit-Trail Unformatted Release-Note" $field] < 0) || \ [lsearch -exact $TkGnats(MandatoryFields) $field] >= 0} { # This field is mandatory. return 1 } return 0 } proc check_suppressed_field {f} { global TkGnats # Return flags: # 0 don't suppress # 1 suppress totally # 2 read-only in tkeditpr or tkviewpr set field [string trimleft $f >] if {[lsearch -exact $TkGnats(SuppressedFields) $field] >= 0} { # This field is totally suppressed. return 1 } if {$TkGnats(CurrentProgram) == "tkviewpr"} { # View is all read-only. return 2 } # The remainder (the "unless" options) only applies to Send and Edit set apps(tksendpr) Send set apps(tkeditpr) Edit if {![info exists apps($TkGnats(CurrentProgram))]} { # Don't suppress. return 0 } set app $apps($TkGnats(CurrentProgram)) set idx [lsearch -exact $TkGnats(Suppressed${app}Fields) $field] if {$idx < 0} { # No mention of this field for this app; don't suppress. return 0 } # If suppressing, return 1 (suppress) for Send and 2 (read-only) for Edit. set suppressflags(Send) 1 set suppressflags(Edit) 2 if {[info exists TkGnats(${field}In${app}Pr)] && $TkGnats(${field}In${app}Pr) != "0"} { # User asked for it, so don't suppress. set useropt 0 } { # Application suppress default from above. set useropt $suppressflags($app) } set serveropt [lindex $TkGnats(Suppressed${app}FieldsUnless) $idx] set flag $suppressflags($app) switch $serveropt { user { # Whatever the user asked for. set flag $useropt } edit { if {$TkGnats(edit_authorized)} { # User's edit authorized, so don't suppress. set flag 0 } } useredit - edituser { if {$TkGnats(edit_authorized)} { # User's edit authorized, so whatever the user asked for is OK. set flag $useropt } } admin { if {$TkGnats(UserAccess) == "admin"} { # User's admin authorized, so don't suppress. set flag 0 } } useradmin - adminuser { if {$TkGnats(UserAccess) == "admin"} { # User's admin authorized, so whatever the user asked for is OK. set flag $useropt } } } return $flag } proc get_gnatsd_reply_dot_ended {s} { set reply "" set rep [gets $s] while {$rep != "."} { if {[string first "410 Invalid PR " $rep] == 0} { # TTD: There's a bug in gnatsd. If you send "SQL2 23 547" and 547 doesn't exist, # it gives 410 error and closes the socket. We need to do one PR at a time. # This just affects selection query and Number field query. # See query_cmd_socket. break } lappend reply $rep set rep [gets $s] } # don't need the dot at the end # lappend reply $rep return $reply } proc escape_dots {txt} { set txttmp [split $txt \n] set len [llength $txttmp] for {set l 0} {$l < $len} {incr l} { set line [lindex $txttmp $l] if {[string match .* $line]} { #puts "escaping this line: $line" set txttmp [lreplace $txttmp $l $l .$line] } } set newlen [llength $txttmp] if {$len != $newlen} { Msg "Internal programming error escaping .'s in message body.\n" \ "Lines in=$len; lines out=$newlen" return $txt } return [join $txttmp \n] } proc unescape_dots {txt} { set txttmp [split $txt \n] set len [llength $txttmp] for {set l 0} {$l < $len} {incr l} { set line [lindex $txttmp $l] if {[string match .* $line]} { #puts "unescaping this line: $line" set txttmp [lreplace $txttmp $l $l [string range $line 1 end]] } } set newlen [llength $txttmp] if {$len != $newlen} { Msg "Internal programming error unescaping .'s in message body.\n" \ "Lines in=$len; lines out=$newlen" return $txt } return [join $txttmp \n] } proc TkGnats_sendmail {addrs mailtxt} { global TkGnats return [TkGnats_sendmail_$TkGnats(MailMethod) [fix_email_addresses $addrs] $mailtxt] } proc TkGnats_sendmail_mailer {addrs mailtxt} { global TkGnats # sendmail errors are mailed back to sender by sendmail if {[catch {open "|$TkGnats(Mailer)" w} fout]} { Msg "Error executing mailer \"$TkGnats(Mailer)\":\n" $fout return -1 } puts $fout $mailtxt close $fout return 0 } proc TkGnats_sendmail_smtp {addrs mailtxt} { global TkGnats if {[set s [open_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT)]] == "-1"} { return -1 } set my_addr $TkGnats(HOSTNAME) gnatsd_send $s "HELO $my_addr" set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 2* [lindex $rep 0]]} { Msg "SMTP error sending HELO $my_addr:\n" "[join $rep \n]" close_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT) return -1 } set add [lindex [extract_email_address $TkGnats(EmailAddr)] 0] gnatsd_send $s "MAIL FROM: <$add>" set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 2* [lindex $rep 0]]} { Msg "SMTP error sending MAIL FROM: <$add>\n" "[join $rep \n]" close_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT) return -1 } foreach addr [split $addrs ,] { set add [lindex [extract_email_address $addr] 0] if {$add == {}} { continue } gnatsd_send $s "RCPT TO: <$add>" set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 2* [lindex $rep 0]]} { Msg "SMTP error sending RCPT TO: <$add>\n" "[join $rep \n]" close_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT) return -1 } } set mailtxt [escape_dots $mailtxt] gnatsd_send $s "DATA" set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 3* [lindex $rep 0]]} { Msg "SMTP error sending DATA:\n" "[join $rep \n]" close_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT) return -1 } gnatsd_send $s $mailtxt gnatsd_send $s "." set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 2* [lindex $rep 0]]} { Msg "SMTP error sending complete message:\n" "[join $rep \n]" close_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT) return -1 } #puts "message=$mailtxt" close_socket $TkGnats(SMTP_SERVER) $TkGnats(SMTP_PORT) return 0 } proc fix_email_addresses {addrs} { set fixed "" set str $addrs while {$str != ""} { set f [string first \" $str] if {$f < 0} { append fixed $str break } append fixed [string range $str 0 $f] set str [string range $str [incr f] end] set l [string first \" $str] if {$l < 0} { append fixed $str break } set seg [string range $str 0 [expr $l - 1]] #puts seg=$seg set str [string range $str [incr l] end] if {[string first , $seg] >= 0} { set lseg [split $seg ,] set seg "[string trim [lindex $lseg 1]] [string trim [lindex $lseg 0]]" } append fixed $seg\" } return $fixed } proc email_originator_send {prid textw top} { global TkGnats bugsval respval origval mail_cc replvals mail_sj if {[string trim [$textw get 1.0 end]] == ""} { Msg "The body of the message is blank." return } set addrs "" foreach a "bugsval respval origval mail_cc" { if {"[string trim [subst $$a]]" != ""} { if {"$addrs" != ""} { set addrs "$addrs, " } set addrs "$addrs[string trim [subst $$a]]" } } for {set i 1} {$i <= $replvals(nreps)} {incr i} { set a [string trim $replvals($i)] if {"$a" != ""} { if {"$addrs" != ""} { set addrs "$addrs, " } set addrs "$addrs$a" } } set mailtxt "" append mailtxt "From: $TkGnats(EmailAddr)\n" append mailtxt "Reply-To: $TkGnats(EmailAddr)\n" append mailtxt "To: $addrs\n" append mailtxt "Subject: Re: $prid: $mail_sj\n" append mailtxt "\n" append mailtxt "[$textw get 1.0 end]" if {[TkGnats_sendmail $addrs $mailtxt] == 0} { destroy $top } return } proc email_originator {to_rep to_res to_org prid synopsis} { global TkGnats mail_cc mail_sj bugsval respval origval replvals set to_rep [fix_email_addresses $to_rep] set to_res [fix_email_addresses $to_res] set to_org [fix_email_addresses $to_org] #puts "to_rep=$to_rep" #puts "to_res=$to_res" #puts "to_org=$to_org" # expand the Responsible address, which could be an alias in the responsibles file set to_org [add_email_domainname $to_org] #puts "to_org=$to_org" set tmp_org [lindex [extract_email_address $to_org] 0] set tmp_usr [lindex [extract_email_address $TkGnats(EmailAddr)] 0] set to_res_addr [add_email_domainname [get_responsible_addr $to_res]] if {"$to_res" != "$to_res_addr"} { set restmp "$to_res: $to_res_addr" } { set restmp "$to_res" } set to_res "$to_res_addr" set tmp_res [lindex [extract_email_address $to_res] 0] set tlist {} set t [toplevel .tkgnats_email] wm minsize $t 100 100 wm title $t "TkGnats - Send Email to Problem Report: $prid" wm iconbitmap $t @$TkGnats(lib)/tkeditpr.xbm wm iconname $t "$TkGnats(LogName)'s tkemailpr [file tail $prid]" set f [frame $t.mframe -borderwidth 1 -relief raised] pack $f -side top -fill x menubutton $f.file -text "File" -menu $f.file.m -underline 0 menu $f.file.m $f.file.m add command -label "Send" \ -command "email_originator_send $prid $f.text $t" $f.file.m add separator $f.file.m add command -label "Cancel" -command "destroy $t" menubutton $f.edit -text "Edit" -menu $f.edit.m -underline 0 menu $f.edit.m $f.edit.m configure -disabledforeground [$f.edit.m cget -foreground] $f.edit.m add command -label "Use right mouse button for Cut/Copy/Paste" -state disabled $f.edit.m add separator $f.edit.m add command -label "Fonts..." -command "edit_fonts" pack $f.file $f.edit -side left menubutton $f.help -text "Help" -menu $f.help.m -underline 0 menu $f.help.m pack $f.help -side right $f.help.m add command -label "Cut, Copy, Paste Operations" \ -command "helpMsg Cut_Copy_Paste" $f.help.m add separator $f.help.m add command -label "View Configuration Variables" \ -command "helpMsg TkGnats_Variables" $f.help.m add separator $f.help.m add command -label "Changes" \ -command "helpMsg Changes" $f.help.m add command -label "About" \ -command "helpMsg TkGnats_About" set f [frame $t.f] pack $f -side top -fill both -expand true set b [frame $f.b -borderwidth 1 -relief raised] pack $b -side top -fill x -anchor w #button $b.cancel -borderwidth 1 -text Cancel -command "destroy $t" button $b.send -borderwidth 1 -text Send \ -command "email_originator_send $prid $f.text $t" pack $b.send -side left -padx 0 -pady 0 #pack $b.cancel -side left -padx 0 -pady 0 frame $f.ad pack $f.ad -side top -anchor n -fill x frame $f.ad.lab pack $f.ad.lab -side left -anchor w -fill y frame $f.ad.ent pack $f.ad.ent -side left -anchor w -fill x -expand true label $f.ad.lab.to -relief flat -anchor e -text "To:" -width 8 pack $f.ad.lab.to -side top -anchor n label $f.ad.lab.sj -relief flat -anchor e -text "Subject:" pack $f.ad.lab.sj -side bottom -anchor s -pady 2 label $f.ad.lab.cc -relief flat -anchor e -text "Cc:" -width 8 pack $f.ad.lab.cc -side bottom -anchor s -pady 2 checkbutton $f.ad.ent.to -relief flat -pady 0 -highlightthickness 0 -anchor w \ -variable bugsval -text "$TkGnats(GNATS_ADDR)" \ -offvalue "" -onvalue "$TkGnats(GNATS_ADDR)" pack $f.ad.ent.to -side top -anchor w checkbutton $f.ad.ent.resp -relief flat -pady 0 -highlightthickness 0 -anchor w \ -variable respval -text "Responsible ($restmp)" -offvalue "" -onvalue "$to_res" pack $f.ad.ent.resp -side top -anchor w checkbutton $f.ad.ent.orig -relief flat -pady 0 -highlightthickness 0 -anchor w \ -variable origval -text "Originator ($to_org)" -offvalue "" -onvalue "$to_org" pack $f.ad.ent.orig -side top -anchor w set reps [split $to_rep ,] set nreps [llength $reps] set nrep 0 catch {unset replvals} for {set i 0} {$i < $nreps} {incr i} { set rep [string trim [lindex $reps $i] "{} \t\n"] #puts "rep($i)=$rep" set repaddr [lindex [extract_email_address $rep] 0] #puts repaddr=$repaddr set tmp_rep [add_email_domainname [get_responsible_addr $repaddr]] #puts tmp_rep=$tmp_rep if {"$tmp_rep" != "$repaddr"} { set reptmp "$rep: $tmp_rep" } { set reptmp "$rep" } # if {"$rep" == "$tmp_org"} { #puts "skipping notify: $rep: $tmp_rep" # continue # } incr nrep set replvals($nrep) $tmp_rep checkbutton $f.ad.ent.repl_$nrep -relief flat -pady 0 -highlightthickness 0 -anchor w \ -variable replvals($nrep) -text "Notify-List ($reptmp)" \ -offvalue "" -onvalue "$tmp_rep" pack $f.ad.ent.repl_$nrep -side top -anchor w } set replvals(nreps) $nrep lappend tlist [entry $f.ad.ent.cc -relief sunken -borderwidth 2 \ -background $TkGnats(EditFieldBackground) \ -highlightthickness 2 -textvariable mail_cc] pack $f.ad.ent.cc -side top -anchor w -fill x -expand true set_focus_style $f.ad.ent.cc bind $f.ad.ent.cc <3> "clipboard_post $f.ad.ent.cc %X %Y" frame $f.ad.ent.sj pack $f.ad.ent.sj -anchor w -fill x -expand true label $f.ad.ent.sj.def -relief sunken -anchor w -text "Re: $prid:" pack $f.ad.ent.sj.def -side left lappend tlist [entry $f.ad.ent.sj.ent -relief sunken -borderwidth 2 \ -background $TkGnats(EditFieldBackground) \ -highlightthickness 2 -textvariable mail_sj] pack $f.ad.ent.sj.ent -side left -anchor w -fill x -expand true set_focus_style $f.ad.ent.sj.ent bind $f.ad.ent.sj.ent <3> "clipboard_post $f.ad.ent.sj.ent %X %Y" scrollbar $f.sb -command "$f.text yview" -relief sunken # The text entry is hardwired to no wrap because the wrap is only visual anyway # (no LF's are actually inserted) lappend tlist [text $f.text \ -wrap none \ -yscrollcommand "$f.sb set" \ -height 30 -width 80 -relief sunken -padx 4 -insertwidth 1 \ -insertofftime 400 -borderwidth 2 -highlightthickness 2 -background $TkGnats(EditFieldBackground)] set_focus_style $f.text bind $f.text <3> "clipboard_post $f.text %X %Y" set_text_traversal $tlist pack $f.sb -side left -fill y pack $f.text -side right -expand true -fill both focus $f.text set bugsval "$TkGnats(GNATS_ADDR)" if {$tmp_res != $tmp_usr} { set respval $to_res } { set respval "" $f.ad.ent.resp configure -state disabled } if {$tmp_org != $tmp_usr && $tmp_org != $tmp_res} { set origval $to_org } { set origval "" $f.ad.ent.orig configure -state disabled } #dputs "tmp_usr=$tmp_usr tmp_org=$tmp_org tmp_res=$tmp_res tmp_org=$tmp_org to_res=$to_res to_org=$to_org" #puts "replvals=[array get replvals]" # Disable any duplicate recipients #dputs "nrep=$nrep" for {set i 1} {$i <= $nrep} {incr i} { set tmp_rep [get_responsible_addr [lindex [extract_email_address $replvals($i)] 0]] set tmp_rep [add_email_domainname $tmp_rep] #dputs "replvals($i)=$replvals($i) tmp_rep=$tmp_rep" if {$tmp_rep == $tmp_usr || "$tmp_rep" == "$tmp_res"} { set replvals($i) "" $f.ad.ent.repl_$i configure -state disabled } } set mail_cc "" set mail_sj "$synopsis" } proc entryDialog {msg {cancel Cancel} {initial_value ""} {blankok 1} {master .}} { global entryDialog_Done TkGnats set entryDialog_Done 0 catch {destroy .entryDialog} set t [toplevel .entryDialog -borderwidth 2 -relief raised] message $t.msg -text $msg -aspect 99999 entry $t.e -width 50 -borderwidth 2 -relief sunken \ -highlightthickness 2 -background $TkGnats(EditFieldBackground) frame $t.bar button $t.bar.ok -text "OK" -command "set entryDialog_Done 1" pack $t.bar.ok -side left -padx 8 -pady 8 if {$cancel != ""} { button $t.bar.cancel -text $cancel -command "set entryDialog_Done -1" pack $t.bar.cancel -side left -padx 8 -pady 8 } pack $t.msg -side top -fill x pack $t.e -side top -padx 8 -pady 8 pack $t.bar -side bottom -anchor center bind $t.e <3> "clipboard_post $t.e %X %Y" bind $t.e "set entryDialog_Done 1" # Center the dialog over the master wm withdraw $t update wm geometry $t +[expr [winfo rootx $master] + ([winfo width $master] - [winfo reqwidth $t]) / 2]+[expr [winfo rooty $master] + ([winfo height $master] - [winfo reqheight $t]) / 2] wm deiconify $t wm transient $t $master set_focus_style $t.e focus $t.e $t.e insert 0 $initial_value set done 0 while {$done == 0} { grab $t # This raise causes a few seconds delay second time through the loop (when blank entered). # Lowering it first gets around this wierdness. lower $t raise $t tkwait variable entryDialog_Done grab release $t set text [string trim [$t.e get]] if {$entryDialog_Done != -1 && !$blankok && $text == ""} { $t.e delete 0 end bell Msg "Blank entered!" "You must enter a value." set done 0 } { set done 1 } } destroy $t update idletasks if {$entryDialog_Done == -1} { error "$text" } return $text } proc textEntryDialog {msg {cancel Cancel} {initial_value ""} {blankok 1} {master .}} { global textEntryDialog_Done TkGnats set textEntryDialog_Done 0 catch {destroy .textEntryDialog} set t [toplevel .textEntryDialog -borderwidth 2 -relief raised] message $t.msg -text $msg -aspect 99999 text $t.e -width 50 -height 8 -borderwidth 2 -relief sunken \ -highlightthickness 2 -background $TkGnats(EditFieldBackground) frame $t.bar button $t.bar.ok -text "OK" -command "set textEntryDialog_Done 1" pack $t.bar.ok -side left -padx 8 -pady 8 if {$cancel != ""} { button $t.bar.cancel -text $cancel -command "set textEntryDialog_Done -1" pack $t.bar.cancel -side left -padx 8 -pady 8 } pack $t.msg -side top -fill x pack $t.e -side top -padx 8 -pady 8 pack $t.bar -side bottom -anchor center bind $t.e <3> "clipboard_post $t.e %X %Y" # Center the dialog over the master wm withdraw $t update wm geometry $t +[expr [winfo rootx $master] + ([winfo width $master] - [winfo reqwidth $t]) / 2]+[expr [winfo rooty $master] + ([winfo height $master] - [winfo reqheight $t]) / 2] wm deiconify $t wm transient $t $master set_focus_style $t.e focus $t.e $t.e insert 1.0 $initial_value set done 0 while {$done == 0} { grab $t # This raise causes a few seconds delay second time through the loop (when blank entered). # Lowering it first gets around this wierdness. lower $t raise $t tkwait variable textEntryDialog_Done grab release $t set text [string trim [$t.e get 1.0 end]] if {$textEntryDialog_Done != -1 && !$blankok && $text == ""} { $t.e delete 1.0 end bell Msg "Blank entered!" "You must enter a value." set done 0 } { set done 1 } } destroy $t update idletasks if {$textEntryDialog_Done == -1} { error "$text" } return $text } proc quickfill_entry_from_listbox {ab ew lw vlist} { upvar 1 $ab tvar set cur [$lw curselection] if {$tvar == "" && $cur == ""} { return } set eidx [$ew index insert] set tmpval [string range [$ew get] 0 [expr $eidx - 1]] if {$tmpval != ""} { set tvar $tmpval } set lidx [lsearch -glob $vlist $tvar*] if {$lidx < 0 || $tvar == ""} { if {$cur != ""} { set tvar [$lw get $cur] } { set tvar [string range [$ew get] 0 [expr $eidx - 2]] } set lidx [lsearch -glob $vlist $tvar*] incr eidx -1 bell } $lw selection clear 0 end if {$tvar != ""} { if {$lidx >= 0} { $lw selection set $lidx $lw see $lidx set tvar [$lw get [$lw curselection]] } } set tmpval $tvar $ew delete 0 end $ew insert 0 $tmpval $ew icursor $eidx if {$eidx > 0} { $ew selection range $eidx [string length $tmpval] } } proc save_help {w} { set file [tk_getSaveFile] if {$file != ""} { if {[file_put_text $file [$w get 1.0 end]] == ""} { Msg "Unable to save help text to file \"$file\"." } { Msg "Saved help text to file \"$file\"." } } { Msg "Save help text aborted." } } proc show_help {title help} { global TkGnats set w .help_$title catch {destroy $w} regsub -all "_" $title " " Title toplevel $w wm title $w "$Title Help" frame $w.opts pack $w.opts -side top button $w.opts.quit -text "OK" -command "destroy $w" button $w.opts.save -text "Save to file..." -command "save_help $w.text" pack $w.opts.quit $w.opts.save -side left -pady 2 -padx 20 # Create a scrollbar and a text box in the main window. scrollbar $w.scrollx -orient horiz -command "$w.text xview" pack $w.scrollx -side bottom -fill x scrollbar $w.scrolly -command "$w.text yview" pack $w.scrolly -side right -fill y text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scrolly set" \ -xscrollcommand "$w.scrollx set" -setgrid 1 -height 24 -width 82 \ -font $TkGnats(helpfont) -background [$w.opts.quit cget -background] pack $w.text -side left -fill both -expand yes $w.text insert end $help set nlines [lindex [split [$w.text index end] "."] 0] set height 24 if {$height > $nlines} { set height $nlines } $w.text configure -state disabled -height $height set_focus_style $w.text bind $w.text <3> "clipboard_post $w.text %X %Y" } proc add_email_domainname {addrs} { global TkGnats #puts "addrs=$addrs" if {![info exists TkGnats(DefaultDomainName)] || $TkGnats(DefaultDomainName) == ""} { return $addrs } set new_addrs "" foreach add [split $addrs ,] { #puts "add=$add" set addr [lindex [extract_email_address $add] 0] set name [lindex [extract_email_address $add] 1] #puts "addr=$addr" #puts "name=$name" if {[string first "@" $addr] < 0} { set addr ${addr}@$TkGnats(DefaultDomainName) } if {$name != ""} { lappend new_addrs "$name <$addr>" } { lappend new_addrs $addr } } return [join $new_addrs ", "] } proc extract_email_address {addr} { # Supported formats: # 01: "Rick Macdonald" # Rick Macdonald # 02: rickm@vsl.com (Rick Macdonald) # 03: rickm@vsl.com # # 01 and 02 return: {rickm@vsl.com} {Rick Macdonald} # 03 returns: {rickm@vsl.com} {} set fmt01_exp {^(.*[^<]+)(<.*>)} set fmt02_exp {^(.*[^\(]+)(\(.*\))} set fmt03_exp {(.*)} set name "" set address "" if {![regexp $fmt01_exp $addr matched name address]} { if {![regexp $fmt02_exp $addr matched address name]} { set address $addr } } set name [string trim $name "{}()<>\"\' \n"] if {[string first , $name] >= 0} { regexp {(.*),(.*)} $name match last first set name "[string trim $first] [string trim $last]" } return [list [string trim $address "{}()<>\"\' \n"] \ [string trim $name "{}()<>\"\' \n"]] } proc extract_full_name_from_address {addr} { set name [extract_email_address $addr] if {[lindex $name 1] != {}} { return [lindex $name 1] } { return $addr } } proc lock_pr_batch {me prid txt} { global TkGnats upvar 1 $txt text return [catch {eval exec $TkGnats(pr-edit) $TkGnats(UseridPassword) --lock $me $prid} text] } proc lock_pr_socket {me prid txt} { global TkGnats upvar 1 $txt text if {[set s [open_socket_gnatsd]] == "-1"} { set text "Can't open socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT)" return 1 } gnatsd_send $s "LOCK $prid $me" set rep [get_socket_reply $s] #puts "rep=$rep" if {![string match 300* [lindex $rep 0]]} { set text [lindex $rep 0] return 1 } set text [join [get_gnatsd_reply_dot_ended $s] \n] close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) set text [unescape_dots $text] return 0 } proc lock_pr {prid} { global TkGnats ### find a username@hostname set me $TkGnats(LogName) if {"$TkGnats(HOSTNAME)" != ""} { set me "$me@$TkGnats(HOSTNAME)" } ### lock the PR and bail out if the lock fails set stat [lock_pr_$TkGnats(GNATS_ACCESS_METHOD) $me $prid text] #puts "stat=$stat text=$text" if {$stat == 0} { set prtxt $text } { wm withdraw . if {[string first "locked by" $text] >= 0} { # gnatsd, npr-edit, pr-edit Msg "Problem report '$prid' is locked by '[lindex [split $text] end]'" } { Msg "Can't lock problem report '$prid':\n\n$text" } exit 1 } return $prtxt } proc unlock_pr_batch {prid} { global TkGnats catch {eval exec $TkGnats(pr-edit) $TkGnats(UseridPassword) --unlock $prid} rep return $rep } proc unlock_pr_socket {prid} { global TkGnats if {[set s [open_socket_gnatsd]] == "-1"} { return "Error-3 opening socket/port $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT)" } gnatsd_send $s "UNLK $prid" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { set rep [lindex $rep 0] } { set rep "" } close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) return $rep } proc unlock_pr {prid} { global TkGnats set rep [unlock_pr_$TkGnats(GNATS_ACCESS_METHOD) $prid] if {$rep != ""} { Msg "Error unlocking PRID $prid:\n\n$rep" } } proc get_pr_full_text {prid} { global TkGnats return [get_pr_full_text_$TkGnats(GNATS_ACCESS_METHOD) $prid] } proc get_pr_full_text_batch {prid} { global TkGnats if {[catch {eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) --full [file tail $prid]} rep]} { Msg "GNATS error getting full text of PRID $prid:\n\n$rep" return -1 } return $rep } proc get_pr_full_text_socket {prid} { global TkGnats if {[set s [open_socket_gnatsd]] == "-1"} { return "-1" } gnatsd_send $s "RSET" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { Msg "GNATSD error sending RSET getting full text of PRID $prid:\n" "[join $rep \n]" return -1 } gnatsd_send $s "QFMT full" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { Msg "GNATSD error setting format to full text (for PRID $prid):\n" "[join $rep \n]" return -1 } gnatsd_send $s "QUER $prid" set rep [get_socket_reply $s] if {![string match 300* [lindex $rep 0]]} { Msg "GNATSD error getting full text of PRID $prid:\n" "[join $rep \n]" return -1 } set plist [join [get_gnatsd_reply_dot_ended $s] \n] close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) return [unescape_dots $plist] } proc get_pr_medium_text {prid} { global TkGnats return [get_pr_medium_text_$TkGnats(GNATS_ACCESS_METHOD) $prid] } proc get_pr_medium_text_batch {prid} { global TkGnats return [eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) [file tail $prid]] } proc get_pr_medium_text_socket {prid} { global TkGnats if {[set s [open_socket_gnatsd]] == "-1"} { return "-1" } gnatsd_send $s "RSET" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { Msg "GNATSD error sending RSET getting full text of PRID $prid:\n" "[join $rep \n]" return -1 } gnatsd_send $s "QURY $prid" set rep [get_socket_reply $s] if {![string match 2* [lindex $rep 0]]} { Msg "GNATSD error getting medium text of PRID $prid:\n" "[join $rep \n]" return -1 } set plist [join [get_gnatsd_reply_dot_ended $s] \n] close_socket $TkGnats(GNATS_SERVER) $TkGnats(GNATS_PORT) return $plist } proc delete_pr {prid} { global TkGnats return [delete_pr_$TkGnats(GNATS_ACCESS) $prid] } proc delete_pr_network {prid} { global TkGnats bell Msg "delete_pr is only available for GNATS_ACCESS=local" return "delete_pr is only available for GNATS_ACCESS=local" } proc delete_pr_local {prid} { global TkGnats # TTD: This is missing a global lock on the gnats database! # TTD: This is missing a global lock on the gnats database! # TTD: some things here need re-ordering (lock_pr, etc) # TTD: some things here need re-ordering (lock_pr, etc) set INDEX $TkGnats(GNATS_ROOT)/gnats-adm/index set prtext [get_pr_medium_text $prid] parsepr_txt $prtext flds set full_id [string trim $flds(>Category)]/$prid if {"$full_id" == ""} { #####wm withdraw . Msg "Error accessing problem report '$prid'!" return "" } set pr $TkGnats(GNATS_ROOT)/$full_id if {![file writable $INDEX] || ![file writable $pr]} { Msg "You don't have proper file permissions to delete $full_id." return "" } set state [string trim $flds(>State)] if {"$state" != "closed"} { Msg "Problem reports must be closed before deleting." unlock_pr $full_id return "" } bell if {[tk_dialog .tkquerypr_delete "Confirm_Delete" \ "This will PERMANENTLY delete this bug report.\n\nAre you sure?" \ "warning" -1 "Delete Report" "Cancel"] != 0} { return "" } lock_pr $full_id # take the relevant line out of the index - it should only be there once set stamp tkdeletepr.$TkGnats(LogName).[clock format [clock seconds] -format "%j:%T"] # catch {exec egrep -v ^$full_id: $INDEX > $INDEX.$stamp} set index [split [file_get_text $INDEX] \n] if {"$index" == ""} { Msg "Unable to read GNATS index." return "" } set idx [lsearch -regexp $index ^$full_id|] if {$idx < 0} { Msg "Problem report '$prid' not found in GNATS index!" return "" } set index [lreplace $index $idx $idx] set idx [lsearch -regexp $index ^$full_id|] if {$idx >= 0} { Msg "Problem report '$prid' seems to exist more than once in the GNATS index!" return "" } if {[file_put_text $INDEX.$stamp [join $index \n]] == ""} { Msg "Unable to write temporary GNATS index file." return "" } # here's where we actually delete the file. file rename -force $INDEX $INDEX.bak file delete $pr file rename -force $INDEX.$stamp $INDEX # It doesn't seem necessary to send mail about this # call PR_EDIT on the new file and clean up unlock_pr $full_id return "All references to $full_id now deleted." } proc chk_fld {fldname val {flag_if_missing 1}} { global mlist upvar 1 $fldname fld if {![info exists fld]} { if {$flag_if_missing} { set match "" regexp "\\(.*\\)" $fldname match set match [string trim $match ()] if {$match != ""} { lappend mlist $match } } set fld $val } } proc load_field_defaults {field_array} { global TkGnats mlist upvar 1 $field_array field set mlist {} chk_fld field(>State) [lindex $TkGnats(StatesList) 0] chk_fld field(>Confidential) no chk_fld field(>Severity) serious chk_fld field(>Priority) medium chk_fld field(>Class) [lindex $TkGnats(ClassesList) 0] chk_fld field(>Arrival-Date) [clock format [clock seconds]] chk_fld field(>Last-Modified) "\n" chk_fld field(>Closed-Date) "\n" chk_fld field(>Start-Date) "\n" chk_fld field(>End-Date) "\n" chk_fld field(>Cost) "" chk_fld field(>XrefPR) "" chk_fld field(>Originator) Unknown chk_fld field(>Responsible) gnats chk_fld field(>Category) pending chk_fld field(>Synopsis) None chk_fld field(>Release) Unknown chk_fld field(>Description) None chk_fld field(>Environment) "\n" chk_fld field(>Audit-Trail) "\n" chk_fld field(>How-To-Repeat) "\n" chk_fld field(>IPsec-barf-location) "http://" 0 chk_fld field(>IPsec-look) "\n" chk_fld field(Reply-To) "" chk_fld field(X-GNATS-Notify) nobody 0 # It's ok if these are missing chk_fld field(>Unformatted) "\n" 0 chk_fld field(>Fix) "\n" chk_fld field(>Release-Note) "\n" if {$TkGnats(ReleaseBased)} { chk_fld field(>Keywords) "" 0 chk_fld field(>$TkGnats(Quarter)) "" 0 chk_fld field(>Date-Required) "" 0 } return $mlist } TkGnats_config gnats-4.1.0/contrib/tkgnats/tkprdatesel.tcl0000644000175000017500000001547606665615034021553 0ustar chewiechewie00000000000000proc {datesel} {{date {}} {title {Select Date}} {font fixed}} { global dsel set dsel(return) "" catch {destroy .dsel} #TTD remove this if the bug is ever fixed datesel_CheckTclClockBug set t $date # convert yy-mm-dd format coming in if {[regexp {^[0-9][0-9]?[0-9]?[0-9]?-[0-9][0-9]?-[0-9][0-9]?([ \t]?[0-9][0-9]?:[0-9][0-9]?)?$} $t]} { set t [datesel_ConvertDateFormat $t] } if {$date == "" || [catch {clock scan $t}] } { set dsel(time) [clock seconds] } { set dsel(time) [clock scan $t] } set dsel(startdate) [clock format $dsel(time) -format "%Y-%m"] datesel_Create .dsel $title $dsel(time) $font grab .dsel tkwait variable dsel(return) grab release .dsel destroy .dsel return $dsel(return) } proc {datesel_ChangeMonth} {opt} { global dsel # Tcl bug! "next month" and "next year" adds 2 months or years, # so we have to go back 1 then forward 2. switch $opt { m { set dsel(time) [clock scan "last month" -base $dsel(time)] } h { if {$dsel(clockbug)} { set dsel(time) [clock scan "last month" -base $dsel(time)] } set dsel(time) [clock scan "next month" -base $dsel(time)] } y { set dsel(time) [clock scan "last year" -base $dsel(time)] } r { if {$dsel(clockbug)} { set dsel(time) [clock scan "last year" -base $dsel(time)] } set dsel(time) [clock scan "next year" -base $dsel(time)] } } datesel_SetMonth $dsel(time) } proc datesel_CheckTclClockBug {} { global dsel #TTD remove this if the bug is ever fixed set t [clock scan "01/01/1999"] set mm [clock format $t -format "%m"] if {[clock format [clock scan "next month" -base $t] -format "%m"] == [expr $mm + 1]} { set dsel(clockbug) 0 } { set dsel(clockbug) 1 } } proc {datesel_ConvertDateFormat} {date} { set dt [split $date] set d [split [lindex $dt 0] -] return "[lindex $d 1]/[lindex $d 2]/[lindex $d 0] [lindex $dt 1]" } proc {datesel_Return} {dd} { global dsel if {$dd == ""} { set dsel(return) "" } { set dsel(return) "$dsel(YY)-$dsel(mm)-[format "%02d" $dd]" } } proc {datesel_SetMonth} {t} { global dsel set dsel(title) [clock format $t -format "%B - %Y"] set dsel(mm) [clock format $t -format "%m"] set dsel(YY) [clock format $t -format "%Y"] set fdm [clock format [clock scan "$dsel(mm)/01/$dsel(YY)"] -format "%w"] # get the first day of next month set nm $dsel(time) if {$dsel(clockbug)} { # Tcl bug! "next month" and "next year" adds 2 months or years, # so we have to go back 1 then forward 2. set nm [clock scan "last month" -base $nm] } set nm [clock scan "next month" -base $nm] set mm [clock format $nm -format "%m"] set YY [clock format $nm -format "%Y"] set nm [clock scan "$mm/01/$YY"] # get last day of this month set ld [clock scan "yesterday" -base $nm] # get number of days this month set nd [string trimleft [clock format $ld -format "%d"] 0] for {set d 1} {$d <= $fdm} {incr d} { $dsel(datesel_$d) config -text "" -relief flat -state disabled } for {set date 1} {$date <= $nd} {incr date} { $dsel(datesel_$d) config -text $date -relief flat -state normal \ -command "datesel_Return $date" incr d } for {set d $d} {$d < 42} {incr d} { $dsel(datesel_$d) config -text "" -relief flat -state disabled } if {$dsel(startdate) == [clock format $dsel(time) -format "%Y-%m"]} { set but [expr $fdm + [string trimleft [clock format $dsel(time) -format "%d"] 0]] $dsel(datesel_$but) config -relief sunken } } proc datesel_Create {base title time font} { global dsel TkGnats set master . toplevel $base -class Toplevel wm title $base $title wm transient $base $master set xpos [expr [winfo rootx $master]+[winfo width $master]/2] set ypos [expr [winfo rooty $master]+[winfo height $master]/2] wm geometry $base +${xpos}+${ypos} frame $base.cal -height 75 -width 125 frame $base.cal.head -height 75 -width 125 -borderwidth 1 -relief raised frame $base.cal.head.t1 -height 75 -width 125 -borderwidth 2 button $base.cal.head.t1.y -command {datesel_ChangeMonth y} -font $font \ -highlightthickness 0 -padx 8 -pady 0 -relief groove -text << -width 1 button $base.cal.head.t1.r -command {datesel_ChangeMonth r} -font $font \ -highlightthickness 0 -padx 8 -pady 0 -relief groove -text >> -width 1 button $base.cal.head.t1.m -command {datesel_ChangeMonth m} -font $font \ -highlightthickness 0 -padx 8 -pady 0 -relief groove -text < -width 1 button $base.cal.head.t1.h -command {datesel_ChangeMonth h} -font $font \ -highlightthickness 0 -padx 8 -pady 0 -relief groove -text > -width 1 label $base.cal.head.t1.t -width 16 \ -background gray85 -borderwidth 1 -font $font -textvariable dsel(title) pack $base.cal -anchor center -expand 1 -fill both -side top pack $base.cal.head -anchor center -expand 1 -fill both -side top -padx 1 pack $base.cal.head.t1 -anchor center -expand 1 -fill both -side top pack $base.cal.head.t1.y -anchor center -expand 0 -fill none -side left pack $base.cal.head.t1.r -anchor center -expand 0 -fill none -side right pack $base.cal.head.t1.m -anchor center -expand 0 -fill none -side left -padx 2 pack $base.cal.head.t1.t -anchor center -expand 1 -fill x -side left pack $base.cal.head.t1.h -anchor center -expand 0 -fill none -side right -padx 2 frame $base.cal.head.t2 -borderwidth 2 -height 75 -width 125 pack $base.cal.head.t2 -anchor center -expand 1 -fill both -side top set d 0 foreach day "Su Mo Tu We Th Fr Sa" { incr d label $base.cal.head.t2.$d -background gray85 -borderwidth 1 \ -font $font -text $day -width 1 pack $base.cal.head.t2.$d -anchor center -expand 1 -fill x -side left } set d 0 foreach week "w1 w2 w3 w4 w5 w6" { frame $base.cal.$week -height 75 -width 125 pack $base.cal.$week -anchor center -expand 1 -fill both -padx 3 -side top for {set day 1} {$day <= 7} {incr day} { incr d set dsel(datesel_$d) [button $base.cal.$week.$day \ -borderwidth 1 -font $font -highlightthickness 0 -padx 1 \ -pady 1 -relief flat -width 1] pack $dsel(datesel_$d) -anchor center -expand 1 -fill both -side left } } $dsel(datesel_42) config -text Exit -command {datesel_Return ""} -relief raised datesel_SetMonth $time } gnats-4.1.0/contrib/tkgnats/tkprfolder.tcl0000644000175000017500000001523007005513656021365 0ustar chewiechewie00000000000000# # TkGnats PR folders module # # # -- globals # set Tkprfolder(site_print_dir) "$TkGnats(SiteServerDir)/print" set Tkprfolder(site_query_dir) "$TkGnats(SiteServerDir)/query" set Tkprfolder(site_sort_dir) "$TkGnats(SiteServerDir)/sort" set Tkprfolder(user_query_dir) "$TkGnats(UserServerDir)/query" set Tkprfolder(user_sort_dir) "$TkGnats(UserServerDir)/sort" set Tkprfolder(build_query_menu) build_query_menu set Tkprfolder(build_sort_menu) build_sort_menu set Tkprfolder(foldernameregexp) {^[a-zA-Z0-9]+[a-zA-Z0-9_.]*} proc tkprfolder_button_cmd {cmd top lbox type} { global Tkprfolder Query if {"$cmd" == "Close"} { destroy $top return } if {"$cmd" == "New"} { tkprfolder_new $top $type return } # get the selected item (if there is one) set x [$lbox curselection] if {"$x" == ""} { Msg "No selection available in the folder list box!" return } set idx [lindex $x 0] set folder [$lbox get $idx] if {"$cmd" == "Rename"} { if {[catch {entryDialog "Enter new name for $folder" Cancel "" 0 $top} newname]} { return "" } regexp $Tkprfolder(foldernameregexp) $newname match if {$newname != $match} { Msg "Folder names must be composed only of letters, numbers, underscores and periods." return } if {[file exists $Tkprfolder(user_${type}_dir)/$newname]} { bell if {[tk_dialog .tkprfolder_delete "Confirm_Rename" "$newname already exists" \ "warning" -1 "Rename" "Cancel"] != 0} { return } } file rename -force \ $Tkprfolder(user_${type}_dir)/$folder $Tkprfolder(user_${type}_dir)/$newname tkprfolder_resync $top $type $newname $Tkprfolder(build_${type}_menu) return } if {"$cmd" == "Delete"} { ##### if {"$folder" == "Backup--Folder"} { ##### Msg "You are not allowed to delete $folder." ##### return ##### } ##### file rename $Tkprfolder(user_${type}_dir)/$folder $Tkprfolder(user_${type}_dir)/Backup--Folder bell if {[tk_dialog .tkprfolder_delete "Confirm_Delete" "Delete $folder?" "warning" -1 \ "Delete" "Cancel"] == 0} { file delete $Tkprfolder(user_${type}_dir)/$folder tkprfolder_resync $top $type $Tkprfolder(build_${type}_menu) } return } if {"$cmd" == "Edit"} { ##### if {"$folder" == "Backup--Folder"} { ##### Msg "You are not allowed to edit $folder." ##### return ##### } ##### file copy $Tkprfolder(user_${type}_dir)/$folder $Tkprfolder(user_${type}_dir)/Backup--Folder tkprfolder_edit $folder $top $type return } Msg "tkprfolder_button_cmd:\n" "do not understand the '$cmd' operation" } proc tkprfolder_edit_Cancel {top txt fname flisttop type} { destroy $top } proc tkprfolder_edit_Save {top txt fname flisttop type} { global Tkprfolder file_put_text $Tkprfolder(user_${type}_dir)/$fname [$txt get 1.0 end] destroy $top tkprfolder_resync $flisttop $type $fname $Tkprfolder(build_${type}_menu) } proc tkprfolder_resync {w type {activate ""}} { global Tkprfolder ##### if {[winfo exists $flisttop]} { ##### tkprfolder_dialog $flisttop ##### } # first get the list of folders for this person set folder_list {} set ltemp "" catch {[set ltemp [lsort [glob $Tkprfolder(user_${type}_dir)/*]]]} foreach file $ltemp { lappend folder_list [file tail $file] } # decide which element from the new list to activate if {$activate == ""} { set active [$w.list index active] } { set active [lsearch -exact $folder_list $activate] } $w.list delete 0 end eval $w.list insert end $folder_list $w.list activate $active $w.list selection set active } proc tkprfolder_edit {fname flisttop type} { global TkGnats Tkprfolder set f .tkprfolder_edit_file if {[winfo exists $f]} { Msg "You can only edit one folder at a time." return } toplevel $f frame $f.buttons foreach x {Save Cancel} { button $f.buttons._$x -text $x \ -command "tkprfolder_edit_$x $f $f.text $fname $flisttop $type" pack $f.buttons._$x -side left -padx 4 } scrollbar $f.sb -command "$f.text yview" -relief sunken text $f.text \ -font $TkGnats(textfont) \ -yscrollcommand "$f.sb set" \ -height 20 -width 90 -relief sunken -padx 4 -insertwidth 1 \ -insertofftime 400 -borderwidth 2 -background $TkGnats(EditFieldBackground) set_focus_style $f.text bind $f.text { set s [prid_from_selection] if {"$s" != ""} { %W insert 1.0 "$s\n" } } bind $f.text <3> "clipboard_post $f.text %X %Y" pack $f.buttons -side bottom pack $f.sb -side left -fill y pack $f.text -side right -fill both -expand true if {[file exists $Tkprfolder(user_${type}_dir)/$fname]} { $f.text insert 1.0 [file_get_text $Tkprfolder(user_${type}_dir)/$fname] } wm title $f "Tkprfolder: $fname" } proc tkprfolder_new {flisttop type} { global Tkprfolder if {[catch {entryDialog "Enter name of folder file" Cancel "" 0 $flisttop} fname]} { return "" } regexp $Tkprfolder(foldernameregexp) $fname match if {$fname != $match} { Msg "Folder names must be composed only of letters, numbers, underscores and periods." return } if {[file exists $Tkprfolder(user_${type}_dir)/$fname]} { bell if {[tk_dialog .tkprfolder_delete "Confirm_New" "$fname already exists" \ "warning" -1 "Edit" "Cancel"] != 0} { return } } tkprfolder_edit $fname $flisttop $type } proc XXXXXtkprfolder_cmd {cmd w y} { set idx [$w nearest $y] set fname [$w get $idx] query_cmd [split [file_get_text $fname] " \n\t"] } proc tkprfolder_dialog {w type title} { global Tkprfolder TkGnats env if {[winfo exists $w]} { $w.list delete 0 end } { toplevel $w wm title $w "TkGnats - $title" wm iconbitmap $w @$TkGnats(lib)/tkgnats.xbm wm iconname $w "$TkGnats(LogName)'s tkquerypr $title" message $w.msg -anchor center -text $title -aspect 10000 scrollbar $w.sb -borderwidth 2 -relief sunken -command "$w.list yview" listbox $w.list -yscroll "$w.sb set" -setgrid 1 -relief sunken -borderwidth 2 \ -width 24 -height 8 -exportselection false frame $w.buttons foreach x {Close Edit Delete Rename New} { button $w.buttons._$x -text $x -width 6 \ -command "tkprfolder_button_cmd $x $w $w.list $type" pack $w.buttons._$x -side top -padx 5 -pady 5 } pack $w.msg -side top -fill x pack $w.buttons -side right pack $w.sb -side left -fill y pack $w.list -side right -fill both -expand true } tkprfolder_resync $w $type } gnats-4.1.0/contrib/tkgnats/tkprfont.tcl0000644000175000017500000002624307005513656021066 0ustar chewiechewie00000000000000proc TkFont_Select {{top .tkfont} {fonts {DialogFont}} {font {}}} { global TkFont TkGnats if {[info tclversion] < 8.0} { bell tk_dialog .fontError "TkFont Select Error" \ "TkFont Select requires Tcl/Tk version 8.0 or newer." "error" 0 "OK" return {} } set TkFont(top) $top toplevel $top -class TkFont set TkFont(select) [string tolower [lindex $fonts 0]] if {$font != ""} { option add *TkFont*font $font 100 } set f [frame $top.mframe -borderwidth 1 -relief raised] pack $f -side top -fill x menubutton $f.file -text "File" -menu $f.file.m -underline 0 menu $f.file.m $f.file.m add command -label "Apply" -command {set TkFont(ok) 2} $f.file.m add command -label "Reset" -command {set TkFont(ok) 4} $f.file.m add command -label "Save" -command {set TkFont(ok) 3} $f.file.m add separator $f.file.m add command -label "Close" -command {set TkFont(ok) 1} menubutton $f.edit -text "Edit" -menu $f.edit.m -underline 0 -state disabled menu $f.edit.m pack $f.file $f.edit -side left menubutton $f.help -text "Help" -menu $f.help.m -underline 0 -state disabled menu $f.help.m pack $f.help -side right # $f.help.m add separator # $f.help.m add command -label "Changes" \ # -command "helpMsg Changes" # $f.help.m add command -label "About" \ # -command "helpMsg TkGnats_About" set f [frame $top.buttons -relief raised -borderwidth 1] button $f.close -text Close -bd 1 -command {set TkFont(ok) 1} button $f.apply -text Apply -bd 1 -command {set TkFont(ok) 2} button $f.reset -text Reset -bd 1 -command {set TkFont(ok) 4} button $f.save -text Save -bd 1 -command {set TkFont(ok) 3} pack $f.close $f.apply $f.reset $f.save -padx 0 -pady 0 -side left -anchor w pack $f -side top -pady 0 -anchor nw -fill x TkFontInit # Font Selection, Type, Format and Size set sf [frame $top.sf -relief groove -borderwidth 2] pack $sf -side top -anchor nw -fill x -pady 12 -padx 12 label $sf.label -text "Apply To:" -width 10 -anchor e pack $sf.label -side left foreach B $fonts { set b [string tolower $B] radiobutton $sf.$b -text $B -command TkFontSetSelect -value $b -variable TkFont(select) pack $sf.$b -side left -padx 6 -pady 2 set TkFont($b) $B set TkFont(orig$b) [font actual $b] } set tf [frame $top.tf] pack $tf -side top -anchor nw -pady 4 label $tf.label -text "Font Type:" -width 12 -anchor e pack $tf.label -side left foreach b {all fixed proportional} { radiobutton $tf.$b -text $b -command TkFontLoad -value $b -variable TkFont(type) pack $tf.$b -side left -padx 6 } set ff [frame $top.ff] pack $ff -side top -anchor nw -pady 0 label $ff.label -text "Font Format:" -width 12 -anchor e pack $ff.label -side left checkbutton $ff.bold -text Bold -variable TkFont(-weight) \ -onvalue bold -offvalue normal -command TkFontUpdate checkbutton $ff.italic -text Italic -variable TkFont(-slant) \ -onvalue italic -offvalue roman -command TkFontUpdate checkbutton $ff.underline -text underline -variable TkFont(-underline) \ -command TkFontUpdate checkbutton $ff.overstrike -text overstrike -variable TkFont(-overstrike) \ -command TkFontUpdate pack $ff.bold $ff.italic $ff.underline $ff.overstrike -side left -padx 6 # Add an entry to enter a specific size. set f [frame $top.size] pack $f -side top -fill x -anchor nw -pady 4 label $f.msg -text "Size:" -width 12 -anchor e entry $f.entry -textvariable TkFont(-size) -width 4 -background $TkGnats(EditFieldBackground) bind $f.entry {TkFontUpdate ; TkFontGetSizes quick} pack $f.msg -side left -anchor w pack $f.entry -side left -fill none -anchor w -padx 6 -pady 4 button $f.stop -text Stop -bd 1 -command {set TkFont(stopflag) 1} label $f.prog -text "" -background $TkGnats(ReadOnlyBackground) -textvariable TkFont(progress_txt) set TkFont(stop) $f.stop set TkFont(progress) $f.prog # Listboxes for the font families and the available sizes for the current font set lf [frame $top.lboxes] set TkFont(slb) [TkFontScrolledListbox $lf.slb "Sizes:" \ -width 4 -height 12 -exportselection 0 -setgrid 1] set TkFont(flb) [TkFontScrolledListbox $lf.flb "Families:" \ -width 25 -height 12 -exportselection 0 -setgrid 1] pack $lf -side top -fill both -pady 4 -expand 1 -padx 6 pack $lf.slb -side left -fill both -padx 6 -expand 0 -anchor w pack $lf.flb -side left -fill both -padx 6 -expand 1 -anchor w bind $TkFont(slb) \ {set TkFont(-size) [$TkFont(slb) get [$TkFont(slb) curselection]] ; TkFontUpdate} bind $TkFont(flb) \ {set TkFont(-family) [$TkFont(flb) get [$TkFont(flb) curselection]] ; TkFontUpdate ; TkFontGetSizes} # This label displays the current font label $top.font -textvar TkFont(name) -bd 5 # A message displays a string in the font. message $top.msg -aspect 1000 \ -borderwidth 10 -font tkfont \ -text "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789\n!@#$%^&*()_+-=[]{};:\"'` ~,.<>/?\\|" pack $top.font $top.msg -side top set allfonts [lsort [font families]] set TkFont(type) all set TkFont(all) $allfonts TkFontLoad quick TkFontSetSelect TkFontGetSizes } proc TkFontSetFamily {} { global TkFont set f [list $TkFont(-family) $TkFont(-size) $TkFont(-weight) $TkFont(-slant)] foreach opt {underline overstrike} { if {$TkFont(-$opt)} { lappend f $opt } } return $f } proc edit_fonts {} { global TkGnats TkFont set top .tkfont set fonts {DialogFont TextFont HelpFont} TkFont_Select $top $fonts $TkGnats(TkDialogFont) set TkFont(ok) 1 while {$TkFont(ok) != 0} { tkwait variable TkFont(ok) switch $TkFont(ok) 1 { # Close set TkFont(ok) 0 } 2 { # Apply eval {font configure $TkGnats($TkFont(select))} [array get TkFont -*] set TkGnats($TkFont($TkFont(select))) [TkFontSetFamily] #puts "$TkFont($TkFont(select))=$TkGnats($TkFont($TkFont(select)))" } 3 { # Save set txt "" foreach f $fonts { append txt "set TkGnats($f) \{$TkGnats($f)\}\n" } file_put_text $TkGnats(UserDir)/fonts $txt tk_dialog .fontSave "TkFonts Saved" \ "Fonts have been saved in $TkGnats(UserDir)/fonts." "info" 0 "OK" } 4 { # Reset eval font configure $TkGnats($TkFont(select)) $TkFont(orig$TkFont(select)) TkFontSetSelect TkFontGetSizes set TkGnats($TkFont($TkFont(select))) [TkFontSetFamily] } } destroy $top } proc TkFontHideStop {} { global TkFont set TkFont(progress_txt) "" pack forget $TkFont(stop) $TkFont(progress) $TkFont(top) config -cursor "" } proc TkFontShowStop {} { global TkFont set TkFont(stopflag) 0 pack $TkFont(stop) $TkFont(progress) -side left -padx 6 $TkFont(top) config -cursor watch } proc TkFontLoad {{quick {}}} { global TkFont if {$TkFont(type) != "all" && $quick == {} && ![info exists TkFont(fixed)]} { TkFontShowStop set TkFont(fixed) {} set TkFont(proportional) {} set num [llength $TkFont(all)] set n 1 foreach f $TkFont(all) { set TkFont(progress_txt) "Scanning $n of $num fonts..." incr n update if {$TkFont(stopflag)} { unset TkFont(fixed) unset TkFont(proportional) break } if {[font metrics [list $f] -fixed]} { lappend TkFont(fixed) $f } else { lappend TkFont(proportional) $f } } TkFontHideStop } if {![info exists TkFont(fixed)]} { set TkFont(type) all } catch {set TkFont(prev) [$TkFont(flb) get [$TkFont(flb) curselection]]} $TkFont(flb) delete 0 end foreach f $TkFont($TkFont(type)) { $TkFont(flb) insert end $f } if {[info exists TkFont(prev)]} { TkFontListboxSelect flb $TkFont(prev) } } proc TkFontGetSizes {{quick {}}} { global TkFont $TkFont(slb) delete 0 end if {[info exists TkFont($TkFont(-family),sizes)]} { foreach s $TkFont($TkFont(-family),sizes) { $TkFont(slb) insert end $s } } { if {$quick != {}} { return } TkFontShowStop for {set s 2} {$s < 25} {incr s} { set TkFont(progress_txt) "Scanning $s of 25 sizes..." update if {$TkFont(stopflag)} { break } if {[font actual [list $TkFont(-family) $s] -size] == "$s"} { $TkFont(slb) insert end $s lappend TkFont($TkFont(-family),sizes) $s } } TkFontHideStop } TkFontListboxSelect slb $TkFont(-size) } proc TkFontSetSelect {} { global TkFont array set TkFont [font actual $TkFont(select)] TkFontUpdate set TkFont(type) all TkFontLoad quick TkFontListboxSelect flb $TkFont(-family) TkFontListboxSelect slb $TkFont(-size) } proc TkFontUpdate { } { global TkFont # The elements of font that have a leading - are # used directly in the font configuration command. eval {font configure tkfont} [array get TkFont -*] TkFontSet } proc TkFontInit {} { global TkFont TkGnats catch {font delete tkfont} font create tkfont -family $TkGnats($TkFont(select)) } proc TkFontSet {} { global TkFont # Save the actual font parameters after any font substitutions. # "TkFont(name)" is the font configuration information # with a line break before "-slant" so it looks nicer. # The code is ordered to only execute "font actual" once. set fn [font actual tkfont] array set TkFont $fn append fn \n[lrange [font metrics tkfont] 0 5] regsub -- "-slant" $fn "\n-slant" TkFont(name) } proc TkFontListboxSelect {lb element} { global TkFont $TkFont($lb) selection clear 0 end set l [$TkFont($lb) get 0 end] if {[set n [lsearch $l $element]] >= 0} { $TkFont($lb) selection set $n $TkFont($lb) see $n } } proc TkFontScrolledListbox { f title args } { frame $f -relief groove -borderwidth 2 listbox $f.list \ -xscrollcommand [list $f.xscroll set] \ -yscrollcommand [list $f.yscroll set] eval {$f.list configure} $args scrollbar $f.xscroll -orient horizontal -command [list $f.list xview] scrollbar $f.yscroll -orient vertical -command [list $f.list yview] if {$title != {}} { label $f.label -text $title -anchor nw grid $f.label -sticky nw } grid $f.list $f.yscroll -sticky news grid $f.xscroll -sticky news grid rowconfigure $f 1 -weight 1 grid columnconfigure $f 0 -weight 1 return $f.list } #wm withdraw . #puts [TkFont_Select] #exit gnats-4.1.0/contrib/tkgnats/tkprhelp.tcl0000644000175000017500000011270007005513656021042 0ustar chewiechewie00000000000000proc helpMsg {field} { global TkGnats help_text env set help_text(TkGnats_Version) "\n$TkGnats(tkgnats_version)\n\nYou are running [info nameofexecutable] patchlevel [info patchlevel]." if {$field == "Changes"} { show_help $field [file_get_text $TkGnats(TKGNATSLIB)/CHANGES] return } if {$field == "TkGnats_Version"} { if {[info exists TkGnats(Servers)]} { append help_text($field) "\n\nServers: $TkGnats(Servers)" } show_help $field $help_text($field) return } set help_text(TkGnats_Variables) $help_text(TkGnats_Version)\n foreach t [lsort [array names TkGnats]] { if {[string first "Password" $t] < 0} { append help_text(TkGnats_Variables) "[format "\n%-24s:" $t] $TkGnats($t)" } } set help_text(TkGnats_About) $help_text(TkGnats_Version) if {$TkGnats(GNATS_ACCESS) == "network"} { if {[info exists TkGnats(GNATS_SERVER)] && $TkGnats(GNATS_SERVER) != ""} { set host " (host: $TkGnats(GNATS_SERVER) port: $TkGnats(GNATS_PORT))" } { set host "" } append help_text(TkGnats_About) "\n\nTkGnats is accessing a network GNATS daemon.$host\n" } { append help_text(TkGnats_About) "\n\nTkGnats is accessing a local GNATS database.\n" } append help_text(TkGnats_About) "\nGNATS_Version: $TkGnats(GNATS_Version)" append help_text(TkGnats_About) "\nGNATS_ACCESS: $TkGnats(GNATS_ACCESS)" if {$TkGnats(GNATS_ACCESS) == "local"} { append help_text(TkGnats_About) "\nGNATS_USER: $TkGnats(GNATS_USER)" } { append help_text(TkGnats_About) "\nGNATS_SERVER: $TkGnats(GNATS_SERVER)" append help_text(TkGnats_About) "\nGNATS_PORT : $TkGnats(GNATS_PORT)" if {[info exists TkGnats(ServerInfo)]} { append help_text(TkGnats_About) "\nServerInfo: $TkGnats(ServerInfo)" } } append help_text(TkGnats_About) "\nGNATS_ACCESS_METHOD: $TkGnats(GNATS_ACCESS_METHOD)" if {$TkGnats(GNATS_ACCESS_METHOD) == "batch"} { append help_text(TkGnats_About) "\nGNATS_ROOT: $TkGnats(GNATS_ROOT)" append help_text(TkGnats_About) "\nLIBEXECDIR: $TkGnats(GNATS_LIBEXECDIR)" } append help_text(TkGnats_About) "\nGNATS_ADDR: $TkGnats(GNATS_ADDR)" append help_text(TkGnats_About) "\nSUBMITTER: $TkGnats(SUBMITTER)" append help_text(TkGnats_About) "\nEmailAddr: $TkGnats(EmailAddr)" append help_text(TkGnats_About) "\nLogName: $TkGnats(LogName)" append help_text(TkGnats_About) "\nFullName: $TkGnats(FullName)" append help_text(TkGnats_About) "\nGroupName: $TkGnats(GroupName)" append help_text(TkGnats_About) "\nORGANIZATION: $TkGnats(ORGANIZATION)" append help_text(TkGnats_About) "\nHOSTNAME: $TkGnats(HOSTNAME)" append help_text(TkGnats_About) "\nMailMethod: $TkGnats(MailMethod)" if {$TkGnats(MailMethod) == "mailer"} { append help_text(TkGnats_About) "\nMailer: $TkGnats(Mailer)" } { append help_text(TkGnats_About) "\nSMTP_SERVER: $TkGnats(SMTP_SERVER)" append help_text(TkGnats_About) "\nSMTP_PORT : $TkGnats(SMTP_PORT)" } append help_text(TkGnats_About) "\nQuerySortMethod: $TkGnats(QuerySortMethod)" append help_text(TkGnats_About) "\nQueryMode: $TkGnats(QueryMode)" if {[info exists TkGnats(ReleaseBased)]} { append help_text(TkGnats_About) "\nReleasedBased: $TkGnats(ReleaseBased)" } if {[info exists TkGnats(TKGNATSINI)]} { set ini $TkGnats(TKGNATSINI) } { set ini "" } append help_text(TkGnats_About) "\nTKGNATSINI: $ini" append help_text(TkGnats_About) "\nWISHPATH: $TkGnats(WISHPATH)" append help_text(TkGnats_About) "\nTKGNATSLIB: $TkGnats(lib)" append help_text(TkGnats_About) "\nSiteServerDir: $TkGnats(SiteServerDir)" append help_text(TkGnats_About) "\nUserAccess: $TkGnats(UserAccess)" append help_text(TkGnats_About) "\nUserDir: $TkGnats(UserDir)" append help_text(TkGnats_About) "\nUserServerDir: $TkGnats(UserServerDir)" append help_text(TkGnats_About) "\nedit_authorized: $TkGnats(edit_authorized)" append help_text(TkGnats_About) "\ndelete_authorized: $TkGnats(delete_authorized)" append help_text(TkGnats_About) "\nDialogFont: $TkGnats(DialogFont)" append help_text(TkGnats_About) "\nTestFont: $TkGnats(TextFont)" append help_text(TkGnats_About) "\nHelpFont: $TkGnats(HelpFont)" set help_text(Cut_Copy_Paste) { Selections and Cut, Copy and Paste operations Text is selected by clicking and dragging the mouse. Control-/ selects the entire contents of the widget, and Control-\ clears any selection in the widget. There are many other selection bindings. See the Tk manual page for the Text and Entry widgets. On UNIX, selected text is exported to the Xselection buffer and can be pasted directly into Tk widgets with the middle mouse button or the Insert key. This is true even for text selected in other UNIX applications such as xterms, Emacs, etc. Text selected in Tk widgets can also be pasted into other UNIX applications with the middle mouse button. One problem with pasting text into Tk widgets is that you have to hold the mouse very still when you press and release the mouse button. If it moves even one pixel, the mouse motion is detected and it interprets your movement to be a scrolling action. Besides the Xselection buffer, UNIX also has a "Clipboard" buffer, which Windows also has. On both UNIX and Windows, you can Cut or Copy the selection into the Clipboard with the ^x, ^c keys respectively. ^v pastes the clipboard contents into the widget. On Sun workstations, the Keyboard keys labelled Cut, Copy and Paste also do these functions. Cut/Copy/Paste/SelectAll operations can be found on the right mouse button pop-up menu. } set help_text(Edit_Overview) { Overview of Editing Problem Reports Make your changes, and click "Update edits"! If you change the Responsible or the State, you will be prompted for a reason for the change. This gets stored in the Audit-Trail for the problem report. } set help_text(Edit_Radio_Buttons) { Radio Buttons: Class, State, Priority, Severity and Confidential Clicking the buttons selects the value. Please use reasonable priorities when reporting problems. Click the heading title (eg Class:) for a definition of the field itself. } set help_text(Edit_Listbox_Selectors) { Listbox Selectors: Category, Submitter-Id and Responsible Click on a listbox item and it gets entered into the entry box for you. The entry box uses a quick-fill feature for easy entry if you choose not to scroll the listbox looking for an item. As you type in each character, it automatically completes the value according to the available items in the listbox. It will not allow you to enter anything that isn't in the listbox. Click the heading title (eg Category:) for a definition of the field itself. Besides the scroll-bar, you can also scroll the listbox with the middle mouse button. Just click and hold the middle button anywhere in the listbox data area, and drag it vertically. } set help_text(Edit_Entry_Fields) { Entry Fields: Originator, Notify-List, Release and Synopsis These are one-line, free-format text entry fields. For Notify-List, TkGnats expects one or more valid email-addresses for any additional people interested in the progress of this bug report. They will be copied on all email. The list must be comma-separated. If domain names are not specified (@somewhere.something) they will be added if you have set TkGnats(DefaultDomainName). } set help_text(Edit_Text_Fields) { Text Fields: Description, How-To-Repeat, Environment, Audit-Trail, Unformatted, Fix and Release-Note These are the multi-line, free-format text entry fields of a problem report. The MultiText fields are shown one at a time. Click on the field buttons to change fields. When the button is depressed, click again to get help for that field. The "Insert File..." button gives a file selector. Select a file to insert at the cursor position. } set help_text(View_Overview) { Overview of Viewing Problem Reports You can look, but don't touch! } set help_text(View_Text_Fields) { Text Fields: Description, How-To-Repeat, Environment, Audit-Trail, Unformatted, Fix and Release-Note These are the multi-line, free-format text entry fields of a problem report. The MultiText fields are shown one at a time. Click on the field buttons to change fields. When the button is depressed, click again to get help for that field. } #TTD: Yikes! How can this (change-request) be dynamic? set help_text(Create_Overview) { Overview of Creating Problem Reports Fill in the form, and click "Send"! All fields must be filled in, except Release, Environment and Fix are optional. If Class is set to "change-request", then How-To-Repeat becomes optional as well. } set help_text(Create_Radio_Buttons) { Radio Buttons: Class, Priority, Severity and Confidential Clicking the buttons selects the value. Please use reasonable priorities when reporting problems. Click the heading title (eg Class:) for a definition of the field itself. } set help_text(Create_Listbox_Selectors) { Listbox Selectors: Category and Submitter-Id Click on a listbox item and it gets entered into the entry box for you. The entry box uses a quick-fill feature for easy entry if you choose not to scroll the listbox looking for an item. As you type in each character, it automatically completes the value according to the available items in the listbox. It will not allow you to enter anything that isn't in the listbox. Click the heading title (eg Category:) for a definition of the field itself. Besides the scroll-bar, you can also scroll the listbox with the middle mouse button. Just click and hold the middle button anywhere in the listbox data area, and drag it vertically. } set help_text(Create_Entry_Fields) { Entry Fields: Originator, Notify-List, Release and Synopsis These are one-line, free-format text entry fields. For Notify-List, TkGnats expects one or more valid email-addresses for any additional people interested in the progress of this bug report. They will be copied on all email. The list must be comma-separated. If domain names are not specified (@somewhere.something) they will be added if you have set TkGnats(DefaultDomainName). } #TTD: Yikes! How can this (change-request) be dynamic? set help_text(Create_Text_Fields) { Text Fields: Description, How-To-Repeat, Environment and Fix These are the multi-line, free-format text entry fields of a problem report. Environment and Fix are optional. If Class is set to "change-request", then How-To-Repeat becomes optional as well. TkGnats tries to fill the Environment section with meaningfull information about the system that you're running TkGnats on. If this is not the system where the problem occured, be sure to change the entry. If you have a work-around for the problem, enter the details into the Fix field. Otherwise, leave Fix blank. The MultiText fields are shown one at a time. Click on the field buttons to change fields. When the button is depressed, click again to get help for that field. The "Insert File..." button gives a file selector. Select a file to insert at the cursor position. } set help_text(Query_Overview) { Overview of the Query System Select the search criteria, and click "Do Query"! All of the fields are logically and'd together. Only problem reports that match everything that you specify are selected. Leaving any field blank, or not selecting any check buttons (Class, State, etc), means that field is unrestricted in the search. Be warned that searching the "Text-Fields" causes the entire bug report to be read (by the server) and will take much longer to run. Be sure to restrict the search by specifying other search criteria, and thereby minimizing the number of reports that have to actually be read. Pressing the "Return" key in the entry fields is a shortcut for the "Do Query" button. } set help_text(Field_Definitions) { GNATS Problem Report Fields All of the field headings that are terminated with a colon ":", such as "Class:", "State:", etc, are also Help Buttons. Notice that they get highlighted as the mouse pointer passes over them. Click them to get the definition of each field. In Create, View and Edit modes, the MultiText fields such as "Description:", "How-To-Repeat:", etc are shown one at a time. Click on the MultiText field buttons to change fields. When the button is depressed, click again to get help for that field. } set help_text(Query_Regular_Expressions) { Regular Expressions The following applies to the "RexExp:" fields and the text entry widgets that accept regular expressions. o the match is _not_ case sensitive. o use ".*", not just "*", to mean zero or more of any character. o use "|" to specify values to be or'd, such as "seg|bus". o the "RexExp:" fields use "matching", so you must specify a leading ".*" to match the middle of a string. For example, ".*alg" matches the Submitter-Id "calgary", but "alg" alone does not. The other input fields use "searching", and don't require this. o a trailing ".*" is never required. Click on "RegExp:" in one of the listbox selectors for a more detailed discussion of regular expressions. } set help_text(Query_Check_Buttons) { Check Buttons: Class, State, Priority, Severity and Confidential Clicking the buttons turns them on and off. Leaving all buttons unchecked is the same as selecting them all. Select the values that you want to include in the search. Click the heading title (eg Class:) for a definition of the field itself. } set help_text(Query_Listbox_Selectors) { Listbox Selectors: Category, Submitter-Id and Responsible Click on the items to move them back and forth between "Available" and "Selected". Within the listboxes, the selected items and the "regular expression" input field ("RegExp:") are logically or'd together. If at least one of the two are matched, this is and'd with all of the other search criteria specified. See the Regular Expression help for some highlights about using regular expressions in the Query dialog. Click "RegExp:" for a detailed explanation of regular expressions. Click the heading title (eg Category:) for a definition of the field itself. Besides the scroll-bar, you can also scroll the Query Listbox with the middle mouse button. Just click and hold the middle button anywhere in the listbox data area, and drag it vertically. } set help_text(Query_Entry_Fields) { Entry Widgets: Synopsis, Release, Originator and Text-Fields These are all regular expression input fields. The Text-Fields are the multi-line, free-format text entry fields of a problem report such as Description, How-To-Repeat, Environment, Audit-Trail, Unformatted, Fix and Release-Note. They are all searched with the one regular expression that you enter. Be warned that searching the "Text-Fields" causes the entire bug report to be read (by the server) and will take much longer to run. Be sure to restrict the search by specifying other search criteria, and thereby minimizing the number of reports that have to actually be read. Note that some fields, such as Originator, don't show their entire contents in the Query Listbox for space reasons. Thus, you may get matches that appear to be incorrect. For example, searching for Originator "don" may find "donw" and "rickm". "rickm" is matched because the full value for Originator is: "rickm (Rick Macdonald)". Click the heading title (eg Synopsis:) for a definition of the field itself. See the Regular Expression help for some highlights about using regular expressions in the Query dialog. Click on "RegExp:" in one of the listbox selectors for a more detailed discussion of regular expressions. Entry Widgets: Number Enter one or more problem report numbers separated by blanks or commas to get to specific problem reports directly. There is no warning if some of the problem reports are not found, or even if you enter non-numeric values. All of the other selections are cleared when the Number entry is used. Click the heading title (eg Number:) for a definition of the field itself. Entry Widgets: Days-Idle This checks the "Last-Modifed-Date" against todays date and compares the difference (in days) to the value that you enter. Click the heading title (eg Days-Idle:) for a definition of the field itself. } set help_text(Query_Menubar) { Menu Bar The menu bar contains buttons and menus. Note that the menus have "tear-off" bars. Click on the "perforated" line ("--------") to make the menu appear in a little window of its own. This is very handy when playing with the "Fields" selection, for example. Do Query (button) Just Do It. Clear (button) All the selection widgets are cleared. Query Do Query - same as the button above. Clear Widgets - same as the button above. Query Selection - extract problem Ids from active selection Save Current > - cascaded menu - To Saved Queries Menu... - save the current state of the selection widgets, sort order and selected fields and add a command to the Query Menu. Manage Saved... - delete or rename saved queries. Query For > - cascaded menu - these are queries that your site administrator has created for global use. Saved Queries: - these are queries that you have saved above. They are permanent until you delete them. Sort New... - specify a new sort order Save Current > - cascaded menu - To Saved Sorts Menu... - save the current sort order and add a command to the Sort Menu. - As Startup Default - save the current sort order as the default for when TkGnats is started. Manage Saved... - delete or rename saved sorts. Sort By > - cascaded menu - these are sorts that your site administrator has saved for global use. Saved Sorts: - these are sorts that you have saved. They are permanent until you delete them. Fields Save Current > - cascaded menu - As Startup Default - save the currently selected fields as the default for when TkGnats is started. Click on the check buttons to specify the fields that you want see in the Query Listbox. The fields selected in no way effects or restricts the search itself. Print This menu contains various reports that can be previewed and printed. The numbered entries below the separator line of the menu are reports that your site administrator has added to the system. (Well, we supplied the first few to get them started.) Each entry brings up a configuration menu that allows specification of the device (printer, previewer or file) and the format (postscript, ascii text, etc). Also, you can print all the problem reports currently displayed in the Query Listbox, or just the one that is currently selected (highlighted). Actions These actions apply _only_ to the problem report currently selected (highlighted) in the Query Listbox. You can get this same menu to pop-up by clicking the right mouse button on any report in the listbox. Edit... - invoke the problem report editor. View... - invoke the problem report viewer. View Raw Data... - have a look at how the data is stored. Remove From List - this temporarily removes the problem report from the Query Listbox. This allows more control when printing more than one problem report. Send Email... - send email to GNATS and optionally various people involved with this problem. GNATS adds the emaiil to the Audit-Trail field of the problem report. Exit Click here when you've fixed all the bugs that have been reported. } set help_text(Query_Results_Listbox) { Query Listbox Problem reports that match your search criteria are listed here. The fields displayed are not related to the search, they are set according to the fields that you select in the "Fields" menu on the menubar. Click the left mouse button on any problem report to "select" it. Click the right mouse button on any problem report to pop-up the Actions menu. Actions, such as editing or sending follow-up email, can be found under the "Actions" menubar item. The actions there are performed on the problem report in the Query Listbox that is currently highlighted. Double-clicking on a listbox entry is a shortcut to "View" that problem report. Besides the scroll-bars, you can also scroll the Query Listbox with the middle mouse button. Just click and hold the middle button anywhere in the listbox data area, and drag it vertically and horizontally. } ###append help_text(Query_Dialog) \ ### $help_text(Field_Definitions) \ ### $help_text(Query_Widget_Help) set help_text(Text-Fields) { Text-Fields These are the multi-line, free-format text entry fields of a problem report such as Description, How-To-Repeat, Environment, Audit-Trail, Unformatted, Fix and Release-Note. Be warned that searching the "Text-Fields" causes the entire bug report to be read (by the server) and will take much longer to run. Be sure to restrict the search by specifying other search criteria, and thereby minimizing the number of reports that have to actually be read. In Create, View and Edit modes, the MultiText fields are shown one at a time. Click on the field buttons to change fields. When the button is depressed, click again to get help for that field. In Create and Edit modes, the "Insert File..." button gives a file selector. Select a file to insert at the cursor position. } set help_text(State) "\n`>State:'\n (ENUMERATED) The current state of the PR. Accepted values are:\n" foreach state $TkGnats(StatesFile) { append help_text(State) "\n `[lindex [split $state ":"] 0]'\n [lindex [split $state ":"] 2]\n" if {[lindex [split $state ":"] 1] != ""} { append help_text(State) "\n This state has the state type \"[lindex [split $state ":"] 1]\".\n" } } set help_text(Submitter-Id) { `>Submitter-Id:' (TEXT) A unique identification code assigned by the Support Site. It is used to identify all Problem Reports coming from a particular site. (Submitters without a value for this field can invoke `send-pr' with the `--request-id' option to apply for one from the support organization. Problem Reports from those not affiliated with the support organization should use the default value of `net' for this field.) } set help_text(Originator) { `>Originator:' (TEXT) Originator's real name. The default is the value of the originator's environment variable `NAME'. } set help_text(Notify-List) { `Notify-List:' (TEXT) Email addresses for any additional people interested in the progress of this bug report. They will be copied on all email. The list must be comma-separated. If domain names are not specified (@somewhere.something) they will be added if you have set TkGnats(DefaultDomainName). } set help_text(Organization) { `>Organization:' (MULTITEXT) The originator's organization. The default value is set with the variable `TkGnats(ORGANIZATION)' in the `config' file. } set help_text(Confidential) { `>Confidential:' (ENUMERATED) Use of this field depends on the originator's relationship with the support organization; contractual agreements often have provisions for preserving confidentiality. Conversely, a lack of a contract often means that any data provided will not be considered confidential. Submitters should be advised to contact the support organization directly if this is an issue. If the originator's relationship to the support organization provides for confidentiality, then if the value of this field is `yes' the support organization treats the PR as confidential; any code samples provided are not made publicly available (e.g., in regression test suites). The default value is `yes'. } set help_text(Synopsis) { `>Synopsis:' (TEXT) One-line summary of the problem. `send-pr' copies this information to the `Subject:' line when you submit a Problem Report. } set help_text(Severity) { `>Severity:' (ENUMERATED) The severity of the problem. Accepted values include: `critical' The product, component or concept is completely non-operational or some essential functionality is missing. No workaround is known. `serious' The product, component or concept is not working properly or significant functionality is missing. Problems that would otherwise be considered `critical' are rated `serious' when a workaround is known. `non-critical' The product, component or concept is working in general, but lacks features, has irritating behavior, does something wrong, or doesn't match its documentation. The default value is `serious'. } set help_text(Priority) { `>Priority:' (ENUMERATED) How soon the originator requires a solution. Accepted values include: `high' A solution is needed as soon as possible. `medium' The problem should be solved in the next release. `low' The problem should be solved in a future release. The default value is `medium'. } set help_text(Category) { `>Category:' (TEXT) The name of the product, component or concept where the problem lies. The values for this field are defined by the Support Site. } set help_text(Class) "\n`>Class:'\n (ENUMERATED) The current class of the PR. Accepted values are:\n" foreach class $TkGnats(ClassesFile) { append help_text(Class) "\n `[lindex [split $class ":"] 0]'\n [lindex [split $class ":"] 2]\n" if {[lindex [split $class ":"] 1] != ""} { append help_text(Class) "\n This class has the class type \"[lindex [split $class ":"] 1]\".\n" } } set help_text(Release) { `>Release:' (TEXT) Release or version number of the product, component or concept. } set help_text(Keywords) { `>Keywords:' (TEXT) This field is available if your GNATS system has been configured with the flag "--with-released-based". Text entered here can be queried directly. } set help_text($TkGnats(Quarter)) " `>$TkGnats(Quarter):' (TEXT) This field is available if your GNATS system has been configured with the flag \"--with-released-based\". Text entered here can be queried directly. " set help_text(Date-Required) { `>Date-Required:' (TEXT) This field is available if your GNATS system has been configured with the flag "--with-released-based". Dates entered here can be queried directly. } set help_text(Environment) { `>Environment:' (MULTITEXT) Description of the environment where the problem occured: machine architecture, operating system, host and target types, libraries, pathnames, etc. } set help_text(Description) { `>Description:' (MULTITEXT) Precise description of the problem. } set help_text(How-To-Repeat) { `>How-To-Repeat:' (MULTITEXT) Example code, input, or activities to reproduce the problem. The support organization uses example code both to reproduce the problem and to test whether the problem is fixed. Include all preconditions, inputs, outputs, conditions after the problem, and symptoms. Any additional important information should be included. Include all the details that would be necessary for someone else to recreate the problem reported, however obvious. Sometimes seemingly arbitrary or obvious information can point the way toward a solution. } set help_text(Release-Note) { `>Release-Note:' (MULTITEXT) Human readable (user friendly) comments about problems or fixes suitable for incorporation into release notes for a given software distribution. } set help_text(Fix) { `>Fix:' (MULTITEXT) A description of a solution to the problem, or a patch which solves the problem. (This field is most often filled in at the Support Site; we provide it to the submitter in case she has solved the problem.) } set help_text(Number) { `>Number:' (ENUMERATED) The incremental identification number for this PR. This is included in the automated reply to the submitter (if that feature of GNATS is activated. It is also included in the copy of the PR that is sent to the maintainer. The `>Number:' field is often paired with the `>Category:' field as CATEGORY/NUMBER in subsequent email messages. This is for historical reasons, as well as because Problem Reports are stored in subdirectories which are named by category. } set help_text(Responsible) { `>Responsible:' (TEXT) The person responsible for this category. GNATS retrieves this information from the `categories' file. } set help_text(Arrival-Date) { `>Arrival-Date:' (TEXT) The time that this PR was received by GNATS. The date is provided automatically by GNATS. } set help_text(Last-Modified) { `>Last-Modified:' (TEXT) The time that this PR was last edited or changed. } set help_text(Closed-Date) { `>Closed-Date:' (TEXT) The time that this PR was closed. } set help_text(Audit-Trail) { `>Audit-Trail:' (MULTITEXT) Tracks related electronic mail as well as changes in the `>State:' and `>Responsible:' fields with the sub-fields: `State-Changed--: OLDSTATE>-State:' field values. `Responsible-Changed--: OLDRESP>-Responsible:' field values. `State-Changed-By: NAME' `Responsible-Changed-By: NAME' The name of the maintainer who effected the change. `State-Changed-When: TIMESTAMP' `Responsible-Changed-When: TIMESTAMP' The time the change was made. `State-Changed-Why: REASON...' `Responsible-Changed-Why: REASON...' The reason for the change. The `>Audit-Trail:' field also contains any mail messages received by GNATS related to this PR, in the order received. Use a Subject of the following format and copy the email to the gnats address. Subject: Re: category/prnum } set help_text(Unformatted) { `>Unformatted:' (MULTITEXT) Any random text found outside the fields in the original Problem Report. } set help_text(Days-Idle) { `Days-Idle' This is for selecting problem reports that have not been updated for this number of days or more. } set help_text(RegExp) { Querying using regular expressions ********************************** GNATS uses GNU regular expression syntax with these settings: RE_SYNTAX_POSIX_EXTENDED | RE_BK_PLUS_QM & RE_DOT_NEWLINE This means that parentheses (`(' and `)') and pipe symbols (`|') do not need to be used with the escape symbol `\'. The tokens `+' and `?' do need the escape symbol, however. Unfortunately, we do not have room in this manual for an adequate tutorial on regular expressions. The following is a basic summary of some regular expressions you might wish to use. *Note Regular Expression Syntax: (regex)Regular Expression Syntax, for details on regular expression syntax. Also see *Note Syntax of Regular Expressions: (emacs)Regexps, but beware that the syntax for regular expressions in Emacs is slightly different. All search criteria options to `query-pr' rely on regular expression syntax to construct their search patterns. For example, query-pr --state=open matches all PRs whose `>State:' values match with the regular expression `open'. We can substitute the expression `o' for `open', according to GNU regular expression syntax. This matches all values of `>State:' which begin with the letter `o'. query-pr --state=o is equivalent to query-pr --state=open in this case, since the only value for `>State:' which matches the expression `o' is `open'. (Double quotes (`"') are used to protect the asterix (`*') from the shell.) `--state=o' also matches `o', `oswald', and even `oooooo', but none of those values are valid states for a Problem Report. Regular expression syntax considers a regexp token surrounded with parentheses, as in `(REGEXP)', to be a "group". This means that `(ab)*' matches any number of contiguous instances of `ab', including zero. Matches include `', `ab', and `ababab'. Regular expression syntax considers a regexp token surrounded with square brackets, as in `[REGEXP]', to be a "list". This means that `Char[(ley)(lene)(broiled)' matches any of the words `Charley', `Charlene', or `Charbroiled' (case is significant; `charbroiled' is not matched). Using groups and lists, we see that query-pr --category="gcc|gdb|gas" is equivalent to query-pr --category="g(cc|db|as)" and is also very similar to query-pr --category="g[cda]" with the exception that this last search matches any values which begin with `gc', `gd', or `ga'. The `.' character is known as a "wildcard". `.' matches on any single character. `*' matches the previous character (except newlines), list, or group any number of times, including zero. Therefore, we can understand `.*' to mean "match zero or more instances of any character." For this reason, we never specify it at the end of a regular expression, as that would be redundant. The expression `o' matches any instance of the letter `o' (followed by anything) at the beginning of a line, while the expression `o.*' matches any instance of the letter `o' at the beginning of a line followed by any number (including zero) of any characters. We can also use the expression operator `|' to signify a logical `OR', such that query-pr --state="o|a" matches all `open' or `analyzed' Problem Reports. (Double quotes (`"') are used to protect the pipe symbol (`|') from the shell.) By the same token,(1) using query-pr --state=".*a" matches all values for `>State:' which contain an `a'. (These include `analyzed' and `feedback'.) Another way to understand what wildcards do is to follow them on their search for matching text. By our syntax, `.*' matches any character any number of times, including zero. Therefore, `.*a' searches for any group of characters which end with `a', ignoring the rest of the field. `.*a' matches `analyzed' (stopping at the first `a') as well as `feedback'. *Note:* When using `--text' or `--multitext', you do not have to specify the token `.*' at the beginning of TEXT to match the entire field. For the technically minded, this is because `--text' and `--multitext' use `re_search' rather than `re_match'. `re_match' "anchors" the search at the beginning of the field, while `re_search' does not anchor the search. For example, to search in the `>Description:' field for the text The defrobulator component returns a nil value. we can use query-pr --multitext="defrobulator.*nil" To also match newlines, we have to include the expression `(.|^M)' instead of just a dot (`.'). `(.|^M)' matches "any single character except a newline (`.') *or* (`|') any newline (`^M')." This means that to search for the text The defrobulator component enters the bifrabulator routine and returns a nil value. we must use query-pr --multitext="defrobulator(.|^M)*nil" To generate the newline character `^M', type the following depending on your shell: `csh' `*control*-V *control*-M' `tcsh' `*control*-V *control*-J' `sh (*or* bash)' Use the RETURN key, as in (.| ) Again, see *Note Regular Expression Syntax: (regex)Regular Expression Syntax, for a much more complete discussion on regular expression syntax. ---------- Footnotes ---------- (1) No pun intended. } set alias [get_field_alias $field] if {![info exists help_text($alias)]} { set help_text($alias) "\n No help available for $alias" } show_help $alias $help_text($alias) } gnats-4.1.0/contrib/tkgnats/tkprprint.tcl0000644000175000017500000003007706665615034021260 0ustar chewiechewie00000000000000proc putlines {fout lst} { foreach ln $lst { puts $fout $ln ## puts "$ln" } } proc putfld {fout f tag {prefix ""}} { upvar 1 $f flds ## set data [string trimright [string trim $flds($tag) " \t"] "\n"] set data [ftrim $flds($tag)] if {"$prefix" == ""} { set prefix [string trimright [string trimleft $tag >] :] } puts $fout ".ti +.1i" puts $fout "${prefix}:%" nonewline puts $fout "T{\n.nf" puts $fout $data puts $fout ".fi\nT}" } proc putfldvalbold {fout f tag} { upvar 1 $f flds ## set data [string trimright [string trim $flds($tag) " \t"] "\n"] set data [ftrim $flds($tag)] puts $fout "\\fB$data\\fR" nonewline } proc putfldval1 {fout f tag} { upvar 1 $f flds ## set data [string trimright [string trim $flds($tag) " \t"] "\n"] set data [ftrim $flds($tag)] puts $fout "$data" nonewline } proc putfldval2 {fout f tag} { upvar 1 $f flds ## set data [string trimright [string trim $flds($tag) " \t"] "\n"] set data [ftrim $flds($tag)] puts $fout "T{\n.na" puts $fout $data puts $fout ".ad\nT}" } proc endtbl {fout} { putlines $fout { {.TE} } } proc starttbl {fout} { putlines $fout { {.sp} {.sp} {.TS} {box, expand, tab(%);} } } proc heading {fout s} { putlines $fout [list $s _] } proc freeform_text {fout f tag {prefix ""}} { upvar 1 $f flds if {![info exists flds($tag)]} { return } set data [string trimright [string trim $flds($tag) " \t"] "\n"] if {[string compare "$data" ""] == 0} { return } if {"$prefix" == ""} { set prefix [string trimright [string trimleft $tag >] :] } starttbl $fout putlines $fout [list {Cbp12w(7.75i).} $prefix] endtbl $fout putlines $fout { {.sp} {.nf} } puts $fout $data putlines $fout { {.fi} } } proc freeform_text2 {fout f tag} { upvar 1 $f flds if {![info exists flds($tag)]} { return } set data [string trimright [string trim $flds($tag) " \t"] "\n"] if {[string compare "$data" ""] == 0} { return } puts $fout "T{\n.nf" puts $fout $data puts $fout ".fi\nT}" } proc Summary {prid ln} { global Print headingMsg "Doing $prid..." set fout $Print(fout) set fields $Print(fields) set widths $Print(widths) set nfields [llength $fields] if {$Print(first_time) == 1} { # title section set dat "[clock format [clock seconds] -format "%a %b %e %H:%M %Y"]" putlines $fout { {.po 0.375i} {.ll 7.75i} } putlines $fout { {.TS} {expand, tab(%);} } putlines $fout [list {Cbp12w(7.75i).} "Problem Report Summary -- $dat" {.TE}] puts $fout ".sp" # format section putlines $fout { {.ds CF " \\n(yr / \\n(mo / \\n(dy} {.TS H} {box;} } ## {.sp 1} set headspec "Cb" set dataspec "N" set heading [lindex $fields 0] for {set i 1} {$i < $nfields} {incr i} { append headspec "|Lb" append dataspec "|L" append heading "\t[lindex $fields $i]" } if {[lsearch -exact $fields "Synopsis"] >= 0} { set wid [expr 7.625 - [expr 0.75 * [expr $nfields - 1]]] if {$wid < 1.0} { set wid 1.0 } append headspec "w(${wid}i)" } putlines $fout [list "$headspec" "$dataspec."] # table heading putlines $fout [list "$heading" {=} {.TH}] } set end -2 for {set i 0} {$i < [expr $nfields - 1]} {incr i} { set beg [expr $end + 2] set end [expr $end + 1 + [lindex $widths $i]] if {$i == 0} { puts $fout "\\fB[string range $ln $beg $end]\\fR\t" nonewline } { puts $fout "[string trim [string range $ln $beg $end]]\t" nonewline } } set beg [expr $end + 2] puts $fout "T{\n.na\n[string trim [string range $ln $beg end]]\n.ad\nT}" puts $fout "_" if {$Print(last_time) == 1} { # trailer puts $fout ".TE" } return 0 } proc Medium {prid ln} { global Print TkGnats ## workingMsg headingMsg "Doing $prid..." if {$Print(first_time) == 1} { # title section set dat "[clock format [clock seconds] -format "%a %b %e %H:%M %Y"]" putlines $Print(fout) { {.po 0.375i} {.ll 7.75i} } putlines $Print(fout) { {.TS} {box, expand, tab(%);} } putlines $Print(fout) [list {Cbp12w(7.75i).} "Problem Report Summary -- $dat" {.TE}] puts $Print(fout) ".sp 2" # format section putlines $Print(fout) { {.ds CF " \\n(yr / \\n(mo / \\n(dy} } } puts $Print(fout) ".nf" puts $Print(fout) [get_pr_medium_text $prid] puts $Print(fout) "============================================================\n" puts $Print(fout) ".fi" return 0 } proc Full {prid ln} { global Print TkGnats ## workingMsg headingMsg "Doing $prid..." set fout $Print(fout) print_parsepr $prid flds if {$Print(first_time) == 1} { # format section putlines $fout [list {.po 0.375i} {.ll 7.75i}] putlines $fout { {.ds CF " \\n(yr / \\n(mo / \\n(dy} } } ################################### putlines $fout { {.TS} {doublebox, expand, tab(%);} } putlines $fout [list {Cbp12w(7.75i).} \ "Problem Report -- [string trimright [string trim $flds(>Category) " \t"] "\n"]/\ [string trimright [string trim $flds(>Number) " \t"] "\n"] \ [clock format [clock seconds] -format "%a %b %e %H:%M %Y"]" {.TE}] ################################### starttbl $fout putlines $fout { {Cbp12 s} {Lbp10w(1.1i) Lw(6.65i).} } heading $fout Identification putfld $fout flds {>Synopsis} putfld $fout flds {>Release} putfld $fout flds {>Confidential} putlines $fout {.sp} putfld $fout flds {>Arrival-Date} putfld $fout flds {>Last-Modified} putfld $fout flds {>Closed-Date} putfld $fout flds {>Responsible} putlines $fout {.sp} putfld $fout flds {>Class} putfld $fout flds {>State} putfld $fout flds {>Priority} putfld $fout flds {>Severity} if {$TkGnats(ReleaseBased)} { putlines $fout {.sp} putfld $fout flds ">$TkGnats(Quarter)" putfld $fout flds {>Keywords} putfld $fout flds {>Date-Required} } putlines $fout {.sp} putfld $fout flds {>Originator} putfld $fout flds {>Submitter-Id} putfld $fout flds {>Organization} putfld $fout flds {>Environment} endtbl $fout ################################### freeform_text $fout flds {>Description} freeform_text $fout flds {>How-To-Repeat} freeform_text $fout flds {>Audit-Trail} freeform_text $fout flds {>Fix} freeform_text $fout flds {>Release-Note} freeform_text $fout flds {>Unformatted} ################################### if {$Print(last_time) != 1} { puts $fout ".sp 2" } return 0 } proc Raw_Data {prid ln} { global Print ## workingMsg headingMsg "Doing $prid..." if {$Print(first_time) == 1} { # title section set dat "[clock format [clock seconds] -format "%a %b %e %H:%M %Y"]" putlines $Print(fout) { {.po 0.375i} {.ll 7.75i} } putlines $Print(fout) { {.TS} {box, expand, tab(%);} } putlines $Print(fout) [list {Cbp12w(7.75i).} "Problem Report Summary -- $dat" {.TE}] puts $Print(fout) ".sp 2" # format section putlines $Print(fout) { {.ds CF " \\n(yr / \\n(mo / \\n(dy} } } puts $Print(fout) ".nf" puts $Print(fout) [get_pr_full_text $prid] puts $Print(fout) "============================================================\n" puts $Print(fout) ".fi" return 0 } proc print_listbox {lbname procname} { global Print if {[string compare $Print(Select) "all"] == 0} { set Print(first_time) 1 set Print(last_time) 0 set sz [$lbname size] set Print(num_ids) $sz for {set x 0} {$x < $sz} {incr x 1} { if {$x == [expr $sz - 1]} { set Print(last_time) 1 } set ln [$lbname get $x] set prid [pridfromsummaryline $ln] if {[$procname $prid $ln] != 0} { return } set Print(first_time) 0 } } { set Print(first_time) 1 set Print(last_time) 1 set Print(num_ids) 1 set ln [selln $lbname] set prid [pridfromsummaryline $ln] $procname $prid $ln } } proc print_parsepr {prid varname} { upvar 1 $varname flds set prtext [get_pr_full_text $prid] parsepr_txt $prtext flds } proc print_parsepr_medium {prid varname} { upvar 1 $varname flds set prtext [get_pr_medium_text $prid] parsepr_txt $prtext flds } proc print_dialog_SetDevice {a b c} { global Print TkGnats if {"$Print(Device)" == "file"} { .print.d.f configure -foreground [.print.d.file cget -foreground] .print.d.e configure -state normal -background $TkGnats(EditFieldBackground) } { .print.d.f configure -foreground [.print.d.file cget -disabledforeground] .print.d.e configure -state disabled -background [.print.d.file cget -background] } } proc print_dialog {} { global Print TkGnats env set w [toplevel .print] wm title $w {TkGnats - Print Configuration} wm iconbitmap $w @$TkGnats(lib)/tkgnats.xbm wm iconname $w "$TkGnats(LogName)'s TkGnats Print Config" #### frame $w.d -borderwidth 5 pack $w.d -anchor w label $w.d.l -text "Device:" -anchor w -width 7 pack $w.d.l -side left -anchor w foreach b {printer previewer file} { radiobutton $w.d.$b -text $b -relief flat -variable Print(Device) -value $b pack $w.d.$b -side left } label $w.d.f -text " Filename:" -anchor w pack $w.d.f -side left entry $w.d.e -width 32 -textvariable Print(savefile) -relief sunken -highlightthickness 2 pack $w.d.e -side left #### frame $w.t -borderwidth 5 pack $w.t -anchor w label $w.t.l -text "Format:" -anchor w -width 7 pack $w.t.l -side left -anchor w foreach b {ps ascii dvi latin1 troff} { radiobutton $w.t.$b -text $b -relief flat -variable Print(Format) -value $b pack $w.t.$b -side left } #### frame $w.s -borderwidth 5 pack $w.s -anchor w label $w.s.l -text "Select:" -anchor w -width 7 pack $w.s.l -side left -anchor w radiobutton $w.s.all -text "All Ids in Listbox" -relief flat -variable Print(Select) \ -value all radiobutton $w.s.sel -text "Current Selection Only" -relief flat -variable Print(Select) \ -value select pack $w.s.all $w.s.sel -side left #### frame $w.a -borderwidth 5 pack $w.a button $w.a.ok -text OK -command "set Print(setup_done) 0" pack $w.a.ok -side left -padx 20 button $w.a.no -text Cancel -command "set Print(setup_done) 1" pack $w.a.no -side right -padx 20 #### print_dialog_SetDevice a b c trace variable Print(Device) w print_dialog_SetDevice set err 1 while {"$err" != 0} { grab $w tkwait variable Print(setup_done) grab release $w if {$Print(setup_done) == 1} { break } set err 0 case $Print(Device) previewer { if {[info exists Print(Previewer,$Print(Format))] == 0} { set err 1 } } printer { if {[info exists Print(PrintSpooler,$Print(Format))] == 0} { set err 1 } } if {$err == 1} { Msg "Print Configuration Error!\n" \ "Sorry, there is no $Print(Device) configured for $Print(Format)." } } destroy $w return $Print(setup_done) } gnats-4.1.0/contrib/tkgnats/tkprsort.tcl0000644000175000017500000001101307005513656021074 0ustar chewiechewie00000000000000# # -- Sort Callbacks # proc clear_cmd {} { global sortDialog make_lists .sort.fields $sortDialog(fieldnames) {} } proc defaults_cmd {} { global sortDialog make_lists .sort.fields $sortDialog(fieldnames) $sortDialog(sortdefault) } proc reset_cmd {} { global sortDialog make_lists .sort.fields $sortDialog(fieldnames) $sortDialog(sortfields) } proc cancel_cmd {} { global sortDialog set sortDialog(done) 1 } proc apply_cmd {lbname} { global sortDialog Query if {[$lbname size] == 0} { Msg "Please select some sort fields." return } busy_cursor set #set sortDialog(sortfields) [$lbname get 0 end] set sortDialog(sortfields) "" foreach fname [$lbname get 0 end] { lappend sortDialog(sortfields) [get_field_alias_reverse $fname] } set Query(user_sort_flds) $sortDialog(sortfields) perform_sort_cmd busy_cursor clear } # # -- Sort Procs # proc fld_cmd {srcw y destw} { set idx [$srcw nearest $y] set ln [$srcw get $idx] if {"$ln" != ""} { $srcw delete $idx $destw insert end $ln } } proc make_lists {parent choices selected} { global sortDialog if {![winfo exists $parent.l]} { frame $parent.l frame $parent.r pack $parent.l -side left -padx 10 -pady 6 pack $parent.r -side right -padx 10 -pady 6 set lbl(l) "Field Choices" set lbl(r) "Sorted as" foreach side {l r} { set p $parent.$side message $p.msg -anchor center -text $lbl($side): -aspect 10000 scrollbar $p.sb -command "$p.list yview" -borderwidth 2 -relief sunken listbox $p.list -yscroll "$p.sb set" -setgrid 1 \ -relief sunken -borderwidth 2 \ -width [expr 2 + [get_max_strlen $sortDialog(fieldnames)]] \ -height [llength $choices] pack $p.msg -side top -fill x pack $p.list -side right -fill both -expand true ##### pack $p.sb -side left -fill y } bind $parent.l.list "fld_cmd %W %y $parent.r.list" bind $parent.r.list "fld_cmd %W %y $parent.l.list sort_listbox $parent.l.list" } { clear_lists .sort.fields } foreach fname $selected { #$parent.r.list insert end $fname $parent.r.list insert end [get_field_alias $fname] } foreach fname $choices { if {[lsearch $selected $fname] < 0} { #$parent.l.list insert end $fname $parent.l.list insert end [get_field_alias $fname] } } sort_listbox $parent.l.list } proc clear_lists {parent} { $parent.l.list delete 0 end $parent.r.list delete 0 end } # # -- Sort Widgets # proc sort_Dialog {names flgs fields default file} { global sortDialog TkGnats env set sortDialog(fieldnames) $names set sortDialog(fieldflgs) $flgs set sortDialog(sortfields) $fields set sortDialog(sortdefault) $default set sortDialog(sortfile) $file set sortDialog(msg_strings) {} set sortDialog(done) 0 ### -- root frame catch {destroy .sort} set w [toplevel .sort] ### -- msg area message $w.msg -aspect 500 -justify center \ -text "Click on an item to move it\nfrom one box to another" pack $w.msg -side top -padx 4 -pady 4 ### -- fields frame $w.fields reset_cmd pack $w.fields -side left -padx 2 -pady 4 ### -- buttons frame $w.buttons button $w.buttons.clear -text Clear -width 8 -command clear_cmd button $w.buttons.reset -text Reset -width 8 -command reset_cmd button $w.buttons.defaults -text Defaults -width 8 -command defaults_cmd button $w.buttons.cancel -text Close -width 8 -command cancel_cmd button $w.buttons.apply -text Apply -width 8 -command "apply_cmd $w.fields.r.list" button $w.buttons.save -text "Save..." -width 8 -command folder_save_sort_cmd message $w.buttons.filler -text " " -width 8 -anchor center -pady 0 pack $w.buttons.filler $w.buttons.cancel $w.buttons.apply $w.buttons.clear \ $w.buttons.reset $w.buttons.defaults $w.buttons.save -side top -padx 10 -pady 5 pack $w.buttons wm title $w "TkGnats - New Query Sort" wm iconbitmap $w @$TkGnats(lib)/tkgnats.xbm wm iconname $w "$TkGnats(LogName)'s tkquerypr sort" tkwait variable sortDialog(done) destroy $w ##### return $sortDialog(sortfields) } gnats-4.1.0/contrib/tkgnats/tkquerypr.tcl0000644000175000017500000021372707642176774021307 0ustar chewiechewie00000000000000proc tkquerypr_usage {{str ""}} { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "${str}usage: tkquerypr -server 'ServerInfo'" "error" 0 "OK" exit } proc tkquerypr_process_args {} { global TkGnats argc argv env set TkGnats(CurrentProgram) tkquerypr if {$argc != 0} { if {$argc%2 != 0} { tkquerypr_usage } for {set x 0} {$x<$argc} {incr x 2} { set opt [lindex $argv $x] set val [lindex $argv [expr $x+1]] switch -exact -- $opt -server { set TkGnats(ServerInfo) $val } default { tkquerypr_usage "Illegal option pair:\n'$opt $val'\n\n" } } } if {![info exists TkGnats(ServerInfo)]} { tkquerypr_usage "No -server argument given.\n\n" } foreach var {TKGNATSLIB TKGNATSINI} { if {[info exists env($var)]} { set TkGnats($var) $env($var) } } set TkGnats(lib) $TkGnats(TKGNATSLIB) if {[info exists TkGnats(TKGNATSINI)]} { if {[file readable $TkGnats(TKGNATSINI)]} { source $TkGnats(TKGNATSINI) } { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "TkGnats INI file '$TkGnats(TKGNATSINI)' not readable" "error" 0 "OK" exit } } if {[file exists $TkGnats(lib)/tkgnatsini]} { source $TkGnats(lib)/tkgnatsini } } tkquerypr_process_args foreach f { tkpr_library.tcl tkprprint.tcl tkprfolder.tcl tkprsort.tcl tkprhelp.tcl tkprfont.tcl tkprdatesel.tcl } { source $TkGnats(lib)/$f } if {[get_gnats_config] == "-1"} { exit } set Query(query_mode) sql2 #TTD remove me after testing #set Query(query_mode) sql2 set Query(sort_flds) { Number Category Synopsis Confidential Severity Priority Responsible State Class Submitter-Id Arrival-Date Originator Release Last-Modified Closed-Date } set Query(sort_flgs) { "n" "" "" "" "n" "n" "" "n" "n" "" "" "" "" "" "" } set Query(default_sort_flds) {Category State Priority Severity Number} set Query(user_sort_flds) {} set Query(default_sort_file) "$TkGnats(UserServerDir)/default-sort" set Query(default_view_file) "$TkGnats(UserServerDir)/default-view" # Query listbox headings set list_flds_list [list \ Number Id \ Submitter-Id Sub-Id \ Originator Originator \ Responsible Responsible \ Category Category \ Class Class \ Confidential Conf \ State State \ Priority Priority \ Severity Severity \ Release Release \ Arrival-Date Arr-Date \ Last-Modified Last-Mod \ Closed-Date Clos-Date \ Synopsis Synopsis \ ] array set list_flds_headings $list_flds_list #TTD: for custom states and classes, we need to dynamically size the field-width array set list_flds_formats [list \ Number "%6d" \ Submitter-Id " %-8s" \ Originator " %-10s" \ Responsible " %-11s" \ Category " %-16s" \ Class " %-5s" \ Confidential " %-4s" \ State " %-9s" \ Priority " %-8s" \ Severity " %-12s" \ Release " %-28s" \ Arrival-Date " %-10s" \ Last-Modified " %-10s" \ Closed-Date " %-10s" \ Synopsis " %s" \ ] array set list_flds_defaults [list \ Number " Number" \ Submitter-Id "" \ Originator "" \ Responsible "Responsible" \ Category "Category" \ Class "Class" \ Confidential "" \ State "State" \ Priority "Priority" \ Severity "Severity" \ Release "" \ Arrival-Date "" \ Last-Modified "" \ Closed-Date "" \ Synopsis "Synopsis" \ ] if {$TkGnats(ReleaseBased)} { set Query(sort_flds) [concat $Query(sort_flds) Keywords $TkGnats(Quarter) Date-Required] set Query(sort_flgs) [concat $Query(sort_flgs) "" "" ""] set list_flds_list [concat [lrange $list_flds_list 0 [expr [llength $list_flds_list] - 3]] \ Keywords Keywords \ $TkGnats(Quarter) $TkGnats(Quarter) \ Date-Required Date-Req \ Synopsis Synopsis \ ] array set list_flds_headings $list_flds_list array set list_flds_formats [list \ Keywords " %-9s" \ $TkGnats(Quarter) " %-9s" \ Date-Required " %-10s" \ ] array set list_flds_defaults [list \ Keywords "" \ $TkGnats(Quarter) "" \ Date-Required "" \ ] } set Query(orig_wid) [expr [string trim $list_flds_formats(Originator) " %-s"] - 1] if {[info exists TkGnats(QueryOriginatorFormat)] && \ $TkGnats(QueryOriginatorFormat) == "short"} { set Query(orig_short) 1 } { set Query(orig_short) 0 } set Query(done_msg) "" # # numeric --> textual mappings for some query-pr --sql2 fields # ####set Mappings(State) {open analyzed suspended feedback closed} set Mappings(State) $TkGnats(StatesList) set Mappings(Priority) {high medium low} set Mappings(Severity) {critical serious non-critical} ####set Mappings(Class) {sw-bug doc-bug support change-request mistaken duplicate} set Mappings(Class) $TkGnats(ClassesList) # List of entry widgets for traverse key binding set Query(tlist) {} # # ---- Procedures # proc disable_listbox_menus {} { global Query .menu.print configure -state disabled .menu.sel configure -state disabled # current selection for maintaining selection across queries, when possible } proc enable_listbox_menus {} { .menu.print configure -state normal .menu.sel configure -state normal } proc headingMsg {s} { .menu.msg configure -text $s update } proc get_default_sort_criteria {} { global Query set Query(user_sort_flds) $Query(default_sort_flds) catch {source $Query(default_sort_file)} } proc get_default_view_fields {} { global Query list_flds_selected list_flds_defaults list_flds_list # set default view fields for {set i 0} {$i < [llength $list_flds_list]} {incr i 2} { set x [lindex $list_flds_list $i] set list_flds_selected($x) $list_flds_defaults($x) } if {$Query(default_view_file) != ""} { if {[file exists $Query(default_view_file)]} { source $Query(default_view_file) } } } proc prids_from_selection {} { set s "" catch {set s [selection get STRING]} set lines [split $s] set s {} foreach line $lines { set num [lindex [string trim $line "\t\n !@#\$%^&*()_-+=|\\{}\[\]:;'~`<>,.?\""] 0] if {[regexp {(.*/|)[0-9]+$} $num]} { lappend s $num } } return $s } proc query_from_selection {} { global TkGnats Query if {[TkGnats_UpdateCheck]} { return } set prid_list [prids_from_selection] if {"$prid_list" == ""} { bell Msg "No PR id available in selection!" return; } clear_query_cmd set Query(default__query) [list proc default__query {flds} {return 1}] if {$TkGnats(GNATS_ACCESS_METHOD) == "batch"} { set Query(query_pr_opts) "$prid_list" } { set Query(query_pr_opts) "" set sep "" foreach prid $prid_list { append Query(query_pr_opts) [concat $sep "Number==$prid_list"] set sep "|" } append Query(query_pr_opts) " " } set Query(by_id_only) 1 set Query(done_msg) "query from selection for Id $prid_list" if {[catch {perform_query_cmd prid $prid_list} errs]} { Msg "Error querying with selection\n<<<$prid_list>>>\n$errs" } } proc category_listbox {parent} { global TkGnats Query Category Category_regexp if {![winfo exists $parent.tit]} { set wid [expr 2 + [get_max_strlen $TkGnats(CategoryList)]] set alias [get_field_alias Category] button $parent.tit -anchor center -text "${alias}:" \ -command "helpMsg $alias" -relief flat -padx 0 -pady 0 -borderwidth 0 pack $parent.tit -side top -fill x frame $parent.cat pack $parent.cat -side top -fill x frame $parent.cat.l message $parent.cat.l.msg -anchor center -relief sunken -borderwidth 2 \ -text "Available" -aspect 10000 -padx 0 pack $parent.cat.l -side left -padx 0 frame $parent.cat.r message $parent.cat.r.msg -anchor center -relief sunken \ -text "Selected" -aspect 10000 -padx 0 pack $parent.cat.r -side right -padx 0 foreach side {l r} { set p $parent.cat.$side scrollbar $p.sb -command "$p.list yview" -borderwidth 2 \ -relief sunken listbox $p.list -yscroll "$p.sb set" -setgrid 1 \ -relief sunken -borderwidth 2 -width $wid -height 6 pack $p.msg -side top -fill x pack $p.sb -side left -fill y pack $p.list -side right -fill both -expand true } bind $parent.cat.l.list \ "category_add_cmd %W %y $parent.cat.r.list" bind $parent.cat.r.list \ "category_delete_cmd %W %y $parent.cat.l.list" frame $parent.reg pack $parent.reg -side top -fill x lappend Query(tlist) [singletext $parent.reg "RegExp" 10 "" 7] set Category_regexp $parent.reg } { # Just clear out the existing widgets $parent.cat.l.list delete 0 end $parent.cat.r.list delete 0 end unset Category } # Just a place holder so that Category is defined as an array set Category(All) "" eval $parent.cat.l.list insert end $TkGnats(CategoryList) } proc submitter-id_listbox {parent} { global TkGnats Query Submitter-Id Submitter-Id_regexp if {![winfo exists $parent.tit]} { set wid [expr 2 + [get_max_strlen $TkGnats(SubmitterList)]] set alias [get_field_alias Submitter-Id] button $parent.tit -anchor center -text "${alias}:" \ -command "helpMsg $alias" -relief flat -padx 0 -pady 0 -borderwidth 0 pack $parent.tit -side top -fill x frame $parent.sub pack $parent.sub -side top -fill x frame $parent.sub.l message $parent.sub.l.msg -anchor center -relief sunken \ -text "Available" -aspect 10000 pack $parent.sub.l -side left frame $parent.sub.r message $parent.sub.r.msg -anchor center -relief sunken \ -text "Selected" -aspect 10000 pack $parent.sub.r -side right foreach side {l r} { set p $parent.sub.$side scrollbar $p.sb -command "$p.list yview" -borderwidth 2 \ -relief sunken listbox $p.list -yscroll "$p.sb set" -setgrid 1 \ -relief sunken -borderwidth 2 -width $wid -height 6 pack $p.msg -side top -fill x pack $p.sb -side left -fill y pack $p.list -side right -fill both -expand true } bind $parent.sub.l.list \ "submitter-id_add_cmd %W %y $parent.sub.r.list" bind $parent.sub.r.list \ "submitter-id_delete_cmd %W %y $parent.sub.l.list" frame $parent.reg pack $parent.reg -side top -fill x lappend Query(tlist) [singletext $parent.reg "RegExp" 10 "" 7] set Submitter-Id_regexp $parent.reg } { # Just clear out the existing widgets $parent.sub.l.list delete 0 end $parent.sub.r.list delete 0 end unset Submitter-Id } # Just a place holder so that Submitter-Id is defined as an array set Submitter-Id(All) "" eval $parent.sub.l.list insert end $TkGnats(SubmitterList) } proc responsible_listbox {parent} { global TkGnats Query Responsible Responsible_regexp if {![winfo exists $parent.tit]} { set wid [expr 2 + [get_max_strlen $TkGnats(ResponsibleList)]] set alias [get_field_alias Responsible] button $parent.tit -anchor center -text "${alias}:" \ -command "helpMsg $alias" -relief flat -padx 0 -pady 0 -borderwidth 0 pack $parent.tit -side top -fill x frame $parent.res pack $parent.res -side top -fill x frame $parent.res.l message $parent.res.l.msg -anchor center -relief sunken \ -text "Available" -aspect 10000 pack $parent.res.l -side left frame $parent.res.r message $parent.res.r.msg -anchor center -relief sunken \ -text "Selected" -aspect 10000 pack $parent.res.r -side right foreach side {l r} { set p $parent.res.$side scrollbar $p.sb -command "$p.list yview" -borderwidth 2 \ -relief sunken listbox $p.list -yscroll "$p.sb set" -setgrid 1 \ -relief sunken -borderwidth 2 -width $wid -height 6 pack $p.msg -side top -fill x pack $p.sb -side left -fill y pack $p.list -side right -fill both -expand true } bind $parent.res.l.list \ "responsible_add_cmd %W %y $parent.res.r.list" bind $parent.res.r.list \ "responsible_delete_cmd %W %y $parent.res.l.list" frame $parent.reg pack $parent.reg -side top -fill x lappend Query(tlist) [singletext $parent.reg "RegExp" 10 "" 7] set Responsible_regexp $parent.reg } { # Just clear out the existing widgets $parent.res.l.list delete 0 end $parent.res.r.list delete 0 end unset Responsible } # Just a place holder so that Responsible is defined as an array set Responsible(All) "" eval $parent.res.l.list insert end $TkGnats(ResponsibleList) } proc list_item_switch_cmd {srcw y destw} { set idx [$srcw nearest $y] set ln [$srcw get $idx] if {"$ln" != ""} { $srcw delete $idx $destw insert end $ln } return $ln } proc category_add_cmd {srcw y destw} { global Category set val [list_item_switch_cmd $srcw $y $destw] set Category($val) $val } proc category_delete_cmd {srcw y destw} { global Category set val [list_item_switch_cmd $srcw $y $destw] if {"$val" != ""} { unset Category($val) } sort_listbox $destw } proc submitter-id_add_cmd {srcw y destw} { global Submitter-Id set val [list_item_switch_cmd $srcw $y $destw] set Submitter-Id($val) $val } proc submitter-id_delete_cmd {srcw y destw} { global Submitter-Id set val [list_item_switch_cmd $srcw $y $destw] if {"$val" != ""} { unset Submitter-Id($val) } sort_listbox $destw } proc responsible_add_cmd {srcw y destw} { global Responsible set val [list_item_switch_cmd $srcw $y $destw] set Responsible($val) $val } proc responsible_delete_cmd {srcw y destw} { global Responsible set val [list_item_switch_cmd $srcw $y $destw] if {"$val" != ""} { unset Responsible($val) } sort_listbox $destw } proc set_query_view_heading {} { global list_flds_selected list_flds_formats list_flds_format list_flds_list \ list_flds_headings list_flds_heading list_flds_widths set list_flds_heading " Id" set list_flds_widths [string length $list_flds_heading] for {set i 2} {$i < [llength $list_flds_list]} {incr i 2} { set x [lindex $list_flds_list $i] if {$list_flds_selected($x) != ""} { #append list_flds_heading [format $list_flds_formats($x) $list_flds_headings($x)] append list_flds_heading [format $list_flds_formats($x) [get_field_alias $list_flds_headings($x)]] lappend list_flds_widths [string trim $list_flds_formats($x) "%- s"] } } } proc save_query_view_fields {sfout} { global list_flds_selected puts $sfout "array set list_flds_selected \{[array get list_flds_selected]\}" puts $sfout "set_query_view_fields" } proc update_query_view_fields {} { global Query list_flds_selected list_flds_heading set_query_view_fields query_fill_listbox } proc set_query_view_fields {} { global Query list_flds_selected list_flds_heading set_query_view_heading set Query(lbheading) $list_flds_heading } proc query_listbox {p} { global TkGnats Query Category list_flds_heading tcl_platform set lboxwidth 100 set Query(maxlen) $lboxwidth #set Query(lbheading) $list_flds_heading frame $p.query pack $p.query -side top -fill both -expand true set_query_view_heading button $p.temp set bg [$p.temp cget -background] destroy $p.temp frame $p.query.top entry $p.query.entry -font $TkGnats(textfont) -textvar Query(lbheading) -background $bg \ -borderwidth 2 -highlightthickness 0 -state disabled -relief flat -cursor left_ptr bind $p.query.entry <1> "break" bind $p.query.entry "break" bind $p.query.entry <2> "break" bind $p.query.entry "break" listbox $p.query.list -font $TkGnats(textfont) -relief sunken -setgrid 1 \ -xscroll "query_listbox_xscroll $p.query.sbx $p.query.list" \ -yscroll "$p.query.sby set" -takefocus 1 \ -width ${lboxwidth} -height 12 -exportselection false \ -borderwidth 2 -highlightthickness 2 scrollbar $p.query.sby -command "$p.query.list yview" \ -borderwidth 2 -highlightthickness 2 -orient vertical -takefocus 0 # Create padding based on the y scrollbar width and border frame $p.query.bottom scrollbar $p.query.sbx -command "$p.query.list xview" \ -borderwidth 2 -highlightthickness 2 -orient horizontal -takefocus 0 if {$tcl_platform(platform) == "unix"} { set pad2 [expr 2 * ([$p.query.sby cget -bd] + [$p.query.sby cget -highlightthickness])] } { set pad2 0 } set pad [expr [$p.query.sby cget -width] + $pad2] frame $p.query.padt -width $pad -height $pad frame $p.query.padb -width $pad -height $pad pack $p.query.padt -in $p.query.top -side left pack $p.query.entry -in $p.query.top -side left -fill x -anchor w -expand true \ -padx [$p.query.list cget -highlightthickness] pack $p.query.top -side top -fill x pack $p.query.padb -in $p.query.bottom -side left pack $p.query.sbx -in $p.query.bottom -side bottom -fill x pack $p.query.bottom -side bottom -fill x pack $p.query.sby -side left -fill y pack $p.query.list -side right -fill both -expand true # I think this is a bug in the listbox widget. Prior and Next are missing the selection set. bind Listbox { %W yview scroll -1 pages %W activate @0,0 %W selection clear 0 end %W selection set active } bind Listbox { %W yview scroll 1 pages %W activate @0,0 %W selection clear 0 end %W selection set active } bind Listbox { tkCancelRepeat %W activate @%x,%y %W selection clear 0 end %W selection set active } if {[info exists TkGnats(QueryDefaultAction)] && \ $TkGnats(QueryDefaultAction) == "edit" && $TkGnats(edit_authorized)} { bind $p.query.list "selection_Edit_cmd $p.query.list" bind $p.query.list "selection_Edit_cmd $p.query.list" } { set TkGnats(QueryDefaultAction) view bind $p.query.list "selection_View_Formatted_cmd %W" bind $p.query.list "selection_View_Formatted_cmd %W" } bind $p.query.list "%W xview 0" bind $p.query.list "%W xview 0" bind $p.query.list "%W xview [expr $lboxwidth/2]" bind $p.query.list "%W xview [expr $lboxwidth/2]" bind $p.query.list <3> { %W activate @%x,%y %W selection clear 0 end %W selection set active tk_popup .menu.sel.m %X %Y } set_focus_style $p.query.list if {$TkGnats(edit_authorized)} { bind $p.query.list e "selection_Edit_cmd $p.query.list" bind $p.query.list E "selection_Edit_cmd $p.query.list" } if {$TkGnats(delete_authorized)} { bind $p.query.list d "selection_Delete_cmd $p.query.list" bind $p.query.list D "selection_Delete_cmd $p.query.list" } bind $p.query.list v "selection_View_Formatted_cmd %W" bind $p.query.list V "selection_View_Formatted_cmd %W" bind $p.query.list r "selection_View_Raw_cmd %W" bind $p.query.list R "selection_View_Raw_cmd %W" bind $p.query.list h "selection_Remove_cmd %W" bind $p.query.list H "selection_Remove_cmd %W" bind $p.query.list m "selection_Email_cmd %W" bind $p.query.list M "selection_Email_cmd %W" return $p.query.list } proc query_listbox_xscroll {args} { global Query list_flds_heading eval [lindex $args 0] set [lrange $args 2 end] set first [expr int([lindex [[lindex $args 1] xview] 0] * $Query(maxlen) + .5)] set Query(lbheading) [string range $list_flds_heading $first end] } # # ---- Callbacks # proc folder_view_query_cmd {} { tkprfolder_dialog .tkprqueryfolder query "Saved Query Commands" } proc folder_save_query_cmd {} { save_query_cmd save build_query_menu } proc folder_view_sort_cmd {} { tkprfolder_dialog .tkprsortfolder sort "Saved Sort Commands" } proc folder_save_sort_cmd {{fname ""}} { global Query Tkprfolder if {$fname == ""} { while {"$fname" == ""} { ###set fname [file tail [get_save_file_name Sort]] set fname [get_save_file_name Sort] if {"$fname" == ""} { headingMsg "Save cancelled" return } regexp $Tkprfolder(foldernameregexp) $fname match if {$fname != $match} { Msg "Folder names must be composed only of letters, numbers, underscores and periods." return } if {[file exists $Tkprfolder(user_sort_dir)/$fname]} { bell if {[tk_dialog .tkprfolder_delete "Confirm_Save" "$fname already exists" \ "warning" -1 "Overwrite" "Cancel"] != 0} { set fname "" } } } set fname $Tkprfolder(user_sort_dir)/$fname } save_sort_fields $fname $Query(user_sort_flds) build_sort_menu } proc pridfromsummaryline {ln} { if {[scan $ln "%d" prid] < 1} { return 0 } { return $prid } } proc selln {w} { set x [$w curselection] if {[llength $x] == 0} { return "" } { return [$w get [lindex $x 0]] } } proc selection_Remove_cmd {w} { global Query if {[$w curselection] != ""} { set idx [$w curselection] $w delete $idx $w selection set active set Query(PrList) [lreplace $Query(PrList) $idx $idx] } if {[$w size] == 0} { disable_listbox_menus } } proc selection_Delete_cmd {w} { set ln [selln $w] if {"$ln" != ""} { set prid [pridfromsummaryline $ln] busy_cursor set headingMsg "Please Wait..." set result [delete_pr $prid] if {[string first deleted $result] >= 0} { # Successful deletion $w delete [$w curselection] $w selection set active headingMsg "$result" } { if {"$result" != ""} { tk_dialog .tkquerypr_delete "TkQuery Delete" $result "info" -1 "OK" } headingMsg "Delete failed." } busy_cursor clear } if {[$w size] == 0} { disable_listbox_menus } } proc selection_Email_cmd {w} { set ln [selln $w] if {"$ln" != ""} { busy_cursor set headingMsg "Please Wait..." set prid [pridfromsummaryline $ln] if {[set prtext [get_pr_full_text $prid]] == "-1"} { set time 1 } { set time 2250 parsepr_txt $prtext flds email_originator [ftrim $flds(X-GNATS-Notify)] [ftrim $flds(>Responsible)] \ [ftrim $flds(Reply-To)] [ftrim $flds(>Category)]/$prid [ftrim $flds(>Synopsis)] } after $time {headingMsg " " ; busy_cursor clear} } } proc selection_Edit_cmd {w} { global TkGnats set ln [selln $w] if {"$ln" != ""} { headingMsg "Please Wait..." busy_cursor set set prid [pridfromsummaryline $ln] TkGnats_exec $TkGnats(WISHPATH) $TkGnats(lib)/tkeditpr.tcl -prid $prid \ -server $TkGnats(ServerInfo) \ -classes $TkGnats(ClassesFile) -states $TkGnats(StatesFile) \ -categories $TkGnats(CategoryList) -submitters $TkGnats(SubmitterList) \ -responsible $TkGnats(ResponsibleFile) & schedule_reap after 2250 {headingMsg " " ; busy_cursor clear} } } proc selection_View_Formatted_cmd {w} { global TkGnats set ln [selln $w] if {"$ln" != ""} { headingMsg "Please Wait..." busy_cursor set set prid [pridfromsummaryline $ln] TkGnats_exec $TkGnats(WISHPATH) $TkGnats(lib)/tkviewpr.tcl -prid $prid \ -server $TkGnats(ServerInfo) \ -classes $TkGnats(ClassesFile) -states $TkGnats(StatesFile) \ -categories $TkGnats(CategoryList) -submitters $TkGnats(SubmitterList) \ -responsible $TkGnats(ResponsibleFile) & schedule_reap after 2250 {headingMsg " " ; busy_cursor clear} } } proc selection_View_Raw_cmd {w} { global TkGnats set ln [selln $w] if {"$ln" != ""} { busy_cursor set headingMsg "Please Wait..." set prid [pridfromsummaryline $ln] TkGnats_exec $TkGnats(WISHPATH) $TkGnats(lib)/tkviewpr.tcl -prid $prid -raw 1 \ -server $TkGnats(ServerInfo) \ -classes $TkGnats(ClassesFile) -states $TkGnats(StatesFile) \ -categories $TkGnats(CategoryList) -submitters $TkGnats(SubmitterList) \ -responsible $TkGnats(ResponsibleFile) & schedule_reap after 2250 {headingMsg " " ; busy_cursor clear} } } proc build_query_header {} { global TkGnats Query set Query(query_pr_opts) "" set Query(by_id_only) 0 set Query(default__query) "proc default__query \{f\} \{\n" append Query(default__query) "\tupvar 1 \$f flds\n" append Query(default__query) "\tif \{\n" } proc build_query_trailer {} { global Query append Query(default__query) "\t\t1==1 \} \{\n" append Query(default__query) "\t\treturn 1\n\t\}\n" append Query(default__query) "\treturn 0\n" append Query(default__query) \} } proc build_date_query_qualifier {tag d when} { global TkGnats Query set mode $TkGnats(GNATS_ACCESS_METHOD) set times(after) "00:00" set times(before) "23:59" set vars(Arrival-Date.before) arrived-before set vars(Arrival-Date.after) arrived-after set vars(Last-Modified.before) modified-before set vars(Last-Modified.after) modified-after set vars(Closed-Date.before) closed-before set vars(Closed-Date.after) closed-after set vars(Date-Required.before) required-before set vars(Date-Required.after) required-after set var $vars($tag.$when) set last [lindex $d end] set date $d if {![regexp {[0-9][0-9]:[0-9][0-9]} $last]} { append date " $times($when)" } if {$mode == "socket"} { # XXX GNATS 4 #set str "$gnatsd_commands($tag.$when) $date" if { $when == "after" } { set str "$tag > \"$date\"" } { set str "$tag < \"$date\"" } } { set str "--$var=$date" } lappend Query(query_pr_opts) "$str" } proc build_regex_query_qualifier {subclauseop type tag lst regexp} { global TkGnats Query dputs "build_regex_query_qualifier: $subclauseop $type $tag $lst $regexp" if {$tag == "Submitter-Id"} { set tag2 Submitter } { set tag2 $tag } set mode $TkGnats(GNATS_ACCESS_METHOD) # set AND or OR subclaus operator switch -exact -- $subclauseop -and { set subclauseop & } -or { set subclauseop | } set subclausestr "" set subclauseopstr "" foreach data $lst { set data [string trim $data " \n\t"] if {"$data" == ""} { continue } # first clause: put in leading option stuff if {"$subclausestr" == ""} { if {$mode == "socket"} { set subclausestr "" } { set subclausestr [format "--%s=" [string tolower $tag2]] } } switch -exact -- $type -exact { append subclausestr "$subclauseopstr $tag = \"$data\"" } -glob { append subclausestr "$subclauseopstr$data" } set subclauseopstr $subclauseop } if {"$subclausestr" == ""} { # no clauses were written if {"$regexp" != "" } { if {$mode == "socket"} { set subclausestr "$tag = $regexp" } { set subclausestr [format "--%s=" [string tolower $tag2]]$regexp } } } { if {"$regexp" != "" } { append subclausestr "|$regexp" } } if {$subclausestr != ""} { lappend Query(query_pr_opts) "$subclausestr" } } # This isn't currently used: query-pr can handle all fields now, as of beta 3.102. proc build_dumb_query_qualifier {subclauseop type tag lst} { # puts "build dumb! subclauseop=$subclauseop type=$type tag=$tag lst=$lst" # set AND or OR subclaus operator switch -exact -- $subclauseop -and { set subclauseop && } -or { set subclauseop || } set subclausestr "" foreach data $lst { set data [string trim $data " \n\t"] if {"$data" == ""} { continue } # first clause , put in the leading parens if {"$subclausestr" == ""} { append Query(default__query) "\t\t" append Query(default__query) "( " } switch -exact -- $type -exact { append Query(default__query) \ "$subclausestr ( \$flds($tag) == \"$data\" ) " nonewline } -glob { append Query(default__query) \ "$subclausestr ( \[info exists flds($tag)\] && \ \[regexp -nocase -- \{$data\} \$flds($tag) \] ) " nonewline } set subclausestr "\\\n\t\t\t$subclauseop" } ##### "$subclausestr ( \[string match \{$data\} \$flds($tag) \] ) " if {"$subclausestr" == ""} { # no clauses were written so just return return } append Query(default__query) ") && \\" } proc get_last_modified {arr_date last_mod} { if {$last_mod != ""} { set date $last_mod } { set date $arr_date } return [clock scan [convert_date_format $date]] } proc build_mtime_query_qualifier {mtime} { global Query set mtime [expr [clock seconds] - $mtime * 24 * 60 * 60] append Query(default__query) "\t\t( \[get_last_modified \$flds(Arrival-Date) \$flds(Last-Modified)\] <= $mtime ) && \\\n" } proc XXXbuild_mtime_query_qualifier {mtime} { global TkGnats Query set mtime [expr [clock seconds] - $mtime * 24 * 60 * 60] append Query(default__query) "\t\t( \[file exists $TkGnats(GNATS_ROOT)/\$flds(Category)/\$flds(Number)\] && \\\n" append Query(default__query) "\t\t \[file mtime $TkGnats(GNATS_ROOT)/\$flds(Category)/\$flds(Number)\] <= $mtime ) && \\\n" } proc save_query_listbox { sfout s } { switch $s { Category { set ew .eboxs.clb } Submitter-Id { set ew .eboxs.slb } Responsible { set ew .eboxs.rlb } } if {![winfo exists $ew]} { return } puts $sfout "load_query_listbox $s \{[textget RegExp $ew.reg]\}" } proc load_query_listbox { s {re {}}} { global TkGnats $s switch $s { Category { set lb .eboxs.clb.cat set ew .eboxs.clb set list Category } # Submitter is for compatibility with old saved queries prior to tkgnats-3.0.12 Submitter - Submitter-Id { set lb .eboxs.slb.sub set ew .eboxs.slb set list Submitter } Responsible { set lb .eboxs.rlb.res set ew .eboxs.rlb set list Responsible } } if {![winfo exists $lb]} { return } $lb.l.list delete 0 end $lb.r.list delete 0 end foreach a $TkGnats(${list}List) { if {[lsearch [array names $s] $a] < 0} { $lb.l.list insert end $a } { $lb.r.list insert end $a } } if {$re != ""} { textset RegExp $re $ew.reg } } proc load_query_entry { s re {when {}}} { global Query if {![info exists Query(stextparent,$s)]} { return } if {$when == ""} { textset $s $re $Query(stextparent,$s) } { textset $s $re $Query(stextparent,$s) $when } } proc get_save_file_name {title} { if {[catch {entryDialog "Enter name of file to save $title into:\n\n(Hint: underscores in name are replaced\nwith blanks for nice looking menu names)" Cancel "" 0 .} origp]} { return "" } set p [string trim $origp " \t\n!;'<>?*%$#"] if {"$p" == ""} { Msg "'$origp' is not a legal filename." } return $p } proc save_query_cmd {mode} { global TkGnats Query Tkprfolder lbpath if {$mode == "save"} { set p "" while {"$p" == ""} { ###set p [file tail [get_save_file_name Query]] set p [get_save_file_name Query] if {"$p" == ""} { headingMsg "Save cancelled" return } regexp $Tkprfolder(foldernameregexp) $p match if {$p != $match} { Msg "Folder names must be composed only of letters, numbers, underscores and periods." return } set sfname $Tkprfolder(user_query_dir)/$p if {[file exists $sfname]} { bell if {[tk_dialog .tkprfolder_delete "Confirm_Save" "$p already exists" \ "warning" -1 "Overwrite" "Cancel"] != 0} { set p "" } } } } set number_field [textget Number $Query(stextparent,Number)] if {"$number_field" != ""} { clear_query_cmd noclearheadingmsg regsub -all "," $number_field " " prid_list textset Number $prid_list $Query(stextparent,Number) if {$mode != "save"} { set Query(default__query) [list proc default__query {flds} {return 1}] set Query(query_pr_opts) "" set sep "" foreach prid $prid_list { append Query(query_pr_opts) [concat $sep "Number==$prid_list"] set sep "|" } append Query(query_pr_opts) " " set Query(by_id_only) 1 query_cmd $prid_list return 1 } } if {$mode == "save"} { set sfout [open $sfname w] puts $sfout "clear_query_cmd" puts $sfout "set Query(user_sort_flds) \{$Query(user_sort_flds)\}" save_query_view_fields $sfout } { build_query_header } # for array globals foreach f {State Priority Confidential Category Severity Class Responsible Submitter-Id} { if {[check_suppressed_field $f]} { continue } global $f if {$mode == "save"} { foreach a [array names $f] { if {"[set [set f]($a)]" != ""} { puts $sfout "set [format "%s(%s)" $f $a] [set [set f]($a)]" } } } { set l {} foreach a [array names $f] { lappend l [set [set f]($a)] } global ${f}_regexp set regexp "" if {[info exists ${f}_regexp]} { set regexp [textget RegExp [set [set f]_regexp]] } build_regex_query_qualifier -or -exact $f $l $regexp } } # save query for listboxes if {$mode == "save"} { save_query_listbox $sfout Category save_query_listbox $sfout Submitter-Id save_query_listbox $sfout Responsible } # the text field regexp values foreach f "Synopsis Days-Idle Originator Text-Fields Release Keywords $TkGnats(Quarter)" { if {[check_suppressed_field $f]} { continue } if {$mode == "save"} { if {[info exists Query(stextparent,$f)] && "[textget $f $Query(stextparent,$f)]" != ""} { puts $sfout "load_query_entry $f \{[textget $f $Query(stextparent,$f)]\}" } } { if {[info exists Query(stextparent,$f)] && "[textget $f $Query(stextparent,$f)]" != ""} { if {$f == "Text-Fields"} { set tag Multitext } { set tag $f } # This next bit is because the form of the following switch statement doesn't # substitute variables. if {$tag == $TkGnats(Quarter)} { set tmptag Quarter } { set tmptag $tag } switch -exact -- $tmptag { Originator - Keywords - Quarter - Synopsis - Multitext - Release { build_regex_query_qualifier -or -glob $tag {} \ [textget $f $Query(stextparent,$f)] } Days-Idle { build_mtime_query_qualifier [textget $f $Query(stextparent,$f)] } default { Msg "Illegal query text field '$f'." } } } } } # the date field values foreach f {Arrival-Date Last-Modified Closed-Date Date-Required} { if {[check_suppressed_field $f]} { continue } if {$mode == "save"} { if {[info exists Query(stextparent,$f)] && "[textget $f $Query(stextparent,$f) after]" != ""} { puts $sfout "load_query_entry $f \{[textget $f $Query(stextparent,$f) after]\} after" } if {[info exists Query(stextparent,$f)] && "[textget $f $Query(stextparent,$f) before]" != ""} { puts $sfout "load_query_entry $f \{[textget $f $Query(stextparent,$f) before]\} before" } } { if {[info exists Query(stextparent,$f)] && "[textget $f $Query(stextparent,$f) after]" != ""} { build_date_query_qualifier $f [textget $f $Query(stextparent,$f) after] after } if {[info exists Query(stextparent,$f)] && "[textget $f $Query(stextparent,$f) before]" != ""} { build_date_query_qualifier $f [textget $f $Query(stextparent,$f) before] before } } } if {$mode == "save"} { close $sfout headingMsg "Query saved as $sfname" } { build_query_trailer #puts "$Query(default__query)" } } proc clear_query_cmd {{headingmsgflag ""}} { global TkGnats Query Tkprfolder lbpath if {[string compare $headingmsgflag ""] == 0} { headingMsg "" } # for array globals foreach f {State Priority Confidential Category Severity Class Responsible Submitter-Id} { global $f foreach a [array names $f] { set [set f]($a) {} } } # Query listboxes foreach {efield eframe} {Category clb Submitter-Id slb Responsible rlb} { if {![check_suppressed_field $efield]} { [string tolower $efield]_listbox .eboxs.$eframe textset RegExp "" .eboxs.$eframe.reg } } foreach {f t} [list Synopsis text Days-Idle text Originator text Text-Fields text Release text Number text Arrival-Date after Arrival-Date before Last-Modified after Last-Modified before Closed-Date after Closed-Date before Keywords text $TkGnats(Quarter) text Date-Required after Date-Required before] { if {[info exists Query(stextparent,$f)]} { textset $f "" $Query(stextparent,$f) $t } } # the query listbox set prid [pridfromsummaryline [selln $lbpath]] if {$prid > 0} { set Query(curr_prid) $prid } $lbpath delete 0 end disable_listbox_menus } proc query_fill_listbox {} { global TkGnats Query Mappings \ lbpath list_flds_formats list_flds_format list_flds_list list_flds_selected if {![info exists Query(PrList)]} { return } #puts [join $Query(PrList) \n] array set Class_vals \ [list sw-bug sw doc-bug doc change-request chg support sup mistaken mis duplicate dup] foreach fld "Class State" { if {[info exists TkGnats(${fld}Abbreviations)]} { array set ${fld}_vals $TkGnats(${fld}Abbreviations) } } set prid [pridfromsummaryline [selln $lbpath]] if {$prid > 0} { set Query(curr_prid) $prid } $lbpath delete 0 end; # clear current list set c 0 set Query(maxlen) 0 foreach ln $Query(PrList) { incr c if {"$ln" == ""} { Msg "tkquerypr: Line $c empty in query output.\n" \ "Have the GNATS administrator check the index file for bogus entries." continue } # # XXX TBD BUG XXX there is a problemo here if the synopsis # has a '|' character in it.. # set l [split $ln "|"] set llen [llength $l] set len 19 if {$TkGnats(ReleaseBased)} { incr len 3 } if {$llen != $len} { Msg "tkquerypr: Line $ln has $llen fields. It should have $len fields.\n" \ "Have the GNATS administrator check the index file for bogus entries. (Especially for |'s in any of the text fields)" continue } if {$Query(query_mode) == "sql2"} { set flds(Number) [lindex $l 0] set flds(Category) [lindex $l 1] set flds(Synopsis) [lindex $l 2] set flds(Confidential) [lindex $l 3] set flds(Severity) [lindex $l 4] set flds(Priority) [lindex $l 5] set flds(Responsible) [lindex $l 6] set flds(State) [lindex $l 7] set flds(Class) [lindex $l 8] set flds(Submitter-Id) [lindex $l 9] set flds(Arrival-Date) [lindex $l 10] set flds(Originator) [lindex $l 11] set flds(Release) [lindex $l 12] set flds(Last-Modified) [lindex $l 13] set flds(Closed-Date) [lindex $l 14] if {$TkGnats(ReleaseBased)} { set flds($TkGnats(Quarter)) [lindex $l 15] set flds(Keywords) [lindex $l 16] set flds(Date-Required) [lindex $l 17] } } { set flds(Number) [string trimright [lindex $l 0] " "] set flds(Category) [string trimright [lindex $l 1] " "] set flds(Synopsis) [string trimright [lindex $l 2] " "] set flds(Confidential) [string trimright [lindex $l 3] " "] set flds(Severity) [string trimright [lindex $l 4] " "] set flds(Priority) [string trimright [lindex $l 5] " "] set flds(Responsible) [string trimright [lindex $l 6] " "] set flds(State) [string trimright [lindex $l 7] " "] set flds(Class) [string trimright [lindex $l 8] " "] set flds(Submitter-Id) [string trimright [lindex $l 9] " "] set flds(Arrival-Date) [string trimright [lindex $l 10] " "] set flds(Originator) [string trimright [lindex $l 11] " "] set flds(Release) [string trimright [lindex $l 12] " "] set flds(Last-Modified) [string trimright [lindex $l 13] " "] set flds(Closed-Date) [string trimright [lindex $l 14] " "] if {$TkGnats(ReleaseBased)} { set flds($TkGnats(Quarter)) [string trimright [lindex $l 15] " "] set flds(Keywords) [string trimright [lindex $l 16] " "] set flds(Date-Required) [string trimright [lindex $l 17] " "] } } # re-map the numeric fields into text foreach f {State Priority Severity Class} { set flds($f) [lindex $Mappings($f) [expr "$flds($f) - 1"]] } ##### "%5d %-11s %-16s %-5s %-9s %-8s %-12s %s" # list_flds_format doesn't seem to be used anymore? set list_flds_format "" case $flds(Category) "_*" { continue } default { if {[default__query flds]} { set ln "" for {set i 0} {$i < [llength $list_flds_list]} {incr i 2} { set x [lindex $list_flds_list $i] if {$list_flds_selected($x) != ""} { if {$x == "Originator"} { set orig [extract_full_name_from_address $flds($x)] if {[string first "@" $orig] > 0} { set orig [lindex [split $flds($x) "@"] 0] } set orig [string trim $orig] if {$Query(orig_short)} { # The following line reverts to old-style single name set orig [lindex [split $orig " "] 0] } append ln [format $list_flds_formats($x) \ [string range $orig 0 $Query(orig_wid)]] } elseif {($x == "Arrival-Date") || ($x == "Last-Modified") || \ ($x == "Closed-Date") || ($x == "Date-Required")} { append ln [format $list_flds_formats($x) \ [lindex [split $flds($x) "@ "] 0]] } elseif {[info exists ${x}_vals]} { if {[info exists [subst ${x}_vals($flds($x))]]} { set val [subst $${x}_vals($flds($x))] } { set val $flds($x) } append ln [format $list_flds_formats($x) $val] } { append ln [format $list_flds_formats($x) $flds($x)] } append list_flds_format $list_flds_formats($x) #puts "$x width: [string trim $list_flds_formats($x) "%- sd"]" } } $lbpath insert end $ln set maxlen [string length $ln] if {$Query(maxlen) < $maxlen} { set Query(maxlen) $maxlen } } } } if {[$lbpath size] == 0 } { bell disable_listbox_menus } { enable_listbox_menus set lidx 0 if {$Query(curr_prid) > 0} { set lidx [lsearch -regexp [$lbpath get 0 end] "^ *$Query(curr_prid) "] if {$lidx < 0} { set lidx 0 } } $lbpath activate $lidx $lbpath selection set $lidx $lbpath see $lidx } } proc perform_sort_cmd {} { global Query sort_cmd query_fill_listbox } proc sort_cmd {} { global TkGnats Query set_query_sorting_cmd if {![info exists Query(PrList)]} { return } sort_cmd_$TkGnats(QuerySortMethod) #dputs "sort $TkGnats(QuerySortMethod)=[time {sort_cmd_$TkGnats(QuerySortMethod)}]" } proc sort_cmd_external {} { global Query #puts "sort_cmd_external sort=$Query(sort_keys)" set prlist [join $Query(PrList) \n] if {[catch {open "|sort $Query(sort_keys) << [list $prlist]" r} fin]} { Msg "Error executing sort cmd: |sort $Query(sort_keys)\n" "$fin" return } set Query(PrList) [split [string trim [read $fin] \n] \n] close $fin } proc sort_cmd_internal {} { global Query set keys $Query(sort_keys) set nkeys [llength $keys] set sprlist {} foreach l $Query(PrList) { set le [split $l |] set sle {} foreach key $keys { if {$key == 0} { lappend sle [format "%8s" [string trimright [lindex $le $key]]] } { lappend sle [string toupper [lindex $le $key]] } } lappend sprlist [join [concat $sle $le] |] } set sprlist [lsort $sprlist] set Query(PrList) {} foreach l $sprlist { lappend Query(PrList) [join [lrange [split $l |] $nkeys end] |] } } proc query_cmd_batch {} { global TkGnats Query if {$Query(query_mode) == "sqlf"} { set mode "--sql" } { set mode "--$Query(query_mode)" } set prdata "" if {$Query(by_id_only)} { set stat 1 foreach prid [split $Query(query_pr_opts)] { if {[regexp "^\[0-9\]+$" $prid]} { if {![catch {eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) $mode $prid} data]} { set stat 0 lappend prdata $data } } } set Query(PrList) $prdata } { set stat [catch {eval exec $TkGnats(query-pr) $TkGnats(UseridPassword) $mode $Query(query_pr_opts)} Query(PrList)] set Query(PrList) [split $Query(PrList) \n] } if {$stat != 0} { set Query(PrList) "" } if {$mode == ""} { #puts "prlist=$Query(PrList)" set newlist {} set len [llength $Query(PrList)] for {set i 0} {$i < $len} {incr i 15} { lappend newlist [join [lrange $Query(PrList) $i [expr $i + 13]] \n] } set Query(PrList) $newlist #puts "prlist=$Query(PrList)" } } proc query_cmd_socket {} { global TkGnats Query if {[set s [open_socket_gnatsd]] == "-1"} { return } dputs "Query_pr_opts $Query(query_pr_opts)" set clist { "RSET" "QFMT sql2" } foreach condition $Query(query_pr_opts) { lappend clist [concat EXPR $condition] dputs "clist now $clist" } set doit "" foreach cmd $clist { dputs "query sending $cmd" gnatsd_send $s $cmd set rep [get_socket_reply $s] if {![string match 210* [lindex $rep 0]]} { Msg "GNATSD error on cmd: $cmd\n" "[join $rep \n]" close_socket_gnatsd return } } set prdata "" gnatsd_send $s "QUER" set rep [get_socket_reply $s] if {[string match 440* [lindex $rep 0]]} { close_socket_gnatsd return } elseif {![string match 30* [lindex $rep 0]]} { Msg "GNATSD error on cmd: $doit\n" "[join $rep \n]" close_socket_gnatsd return } { set prdata [concat $prdata [get_gnatsd_reply_dot_ended $s]] } set Query(PrList) $prdata catch {close_socket_gnatsd} } proc query_cmd {{prid ""}} { global TkGnats Query if {"$prid" == ""} { # Build a query from the widget specifiers if {[save_query_cmd query] == 1} { return } } eval $Query(default__query) set Query(PrList) {} #puts "query_cmd_$TkGnats(GNATS_ACCESS_METHOD) Query(query_pr_opts)=$Query(query_pr_opts)" #puts "query_cmd_$TkGnats(GNATS_ACCESS_METHOD) Query(default__query)=$Query(default__query)" query_cmd_$TkGnats(GNATS_ACCESS_METHOD) #dputs "query cmd $TkGnats(GNATS_ACCESS_METHOD)=[time {query_cmd_$TkGnats(GNATS_ACCESS_METHOD)}]" } proc perform_query_cmd {{query _list_} {prid {}}} { global TkGnats Query lbpath list_flds_heading if {[TkGnats_UpdateCheck]} { return } busy_cursor set if {[string compare $Query(done_msg) ""] == 0} { set Query(done_msg) Query } headingMsg "Performing $Query(done_msg)..." switch $query { _list_ { query_cmd } prid { query_cmd $prid } } sort_cmd query_fill_listbox headingMsg "Done $Query(done_msg): [$lbpath size] matches found" set Query(done_msg) "" busy_cursor clear return } proc perform_print_cmd {{print _list_}} { global TkGnats Query Print lbpath list_flds_heading list_flds_widths set Print(fields) $list_flds_heading set Print(widths) $list_flds_widths set Query(done_msg) "$print print" headingMsg "Performing $Query(done_msg)..." set done_msg "Done $Query(done_msg)" if {[print_dialog] != 0} { headingMsg "Cancelled $Query(done_msg)" set done_msg "" return } busy_cursor set if {![info exists TkGnats(MsMacroSet)]} { set TkGnats(MsMacroSet) "-ms" } switch $Print(Device) { previewer { set previewfile /tmp/tkq.ps.$TkGnats(LogName) if {[string compare $Print(Format) "troff"] == 0} { set fout [open $previewfile w] } { if {[string compare $Print(Format) "ascii"] == 0 || \ [string compare $Print(Format) "latin1"] == 0} { set fout [open "|groff -t -T$Print(Format) $TkGnats(MsMacroSet) -P-b > $previewfile" w] } { set fout [open "|groff -t -T$Print(Format) $TkGnats(MsMacroSet) > $previewfile" w] } } } printer { if {[string compare $Print(Format) "troff"] == 0} { set fout [open "| $Print(PrintSpooler,$Print(Format))" w] } { set fout [open "|groff -t -T$Print(Format) $TkGnats(MsMacroSet) | $Print(PrintSpooler,$Print(Format))" "w"] } } file { if {[string compare $Print(Format) "troff"] == 0} { set fout [open $Print(savefile) w] } { if {[string compare $Print(Format) "ascii"] == 0 || \ [string compare $Print(Format) "latin1"] == 0} { set fout [open "|groff -t -T$Print(Format) $TkGnats(MsMacroSet) -P-b > $Print(savefile)" w] } { set fout [open "|groff -t -T$Print(Format) $TkGnats(MsMacroSet) > $Print(savefile)" w] } } } } set Print(fout) $fout # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing if {[open_socket_gnatsd 1] == "-1"} { busy_cursor clear return } print_listbox $lbpath $print # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing close_socket_gnatsd 1 catch {close $fout} if {[string compare $Print(Device) "previewer"] == 0} { exec sh -c \ "[format $Print(Previewer,$Print(Format)) $previewfile]\;rm -f $previewfile" & schedule_reap } headingMsg "$done_msg" set Query(done_msg) "" busy_cursor clear return } proc dump_listbox_data {} { global Query headingMsg "Saving Listbox Dump..." busy_cursor set set filename [tk_getSaveFile] if {$filename == ""} { headingMsg "Saving Listbox Dump...Cancelled" } { file_put_text $filename [join $Query(PrList) \n] headingMsg "Saving Listbox Dump...done (written to $filename)" } busy_cursor clear } proc set_query_sorting_cmd {} { global Query set Query(sort_keys) \ [build_sort_cmd $Query(sort_flds) $Query(sort_flgs) $Query(user_sort_flds)] } proc set_query_sort_fields {} { global Query sort_Dialog $Query(sort_flds) $Query(sort_flgs) $Query(user_sort_flds) \ $Query(default_sort_flds) $Query(default_sort_file) } proc save_default_view {} { global Query list_flds_selected # save default-view file set sfout [open $Query(default_view_file) w] puts $sfout "array set list_flds_selected \{[array get list_flds_selected]\}" close $sfout Notice "Default fields saved." } proc save_default_sort {} { global Query save_sort_fields $Query(default_sort_file) $Query(user_sort_flds) Notice "Default sort saved." } proc exit_cmd {} { global Query list_flds_selected Exit 0 } # # ---- Process args # get_default_sort_criteria get_default_view_fields # The following is for compatability with old saved queries set categories $TkGnats(CategoryList) set submitters $TkGnats(SubmitterList) set responsibles $TkGnats(ResponsibleList) # # ---- Build widgets # frame .mframe -borderwidth 1 -relief raised pack .mframe -side top -fill x menubutton .mframe.file -text "File" -menu .mframe.file.m -underline 0 menu .mframe.file.m .mframe.file.m add command -label "New Problem Report..." \ -command {TkGnats_exec $TkGnats(WISHPATH) $TkGnats(lib)/tksendpr.tcl \ -server $TkGnats(ServerInfo) \ -classes $TkGnats(ClassesFile) -states $TkGnats(StatesFile) \ -categories $TkGnats(CategoryList) -submitters $TkGnats(SubmitterList) \ -responsible $TkGnats(ResponsibleFile) &; schedule_reap} .mframe.file.m add separator .mframe.file.m add command -label "Exit" \ -command exit_cmd menubutton .mframe.edit -text "Edit" -menu .mframe.edit.m -underline 0 menu .mframe.edit.m .mframe.edit.m configure -disabledforeground [.mframe.edit.m cget -foreground] .mframe.edit.m add command -label "Use right mouse button for Cut/Copy/Paste" -state disabled .mframe.edit.m add separator .mframe.edit.m add command -label "Fonts..." -command "edit_fonts" pack .mframe.file .mframe.edit -side left menubutton .mframe.help -text "Help" -menu .mframe.help.m -underline 0 menu .mframe.help.m .mframe.help.m add command -label "Overview" \ -command "helpMsg Query_Overview" .mframe.help.m add separator .mframe.help.m add command -label "Cut, Copy, Paste Operations" \ -command "helpMsg Cut_Copy_Paste" .mframe.help.m add separator .mframe.help.m add command -label "Field Definitions" \ -command "helpMsg Field_Definitions" .mframe.help.m add command -label "Regular Expressions" \ -command "helpMsg Query_Regular_Expressions" .mframe.help.m add separator .mframe.help.m add command -label "Check Buttons (Class, etc)" \ -command "helpMsg Query_Check_Buttons" .mframe.help.m add command -label "Listbox Selectors (Category, etc)" \ -command "helpMsg Query_Listbox_Selectors" .mframe.help.m add command -label "Entry Fields (Number, etc)" \ -command "helpMsg Query_Entry_Fields" .mframe.help.m add command -label "Menubar (Do Query, etc)" \ -command "helpMsg Query_Menubar" .mframe.help.m add command -label "Query Results Listbox" \ -command "helpMsg Query_Results_Listbox" .mframe.help.m add separator .mframe.help.m add command -label "View Configuration Variables" \ -command "helpMsg TkGnats_Variables" .mframe.help.m add separator .mframe.help.m add command -label "Changes" \ -command "helpMsg Changes" .mframe.help.m add command -label "About" \ -command "helpMsg TkGnats_About" pack .mframe.help -side right frame .eflds set panelnum 0 radiobar_frame .eflds .eflds.lb foreach {efield elist} [list Class $TkGnats(ClassesList) State $TkGnats(StatesList) Priority {low medium high} Severity {non-critical serious critical} Confidential {no yes}] { if {![check_suppressed_field $efield]} { checkbar .eflds.lb [string tolower $efield] $efield $elist All $panelnum incr panelnum } } pack .eflds.lb -side left -pady 0 pack .eflds -side top -padx 0 -fill x -anchor w #puts stderr [concat "query boxes: " [grid slaves .eflds.lb]] frame .eboxs set nboxes 1 array set xpad {1 0 2 20 3 0} foreach {efield eframe epath} {Category clb cbpath Submitter-Id slb sbpath Responsible rlb rbpath} { if {![check_suppressed_field $efield]} { frame .eboxs.$eframe -relief groove -borderwidth 2 set $epath [[string tolower $efield]_listbox .eboxs.$eframe] pack .eboxs.$eframe -side left -padx $xpad($nboxes) incr nboxes } } if {$nboxes > 1} { pack .eboxs -side top -pady 4 -fill x -anchor w } set tlist [list Number Release Synopsis Originator Text-Fields Days-Idle] if {$TkGnats(ReleaseBased)} { lappend tlist Keywords $TkGnats(Quarter) } set textlist "" set ntlist 0 foreach f $tlist { if {![check_suppressed_field $f]} { lappend textlist $f incr ntlist } } set dlist [list Arrival-Date Last-Modified Closed-Date] if {$TkGnats(ReleaseBased)} { lappend dlist Date-Required } set datelist "" set ndlist 0 foreach f $dlist { if {![check_suppressed_field $f]} { lappend datelist $f incr ndlist } } frame .stext -relief flat frame .stext.l -relief flat pack .stext -side top -fill x -expand no -anchor w pack .stext.l -side left -fill x -expand yes -anchor nw if {$ntlist <= $ndlist} { set frames .stext.l set nframes 1 } { set frames [list .stext.l .stext.c] set nframes 2 frame .stext.c -relief flat pack .stext.c -side left -fill x -expand yes -anchor nw } if {$ndlist > 0} { frame .stext.r -relief flat pack .stext.r -side left -fill none -expand no -anchor nw } set n 0 foreach f $textlist { set Query(stextparent,$f) [lindex $frames [expr $n % $nframes]] lappend Query(tlist) [singletext $Query(stextparent,$f) $f 20 "" 12] incr n } foreach f $datelist { set Query(stextparent,$f) .stext.r eval lappend Query(tlist) [daterange $Query(stextparent,$f) $f 16 "" "" 14] } set Query(curr_prid) 0 # Do this before adding the listbox to Query(tlist); we don't want Return bound there. foreach w $Query(tlist) { bind $w "perform_query_cmd" } # # Menus # frame .menu -relief raised -borderwidth 1 pack .menu -side top -fill x -pady 4 frame .qlb pack .qlb -expand true -fill both set lbpath [query_listbox .qlb] lappend Query(tlist) $lbpath set_text_traversal $Query(tlist) # # Query Menu # proc get_merge_save_dirs {sitedir serverdir} { set queries {} set files {} set paths {} foreach x "[glob -nocomplain $sitedir/*]" { lappend paths $x lappend files [file tail $x] } foreach x "[glob -nocomplain $serverdir/*]" { set i [lsearch $files [file tail $x]] if {$i < 0} { lappend paths $x lappend files [file tail $x] } { set paths [lreplace $paths $i $i $x] } } set spaths {} foreach x [lsort $files] { set i [lsearch -regexp $paths $x\$] lappend spaths [lindex $paths $i] } return $spaths } proc build_query_menu {} { global TkGnats Query Tkprfolder if {[winfo exists .menu.query.m]} { destroy .menu.query.m } { menubutton .menu.query -text "Query" -menu .menu.query.m -underline 0 } menu .menu.query.m .menu.query.m configure -disabledforeground [.menu.query.m cget -foreground] .menu.query.m add command -label "Do Query" -command perform_query_cmd .menu.query.m add command -label "Query Selection" -command query_from_selection .menu.query.m add command -label "Clear Widgets" -command clear_query_cmd .menu.query.m add separator .menu.query.m add cascade -label "Save Current" -menu .menu.query.m.save .menu.query.m add command -label "Manage Saved..." -command folder_view_query_cmd menu .menu.query.m.save -tearoff no .menu.query.m.save add command -label "To Saved Queries Menu..." \ -command folder_save_query_cmd .menu.query.m add separator .menu.query.m add cascade -label "Query For" -menu .menu.query.m.query menu .menu.query.m.query -tearoff no # foreach x "[lsort [glob -nocomplain $Tkprfolder(site_query_dir)/*]]" foreach x [get_merge_save_dirs $TkGnats(lib)/query $Tkprfolder(site_query_dir)] { regsub -all "_" [file tail $x] " " name .menu.query.m.query add command -label " - $name" -command "source $x set Query(done_msg) \"query for $name\" perform_query_cmd" } .menu.query.m add separator .menu.query.m add command -label "Saved Queries:" -state disabled set n 0 # foreach x [get_merge_save_dirs $TkGnats(UserDir)/query $Tkprfolder(user_query_dir)] foreach x "[lsort [glob -nocomplain $Tkprfolder(user_query_dir)/*]]" { incr n regsub -all "_" [file tail $x] " " name .menu.query.m add command -label "$n. $name" -command "source $x set Query(done_msg) \"query for $name\" perform_query_cmd" } } build_query_menu # # Sort Menu # proc build_sort_menu {} { global TkGnats Tkprfolder if {[winfo exists .menu.sort.m]} { destroy .menu.sort.m } { menubutton .menu.sort -text "Sort" -menu .menu.sort.m -underline 0 } menu .menu.sort.m .menu.sort.m configure -disabledforeground [.menu.sort.m cget -foreground] .menu.sort.m add command -label "New..." -command set_query_sort_fields .menu.sort.m add separator .menu.sort.m add cascade -label "Save Current" -menu .menu.sort.m.save .menu.sort.m add command -label "Manage Saved..." -command folder_view_sort_cmd menu .menu.sort.m.save -tearoff no .menu.sort.m.save add command -label "To Saved Sorts Menu..." -command folder_save_sort_cmd .menu.sort.m.save add command -label "As Startup Default" -command save_default_sort .menu.sort.m add separator .menu.sort.m add cascade -label "Sort By" -menu .menu.sort.m.sort menu .menu.sort.m.sort -tearoff no # foreach x "[lsort [glob -nocomplain $Tkprfolder(site_sort_dir)/*]]" foreach x [get_merge_save_dirs $TkGnats(lib)/sort $Tkprfolder(site_sort_dir)] { regsub -all "_" [file tail $x] " " name .menu.sort.m.sort add command -label " - $name" -command "source $x set Query(done_msg) \"sort by $name\" perform_sort_cmd" } .menu.sort.m add separator .menu.sort.m add command -label "Saved Sorts:" -state disabled set n 0 # foreach x [get_merge_save_dirs $TkGnats(UserDir)/sort $Tkprfolder(user_sort_dir)] foreach x "[lsort [glob -nocomplain $Tkprfolder(user_sort_dir)/*]]" { incr n regsub -all "_" [file tail $x] " " name .menu.sort.m add command -label "$n. $name" -command "source $x perform_sort_cmd" } } build_sort_menu # # Fields Menu # menubutton .menu.view -text "Fields" -menu .menu.view.m -underline 0 menu .menu.view.m .menu.view.m add cascade -label "Save Current" -menu .menu.view.m.save menu .menu.view.m.save -tearoff no .menu.view.m.save add command -label "As Startup Default" -command save_default_view .menu.view.m add separator set list_flds_selected(Number) Number for {set i 2} {$i < [llength $list_flds_list]} {incr i 2} { set x [lindex $list_flds_list $i] #if {![check_suppressed_field $x]} { # .menu.view.m add checkbutton -label $x -command "update_query_view_fields" \ # -offvalue "" -onvalue $x -variable [format "list_flds_selected(%s)" $x] #} if {![check_suppressed_field $x]} { .menu.view.m add checkbutton -label [get_field_alias $x] \ -command "update_query_view_fields" \ -offvalue "" -onvalue $x -variable [format "list_flds_selected(%s)" $x] } } # # Print Menu # set Print(savefile) "" set Print(Device) printer set Print(Format) ps set Print(Select) all foreach format {ascii dvi latin1 ps troff} { if {[info exists TkGnats(${format}Previewer)] && \ [string compare $TkGnats(${format}Previewer) ""] != 0} { set Print(Previewer,$format) $TkGnats(${format}Previewer) } if {[info exists TkGnats(${format}PrintSpooler)] && \ [string compare $TkGnats(${format}PrintSpooler) ""] != 0} { set Print(PrintSpooler,$format) $TkGnats(${format}PrintSpooler) } } menubutton .menu.print -text "Print" -menu .menu.print.m -underline 0 menu .menu.print.m .menu.print.m configure -disabledforeground [.menu.print.m cget -foreground] #####.menu.print.m add command -label " Report Formats:" -state disabled .menu.print.m add command -label "Summary..." \ -command "perform_print_cmd Summary" .menu.print.m add command -label "Medium..." \ -command "perform_print_cmd Medium" .menu.print.m add command -label "Full..." \ -command "perform_print_cmd Full" .menu.print.m add command -label "Raw Data..." \ -command "perform_print_cmd Raw_Data" .menu.print.m add separator .menu.print.m add command -label "Dump Listbox Data..." \ -command dump_listbox_data .menu.print.m add separator # Add any site print commands set n 0 #foreach x "[lsort [glob -nocomplain $Tkprfolder(site_print_dir)/*]]" foreach x [get_merge_save_dirs $TkGnats(lib)/print $Tkprfolder(site_print_dir)] { incr n set cmd [file tail $x] regsub -all "_" $cmd " " name .menu.print.m add command -label "$n. $name..." -command "source $x perform_print_cmd $cmd" } # # Actions Menu # menubutton .menu.sel -text "Actions" -menu .menu.sel.m -underline 0 menu .menu.sel.m .menu.sel.m add command -label "Edit..." -command "selection_Edit_cmd $lbpath" -accel e if {! $TkGnats(edit_authorized)} { .menu.sel.m entryconfigure "Edit..." -state disabled } .menu.sel.m add command -label "View..." -command "selection_View_Formatted_cmd $lbpath" -accel v .menu.sel.m add command -label "View Raw Data..." -command "selection_View_Raw_cmd $lbpath" -accel r .menu.sel.m add separator if {$TkGnats(delete_authorized)} { .menu.sel.m add command -label "Delete PERMANENTLY" -command "selection_Delete_cmd $lbpath" -accel d .menu.sel.m add separator } .menu.sel.m add command -label "Hide From List" -command "selection_Remove_cmd $lbpath" -accel h .menu.sel.m add separator .menu.sel.m add command -label "Send Email..." -command "selection_Email_cmd $lbpath" -accel m button .menu.doquery -text "Do Query" -command perform_query_cmd button .menu.clear -text "Clear" -command clear_query_cmd pack .menu.doquery .menu.clear -side left foreach x { query sort view print sel } { pack .menu.$x -side left } disable_listbox_menus message .menu.msg -aspect 10000 -relief sunken -bd 1 pack .menu.msg -side left -fill x -expand 1 ###wm title . "TkGnats - Query Problem Reports" wm title . "TkGnats - [lindex $TkGnats(ServerInfo) 0]" wm iconbitmap . @$TkGnats(lib)/tkquerypr.xbm ###wm iconname . "$TkGnats(LogName)'s tkquerypr" wm iconname . "[lindex $TkGnats(ServerInfo) 0]" gnats-4.1.0/contrib/tkgnats/tkquerypr.xbm0000644000175000017500000000634606665615034021277 0ustar chewiechewie00000000000000#define tkquerypr.xbm_width 64 #define tkquerypr.xbm_height 64 static char tkquerypr.xbm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; gnats-4.1.0/contrib/tkgnats/tksendpr.tcl0000644000175000017500000005060507603743347021056 0ustar chewiechewie00000000000000proc tksendpr_usage {{str ""}} { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "${str}usage: tksendpr -server 'ServerInfo' \[-categories 'list'\] \ \[-classes 'list'\] \[-states 'list'\] \ \[-db 'database'\] \[-submitters 'list'\] \[-responsible 'list'\]" "error" 0 "OK" exit } proc tksendpr_process_args {} { global TkGnats argc argv env set TkGnats(CurrentProgram) tksendpr if {$argc != 0} { if {$argc%2 != 0} { tksendpr_usage } } set addressval "" for {set x 0} {$x<$argc} {incr x 2} { set opt [lindex $argv $x] set val [lindex $argv [expr $x+1]] switch -exact -- $opt -server { set TkGnats(ServerInfo) $val } -categories { set TkGnats(CategoryList) $val } -submitters { set TkGnats(SubmitterList) $val } -responsible { set TkGnats(ResponsibleFile) $val } -classes { set TkGnats(ClassesFile) $val } -states { set TkGnats(StatesFile) $val } default { tksendpr_usage "Illegal option pair:\n'$opt $val'\n\n" } } if {![info exists TkGnats(ServerInfo)]} { tksendpr_usage "No -server argument given.\n\n" } foreach var {TKGNATSLIB TKGNATSINI} { if {[info exists env($var)]} { set TkGnats($var) $env($var) } } set TkGnats(lib) $TkGnats(TKGNATSLIB) if {[info exists TkGnats(TKGNATSINI)]} { if {[file readable $TkGnats(TKGNATSINI)]} { source $TkGnats(TKGNATSINI) } { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "TkGnats INI file '$TkGnats(TKGNATSINI)' not readable" "error" 0 "OK" exit } } if {[file exists $TkGnats(lib)/tkgnatsini]} { source $TkGnats(lib)/tkgnatsini } } tksendpr_process_args foreach f { tkpr_library.tcl tkprhelp.tcl tkprfont.tcl tkprdatesel.tcl } { source $TkGnats(lib)/$f } if {[get_gnats_config] == "-1"} { exit } # Remove "pending" from the Category list set idx [lsearch -exact $TkGnats(CategoryList) "pending"] set TkGnats(CategoryList) [lreplace $TkGnats(CategoryList) $idx $idx] proc headingMsg {a} { .action.msg configure -text $a update idletasks } # Assemble the problem report in gnats format from the fields in # Before assembly some of the widgets are checked for validity. proc send_report {} { global TkGnats Tksendpr frm current_multi_text Class State Priority Severity Confidential Category Submitter-Id Responsible flush_singletext $Tksendpr(singletextflds) flush_multitext # check all the fields first... # Check for blank mandatory fields. foreach f [concat $Tksendpr(radioflds) $Tksendpr(listboxflds) $Tksendpr(singletextflds) $Tksendpr(multitextflds)] { if {[check_suppressed_field $f]} { continue } if {![check_mandatory_field $f]} { continue } if {[info exists frm($f)]} { # singletext and multitext set val $frm($f) } { # radiobutton and listbox fields set val [set $f] } set val [string trim $val " \n\t\f!:~-#_?"] if {$val == ""} { Msg "You must supply a value for '[get_field_alias $f]'." return -1 } } # Check listbox fields foreach {field list} {Category Category Submitter-Id Submitter Responsible Responsible} { if {![check_suppressed_field $field]} { if {[set $field] != "" && [lsearch -exact $TkGnats(${list}List) [set $field]] < 0} { Msg "You have specified an invalid [get_field_alias $field]: [set $field]" return -1 } } } foreach f $Tksendpr(singletextflds) { if {[string first "|" $frm($f)] >= 0} { Msg " '|' is an illegal character for the '[get_field_alias $f]' field!" return -1 } } if {$TkGnats(ReleaseBased) && ![check_suppressed_field Date-Required]} { if {[check_date_invalid $frm(Date-Required) "Invalid [get_field_alias Date-Required]:"]} { return -1 } set frm(Date-Required) [normalize_date $frm(Date-Required)] } # ok, now send off the report set mailtxt "" append mailtxt "From: $TkGnats(EmailAddr)\n" append mailtxt "Reply-To: $TkGnats(EmailAddr)\n" append mailtxt "To: $TkGnats(GNATS_ADDR)\n" append mailtxt "Subject: [string trim $frm(Synopsis)]\n" append mailtxt "X-send-pr-version: $Tksendpr(version)\n" append mailtxt "X-GNATS-Notify: [add_email_domainname [string trim $frm(X-GNATS-Notify)]]\n" append mailtxt "\n" #### End of standard mail headers foreach f [concat $Tksendpr(radioflds) $Tksendpr(listboxflds)] { if {![check_suppressed_field $f]} { append mailtxt ">${f}: [set $f]\n" } elseif {[info exists TkGnats(CreateDefault$f)]} { append mailtxt ">${f}: $TkGnats(CreateDefault$f)\n" } } foreach f $Tksendpr(singletextflds) { if {$f != "X-GNATS-Notify"} { if {![check_suppressed_field $f]} { append mailtxt ">${f}: $frm($f)\n" } elseif {[info exists TkGnats(CreateDefault$f)]} { append mailtxt ">${f}: $TkGnats(CreateDefault$f)\n" } } } foreach f $Tksendpr(multitextflds) { if {![check_suppressed_field $f]} { append mailtxt "${f}:\n$frm($f)\n" } elseif {[info exists TkGnats(CreateDefault[string trim $f >])]} { append mailtxt "${f}:\n$TkGnats(CreateDefault[string trim $f >])\n" } } # # mail the assembled problem report file to the gnats system # headingMsg "Sending Report to $TkGnats(GNATS_ADDR)..." if {[TkGnats_sendmail $TkGnats(GNATS_ADDR) $mailtxt] == "-1"} { headingMsg "Sending Report to $TkGnats(GNATS_ADDR)...***ERROR***" return -1 } { headingMsg "Sending Report to $TkGnats(GNATS_ADDR)...Done" } # # clear out some fields # set flist {Synopsis} if {$TkGnats(ReleaseBased)} { lappend flist Keywords $TkGnats(Quarter) Date-Required } foreach f $flist { textset $f "" } # Some folks may not want these reset #foreach t {Environment Description How-To-Repeat Fix Organization} foreach f {Description How-To-Repeat Fix} { set frm(>$f) "" if {">$f" == $current_multi_text} { .multiline.text delete 1.0 end } } switch_txt $TkGnats(first_multitext) $Tksendpr(multitextflds) return 0 } proc send_report_and_exit {} { if {[send_report] == 0} { Exit 0 } } # bail out completely proc cancel_report {} { Exit 0 } proc snd_category_listbox {p category_list} { global TkGnats Tksendpr Category set Category "" set alias [get_field_alias Category] frame $p.cat -relief groove -borderwidth 2 pack $p.cat -side top -expand true -fill both button $p.cat.lab -anchor w -text "${alias}: " -width 14 -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 frame $p.cat.msg -relief flat set wid [expr 2 + [get_max_strlen $category_list]] set ew [entry $p.cat.msg.ent -width $wid -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground) -highlightthickness 2 \ -textvariable Category] lappend Tksendpr(tlist) $ew trace variable Category w set_snd_category_ew set_focus_style $ew bind $ew { tkEntrySetCursor %W [%W index insert] } bind $ew { tkEntrySetCursor %W [%W index insert] } set height [llength $category_list] if {$height > 6 } { set height 6 } scrollbar $p.cat.msg.sb -command "$p.cat.msg.list yview" -borderwidth 2 -relief sunken listbox $p.cat.msg.list -yscroll "$p.cat.msg.sb set" -setgrid 1 -relief sunken -borderwidth 2 \ -width $wid -height $height -exportselection false eval $p.cat.msg.list insert end $category_list pack $p.cat.msg.ent -side top -fill x pack $p.cat.msg.sb -side right -fill y pack $p.cat.msg.list -side right -fill both -expand true pack $p.cat.lab -side left -anchor nw -ipady 4 pack $p.cat.msg -side left -anchor nw -fill y bind $p.cat.msg.list "set_snd_category $p.cat.msg.ent %W %y" return $p.cat.msg.list } proc snd_submitter-id_listbox {p submitters_list} { global TkGnats Tksendpr Submitter-Id set Submitter-Id "" set alias [get_field_alias Submitter-Id] frame $p.sub -relief groove -borderwidth 2 pack $p.sub -side top -expand true -fill both button $p.sub.lab -anchor w -text "${alias}: " -width 14 -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 frame $p.sub.msg -relief flat set wid [expr 2 + [get_max_strlen $submitters_list]] set ew [entry $p.sub.msg.ent -width $wid -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground) -highlightthickness 2 \ -textvariable Submitter-Id] lappend Tksendpr(tlist) $ew trace variable Submitter-Id w set_snd_submitter-id_ew set_focus_style $ew bind $ew { tkEntrySetCursor %W [%W index insert] } bind $ew { tkEntrySetCursor %W [%W index insert] } set height [llength $submitters_list] if {$height > 6 } { set height 6 } scrollbar $p.sub.msg.sb -command "$p.sub.msg.list yview" -borderwidth 2 -relief sunken listbox $p.sub.msg.list -yscroll "$p.sub.msg.sb set" -setgrid 1 -relief sunken -borderwidth 2 \ -width $wid -height $height -exportselection false eval $p.sub.msg.list insert end $submitters_list pack $p.sub.msg.ent -side top -fill x pack $p.sub.msg.sb -side right -fill y pack $p.sub.msg.list -side right -fill both -expand true pack $p.sub.lab -side left -anchor nw -ipady 4 pack $p.sub.msg -side left -anchor nw -fill y bind $p.sub.msg.list "set_snd_submitter-id $p.sub.msg.ent %W %y" return $p.sub.msg.list } proc snd_responsible_listbox {p responsibles_list} { global TkGnats Tksendpr Responsible set Responsible "" set alias [get_field_alias Responsible] frame $p.res -relief groove -borderwidth 2 pack $p.res -side top -expand true -fill both button $p.res.lab -anchor w -text "${alias}: " -width 14 -command "helpMsg $alias" \ -relief flat -padx 0 -pady 0 -borderwidth 0 frame $p.res.msg -relief flat set wid [expr 2 + [get_max_strlen $responsibles_list]] set ew [entry $p.res.msg.ent -width $wid -insertwidth 1 -insertofftime 400 \ -relief sunken -borderwidth 2 -background $TkGnats(EditFieldBackground) -highlightthickness 2 \ -textvariable Responsible] lappend Tksendpr(tlist) $ew trace variable Responsible w set_snd_responsible_ew set_focus_style $ew bind $ew { tkEntrySetCursor %W [%W index insert] } bind $ew { tkEntrySetCursor %W [%W index insert] } set height [llength $responsibles_list] if {$height > 6 } { set height 6 } scrollbar $p.res.msg.sb -command "$p.res.msg.list yview" -borderwidth 2 -relief sunken listbox $p.res.msg.list -yscroll "$p.res.msg.sb set" -setgrid 1 -relief sunken -borderwidth 2 \ -width $wid -height $height -exportselection false eval $p.res.msg.list insert end $responsibles_list pack $p.res.msg.ent -side top -fill x pack $p.res.msg.sb -side right -fill y pack $p.res.msg.list -side right -fill both -expand true pack $p.res.lab -side left -anchor nw -ipady 4 pack $p.res.msg -side left -anchor nw -fill y bind $p.res.msg.list "set_snd_responsible $p.res.msg.ent %W %y" return $p.res.msg.list } proc set_snd_category_ew {a b c} { upvar #0 $a f global TkGnats quickfill_entry_from_listbox f .eboxs.clb.cat.msg.ent .eboxs.clb.cat.msg.list $TkGnats(CategoryList) } proc set_snd_submitter-id_ew {a b c} { upvar #0 $a f global TkGnats quickfill_entry_from_listbox f .eboxs.slb.sub.msg.ent .eboxs.slb.sub.msg.list $TkGnats(SubmitterList) } proc set_snd_responsible_ew {a b c} { upvar #0 $a f global TkGnats quickfill_entry_from_listbox f .eboxs.rlb.res.msg.ent .eboxs.rlb.res.msg.list $TkGnats(ResponsibleList) } proc set_snd_category {ent w y} { global Category trace vdelete Category w set_snd_category_ew $ent delete 0 end set idx [$w nearest $y] set Category [$w get $idx] trace variable Category w set_snd_category_ew } proc set_snd_submitter-id {ent w y} { global Submitter-Id trace vdelete Submitter-Id w set_snd_submitter-id_ew $ent delete 0 end set idx [$w nearest $y] set Submitter-Id [$w get $idx] trace variable Submitter-Id w set_snd_submitter-id_ew } proc set_snd_responsible {ent w y} { global Responsible trace vdelete Responsible w set_snd_responsible_ew $ent delete 0 end set idx [$w nearest $y] set Responsible [$w get $idx] trace variable Responsible w set_snd_responsible_ew } proc env_fld_text {} { global TkGnats tcl_platform set txt "" if {[info exists TkGnats(ENVIRONMENT)]} { set txt $TkGnats(ENVIRONMENT) } { if {[catch {exec uname -a} result]} { set result "$tcl_platform(os) [info hostname] $tcl_platform(osVersion) $tcl_platform(machine)" } append txt "System: $result\n" if {![catch {exec arch} result]} { append txt "Architecture: $result\n" } if {![catch {exec xdpyinfo | fgrep endor} result]} { append txt "X:\n----\n$result\n" } } return $txt } proc org_fld_text {} { global TkGnats tcl_platform return $TkGnats(ORGANIZATION) } ################################# if {"$TkGnats(LogName)" == "root"} { Msg "You cannot send problem reports as root.\n" "Please use your own login." Exit 1 } # Set Create Defaults foreach d [list [eval list Class $TkGnats(ClassesList)] [eval list State $TkGnats(StatesList)] \ {Priority medium} {Severity serious} {Confidential no}] { if {![info exists TkGnats(CreateDefault[lindex $d 0])]} { set TkGnats(CreateDefault[lindex $d 0]) [lindex $d 1] } } # List of entry widgets for traverse key binding set Tksendpr(tlist) {} set Tksendpr(radioflds) { State Confidential Severity Priority Class } set Tksendpr(listboxflds) { Category Submitter-Id Responsible } set Tksendpr(singletextflds) { Originator X-GNATS-Notify Release Synopsis } if {$TkGnats(ReleaseBased)} { lappend Tksendpr(singletextflds) Keywords $TkGnats(Quarter) Date-Required } set Tksendpr(multitextflds) { >Description >How-To-Repeat >Environment >Organization >Fix >Audit-Trail >Unformatted >Release-Note } ######### if {[regexp "tkgnats-\[^ \]*" $TkGnats(tkgnats_version) ver]} { set Tksendpr(version) $ver } { set Tksendpr(version) "Unknown TkGnats version" } frame .mframe -borderwidth 1 -relief raised pack .mframe -side top -fill x menubutton .mframe.file -text "File" -menu .mframe.file.m -underline 0 menu .mframe.file.m .mframe.file.m add command -label "Send" -command send_report .mframe.file.m add command -label "Send and Exit" -command send_report_and_exit .mframe.file.m add separator .mframe.file.m add command -label "Cancel" -command cancel_report menubutton .mframe.edit -text "Edit" -menu .mframe.edit.m -underline 0 menu .mframe.edit.m .mframe.edit.m configure -disabledforeground [.mframe.edit.m cget -foreground] .mframe.edit.m add command -label "Use right mouse button for Cut/Copy/Paste" -state disabled .mframe.edit.m add separator .mframe.edit.m add command -label "Fonts..." -command "edit_fonts" pack .mframe.file .mframe.edit -side left menubutton .mframe.help -text "Help" -menu .mframe.help.m -underline 0 menu .mframe.help.m .mframe.help.m add command -label "Overview" \ -command "helpMsg Create_Overview" .mframe.help.m add separator .mframe.help.m add command -label "Cut, Copy, Paste Operations" \ -command "helpMsg Cut_Copy_Paste" .mframe.help.m add separator .mframe.help.m add command -label "Field Definitions" \ -command "helpMsg Field_Definitions" .mframe.help.m add separator .mframe.help.m add command -label "Radio Buttons (Class, etc)" \ -command "helpMsg Create_Radio_Buttons" .mframe.help.m add command -label "Listbox Selectors (Category, etc)" \ -command "helpMsg Create_Listbox_Selectors" .mframe.help.m add command -label "Entry Fields (Originator, etc)" \ -command "helpMsg Create_Entry_Fields" .mframe.help.m add command -label "Text Fields (Description, etc)" \ -command "helpMsg Create_Text_Fields" .mframe.help.m add separator .mframe.help.m add command -label "View Configuration Variables" \ -command "helpMsg TkGnats_Variables" .mframe.help.m add separator .mframe.help.m add command -label "Changes" \ -command "helpMsg Changes" .mframe.help.m add command -label "About" \ -command "helpMsg TkGnats_About" pack .mframe.help -side right frame .action -borderwidth 1 -relief raised pack .action -side top -fill x -anchor w #button .action.cancel -borderwidth 1 -text "Cancel" -command cancel_report button .action.send -borderwidth 1 -text "Send" -command send_report button .action.sendandexit -borderwidth 1 -text "Send and Exit" -command send_report_and_exit #pack .action.send .action.sendandexit .action.cancel -side left -padx 0 pack .action.send .action.sendandexit -side left -padx 0 message .action.msg -aspect 10000 -relief sunken -bd 1 -text "" pack .action.msg -side left -fill x -expand 1 frame .eflds radiobar_frame .eflds .eflds.lb set panelnum 0 foreach {efield elist} [list Class $TkGnats(ClassesList) State $TkGnats(StatesList) Priority {low medium high} Severity {non-critical serious critical} Confidential {no yes}] { if {![check_suppressed_field $efield]} { radiobar .eflds.lb [string tolower $efield] $efield $elist None "" "" 0 $panelnum radiobar_set .eflds.lb [string tolower $efield] $TkGnats(CreateDefault$efield) incr panelnum } { set $efield [lindex $elist 0] } } pack .eflds.lb -side left pack .eflds -side top -fill x -anchor w frame .eboxs set nboxes 1 array set xpad {1 0 2 20 3 0} foreach {efield eframe list} {Category clb Category Submitter-Id slb Submitter Responsible rlb Responsible} { if {![check_suppressed_field $efield]} { frame .eboxs.$eframe snd_[string tolower $efield]_listbox .eboxs.$eframe $TkGnats(${list}List) pack .eboxs.$eframe -side left -anchor nw -pady 2 -fill y -padx $xpad($nboxes) incr nboxes } { set $efield "" } } if {$nboxes > 1} { pack .eboxs -side top -fill x -anchor w -pady 2 } set Submitter-Id $TkGnats(SUBMITTER) foreach f $Tksendpr(listboxflds) { if {[info exists TkGnats(CreateDefault$f)]} { set $f $TkGnats(CreateDefault$f) } } foreach f $Tksendpr(singletextflds) { if {[check_suppressed_field $f]} { continue } if {[info exists TkGnats(CreateDefault$f)]} { set val $TkGnats(CreateDefault$f) } { if {$f == "Originator"} { set val $TkGnats(FullName) } { set val "" } } lappend Tksendpr(tlist) [singletext . $f 60 $val 14] } foreach f $Tksendpr(multitextflds) { set frm($f) "" } set frm(>Environment) [env_fld_text] set frm(>Organization) [org_fld_text] foreach f $Tksendpr(multitextflds) { set field [string trimleft $f >] if {[info exists TkGnats(CreateDefault$field)]} { set frm($f) $TkGnats(CreateDefault$field) } } set current_multi_text "" lappend Tksendpr(tlist) [make_txt_mb $Tksendpr(multitextflds)] switch_txt $TkGnats(first_multitext) $Tksendpr(multitextflds) set_text_traversal $Tksendpr(tlist) #frame .action -borderwidth 3 #button .action.cancel -borderwidth 2 -text "Cancel" -command cancel_report #button .action.send -borderwidth 2 -text "Send" -command send_report #button .action.sendandexit -borderwidth 2 -text "Send and Exit" -command send_report_and_exit # #pack .action.send .action.sendandexit .action.cancel -side left -padx 10 # #pack .action -side top wm title . "TkGnats - [lindex $TkGnats(ServerInfo) 0] - $TkGnats(GNATS_ADDR)" wm iconbitmap . @$TkGnats(lib)/tksendpr.xbm wm iconname . "$TkGnats(LogName)'s tksendpr" gnats-4.1.0/contrib/tkgnats/tksendpr.xbm0000644000175000017500000000634306665615034021060 0ustar chewiechewie00000000000000#define tksendpr.xbm_width 64 #define tksendpr.xbm_height 64 static char tksendpr.xbm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x3f, 0x3e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xfb, 0xcf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x47, 0xf7, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, 0x85, 0x01, 0x00, 0x00, 0x80, 0xa1, 0x1b, 0x08, 0xe5, 0x03, 0x00, 0x00, 0xc0, 0xa7, 0x10, 0x08, 0xf7, 0x03, 0x00, 0x00, 0xc0, 0xef, 0x10, 0x08, 0xfe, 0x03, 0x00, 0x00, 0xc0, 0x7f, 0x10, 0x18, 0xfe, 0x0b, 0x00, 0x00, 0xd0, 0x7f, 0x18, 0x10, 0xfc, 0x07, 0x00, 0x00, 0xe0, 0x3f, 0x08, 0x30, 0xfe, 0x01, 0x00, 0x00, 0x80, 0x7f, 0x0c, 0x60, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x7f, 0x06, 0xf0, 0xff, 0x20, 0x00, 0x00, 0x04, 0xff, 0x0f, 0x80, 0x3f, 0x20, 0x00, 0x00, 0x04, 0xfc, 0x01, 0xc0, 0x1f, 0x18, 0x00, 0x00, 0x18, 0xf8, 0x03, 0xc0, 0x1f, 0x0e, 0x00, 0x00, 0x70, 0xf8, 0x03, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0x03, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; gnats-4.1.0/contrib/tkgnats/tkviewpr.tcl0000644000175000017500000002775107642176774021114 0ustar chewiechewie00000000000000proc tkviewpr_usage {{str ""}} { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "${str}usage: tkviewpr -prid nnnn -server 'ServerInfo' \[-raw 1\] \ \[-classes 'list'\] \[-states 'list'\] \ \[-categories 'list'\] \[-submitters 'list'\] \[-responsible 'list'\]" "error" 0 "OK" exit } proc tkviewpr_process_args {} { global TkGnats argc argv env prid rawflag set TkGnats(CurrentProgram) tkviewpr if {$argc != 0} { if {$argc%2 != 0} { tkviewpr_usage } for {set x 0} {$x<$argc} {incr x 2} { set opt [lindex $argv $x] set val [lindex $argv [expr $x+1]] switch -exact -- $opt -server { set TkGnats(ServerInfo) $val } -categories { set TkGnats(CategoryList) $val } -submitters { set TkGnats(SubmitterList) $val } -responsible { set TkGnats(ResponsibleFile) $val } -classes { set TkGnats(ClassesFile) $val } -states { set TkGnats(StatesFile) $val } -prid { set prid $val } -raw { set rawflag $val } default { tkviewpr_usage "Illegal option pair:\n'$opt $val'\n\n" } } } if {![info exists TkGnats(ServerInfo)]} { tkviewpr_usage "No -server argument given.\n\n" } foreach var {TKGNATSLIB TKGNATSINI} { if {[info exists env($var)]} { set TkGnats($var) $env($var) } } set TkGnats(lib) $TkGnats(TKGNATSLIB) if {[info exists TkGnats(TKGNATSINI)]} { if {[file readable $TkGnats(TKGNATSINI)]} { source $TkGnats(TKGNATSINI) } { bell wm withdraw . tk_dialog .tkgnatsError "TkGnats Error" \ "TkGnats INI file '$TkGnats(TKGNATSINI)' not readable" "error" 0 "OK" exit } } if {[file exists $TkGnats(lib)/tkgnatsini]} { source $TkGnats(lib)/tkgnatsini } } proc tkviewpr_raw {prid prtext} { global TkGnats env wm minsize . 100 100 # set f [frame .top] # pack .top -expand true -fill both # set f .top view_menu_bar $prid .mframe.help.m add command -label "Cut, Copy, Paste Operations" \ -command "helpMsg Cut_Copy_Paste" .mframe.help.m add separator .mframe.help.m add command -label "View Configuration Variables" \ -command "helpMsg TkGnats_Variables" .mframe.help.m add separator .mframe.help.m add command -label "Changes" \ -command "helpMsg Changes" .mframe.help.m add command -label "About" \ -command "helpMsg TkGnats_About" view_action_bar $prid scrollbar .sb -command ".text yview" -relief sunken pack .sb -side left -fill y text .text \ -font $TkGnats(textfont) \ -yscrollcommand ".sb set" \ -height 30 -width 80 -relief sunken -padx 4 -insertwidth 1 \ -insertofftime 400 -borderwidth 2 -background [.action.close cget -background] pack .text -side right -expand true -fill both set_focus_style .text .text insert 1.0 $prtext .text configure -state disabled bind .text <3> "clipboard_post .text %X %Y" wm title . "TkGnats - View Problem Report: $prid" wm iconbitmap . @$TkGnats(lib)/tkeditpr.xbm wm iconname . "$TkGnats(LogName)'s tkviewpr $prid" } # bail out completely proc close_report {} { #Exit 0 destroy . } proc fillfrm {} { global Tkviewpr flds frm ### pre-set editable PR values to values currently in the PR # now the multi line textual flds foreach tag $Tkviewpr(multitextflds) { if {[info exists flds($tag)]} { set flds($tag) [string trim $flds($tag) "\n"] set frm($tag) $flds($tag) } { set frm($tag) "\n" set flds($tag) "\n" } } } proc headingMsg {a} { .action.msg configure -text $a update idletasks } proc editSelection_cmd {prid} { global TkGnats busy_cursor set update idletasks headingMsg "Please Wait..." TkGnats_exec $TkGnats(WISHPATH) $TkGnats(lib)/tkeditpr.tcl -prid $prid \ -server $TkGnats(ServerInfo) \ -classes $TkGnats(ClassesFile) -states $TkGnats(StatesFile) \ -categories $TkGnats(CategoryList) -submitters $TkGnats(SubmitterList) \ -responsible $TkGnats(ResponsibleFile) & schedule_reap after 4000 busy_cursor clear close_report } proc view_menu_bar {prid} { global TkGnats flds frame .mframe -borderwidth 1 -relief raised pack .mframe -side top -fill x menubutton .mframe.file -text "File" -menu .mframe.file.m -underline 0 menu .mframe.file.m .mframe.file.m add command -label "Edit Report..." -command "editSelection_cmd $prid" if {! $TkGnats(edit_authorized)} { .mframe.file.m entryconfigure "Edit Report..." -state disabled } .mframe.file.m add command -label "Send Email..." -command \ "email_originator [list [ftrim $flds(X-GNATS-Notify)]] \ [list [ftrim $flds(>Responsible)]] [list [ftrim $flds(Reply-To)]] \ [ftrim $flds(>Category)]/$prid [list [ftrim $flds(>Synopsis)]]" .mframe.file.m add separator .mframe.file.m add command -label "Close" -command close_report menubutton .mframe.edit -text "Edit" -menu .mframe.edit.m -underline 0 menu .mframe.edit.m .mframe.edit.m configure -disabledforeground [.mframe.edit.m cget -foreground] .mframe.edit.m add command -label "Use right mouse button for Cut/Copy/Paste" -state disabled .mframe.edit.m add separator .mframe.edit.m add command -label "Fonts..." -command "edit_fonts" pack .mframe.file .mframe.edit -side left menubutton .mframe.help -text "Help" -menu .mframe.help.m -underline 0 menu .mframe.help.m pack .mframe.help -side right } proc view_action_bar {prid} { global TkGnats flds frame .action -borderwidth 1 -relief raised pack .action -side top -fill x -anchor w button .action.close -borderwidth 1 -text "Close" -command close_report button .action.edit -borderwidth 1 -text "Edit..." -command "editSelection_cmd $prid" button .action.email -borderwidth 1 -text "Send Email..." \ -command "email_originator [list [ftrim $flds(X-GNATS-Notify)]] \ [list [ftrim $flds(>Responsible)]] [list [ftrim $flds(Reply-To)]] \ [ftrim $flds(>Category)]/$prid [list [ftrim $flds(>Synopsis)]]" #### [lrange [split [ftrim $flds(>Originator)]] 0 0] pack .action.close .action.edit .action.email -side left -padx 0 if {! $TkGnats(edit_authorized)} { .action.edit configure -state disabled } message .action.msg -aspect 10000 -relief sunken -bd 1 -text "" pack .action.msg -side left -fill x -expand 1 } proc tkviewpr_formatted {prid} { global TkGnats Tkviewpr flds env current_multi_text set Tkviewpr(shortflds) { >Cost >Release >Responsible } set Tkviewpr(radioflds) { >State >Confidential >Severity >Priority >Class } set Tkviewpr(multitextflds) { >Description >How-To-Repeat >Environment >IPsec-look >Fix >Audit-Trail >Unformatted >Release-Note >Organization } set current_multi_text "" # Get the maximum width of the value fields for the listboxes and radio (enumerated) fields set Tkviewpr(value_width) 0 foreach tag [concat >Category >Submitter-Id >Responsible $Tkviewpr(radioflds)] { set f [ftrim $flds($tag)] if {[string length $f] > $Tkviewpr(value_width)} { set Tkviewpr(value_width) [string length $f] } } incr Tkviewpr(value_width) # Get the maximum width of the value fields for the date fields set Tkviewpr(datevalue_width) 0 set flist {>Last-Modified >Arrival-Date >Closed-Date} foreach tag $flist { set f [ftrim $flds($tag)] if {[string length $f] > $Tkviewpr(datevalue_width)} { set Tkviewpr(datevalue_width) [string length $f] } } incr Tkviewpr(datevalue_width) # Get the maximum width of the value fields for the readonly_singletext fields set Tkviewpr(singletextvalue_width) 0 set flist {>Originator X-GNATS-Notify >Release >Synopsis} if {$TkGnats(ReleaseBased)} { lappend flist >Keywords >$TkGnats(Quarter) >Date-Required } foreach tag $flist { set f [ftrim $flds($tag)] if {[string length $f] > $Tkviewpr(singletextvalue_width)} { set Tkviewpr(singletextvalue_width) [string length $f] } } incr Tkviewpr(singletextvalue_width) fillfrm view_menu_bar $prid .mframe.help.m add command -label "Overview" \ -command "helpMsg View_Overview" .mframe.help.m add separator .mframe.help.m add command -label "Cut, Copy, Paste Operations" \ -command "helpMsg Cut_Copy_Paste" .mframe.help.m add separator .mframe.help.m add command -label "Field Definitions" \ -command "helpMsg Field_Definitions" .mframe.help.m add separator .mframe.help.m add command -label "Text Fields (Description, etc)" \ -command "helpMsg View_Text_Fields" .mframe.help.m add separator .mframe.help.m add command -label "View Configuration Variables" \ -command "helpMsg TkGnats_Variables" .mframe.help.m add separator .mframe.help.m add command -label "Changes" \ -command "helpMsg Changes" .mframe.help.m add command -label "About" \ -command "helpMsg TkGnats_About" view_action_bar $prid set flist [list Arrival-Date Last-Modified Closed-Date Class State Priority Severity Confidential Category Submitter-Id Responsible Originator X-GNATS-Notify Release Synopsis IPsec-barf-location Cost] if {$TkGnats(ReleaseBased)} { lappend flist Keywords $TkGnats(Quarter) Date-Required } foreach f $flist { if {[check_suppressed_field $f] == 1} { continue } #set tmptag [get_field_alias $f] switch $f { Class - State - Priority - Severity - Confidential - Category - Submitter-Id - Responsible { readonly_singletext $f [ftrim $flds(>$f)] 14 $Tkviewpr(value_width) } Arrival-Date - Last-Modified - Closed-Date { readonly_singletext $f [ftrim $flds(>$f)] 14 $Tkviewpr(datevalue_width) } X-GNATS-Notify { readonly_singletext $f [ftrim $flds($f)] 14 $Tkviewpr(singletextvalue_width) } default { readonly_singletext $f [ftrim $flds(>$f)] 14 $Tkviewpr(singletextvalue_width) } } } make_txt_mb $Tkviewpr(multitextflds) destroy .mb.insert .multiline.text configure -height 16 bind multiline.text "" wm title . "TkGnats - [lindex $TkGnats(ServerInfo) 0] - View Problem Report: [ftrim $flds(>Category)]/[ftrim $flds(>Number)]" wm iconbitmap . @$TkGnats(lib)/tkeditpr.xbm wm iconname . "$TkGnats(LogName)'s tkviewpr [ftrim $flds(>Number)]" switch_txt $TkGnats(first_multitext) $Tkviewpr(multitextflds) } set prid "" set rawflag "" tkviewpr_process_args foreach f { tkpr_library.tcl tkprhelp.tcl tkprfont.tcl } { source $TkGnats(lib)/$f } # If TkGnats(GNATS_ACCESS_METHOD) != "socket" then this does nothing if {[open_socket_gnatsd 1] == "-1"} { exit } if {[get_gnats_config] == "-1"} { exit } #TTD remove me after testing #set TkGnats(ReleaseBased) 1 if {"$prid" == ""} { wm withdraw . Msg "Missing prid argument!" close_socket_gnatsd 1 Exit -1 } # load the report fields set prtxt [get_pr_full_text $prid] parsepr_txt $prtxt flds load_field_defaults flds if {"$rawflag" != ""} { tkviewpr_raw $prid $prtxt } { tkviewpr_formatted $prid } #tkwait window . close_socket_gnatsd 1 gnats-4.1.0/contrib/tkgnats/query/0000755000175000017500000000000010212665130017636 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/tkgnats/query/All_Problems0000644000175000017500000000002006665615034022143 0ustar chewiechewie00000000000000clear_query_cmd gnats-4.1.0/contrib/tkgnats/query/Not_Closed0000644000175000017500000000024306665615034021630 0ustar chewiechewie00000000000000clear_query_cmd set Query(user_sort_flds) {Category State Priority Severity Number} set State(analyzed) analyzed set State(feedback) feedback set State(open) open gnats-4.1.0/contrib/tkgnats/sort/0000755000175000017500000000000010212665130017460 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/tkgnats/sort/Category0000644000175000017500000000010406665615034021172 0ustar chewiechewie00000000000000set Query(user_sort_flds) {Category State Priority Severity Number} gnats-4.1.0/contrib/tkgnats/sort/Class0000644000175000017500000000010406665615034020462 0ustar chewiechewie00000000000000set Query(user_sort_flds) {Class Category Priority Severity Number} gnats-4.1.0/contrib/tkgnats/sort/Number0000644000175000017500000000004306665615034020647 0ustar chewiechewie00000000000000set Query(user_sort_flds) {Number} gnats-4.1.0/contrib/tkgnats/sort/Priority0000644000175000017500000000010306665615034021235 0ustar chewiechewie00000000000000set Query(user_sort_flds) {Priority Severity Category Responsible} gnats-4.1.0/contrib/tkgnats/sort/Responsible0000644000175000017500000000012006665615034021700 0ustar chewiechewie00000000000000set Query(user_sort_flds) {Responsible Category State Priority Severity Number} gnats-4.1.0/contrib/tkgnats/sort/State0000644000175000017500000000011206665615034020474 0ustar chewiechewie00000000000000set Query(user_sort_flds) {State Priority Severity Category Class Number} gnats-4.1.0/contrib/www-gnats-admin/0000755000175000017500000000000010212665130020042 5ustar chewiechewie00000000000000gnats-4.1.0/contrib/www-gnats-admin/INSTALL0000644000175000017500000000454107317415052021107 0ustar chewiechewie00000000000000 wwwgnats_admin - web administration tool for gnats Installation guide 1. Install gnats and gnatsd, the gnats network server. Run gnatsd under its own user/group to limit the damage possible if the service is compromised. If you want to manage gnats via the web, you will probably also install gnatsweb on the same server to allow users to create, view, and edit PRs. 2. Some Linux distributions with precompiled packages provide the suexec wrapper in a separate package from the main apache web server. Otherwise configure or recompile Apache to run with suexec enabled. 3. Install Apache on the same server as your gnats database. wwwgnats_admin maintains the list of gnats databases in /usr/local/etc/gnats/databases and follows the paths in that file to the directories containing the actual databases (by default in /var/local/gnats). Although you could reproduce that arrangement on the web server using NFS mounts, it is much simpler to just run a web server for gnats use and administration on the machine with the gnats database. 4. Change line 1 of wwwgnats_admin.pl to point to the location of your 'perl' executable. Perl must be version 5. 5. Install the wwwgnats_admin.pl script to run using the same account as the gnats daemon. You should be able to either a. Create a virtual host which runs suexec under that account and place the script in the cgi-bin directory for that virtual host, b. Create a public_html/ subdirectory in the home directory of the gnatsd account, as indicated by the UserDir directive in the apache configuration file. Copy the script into that directory so that it is then available via http://hostname/~account/wwwgnats_admin.cgi Only approach b) has been tested. More information on Apache suexec configuration is available at http://httpd.apache.org/docs/suexec.html 6. In the script directory use the htpasswd command from the Apache distribution to create, in the file .htpasswd, the list of users authorized to manage gnats. 7. Create a .htaccess file to force user checking against the .htpasswd file. i.e. AuthUserFile /home/gnats/public_html/admin/.htpasswd AuthName Gnats_Admin AuthType Basic require valid-user require valid-user gnats-4.1.0/contrib/www-gnats-admin/README0000644000175000017500000000264107317415052020735 0ustar chewiechewie00000000000000 wwwgnats_admin - web administration tool for gnats Mike Sutton Paul-Andre Panon What is wwwgnats-admin? ====================== wwwgnats-admin is a bare-bones web interface for configuring Gnats, the GNU Problem Report Management System. It allows you to provide project managers with the ability to create and customize gnats databases without command shell accounts on your gnats server. It is a CGI script which runs with the effective userid set to the gnats daemon account. The current version has been tested with the Apache web server's suexec mode. System Requirements =================== wwwgnats-admin requires that you have the following: * gnats 4.0 installed and configured * a web server supporting a suid mechanism such as Apache-suexec * access to the account used for the gnats daemon to install the suexec CGI script. * Perl 5, with the fine CGI.pm module. How do I install it? ==================== Read the INSTALL file. Who wrote it? ============= Mike Sutton created the original CGI script for gnats 3.x. He has authorized releasing his code under the GPL. Paul-Andre Panon updated the script to support multiple databases in gnats 4.0 and to use CGI.pm. The update work was supported by Sierra System Group for internal use. Sierra also have authorized releasing their updates for gnats 4.0 under the GPL. gnats-4.1.0/contrib/www-gnats-admin/wwwgnats_admin.cgi0000744000175000017500000005110607317415052023573 0ustar chewiechewie00000000000000#!/usr/bin/perl -w # # $Id: wwwgnats_admin.cgi,v 1.1 2001/06/30 18:27:54 pdm Exp $ # # This script is used to administrate a GNATS data base using a web # based interface. # # MODIFICATIONS: # 06-Nov-1998 Initially generated... MWS # # 10-Nov-1998 fixed up to run with SUID bit set. MWS # # 28-May-2001 updated for use with gnats 4.0, Apache suexec, and CGI.pm. PAP #---------------------------------------------------------------------- # Copyright (C) 2001 Paul-Andre Panon # Copyright (C) 1998 Mike Sutton # # 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #use strict; my $GNATS_DB_LIST = "/usr/local/etc/gnats/databases"; my $GNATS_REPOSITORY="/var/local/gnats/"; my $GNATS_ADM_SUBDIR="/gnats-adm/"; #$MAKE = "/usr/ccs/bin/make"; my $MKCAT= "/usr/local/libexec/gnats/mkcat"; my $MKDB= "/usr/local/libexec/gnats/mkdb"; my $SHELL = "/bin/sh"; # the CGI object use vars '$q'; # Use CGI::Carp first, so that fatal errors come to the browser, including # those caused by old versions of CGI.pm. use CGI::Carp qw/fatalsToBrowser/; use CGI 2.56 qw/:standard :netscape/; use Socket; use IO::Handle; use File::Basename; # constants my $DEBUG=0; # set to non-zero to enble debug messages my $REVISION = '$Revision: 1.1 $ '; my $REVISION_DATE = '$Date: 2001/06/30 18:27:54 $'; my ($VERSION) = $REVISION =~ m/.*: ([0-9]\..*)\$/ ; $REVISION_DATE =~ m/^\$.+: (.+)\$/; my $VERSION_DATE = "$1 GMT"; ### Environment variables use vars qw($script_name $cmd $server_name $query_string); $script_name = defined $ENV{"SCRIPT_NAME"}? $ENV{"SCRIPT_NAME"} : ''; my $SCRIPT_PATH = dirname($SCRIPT_NAME); my $PATH_INFO = $ENV{"PATH_INFO"}; $SERVER_NAME = defined $ENV{"SERVER_NAME"}? $ENV{"SERVER_NAME"} : ''; my $DOCUMENT_ROOT=$ENV{'DOCUMENT_ROOT'}; my $HTTPD_ROOT= dirname($DOCUMENT_ROOT) if ($DOCUMENT_ROOT); $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:/usr/ccs/bin"; my $FIND = "/usr/bin/find"; my $LOCK_EXT = ".lock"; # untaint the query string for setuid to work properly. $query_string = defined $ENV{"QUERY_STRING"}? $ENV{"QUERY_STRING"}: ''; $query_string =~ /^(.*)$/; $query_string = $1; #and clean up the environment settings for same $ENV{BASH_ENV} = ''; $ENV{ENV} = ''; # Standard header and footer definitions my $HEADING_TEXT1 = "

GNATS System Administration for Host:  " . $SERVER_NAME . "

\n"; my $HEADING_TEXT2a = "

Database:   "; my $HEADING_TEXT2b = "


"; my $FOOTER = "


Web Based Administration Tool Version $VERSION on $VERSION_DATE

" . &main_page_link() . "

"; main(); # # MAIN starts here: # sub main { # Make sure nobody tries to swamp our server with a huge file attachment. # Has to happen before 'new CGI'. $CGI::POST_MAX = $site_post_max if defined($site_post_max); # Create the query object. Check to see if there was an error, which # happens if the post exceeds POST_MAX. $q = new CGI; if ($q->cgi_error()) { print $q->header(-status=>$q->cgi_error()); $q->start_html('Error'); page_heading('Initialization failed', 'Error'); print $q->h3('Request not processed: ', $q->cgi_error()); warn("gnats_admin: cgi error: ", $q->cgi_error(), " stacktrace: ", print_stacktrace()); exit(); } $script_name = $q->script_name; $cmd = $q->param('cmd') || ''; # avoid perl -w warning # print "Content-type: text/html\n\n"; # print "\n"; print $q->header(), $q->start_html("Gnats Admin"); #--------------------------------------------------------------------- # Determine what to do #--------------------------------------------------------------------- if ($cmd eq 'Edit') { &edit_page(); } elsif ($cmd eq 'Save changes') { &handle_edit(); } elsif ($cmd eq 'Abort edit') { &handle_edit(); } elsif ($cmd eq 'View') { &view_page(); } elsif ($cmd eq 'unlock file') { &handle_unlock(); } elsif ($cmd eq 'Configure db') { &config_list(); } elsif ($cmd eq 'Create new db') { &create_db_page(); } elsif ($cmd eq 'Initialize db') { &make_db(); } else # Main menu of choices { &main_menu(); } # else # { # print "GNATS Administration Front End #

Tracking Front End

# #" . heading_text(); # print "Bad subdirectory/parameters specified in URL.\n"; # } #--------------------------------------------------------------------- # print standard footer #--------------------------------------------------------------------- print "$FOOTER \n"; # print "

This script should be run SUID gnats!

" if (! -u $ENV{'SCRIPT_FILENAME'}); $q->end_html(); #print "\n\n"; #print "\n"; exit(0); } #--------------------------------------------------------------------- # #--------------------------------------------------------------------- sub heading_text { my($database) = @_; my $heading = $HEADING_TEXT1; $heading .= $HEADING_TEXT2a . $database . $HEADING_TEXT2b unless !defined $database; return $heading; } #--------------------------------------------------------------------- # #--------------------------------------------------------------------- sub config_list { my($database) = $q->param('database'); # Display title print "GNATS Admin\n ", heading_text($database), $q->p(), "Below are the administrative files for the GNATS database.", $q->p(); &list_file_links(find_db_root($database).$GNATS_ADM_SUBDIR); } #--------------------------------------------------------------------- # #--------------------------------------------------------------------- sub main_menu { # Display title print "GNATS Admin\n \n", heading_text(), "\n"; print "
\n\n", $q->start_form(); print $q->Tr( $q->td( $q->submit('cmd','Create new db'), $q->p(' ') ) ); list_databases(); print $q->end_form(),"
"; } #--------------------------------------------------------------------- # #--------------------------------------------------------------------- sub create_db_page { print "GNATS Admin\n \n", heading_text(), "\n
\n

Enter information for the new database:

"; print $q->start_form(), $q->table( $q->Tr( $q->td("DB Name"), $q->td($q->textfield(-name=>'database', -size=>$textwidth)) ), $q->Tr( $q->td("DB Description"), $q->td($q->textfield(-name=>'dbdesc', -size=>$textwidth)) ), $q->Tr( $q->td("DB Directory"), $q->td($q->textfield(-name=>'dbdir', -size=>$textwidth)), $q->td($q->submit('cmd','Initialize db')) )), $q->end_form(); } #--------------------------------------------------------------------- # #--------------------------------------------------------------------- sub make_db { print "GNATS Admin\n \n", heading_text(), "\n"; my ($database) = $q->param('database'); my ($dbdesc) = $q->param('dbdesc'); my ($dbdir) = $GNATS_REPOSITORY.$q->param('dbdir'); $dbdir=~ /^(.*)$/; # untaint data $dbdir= $1; $| = 1; # force buffer flush print "

Creating new database $database in directory $dbdir\n

";
	system("echo \"($MKDB $dbdir) 2>&1\" | $SHELL");
#    my @arglist = ("mkdb", $dbdir);
#	system($MKDB, @arglist);
	print "
\n"; $| = 0; # stopp flush open (DBLIST, "+>>" . $GNATS_DB_LIST) or die "cannot open $GNATS_DB_LIST: $!"; flock (DBLIST, 2) or die "cannot lock $GNATS_DB_LIST: $!"; print DBLIST "$database:$dbdesc:$dbdir"; flock(DBLIST, 8) or die "cannot unlock $GNATS_DB_LIST: $!"; close (DBLIST); } #--------------------------------------------------------------------- # return a list files # # args: dir #--------------------------------------------------------------------- sub list_files { my($dir) = @_; my($pwd) = $ENV{'PWD'}; my(@list, $file) ; chdir $dir or die "Couldn't change to $dir:$!
"; foreach $file (`$FIND . \\( -type d ! -name . -prune \\) -o \\( -type f -print \\)`) { # filter out .lock, *~, .*, .bak files chomp $file; $file =~ s,^\./(.*),$1,; next if ($file =~ m/\.lock$|~$|^\.|.bak$/); push(@list, $file); } chdir ($pwd); return @list } #--------------------------------------------------------------------- # Lock a file # # args: file # # return: true for successful locking #--------------------------------------------------------------------- sub lock_file { my($file) = @_; my($lockfile) = "$file$LOCK_EXT"; my($text); # see if a lock is already set if (-f $lockfile) { open(FILE, "<$lockfile"); $text = ; print "

File Locked

File $file was locked on :
$text". &file_unlock_link($q->param('database'), basename($file), "

Click here to unlock"); close(FILE); return 0; } # now set the lock file if (! -f $file or !open(FILE, ">$lockfile")) { print "Can't create lock file for $file"; return 0; } print "

lock file name = `$lockfile'" if ($DEBUG); print FILE scalar(localtime) . "\n"; close(FILE); return 1; } #--------------------------------------------------------------------- # Unlock a file # # args: file #--------------------------------------------------------------------- sub unlock_file { my($file) = @_; my($lockfile) = "$file$LOCK_EXT"; unlink $lockfile if (-f $file); } #--------------------------------------------------------------------- # Check for file lock # # args: file #--------------------------------------------------------------------- sub is_locked { my($file) = @_; my($lockfile) = "$file$LOCK_EXT"; return (-f $lockfile); } #--------------------------------------------------------------------- # Read a file # # Args: file # # return: true for success #--------------------------------------------------------------------- sub read_file { my($file) = @_; if (!open(FILE, "<$file")) { print "

Error reading `$file'"; return 0; } # suck up the whole file my(@lines) = ; close(FILE); return @lines; } #--------------------------------------------------------------------- # write the file # # args: file, lines # # return: true for success #--------------------------------------------------------------------- sub write_file { my($file, @lines) = @_; my($tmp,$path); $path = dirname($file); $tmp = "$path/.tmp." . basename($file); if (!open(FILE, "> $tmp")) { print "

Error opening temp file $tmp"; return 0; } print FILE @lines; close(FILE); # now move the temp file to the real file unlink($file); rename($tmp, $file); return 1; } #--------------------------------------------------------------------- # View a file # # args: $file #--------------------------------------------------------------------- sub view_page { my($database) = $q->param('database'); my($file) = $q->param('file'); # Display title print "GNATS Admin\n \n", heading_text($database), "\n"; my($filepath) = find_db_root($database) . $GNATS_ADM_SUBDIR . $file; my(@lines) = &read_file($filepath); if (@lines) { my $text = join("", @lines); print $q->h3("Contents of file `$file'"), "

"; print $q->start_form(), $q->hidden('database', $database), $q->hidden('file', $file), $q->submit('cmd','Edit'), $q->end_form(); print "


$text
"; } else { print $q->h3("No lines in file `$filepath'") ; } print &db_file_config_link($database), "\n"; } #--------------------------------------------------------------------- # list links to found files # # args: dir #--------------------------------------------------------------------- sub list_file_links { my($dir) = @_; my @list = &list_files($dir); print "

no files found in `$dir'\n" unless (@list); my($file); # print "

    \n"; # foreach $file (sort @list) # { # print "
  • ". &file_edit_link($file, "Edit") . " or " . # &file_view_link($file, "View") . "   $file\n"; # } # print "
\n"; print $q->start_form(), $q->hidden('database', $q->param('database')), $q->table( $q->Tr( $q->td( $q->scrolling_list (-name=>"file", -size=>7, -values=>\@list)), $q->td($q->submit('cmd','View'), $q->br(), $q->br(), $q->submit('cmd','Edit')) )); $q->end_form(); } #--------------------------------------------------------------------- # edit page # # args: $file #--------------------------------------------------------------------- sub edit_page { my($database) = $q->param('database'); my($filename) = $q->param('file'); print "GNATS Admin\n \n", heading_text($database); my(@lines); my($file) = find_db_root($database) . $GNATS_ADM_SUBDIR . $filename; $file =~ /^(.*)$/; # untaint data $file = $1; if (&lock_file($file)) { @lines = &read_file($file); my $text = join("",@lines); my $rows = $#lines + 3; $rows = 25 if ($rows > 25); print $q->start_form(), $q->hidden('database', $database), $q->hidden('file', $file), "

Contents of `$file'

NOTE: USE ABORT BUTTON TO CANCEL EDIT!!

", $q->submit('cmd', 'Save changes'), $q->submit('cmd', 'Abort edit'), "

", $q->submit('cmd', 'Save changes'), $q->submit('cmd', 'Abort edit'), } } #--------------------------------------------------------------------- # list the databases available for editing in a form with a button # # args: #--------------------------------------------------------------------- sub list_databases { my(@databaselist) = read_database_list(); print $q->Tr( {-valign=>"top"}, $q->td( $q->submit('cmd','Configure db')), $q->td( $q->scrolling_list (-name=>"database", -size=>9, -values=>\@databaselist)), ); } #--------------------------------------------------------------------- # read and parse the list of databases # # args: #--------------------------------------------------------------------- sub read_database_list { if (!open(FILE, "<$GNATS_DB_LIST")) { print "

Error reading `$GNATS_DB_LIST'"; return 0; } # suck up the whole file my(@lines) = ; close(FILE); # my($masterdbline, $dbname, @dbnamelist, @rest); my($index) = 0; foreach $masterdbline (@lines) { $masterdbline =~ /^(.*)$/; # untaint data (ie. strip CR/LF) ($dbname, @rest) = split(":", $1); $dbnamelist[$i++] = $dbname unless $dbname =~ "^#"; } return sort(@dbnamelist); } #--------------------------------------------------------------------- # find the directory path for the root of a database # # args: #--------------------------------------------------------------------- sub find_db_root { my($database) = @_; if (!open(FILE, "<$GNATS_DB_LIST")) { print "

Error reading `$GNATS_DB_LIST'"; return 0; } # suck up the whole file my(@lines) = ; close(FILE); # my($masterdbline, $dbname, $dbdescription, $dbpath); my($index) = 0; foreach $masterdbline (@lines) { if ($masterdbline =~ /^$database:/) { $masterdbline =~ /^(.*)$/; # untaint data ($dbname, $dbdescription, $dbpath) = split(":", $1); return $dbpath; } } # print "Database $database not found in databases list
"; return 0; } #--------------------------------------------------------------------- # handle the edited page # # args: #--------------------------------------------------------------------- sub handle_edit { print "GNATS Admin\n \n"; # check to see what action to take my $database = $q->param('database'); $database =~ /^(.*)$/; # untaint data $database = $1; my $file = find_db_root($database) . $GNATS_ADM_SUBDIR . $q->param('file'); $file =~ /^(.*)$/; # untaint data $file = $1; print heading_text($database); # make sure file is locked if (! is_locked($file)) { print $q->h3("File `$file' is not locked."). &db_file_config_link($database) . "\n"; } elsif ($cmd eq 'Save changes') { if (write_file($file, $q->param('contents'))) { print "

$file saved."; if (basename($file) eq "categories") { $| = 1; # force buffer flush print "

Verifying categories\n

";
				system("echo \"($MKCAT --database " . $database . ") 2>&1\" | $SHELL");
				print "
\n"; $| = 0; # stopp flush } else { print &db_file_config_link($database) . "\n";} # &run_make(); } } else { print $q->h3("Edit aborted.\n") . &main_page_link() . ".\n"; } &unlock_file($file); } #--------------------------------------------------------------------- # Create a link back to main page # # args: $link_text #--------------------------------------------------------------------- sub main_page_link { my($link_text) = @_; $link_text = "

Back to main page

" unless ($link_text); return "$link_text" } #--------------------------------------------------------------------- # Create a link back to database configuration page # # args: $database #--------------------------------------------------------------------- sub db_file_config_link { my($database) = @_; return "Continue $database configuration" } #--------------------------------------------------------------------- # Handle the unlocking of a file #--------------------------------------------------------------------- sub handle_unlock { my($database) = $q->param('database'); my $file = find_db_root($database) . $GNATS_ADM_SUBDIR . $q->param('file'); $file =~ /^(.*)$/; # untaint data $file = $1; # Display title print "GNATS Admin\n \n", heading_text($database); &unlock_file($file); print "

`$file' Unlocked." . &db_file_config_link($database) . &main_page_link(); } #--------------------------------------------------------------------- # Create a link to unlock a file # # args: $database, $file, $text #--------------------------------------------------------------------- sub file_unlock_link { my($database, $file, $text) = @_; $text = $file unless($text); return "$text" } #--------------------------------------------------------------------- # Translates '+' to ' ' and '%##' to 'chr(0x##)' #--------------------------------------------------------------------- sub cgi_trans { my($str) = @_; $str =~ s/\+/ /g; $str =~ s/%([\dA-Fa-f][\dA-Fa-f])/sprintf("%c",hex($1))/eg; return $str; } #--------------------------------------------------------------------- # Process the makefile if present # # args: #--------------------------------------------------------------------- #sub run_make # { # if (-f "$GNATS_ADM/Makefile") # { # $| = 1; # force buffer flush # print "

Rebuilding admin files\n

";
#		system("echo \"(cd $GNATS_ADM; $MAKE) 2>&1\" | $SHELL");
#		print "
\n"; # $| = 0; # stopp flush # } # } #--------------------------------------------------------------------- # Print a stacktrace # used by the various warn() statments to emit useful diagnostics # to the web server error logs. # # args: #--------------------------------------------------------------------- sub print_stacktrace { my @stacktrace; my $i = 1; while ( my($subroutine) = (caller($i++))[3] ) { push(@stacktrace, $subroutine); } return 'In: ' . join(' <= ', @stacktrace); } # Automatic Emacs style settings # Local Variables: # mode: perl # perl-indent-level: 0 # perl-continued-statement-offset: 4 # perl-continued-brace-offset: -4 # perl-brace-offset: 4 # perl-brace-imaginary-offset: 4 # perl-label-offset: -4 # enable-trim-on-save: t # End: gnats-4.1.0/doc/0000755000175000017500000000000010212665130014123 5ustar chewiechewie00000000000000gnats-4.1.0/doc/man/0000755000175000017500000000000010212665130014676 5ustar chewiechewie00000000000000gnats-4.1.0/doc/man/Makefile.in0000644000175000017500000001156610062420654016757 0ustar chewiechewie00000000000000# Makefile for GNU GNATS manual pages. # Copyright (C) 2001, 2003 Milan Zamazal # Copyright (C) 1993, 2003 Free Software Foundation, Inc. # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. srcdir = @srcdir@ VPATH = @srcdir@ #FIXME GNATS_ROOT = @GNATS_ROOT@ GNATS_SITE = @GNATS_SITE@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ datadir = @datadir@ datadir = @datadir@ mandir = @mandir@ man1dir = $(mandir)/man1 man2dir = $(mandir)/man2 man3dir = $(mandir)/man3 man4dir = $(mandir)/man4 man5dir = $(mandir)/man5 man6dir = $(mandir)/man6 man7dir = $(mandir)/man7 man8dir = $(mandir)/man8 man9dir = $(mandir)/man9 man1ext = .1 man5ext = .5 man7ext = .7 man8ext = .8 infodir = @infodir@ includedir = @includedir@ SHELL = /bin/sh INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ #### host, target, and site dependent makefile fragments come in here. ### SRCS1= edit-pr$(man1ext) query-pr$(man1ext) MAN1= edit-pr.man query-pr.man SRCS5= dbconfig$(man5ext) databases$(man5ext) MAN5= dbconfig.man databases.man SRCS7= gnats$(man7ext) MAN7= gnats.man SRCS8= mkcat$(man8ext) queue-pr$(man8ext) file-pr$(man8ext) rmcat$(man8ext) gen-index$(man8ext) gnatsd$(man8ext) mkdb$(man8ext) delete-pr$(man8ext) pr-edit$(man8ext) getclose$(man8ext) MAN8 = mkcat.man queue-pr.man file-pr.man rmcat.man gen-index.man gnatsd.man mkdb.man delete-pr.man pr-edit.man getclose.man DISTFILES = Makefile.in $(MAN1) $(MAN7) $(MAN8) all: all-gnats all-gnats gnats-man-pages: $(SRCS1) $(SRCS5) $(SRCS7) $(SRCS8) all-tools tools-man-pages: $(SRCS1) .PHONY: check check: $(SRCS1): ../Makefile $(MAN1) @echo Creating $@... @file=`echo $@ | sed -e 's,\$(man1ext),,'` ; \ sed -e 's,xGNATS_ROOTx,$(GNATS_ROOT),g' \ -e 's,xGNATS_SITEx,$(GNATS_SITE),g' \ -e 's,@BINDIR@,$(bindir),g' \ -e 's,@PREFIX@,$(prefix),g' \ -e 's,@VERSION@,$(VERSION),g' $(srcdir)/$$file.man > tmp-$@ @mv tmp-$@ $@ $(SRCS5): ../Makefile $(MAN5) @echo Creating $@... @file=`echo $@ | sed -e 's,\$(man5ext),,'` ; \ sed -e 's,xGNATS_ROOTx,$(GNATS_ROOT),g' \ -e 's,xGNATS_SITEx,$(GNATS_SITE),g' \ -e 's,@BINDIR@,$(bindir),g' \ -e 's,@PREFIX@,$(prefix),g' \ -e 's,@VERSION@,$(VERSION),g' $(srcdir)/$$file.man > tmp-$@ @mv tmp-$@ $@ $(SRCS7): ../Makefile $(MAN7) @echo Creating $@... @file=`echo $@ | sed -e 's,\$(man7ext),,'` ; \ sed -e 's,xGNATS_ROOTx,$(GNATS_ROOT),g' \ -e 's,xGNATS_SITEx,$(GNATS_SITE),g' \ -e 's,@DATADIR@,$(datadir),g' \ -e 's,@PREFIX@,$(prefix),g' \ -e 's,@VERSION@,$(VERSION),g' $(srcdir)/$$file.man > tmp-$@ @mv tmp-$@ $@ $(SRCS8): ../Makefile $(MAN8) @echo Creating $@... @file=`echo $@ | sed -e 's,\$(man8ext),,'` ; \ sed -e 's,xGNATS_ROOTx,$(GNATS_ROOT),g' \ -e 's,xGNATS_SITEx,$(GNATS_SITE),g' \ -e 's,@DATADIR@,$(datadir),g' \ -e 's,@PREFIX@,$(prefix),g' \ -e 's,@VERSION@,$(VERSION),g' $(srcdir)/$$file.man > tmp-$@ @mv tmp-$@ $@ info install-info clean-info: dvi: TAGS: mostlyclean: force rm -f $(SRCS1) $(SRCS5) $(SRCS7) $(SRCS8) clean: mostlyclean distclean: clean rm -f Makefile -rm -f .\#* \#* *~ -rm -f *.orig *.rej maintainer-clean: distclean install: install-gnats install-tools install-gnats install-gnats-man: all-gnats install-tools $(SHELL) $(srcdir)/../../mkinstalldirs $(DESTDIR)$(man5dir)/ for i in $(SRCS5); do \ $(INSTALL_DATA) $$i $(DESTDIR)$(man5dir)/$$i; \ done $(SHELL) $(srcdir)/../../mkinstalldirs $(DESTDIR)$(man7dir)/ for i in $(SRCS7); do \ $(INSTALL_DATA) $$i $(DESTDIR)$(man7dir)/$$i; \ done $(SHELL) $(srcdir)/../../mkinstalldirs $(DESTDIR)$(man8dir)/ for i in $(SRCS8); do \ $(INSTALL_DATA) $$i $(DESTDIR)$(man8dir)/$$i; \ done install-tools install-tools-man: all-tools $(SHELL) $(srcdir)/../../mkinstalldirs $(DESTDIR)$(man1dir)/ for i in $(SRCS1); do \ $(INSTALL_DATA) $$i $(DESTDIR)$(man1dir)/$$i; \ done uninstall: -for i in $(SRCS1); do rm -f $(DESTDIR)$(man1dir)/$$i; done -for i in $(SRCS5); do rm -f $(DESTDIR)$(man5dir)/$$i; done -for i in $(SRCS7); do rm -f $(DESTDIR)$(man7dir)/$$i; done -for i in $(SRCS8); do rm -f $(DESTDIR)$(man8dir)/$$i; done force: dist: # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: Makefile: $(srcdir)/Makefile.in cd .. && $(SHELL) config.status gnats-4.1.0/doc/man/databases.man0000644000175000017500000000644707712014071017340 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 2000, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH databases 5 "August 2003" "GNATS @VERSION@" "GNATS configuration files" .de BP .sp .ti -.2i \(** .. .SH NAME databases \- the known set of GNATS databases .SH DESCRIPTION The \fBdatabases\fR configuration file is a site-wide configuration file containing the list of GNATS databases that are available either on the host itself or remotely over the network, together with some parameters associated with each database. It is located in the directory @PREFIX@/share/gnats. .P The file contains one line for each database. For databases located on the host itself, each line consists of three fields separated by colons: .P .RS database name:short description:/path/to/database .RE .P The first field is the database name. This is the name used to identify the database when invoking programs such as \fBquery-pr\fR or \fBsend-pr\fR, either by using the \fB--database\fR option of the program or by setting the \fBGNATSDB\fR environment variable to the name of the database. The second field is a short human-readable description of the database contents, and the final field is the directory where the database contents are kept. .P For a database that is located across a network, but which should be accessible from this host, the entry for the database should look like this: .P .RS database name:short description of database::hostname:port .RE .P The first two fields are the same as for local databases, the third field is empty (notice the two adjacent `:' symbols, indicating an empty field), the fourth field is the hostname of the remote GNATS server, and the fifth field is the port number that the remote GNATS server is running on. .P Note that if you add a new local database, you must create its data directory, including appropriate subdirectories and administrative files after adding an entry to \fBdatabases\fR. This is best done using the \fBmkdb\fR tool. .P Lines beginning with a # are ignored. .P The database name \fBdefault\fR is special; this is the entry used if no database name is specified via a \fB--database\fR option or the \fBGNATSDB\fR environment variable. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 2000, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/dbconfig.man0000644000175000017500000000342207712014071017152 0ustar chewiechewie00000000000000'\" t .\" Copyright (c) 2000, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH dbconfig 5 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Files" .SH NAME dbconfig \- GNATS database configuration file .SH DESCRIPTION The dbconfig configuration file controls the configuration of a GNATS database. Each database has its own individual copy of the file, which is located in the \fBgnats-adm\fR administrative subdirectory of the database. For further information about the dbconfig file, please see the GNATS manual, .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 2000, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/delete-pr.man0000644000175000017500000000672407712014071017270 0ustar chewiechewie00000000000000.\" Copyright (c) 1999, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH delete-pr 8 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME delete\-pr \- deletes closed PRs .SH SYNOPSIS .hy 0 .na .TP .B delete\-pr [ .B \-V | .B \-\-version ] | [ .B \-h | .B \-\-help ] | .br [ .BI -d \ name | .BI --database= name ] [ .BR \-c\ | \ \-\-closed\ | \ PR ] .ad b .hy 1 .SH DESCRIPTION Deletes the specified .BR PR , or if the \fB\-\-closed\fR option is given, all of the closed PRs in the database are deleted. .P \fBdelete-pr\fR must be run by the GNATS user (by default \fBgnats\fR). .P Note that deleting PRs is generally a \fBvery\fR bad idea. It flies in the face of the very idea of using a Problem Reporting system and should only be considered in special situations. Such a situation might for instance arise if a mail loop causes mass duplicate submissions or if you receive spam to the PR submission e-mail address. .SH OPTIONS .TP .B \-V\fR,\fB \-\-version Prints the program version to stdout and exits. .TP .B \-h\fR,\fB \-\-help Prints a short help text to stdout and exits. .TP .B \-d\fR,\fB \-\-database Specifies the database from which the PR(s) are to be deleted. If no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .TP .B \-\-closed Requests that all closed PRs in the database be deleted. .TP .B PR Requests that the specified \fBPR\fR be deleted. The \fBPR\fR must be in a closed state. .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database, in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set and the \fB--database\fR option is not supplied, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) and .I Reporting Problems Using send-pr (also installed as the GNU Info file .BR send-pr.info ). .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1999, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/edit-pr.man0000644000175000017500000001056507712014071016751 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 1999, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .\" edit-pr, editing function for GNATS - Jeffrey Osier .TH edit-pr 1 "August 2003" "GNATS @VERSION@" "GNATS User Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME edit-pr \- edit a problem report in the GNATS database .SH SYNOPSIS .hy 0 .na .B edit-pr .RS [ .B -h | .B --help ] [ .B -V | .B --version ] .br [ .BI -d \ databasename | .BI --database= databasename ] .br [ .BI -H \ host | .BI --host= host ] [ .BI -P \ port | .BI --port= port ] .br [ .BI -v \ user | .BI --user= user ] [ .BI -w \ password | .BI --passwd= password ] .br .I PR .ad b .hy 1 .SH DESCRIPTION \fBedit-pr\fR is used to make changes to existing PRs in a GNATS database. .P \fBedit-pr\fR first examines the \fIPR\fR and locks it if it is not already locked. This is to prevent a PR from being edited by two users simultaneously. If the PR is already in the process of being edited, \fBedit-pr\fR displays the name of the person who owns the lock. .P \fBedit-pr\fR then calls \fB$EDITOR\fR on \fIPR\fR. After the PR has been edited, it is resubmitted to the database, and the index is updated. .P If you change a field that requires a reason for the change, \fBedit-pr\fR prompts you to supply a reason for the change. A message is then appended to the Audit-Trail field of \fIPR\fR with the changed values and the change reason. .P Depending on how the database is configured, editing various fields in the PR may also cause mail to be sent concerning these changes. In the default configuration, any fields that generate Audit-Trail entries will cause a copy of the new Audit-Trail message to be sent. .SH OPTIONS .TP 1i .B -h\fR,\fB --help Prints a brief usage message for .BR edit-pr . .TP .B -V\fR,\fB --version Prints the version number for .BR edit-pr . .TP .B -d\fR,\fB --database Specifies the database containing the PR to be edited; if no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .SS GNATS network options: .TP .B -H\fR,\fB --host Hostname of the GNATS server. .TP .B -P\fR,\fB --port The port that the GNATS server runs on. .TP .B -v\fR,\fB --username Username used to log into the GNATS server. .TP .B -w\fR,\fB --passwd Password used to log into the GNATS server. .B .SH ENVIRONMENT VARIABLES The environment variable .B EDITOR specifies the editor to invoke on the PR. Default is \fIvi\fR(1). .TP The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database, in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set, it is assumed that the database is local and that its name is \fIdefault\fR. .SH FILES .TP 1i .B /tmp/ep$$ Temporary file for PR being edited. .TP .B /tmp/ed_pr_ch$$ Holds .B Audit-Trail change message, if needed. .TP .B /tmp/u$$ Holds output of lock function. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/file-pr.man0000644000175000017500000000764107712014071016744 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 1999, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH file-pr 8 "August 2003" "GNATS @VERSION@" "GNATS Internal Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME file-pr \- files incoming problem reports in GNATS database .SH SYNOPSIS .hy 0 .na .B file\-pr [ .B \-f \fIfile\fB | .B \-\-file=\fIfile\fB ] [ .B \-h | .B \-\-help ] .br [ .B \-V | .B \-\-version ] [ .BI -H \ host | .BI --host= host ] .br [ .BI -P \ port | .BI --port= port ] [ .BI -v \ user | .BI --user= user ] .br [ .BI -w \ password | .BI --passwd= password ] .br [ .BI -d \ databasename | .BI --database= databasename ] .ad b .hy 1 .SH DESCRIPTION \fBfile-pr\fR files incoming Problem Reports in the GNATS database, sends acknowledgments to approriate parties and logs database activity. .P \fBfile-pr\fR assigns the Problem Report an identification number and then files it in the GNATS database either under the category specified in the Category field of the PR, or under the default category if the Category field is nonexistent or contains an invalid category name. .P For the default GNATS configuration, the person responsible for that category and the person responsible for the submitter site where the PR originated receive a copy of the PR in its entirety. Optionally, the originator of the PR receives an acknowledgment that the PR arrived and was filed .SH OPTIONS .TP .B \-f \fIfile\fB, \-\-filename=\fIfile\fB Accept .I file as input; if this option is not present, standard input is used. .TP .B \-h, \-\-help Display usage summary for .BR file\-pr . .TP .B \-V, \-\-version Display version number for .BR file\-pr . .TP .B -d\fR,\fB --database Specifies the database to which the PR is to be submitted. If no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .SS GNATS network options: .TP .B -H\fR,\fB --host Hostname of the GNATS server. .TP .B -P\fR,\fB --port The port that the GNATS server runs on. .TP .B -v\fR,\fB --username Username used to log into the GNATS server. .TP .B -w\fR,\fB --passwd Password used to log into the GNATS server. .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database, in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 1999, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/gen-index.man0000644000175000017500000000635707712014071017267 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH gen-index 8 "August 2003" "GNATS @VERSION@" "GNATS Administration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME gen-index \- generate new GNATS database index .SH SYNOPSIS .hy 0 .na .B gen\-index .RS [ .B -n | .B --numeric ] [ .B -h | .B --help ] .br [ .B -o .I outfile | .BI --outfile= outfile ] .br [ .B -i | .B --import ] [ .B -e | .B --export ] .br [ .B -d .I databasename | .BI --database= databasename ] .br [ .B -V | .B --version ] .ad b .hy 1 .SH DESCRIPTION Builds an index for the specified GNATS database. The index is printed to standard output by default. .SH OPTIONS .TP 0.5i .B -n, --numeric Sorts index entries numerically rather than by their order in the categories list. .TP .B -d \fIdatabasename\fB, --database=\fIdatabasename\fR Specifies the database to be indexed. If no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .TP .B -o \fIoutfile\fB, --outfile=\fIoutfile\fR Prints the index to .I outfile rather than to the standard output. .TP .B -i, --import Import the existing index file instead of re-indexing the database. .TP .B -e, --export Force plaintext output .TP .B -h, --help Prints usage for .BR gen\-index . .TP .B -V, --version Prints the version number of .BR gen\-index . .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database, in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) and .I Reporting Problems Using send-pr (also installed as the GNU Info file .BR send-pr.info ). .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993 Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/getclose.man0000644000175000017500000000725610062420445017213 0ustar chewiechewie00000000000000.\" Copyright (c) 2004 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .\" getclose, Find PRs fixed in a particular release, Chad Walstrom .\" .TH getclose 8 "April 2004" "GNATS @VERSION@" "GNATS User Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME getclose \- Find PRs fixed in a particular release .SH SYNOPSIS .hy 0 .na .B getclose .BI [OPTIONS] .BI MIGRATION .BI FREEZE .BI LASTFREEZE .ad b .hy 1 .SH DESCRIPTION \fBgetclose\fR uses the three dates specified on the commandline to find and label PRs fixed in a particular release. .TP .B MIGRATION\fR \-\- the date of the migration for the current release .TP .B FREEZE\fR \-\- the date of the freeze for the current release .TP .B LASTFREEZE\fR \-\- the date of the freeze for the previous release .P .SH RESULTS FIXED:foo:1234:the synopsis .br MAYBE:bar:1235:the synopsis .P Those marked \fBFIXED\fR were closed before the migration into the current release. Those marked as \fBMAYBE\fR were closed after the migration, but before the freeze; thus, the fix may or may not have made it into the current release. These need to be researched to find out if the changes, if any, were included. .SH OPTIONS .TP 1i .B -h\fR,\fB --help Prints a brief usage message for .BR getclose . .TP .B -V\fR,\fB --version Prints the version number for .BR getclose . .TP .B -d DATABASE\fR,\fB --database=DATABASE Specifies the database containing the PR to be edited; if no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .SS GNATS network options: .TP .B -H HOSTNAME\fR,\fB --host=HOSTNAME Hostname of the GNATS server. .TP .B -P PORT\fR,\fB --port=PORT The port that the GNATS server runs on. .TP .B -v USERNAME\fR,\fB --username=USERNAME Username used to log into the GNATS server. .TP .B -w PASSWORD\fR,\fB --passwd=PASSWORD Password used to log into the GNATS server. .B .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database, in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 2004 Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/gnats.man0000644000175000017500000001776007712014071016525 0ustar chewiechewie00000000000000.\" -*- nroff -*- .\" --------------------------------------------------------------------------- .\" man page for GNATS (by Heinz G. Seidl, hgs@cygnus.com) .\" updated April 1993 for GNATS @VERSION@ by Jeffrey Osier, jeffrey@cygnus.com .\" .\" This file is part of the GNU Problem Report Management System (GNATS) .\" Copyright 1993 Cygnus Support .\" .\" 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 Library General Public .\" License along with this program; if not, write to the Free .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA .\" .\" --------------------------------------------------------------------------- .\" .TH gnats 7 "August 2003" "GNATS @VERSION@" "Problem Report Management System" .SH NAME gnats \- Problem Report Management System .SH DESCRIPTION .B GNATS is a bug-tracking tool designed for use at a central support site. Software users who experience problems use tools provided with GNATS to submit Problem Reports to the the maintainers of that software; .B GNATS partially automates the tracking of these problems by: .TP .B \(bu organizing problem reports into a database and notifying responsible parties of suspected bugs; .TP .B \(bu allowing support personnel and their managers to edit, query and report on accumulated bugs; and .TP .B \(bu providing a reliable archive of problems with a given program and a history of the life of the program by preserving its reported problems and their subsequent solutions. .LP .B GNATS offers many of the same features offered by more generic databases. You can query and edit existing problem reports (\fIPR\fPs) as well as obtain reports on groups of PRs. The database itself is simply an ordered repository for problem reports; each PR receives a unique, incremental PR number which identifies it throughout its lifetime. .LP Many of the primary functions available with .B GNATS are accessible from within GNU .BR Emacs . .SH "PROBLEM REPORT STATES" PRs go through several states in their lifetimes. The set of states is site-specific. .LP The default set of states are: .TP 2i .I open the initial state of every PR; this means the PR has been filed and the person or group responsible for it has been notified of the suspected problem .TP .I analyzed the problem has been examined and work toward a solution has begun .TP .I feedback a solution has been found and tested at the support site, and sent to the party who reported the problem; that party is testing the solution .TP .I closed the solution has been confirmed by the party which reported it .LP In some cases, it may be necessary to suspend work on a bug; in this case, its state changes to .I suspended rather than .IR closed . .SH STRUCTURE Incoming PRs are assigned an incremental serial number and filed according to category. An index is kept concurrently to accelerate searches of the database. .LP All .B GNATS administration and database files are located in subdirectories of a directory associated with each database. Databases are named, and the association between database names and directories is described by the \fBdatabases\fR file, which is found on this system in .B @PREFIX@/etc/gnats/databases. .LP .I Problem Reports are segregated into subdirectories within the database directory by category. For example, problems submitted with a category of .I gcc will be filed in the database subdirectory .BR gcc . .LP .B GNATS administration files are kept in the database subdirectory .BR gnats-adm : .TP 1.5i .B addresses contains mappings between submitter IDs and corresponding e-mail addresses .TP .B categories table of valid categories and parties responsible for them .TP .B classes table of valid classes of Problem Reports .TP .B current keeps track of incremental PR numbers assigned .TP .B dbconfig describes the structure of the database, and various database-specific options .TP .B gnatsd.user_access lists host names and access levels of hosts authorized to access the database .TP .B gnatsd.user_access lists user names, passwords and access levels of users authorized to access the database .TP .B index database index .TP .B locks directory containing lock files .TP .B responsible table of responsible parties and their email addresses .TP .B states table of valid states of Problem Reports .TP .B submitters database of sites which submit PRs .LP Administrative programs and programs internal to .B GNATS are kept in the directory .BR @PREFIX@/libexec/gnats while those meant for public use are installed in .BR @PREFIX@/bin . .LP .B @PREFIX@/libexec/gnats contains the programs: .TP 1.5i .B mkdb used by the .B GNATS administrator to create a new database .TP .B mkcat used by the .B GNATS administrator to create new categories [obsolete] .TP .B rmcat used by the .B GNATS administrator to remove outdated categories [obsolete] .TP .B gen\-index used by the .B GNATS administrator to generate a new version of the index .TP .B queue-pr mail control program which accepts incoming messages and periodically submits them to the database via .B cron by feeding them through the program .BR file-pr (8) .TP .B pr-edit program which is mainly responsible for editing existing PRs and filing new ones; it is used by .BR edit\-pr \ and\ file\-pr .TP .B file-pr script which uses \fBpr\-edit\fR to file new PRs .TP .B at-pr automatically notifies responsible parties if a PR is not analyzed within a requisite period defined in the .B submitters file .TP .B delete-pr used to delete closed PRs .LP .B @PREFIX@/bin contains the programs .TP 1.5i .B query-pr used to query the database .TP .B edit-pr used to edit individual PRs .TP .B send-pr used to submit problems to .B GNATS .LP Documentation exists for all programs associated with .B GNATS. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH HISTORY .B GNATS was greatly inspired by the BSD .BR sendbug (1) and .BR bugfiler (8) programs. It was originally written in C++, Elisp, shell script, and awk. It presently consists of utilities written in C, shell script, and Elisp. .SH AUTHORS .B GNATS was originally written by Heinz G. Seidl (Cygnus Support). Subsequent iterations were developed by Brendan Kehoe (Cygnus Support) and Jason Merrill (Cygnus Support), with help from Tim Wicinski. Documentation was initially developed by Jeffrey Osier (Cygnus Support) and Brendan Kehoe (Cygnus Support). .P Version 4.x was a substantial rewrite done by Bob Manson (Juniper Networks), Milan Zamazal and Yngve Svendsen (Clustra Systems / Sun Microsystems) .SH COPYING Copyright (c) 1992, 1993, 1999, 2000, 2003, Free Software Foundation .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/gnatsd.man0000644000175000017500000007303707712014071016670 0ustar chewiechewie00000000000000.\" Copyright (c) 2000, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH gnatsd 8 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME gnatsd \- GNATS network server .SH SYNOPSIS .hy 0 .na .TP .B gnatsd [\fB\-\-database\fR\ \fIdatabase\fR\ |\ \fB\-d\fR\ \fIdatabase\fR] [\fB\-\-not\-inetd\fR\ |\ \fB\-n\fR] [\fB\-\-max-access-level\fR\ \fIlevel\fR\ |\ \fB\-m\fR\ \fIlevel\fR] [\fB\-\-version\fR\ |\ \fB\-V\fR] [\fB\-\-help\fR\ |\ \fB\-h\fR] .ad b .hy 1 .SH DESCRIPTION \fBgnatsd\fR is used to service remote GNATS requests such as querying \fIPR\fRs, \fIPR\fR creation, deletion, and editing, and miscellaneous database queries. It uses a simple ASCII-based command protocol (similar to SMTP or POP3) for communicating with remote clients. .P It also provides a security model based either on IP-based authentication (generally a \fBterrible\fR idea) or username/passwords. Passwords may be encrypted using UNIX crypt() or MD5 (for operating systems that support it). Plaintext passwords are also supported but strongly discouraged. .P All of the GNATS clients are capable of communicating via the GNATS remote protocol to perform their functions. .P \fBgnatsd\fR should be run by the GNATS user (by default \fBgnats\fR), and it is usually started from \fIinetd\fR(8). .SH OPTIONS .TP 0.5i .B \-V\fR,\fB \-\-version Prints the program version to stdout and exits. .TP 0.5i .B \-h\fR,\fB \-\-help Prints a short help text to stdout and exits. .TP 0.5i .B \-d\fR,\fB \-\-database Specifies the default database which is to be serviced by this invocation of \fBgnatsd\fR. (The selected database may be changed via the \fBCHDB\fR command; this is simply the default if no \fBCHDB\fR command is issued.) If no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .TP 0.5i \fB\-\-not\-inetd\fR,\ \fB\-n\fR As its name suggests, indicates that \fBgnatsd\fR is not being invoked from \fIinetd\fR. This can be used when testing \fBgnatsd\fR, or if it being run via \fIssh\fR or some other mechanism. .P .RS 0.5i This has the effect of using the local hostname where \fBgnatsd\fR is being invoked for authentication purposes, rather than the remote address of the connecting client. .RE .TP 0.5i \fB\-\-max-access-level\fR,\ \fB\-m\fR Specifies the maximum access level that the connecting client can authenticate to. Authentication is as normal but if the user or host authenticates at a higher level, access level is set to this level. .SH COMMAND PROTOCOL Commands are issued to \fBgnatsd\fR as one or more words followed by a carriage-return/linefeed pair. For example, the \fBCHDB\fR (change databases) command is sent as .RS CHDB \fIdatabase\fR .RE [the CRLF will not be explicitly written for future examples] .P Replies from \fBgnatsd\fR are returned as one or more \fIresponse line\fRs containing a 3-digit numeric code followed by a human-readable string; the line is terminated with a pair. For example, one possible response to the \fBCHDB\fR command above would be: .RS 210 Now accessing GNATS database 'database'. .RE .P The three-digit code is normally followed by a single ASCII space (character 0x20). However, if additional response lines are to be returned from the server, there will be a single dash (`-') instead of the space character after the three-digit code. .P Response code values are divided into ranges. The first digit reflects the general type of response (such as "successful" or "error"), and the subsequent digits identify the specific type of response. .TP Codes 200-299 Positive response indicating that the command was successful. No subsequent data will be transmitted with the response. [In particular, code 210 (\fBCODE_OK\fR) is used as the positive result code for most simple commands.] .RS .P Commands that expect additional data from the client (such as \fBSUBM\fR or \fBVFLD\fR) use a two-step mechanism for sending the data. The server will respond to the initial command with either a 211 (\fBCODE_SEND_PR\fR) or 212 (\fBCODE_SEND_TEXT\fR) response line, or an error code if an error occurred with the initial command. The client is then expected to send the remaining data using the same quoting mechanism as described for server responses in the 300-349 range. The server will then send a final response line to the command. .RE .TP Codes 300-399 Positive response indicating that the query request was successful, and that a \fIPR\fR or other data will follow. Codes 300-349 are used when transmitting \fIPR\fRs, and 350-399 are used for other responses. .P .RS Codes in the 300-349 range are followed by a series of CRLF-terminated lines containing the command response, usually a \fIPR\fR. The final line of the result is a single period (`.'). Result lines that begin with a period have an extra period prepended to them. .P Codes in the 350-399 range use a different scheme for sending their responses. The three-digit numeric code will be followed by either a dash (`-') or a single space. If the code is followed by a dash, that indicates that another response line will follow. The final line of the response has a single space after the three-digit code. .P In previous versions of the protocol the first line of a CODE_INFORMATION (310) response was to be ignored. This is no longer the case. Instead, any lines marked with code CODE_INFORMATION_FILLER (351) are to be ignored. This allows the server to transmit additional headers or other human-readable text that can be safely ignored by the clients. .RE .TP Codes 400-599 An error occurred, usually because of invalid command parameters or invalid input from the client, missing arguments to the comamand, or a command was issued out of sequence. The human-readable message associated with the response line describes the general problem encountered with the command. .P .RS Multiple error messages may be returned from a command; in this case the `-' continuation character is used on all but the last response line. .RE .TP Codes 600-799 An internal error occurred on the server, a timeout occurred reading data from the client, or a network failure occurred. These errors are of the "this should not occur" nature, and retrying the operation may resolve the problem. Fortunately, most GNATS transactions are idempotent; unfortunately, locking the database or a \fIPR\fR are not repeatable actions (we cannot determine if an existing lock is the one we originally requested, or someone else's). .SH COMMANDS Note that the set of GNATS commands and their responses is somewhat inconsistent and is very much in flux. At present the GNATS clients are rather simple-minded and not very strict about processing responses. For example, if the server were to issue a code 300 (\fBCODE_PR_READY\fR) response to a \fBCHDB\fR command, the client would happily expect to see a PR appear (and would print it out if one was sent). .P It is thus suggested that any clients that use the GNATS protocol be equally flexible about the way received responses are handled; in particular, only the first digit of the response code should be assumed to be meaningful, although subsequent digits are needed in some cases (codes 300-399). \fBNo attempt should be made to parse the message strings on error response lines; they are only intended to be read by humans, and will be changed on a regular basis.\fR .P Almost every command may result in the response 440 (\fBCODE_CMD_ERROR\fR). This indicates that there was a problem with the command arguments, usually because of insufficient or too many arguments being specified. .TP 0.5i \fBUSER\fR [<\fIuserid\fR> [<\fIpassword\fR>]] Specifies the userid and password for database access. Both a username and a password may be given, only a username may be given, or both may be omitted; if both are omitted, the current access level is returned. .RS 0.5i .P The possible server responses are: .TP 350 (\fBCODE_INFORMATION\fR) The current access level is specified. .TP 422 (\fBCODE_NO_ACCESS\fR) A matching username and password could not be found. .TP 200 (\fBCODE_OK\fR) A matching username and password was found, and the login was successful. .RE .TP 0.5i \fBQUIT\fR Requests that the connection be closed. Possible responses: .RS 0.5i .TP 201 (\fBCODE_CLOSING\fR) Normal exit. .P The quit command has the dubious distinction of being the only command that cannot fail. .RE .TP 0.5i \fBLIST\fR <\fIlist\ type\fR> Describes various aspects of the database. The lists are returned as a list of records, one per line. Each line may contain a number of colon-separated fields. .P .RS 0.5i Possible values for \fIlist type\fR include .RS 0.25i .TP \fBCategories\fR Describes the legal categories for the database. .TP \fBSubmitters\fR Describes the set of submitters for the database. .TP \fBResponsible\fR Lists the names in the responsible administrative file, including their full names and email addresses. .TP \fBStates\fR Lists the states listed in the state administrative file, including the state type (usually blank for most states; the closed state has a special type). .TP \fBFieldNames\fR Lists the entire set of PR fields. .TP \fBInitialInputFields\fR Lists the fields that should be present when a PR is initially entered. .TP \fBInitialRequiredFields\fR Lists fields that have to be present and nonempty when a PR is initially entered (fields containing only blank characters such as spaces or newlines are considered empty.) .TP \fBDatabases\fR Lists the set of databases. .RE .P The possible responses are: .TP 301 (\fBCODE_TEXT_READY\fR) Normal response, followed by the records making up the list as described above. .TP 416 (\fBCODE_INVALID_LIST\fR) The requested list does not exist. .RE .TP 0.5i \fBFTYP\fR <\fIfield\fR> [<\fIfield\fR> ...] Describes the type of data held in the field(s) specified with the command. The currently-defined data types are: .RS 0.5i .TP Text A plain text field, containing exactly one line. .TP MultiText A text field possibly containing multiple lines of text. .TP Enum An enumerated data field; the value is restricted to one entry out of a list of values associated with the field. .TP MultiEnum The field contains one or more enumerated values. Values are separated with spaces or colons (\fB:\fR). .TP Integer The field contains an integer value, possibly signed. .TP Date The field contains a date. .TP TextWithRegex The value in the field must match one or more regular expressions associated with the field. .P The possible responses are: .TP 350 (\fBCODE_INFORMATION\fR) The normal response; the supplied text is the data type. .TP 410 (\fBCODE_INVALID_FIELD_NAME\fR) The specified field does not exist. .P If multiple field names were given, multiple response lines will be sent, one for each field, using the standard continuation protocol; each response except the last will have a dash (`-') immedately after the response code. .RE .TP \fBFTYPINFO\fR <\fIfield\fR> <\fIproperty\fR> Provides field-type-related information. Currently, only the property `separators' for MultiEnum fields is supported. When `separators' is specified, the possible return codes are: .RS 0.5i .TP 350 (\fBCODE_INFORMATION\fR) A proper MultiEnum field was specified and the returned text is the string of separators specified for the field in the dbconfig file, quoted within ''. .TP 435 (\fBCODE_INVALID_FTYPE_PROPERTY\fR) The `separators' property is not defined for this field, i.e. the specified field is not of type MultiEnum. .P Currently, specifying a different property than `separators' results in return code 435 as above. .RE .TP \fBFDSC\fR <\fIfield\fR> [<\fIfield\fR> ... ] Returns a human-readable description of the listed field(s). The possible responses are: .RS 0.5i .TP 350 (\fBCODE_INFORMATION\fR) The normal response; the supplied text is the field description. .TP 410 (\fBCODE_INVALID_FIELD_NAME\fR) The specified field does not exist. .P Like the \fBFVLD\fR command, the standard continuation protocol will be used if multiple fields were specified with the command. .RE .TP \fBFIELDFLAGS\fR <\fIfield\fR> [<\fIfield\fR> ... ] Returns a set of flags describing the specified field(s). The possible responses are either 410\ (\fBCODE_INVALID_FIELD_NAME\fR), meaning that the specified field is invalid or nonexistent, or 350\ (\fBCODE_INFORMATION\fR) which contains the set of flags for the field. The flags may be blank, which indicate that no special flags have been set for this field. .RS 0.5i .P Like the \fBFDSC\fR and \fBFTYP\fR commands, multiple field names may be listed with the command, and a response line will be returned for each one in the order that the fields appear on the command line. .P The flags include: .TP \fItextsearch\fR The field will be searched when a text field search is requested. .TP \fIallowAnyValue\fR For fields that contain enumerated values, any legal value may be used in the field, not just ones that appear in the enumerated list. .TP \fIrequireChangeReason\fR If the field is edited, a reason for the change must be supplied in the new \fIPR\fR text describing the reason for the change. The reason must be supplied as a multitext \fIPR\fR field in the new \fIPR\fR whose name is \fIfield\fR-Changed-Why (where \fIfield\fR is the name of the field being edited). .TP \fIreadonly\fR The field is read-only, and cannot be edited. .RE .TP \fBFVLD\fR <\fIfield\fR> Returns one or more regular expressions or strings that describe the valid types of data that can be placed in \fIfield\fR. Exactly what is returned is dependent on the type of data that can be stored in the field. For most fields a regular expression is returned; for enumerated fields, the returned values are the list of legal strings that can be held in the field. .P .RS 0.5i The possible responses are: .TP 301 (\fBCODE_TEXT_READY\fR) The normal response, which is followed by the list of regexps or strings. .TP 410 (\fBCODE_INVALID_FIELD_NAME\fR) The specified field does not exist. .RE .TP 0.5i \fBVFLD\fR <\fIfield\fR> \fBVFLD\fR can be used to validate a given value for a field in the database. The client issues the \fBVFLD\fR command with the name of the field to validate as an argument. The server will either respond with 212 (\fBCODE_SEND_TEXT\fR), or 410 (\fBCODE_INVALID_FIELD_NAME\fR) if the specified field does not exist. .P .RS 0.5i Once the 212 response is received from the server, the client should then send the line(s) of text to be validated, using the normal quoting mechanism described for \fIPR\fRs. The final line of text is followed by a line containing a single period, again as when sending \fIPR\fR text. .P The server will then either respond with 210 (\fBCODE_OK\fR), indicating that the text is acceptable, or one or more error codes describing the problems with the field contents. .RE .TP 0.5i \fBINPUTDEFAULT\fR <\fIfield\fR> [<\fIfield\fR> ... ] Returns the suggested default value for a field when a \fIPR\fR is initially created. The possible responses are either 410\ (\fBCODE_INVALID_FIELD_NAME\fR), meaning that the specified field is invalid or nonexistent, or 350\ (\fBCODE_INFORMATION\fR) which contains the default value for the field. .RS 0.5i .P Like the \fBFDSC\fR and \fBFTYP\fR commands, multiple field names may be listed with the command, and a response line will be returned for each one in the order that the fields appear on the command line. .RE .TP 0.5i \fBRSET\fR Used to reset the internal server state. The current query expression is cleared, and the index of PRs may be reread if it has been updated since the start of the session. .RS 0.5i The possible responses are: .TP 200 (\fBCODE_OK\fR) The state has been reset. .TP 440 (\fBCODE_CMD_ERROR\fR) One or more arguments were supplied to the command. .TP 6xx (\fIinternal error\fR) There were problems resetting the state (usually because the index could not be reread). The session will be immediately terminated. .RE .TP \fBLKDB\fR Locks the main GNATS database. No subsequent database locks will succeed until the lock is removed. Sessions that attempt to write to the database will fail. .RS 0.5i The possible responses are: .TP 200 (\fBCODE_OK\fR) The lock has been established. .TP 440 (\fBCODE_CMD_ERROR\fR) One or more arguments were supplied to the command. .TP 431 (\fBCODE_GNATS_LOCKED\fR) The database is already locked, and the lock could not be obtained after 10 seconds. .TP 6xx (\fIinternal error\fR) An internal error occurred, usually because of permission or other filesystem-related problems. The lock may or may not have been established. .RE .TP \fBUNDB\fR Unlocks the database. Any session may steal a database lock; no checking of any sort is done. .RS 0.5i The possible responses are: .TP 200 (\fBCODE_OK\fR) The lock has been removed. .TP 432 (\fBCODE_GNATS_NOT_LOCKED\fR) The database was not locked. .TP 440 (\fBCODE_CMD_ERROR\fR) One or more arguments were supplied to the command. .TP 6xx (\fIinternal error\fR) The database lock could not be removed, usually because of permissions or other filesystem-related issues. .RE .TP \fBLOCK\fR <\fIPR\fR> <\fIuser\fR> [<\fIpid\fR>] Locks the specified \fIPR\fR, marking the lock with the name \fIuser\fR and the optional \fIpid\fR. (No checking is done that the \fIuser\fR or \fIpid\fR arguments are valid or meaningful; they are simply treated as strings.) .RS 0.5i .P The \fBEDIT\fR command requires that the \fIPR\fR be locked before it may be successfully executed. However, it does not require that the lock is owned by the editing session, so the usefulness of the lock is simply as an advisory measure. .P The \fBAPPN\fR and \fBREPL\fR commands lock the \fIPR\fR as part of the editing process, and they do not require that the \fIPR\fR be locked \fIbefore\fR they are invoked. .P The possible responses are: .TP 440 (\fBCODE_CMD_ERROR\fR) Insufficient or too many arguments were specified to the command. .TP 300 (\fBCODE_PR_READY\fR) The lock was successfully obtained; the text of the \fIPR\fR (using the standard quoting mechanism for \fIPR\fRs) follows. .TP 400 (\fBCODE_NONEXISTENT_PR\fR) The \fIPR\fR specified does not exist. .TP 430 (\fBCODE_LOCKED_PR\fR) The \fIPR\fR is already locked by another session. .TP 6xx (\fIinternal error\fR) The \fIPR\fR lock could not be created, usually because of permissions or other filesystem-related issues. .RE .TP \fBUNLK\fR <\fIPR\fR> Unlocks \fIPR\fR. Any user may unlock a \fIPR\fR, as no checking is done to determine if the requesting session owns the lock. .RS 0.5i .P The possible responses are: .TP 440 (\fBCODE_CMD_ERROR\fR) Insufficient or too many arguments were specified to the command. .TP 200 (\fBCODE_OK\fR) The \fIPR\fR was successfully unlocked. .TP 433 (\fBCODE_PR_NOT_LOCKED\fR) The \fIPR\fR was not locked. .TP 6xx (\fIinternal error\fR) The \fIPR\fR could not be unlocked, usually because of permission or other filesystem-related problems. .RE .TP \fBDELETE\fR <\fIPR\fR> Deletes the specified \fIPR\fR. The user making the request must have \fIadmin\fR privileges. If successful, the \fIPR\fR is removed from the filesystem and the index file; a gap will be left in the numbering sequence for \fIPR\fRs. No checks are made that the \fIPR\fR is closed. .RS 0.5i .P The possible responses are: .TP 200 (\fBCODE_OK\fR) The \fIPR\fR was successfully deleted. .TP 422 (\fBCODE_NO_ACCESS\fR) The user requesting the delete does not have \fIadmin\fR privileges. .TP 430 (\fBCODE_LOCKED_PR\fR) The \fIPR\fR is locked by another session. .TP 431 (\fBCODE_GNATS_LOCKED\fR) The database has been locked, and no \fIPR\fRs may be updated until the lock is cleared. .TP 6xx (\fIinternal error\fR) The \fIPR\fR could not be successfully deleted, usually because of permission or other filesystem-related problems. .RE .TP \fBCHEK\fR [initial] Used to check the text of an entire \fIPR\fR for errors. Unlike the \fBVFLD\fR command, it accepts an entire \fIPR\fR at once instead of the contents of an individual field. .RS 0.5i .P The \fIinitial\fR argument indicates that the PR text to be checked is for a \fIPR\fR that will be newly created, rather than an edit or replacement of an existing PR. .P After the \fBCHEK\fR command is issued, the server will respond with either a 440 (\fBCODE_CMD_ERROR\fR) response indicating that the command arguments were incorrect, or a 211 (\fBCODE_SEND_PR\fR) response code will be sent. .P Once the 211 response is received from the server, the client should send the \fIPR\fR using the normal \fIPR\fR quoting mechanism; the final line of the \fIPR\fR is then followed by a line containing a single period, as usual. .P The server will then respond with either a 200 (\fBCODE_OK\fR) response, indicating there were no problems with the supplied text, or one or more error codes listing the problems with the \fIPR\fR. .RE .TP \fBEDIT\fR <\fIPR\fR> Verifies the replacement text for \fIPR\fR. If the command is successful, the contents of \fIPR\fR are completely replaced with the supplied text. \fIPR\fR must previously have been locked with the \fBLOCK\fR command. .RS 0.5i .P The possible responses are: .TP 431 (\fBCODE_GNATS_LOCKED\fR) The database has been locked, and no \fIPR\fRs may be updated until the lock is cleared. .TP 433 (\fBCODE_PR_NOT_LOCKED\fR) The \fIPR\fR was not previously locked with the \fBLOCK\fR command. .TP 400 (\fBCODE_NONEXISTENT_PR\fR) The specified \fIPR\fR does not currently exist. The \fBSUBM\fR command should be used to create new \fIPR\fRs. .TP 211 (\fBCODE_SEND_PR\fR) The client should now transmit the replacement \fIPR\fR text using the normal \fIPR\fR quoting mechanism. After the \fIPR\fR has been sent, the server will respond with either a 200 (\fBCODE_OK\fR) response indicating the edit was successful, or one or more error codes listing problems with either with the replacement \fIPR\fR text, or errors encountered while updating the \fIPR\fR file or index. .RE .TP \fBAPPN\fR <\fIPR\fR> <\fIfield\fR> .TP \fBREPL\fR <\fIPR\fR> <\fIfield\fR> Appends to or replaces the contents of \fIfield\fR in \fIPR\fR with the supplied text. The command returns a 201\ (\fBCODE_SEND_TEXT\fR) response; the client should then transmit the new field contents using the standard \fIPR\fR quoting mechanism. After the server has read the new contents, it then attempts to make the requested change to the \fIPR\fR. .RS 0.5i .P The possible responses are: .TP 200 (\fBCODE_OK\fR) The \fIPR\fR field was successfully changed. .TP 400 (\fBCODE_NONEXISTENT_PR\fR) The \fIPR\fR specified does not exist. .TP 410 (\fBCODE_INVALID_FIELD_NAME\fR) The specified field does not exist. .TP 402 (\fBCODE_UNREADABLE_PR\fR) The \fIPR\fR could not be read. .TP 431 (\fBCODE_GNATS_LOCKED\fR) The database has been locked, and no \fIPR\fRs may be updated until the lock is cleared. .TP 430 (\fBCODE_LOCKED_PR\fR) The \fIPR\fR is locked, and may not be altered until the lock is cleared. .TP 413 (\fBCODE_INVALID_FIELD_CONTENTS\fR) The supplied (or resulting) field contents are not valid for the field. .TP 6xx (\fIinternal error\fR) An internal error occurred, usually because of permission or other filesystem-related problems. The \fIPR\fR may or may not have been altered. .RE .P \fBSUBM\fR Submits a new \fIPR\fR into the database. The supplied text is verified for correctness, and if no problems are found a new \fIPR\fR is created. .RS 0.5i .P The possible responses are: .TP 431 (\fBCODE_GNATS_LOCKED\fR) The database has been locked, and no \fIPR\fRs may be submitted until the lock is cleared. .TP 211 (\fBCODE_SEND_PR\fR) The client should now transmit the new \fIPR\fR text using the normal quoting mechanism. After the \fIPR\fR has been sent, the server will respond with either a 200 (\fBCODE_OK\fR) response indicating that the new PR has been created (and mail sent to the appropriate persons), or one or more error codes listing problems with the new \fIPR\fR text. .RE .TP \fBCHDB\fR <\fIdatabase\fR> [<\fIuserid\fR> [<\fIpassword\fR>]] Switches the current database to the name specified in the command. An optional username or an optional username and password may be given. .RS 0.5i .P The possible responses are: .TP 422 (\fBCODE_NO_ACCESS\fR) The user does not have permission to access the requested database. .TP 417 (\fBCODE_INVALID_DATABASE\fR) The database specified does not exist, or one or more configuration errors in the database were encountered. .TP 210 (\fBCODE_OK\fR) The current database is now \fIdatabase\fR. Any operations performed will now be applied to that database. The user access level for the new database is also returned. .RE .TP \fBDBLS\fR Lists the known set of databases. .RS 0.5i .P The possible responses are: .TP 6xx (\fIinternal error\fR) An internal error was encountered while trying to obtain the list of available databases, usually due to lack of permissions or other filesystem-related problems, or the list of databases is empty. .TP 301 (\fBCODE_TEXT_READY\fR) The list of databases follows, one per line, using the standard quoting mechanism. Only the database names are sent. .RE .TP \fBDBDESC\fR <\fIdatabasename\fR> Returns a human-readable description of the specified database. Responses include: .RS 0.5i .TP 6xx (\fIinternal error\fR) An internal error was encountered while trying to read the list of available databases, usually due to lack of permissions or other filesystem-related problems, or the list of databases is empty. .TP 350 (\fBCODE_INFORMATION\fR) The normal response; the supplied text is the database description. .TP 417 (\fBCODE_INVALID_DATABASE\fR) The specified database name does not have an entry. .RE .TP \fBEXPR\fR <\fIquery expression\fR> Specifies a query expression used to limit which \fIPR\fRs are returned from the \fBQUER\fR command. The expression uses the normal query expression syntax, as described in the manual entry for query-pr(1). .RS 0.5i .P Multiple \fBEXPR\fR commands may be issued; the expressions are boolean \fIAND\fRed together. .P Expressions are cleared by the RSET command. .P Possible responses include: .TP 415 (\fBCODE_INVALID_EXPR\fR) The specified expression is invalid, and could not be parsed. .TP 200 (\fBCODE_OK\fR) The expression has been accepted, and will be used to limit the results returned from \fBQUER\fR. .RE .TP 0.5i \fBQFMT\fR <\fIquery format\fR> Use the specified query format to format the output of the \fBQUER\fR command. The query format may be either the name of a query format known to the server, or an actual query format. .RS 0.5i The possible responses are: .TP 200 (\fBCODE_OK\fR) The normal response, which indicates that the query format is acceptable. .TP 440 (\fBCODE_CMD_ERROR\fR) No query format was supplied. .TP 418 (\fBCODE_INVALID_QUERY_FORMAT\fR) The specified query format does not exist, or could not be parsed. .RE .TP \fBQUER\fR [\fIPR\fR] [\fIPR\fR] [...] Searches the contents of the database for \fIPR\fRs that match the (optional) specified expressions with the \fBEXPR\fR command. If no expressions were specified with \fBEXPR\fR, the entire set of \fIPR\fRs is returned. .RS 0.5i .P If one or more \fIPR\fRs are specified on the commandline, only those \fIPR\fRs will be searched and/or output. .P The format of the output from the command is determined by the query format selected with the \fBQFMT\fR command. .P The possible responses are: .TP 418 (\fBCODE_INVALID_QUERY_FORMAT\fR) A valid format was not specified with the \fBQFMT\fR command prior to invoking \fBQUER\fR. .TP 300 (\fBCODE_PR_READY\fR) One or more \fIPR\fRs will be output using the requested query format. The \fIPR\fR text is quoted using the normal quoting mechanisms for \fIPR\fRs. .TP 220 (\fBCODE_NO_PRS_MATCHED\fR) No \fIPR\fRs met the specified criteria. .RE .TP \fBADMV\fR <\fIfield\fR> <\fIkey\fR> [<\fIsubfield\fR>] Returns an entry from an adm file associated with \fIfield\fR. \fIkey\fR is used to look up the entry in the data file. If \fIsubfield\fR is specified, only the value of that subfield is returned; otherwise, all of the fields in the adm data file are returned, separated by colons (`:'). .RS 0.5i .P The responses are: .TP 410 (\fBCODE_INVALID_FIELD_NAME\fR) The specified field does not exist. .TP 221 (\fBCODE_NO_ADM_ENTRY\fR) An adm entry matching the key was not found, or the field does not have an adm file associated with it. .TP 350 (\fBCODE_INFORMATION\fR) The normal response; the supplied text is the requested field(s). .RE .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. \fBgnatsd\fR cannot service remote databases (tho it might be interesting if it could) so the database is always assumed to be local. .P If \fBGNATSDB\fR is not set and the --database option is not supplied, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 2000, 2003 Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/mkcat.man0000644000175000017500000000463407712014071016504 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 1999, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH mkcat 8 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME mkcat \- create a new GNATS category .SH SYNOPSIS .hy 0 .na .TP .B mkcat [ .BI -d \ databasename | .BI --database= databasename ] .br [ .BI -h | .BI --help ] .ad b .hy 1 .SH DESCRIPTION Scans the database for any new categories, creating new subdirectories in the database directory if any are found. .P This program is mostly obsolete since directories for categories are automatically created as necessary, but is left for histerical reasons. .P mkcat should be run by the GNATS user (by default \fBgnats\fR). .SH OPTIONS .TP .B -d\fR,\fB --database Specifies the database to be scanned for new categories; if no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .TP .B -h\fR,\fB --help Displays a short usage message. .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. If \fBGNATSDB\fR is not set, the database named \fIdefault\fR is used. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 1999, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/mkdb.man0000644000175000017500000000371707712014071016323 0ustar chewiechewie00000000000000.\" Copyright (c) 1999, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH mkdb 8 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME mkdb \- create a new GNATS database .SH SYNOPSIS .hy 0 .na .TP .B mkdb \fIdatabasename\fR .ad b .hy 1 .SH DESCRIPTION Looks up \fIdatabasename\fR in the GNATS \fBdatabases\fR file and creates a database in the location specified there. \fBmkdb\fR creates the directory and populates it with a set of default files copied from the @PREFIX@/share/gnats/defaults directory. .P Note the implications of this: an entry in \fBdatabases\fR must be created before \fBmkdb\fR is run. .P The command should be run as the GNATS user, by default \fBgnats\fR. .SH OPTIONS .TP .B databasename Specifies the name of the database to be created. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 2000, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/pr-edit.man0000644000175000017500000002133607712014071016747 0ustar chewiechewie00000000000000.\" Copyright (c) 2000, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH pr-edit 8 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME pr\-edit \- creates, edits or deletes PRs .SH SYNOPSIS .hy 0 .na .TP .B pr\-edit [\ \fB\-\-lock\fR\=\fIusername\fR\ |\ \fB\-l\fR\ \fIusername\fR\ ] [\ \fB\-\-unlock\fR\ |\ \fB\-u\fR\ ] .br [\ \fB\-\-lockdb\fR\ |\ \fB\-L\fR\ ]\ [\ \fB\-\-unlockdb\fR\ |\ \fB\-U\fR\ ] .br [\ \fB\-\-check\fR\ |\ \fB\-c\fR\ ] [\ \fB\-\-check\-initial\fR\ |\ \fB\-C\fR\ ] .br [\ \fB\-\-submit\fR\ |\ \fB\-s\fR\ ] .br [\ \fB\-\-append\fR\=\fIfield\fR\ |\ \fB\-a\fR\ \fIfield\fR\ ] [\ \fB\-\-replace\fR\=\fIfield\fR\ |\ \fB\-r\fR\ \fIfield\fR\ ] .br [\ \fB\-\-reason\fR\=\fIreason\fR\ |\ \fB\-R\fR\ \fIreason\fR\ ] .br [\ \fB\-\-delete\-pr\fR\ ] .br [\ \fB\-\-process\fR\=\fIprocess\-id\fR\ |\ \fB\-p\fR\ \fIprocess\-id\fR\ ] .br [\ \fB\-\-database\fR\=\fIdatabase\fR\ |\ \fB\-d\fR\ \fIdatabase\fR\ ] .br [\ \fB\-\-filename\fR\=\fIfilename\fR\ |\ \fB\-f\fR\ \fIfilename\fR\ ] .br [\ \fB\-\-version\fR\ |\ \fB\-V\fR\ ] [\ \fB\-\-help\fR\ |\ \fB\-h\fR\ ] .br [\ \fB\-\-user\fR\=\fIusername\fR\ |\ \fB\-v\fR\ \fIusername\fR\ ] .br [\ \fB\-\-passwd\fR\=\fIpassword\fR\ |\ \fB\-w\fR\ \fIpassword\fR\ ] .br [\ \fB\-\-host\fR\=\fIhost\fR\ |\ \fB\-H\fR\ \fIhost\fR\ ] .br [\ \fB\-\-port\fR\=\fIport\fR\ |\ \fB\-P\fR\ \fIport\fR\ ] .br [\ \fB\-\-debug\fR\ |\ \fB\-D\fR\ ] .br [\ \fIPR\fR\ ] .ad b .hy 1 .SH DESCRIPTION \fBpr\-edit\fR can be used to edit an existing \fIPR\fR by either replacing or appending to particular fields within the \fIPR\fR, or providing a new \fIPR\fR to replace the existing one. \fBpr\-edit\fR can also be used to create new \fIPR\fRs from scratch, or delete existing ones. .P \fBpr\-edit\fR also provides miscellaneous services for locking and unlocking \fIPR\fRs, locking or unlocking an entire database, or verifying that proposed \fIPR\fR contents are valid and correct. .SH OPTIONS .TP 0.5i \fB\-\-lockdb\fR,\ \fB\-L\fR Locks the specified database. No PRs may be edited, created or deleted while the database is locked. .LP .RS 0.5i This option is generally used when editing the index file. .RE .TP 0.5i \fB\-\-unlockdb\fR,\ \fB\-U\fR Unlocks the database. No check is made that the invoking user actually had locked the database in the first place; hence, it is possible for anyone to steal a database lock. .TP \fB\-\-check\fR,\ \fB\-c\fR .TP \fB\-\-check\-initial\fR,\ \fB\-C\fR The \fB\-\-check\fR options are used to verify that a proposed \fIPR\fR's field contents are valid. The \fIPR\fR is read in (either from stdin or a file specified with \fB\-\-filename\fR), and its fields are compared against the rules specified by the database configuration of the selected database. Warnings are given for enumerated fields whose contents do not contain one of the required values or fields that do not match required regexps. .P .RS 0.5i \fB\-\-check\-initial\fR is used to verify initial \fIPR\fRs, rather than proposed edits of existing \fIPRs\fR. .RE .TP 0.5i \fB\-\-submit\fR,\ \fB\-s\fR Used to submit a new \fIPR\fR to the database. The \fIPR\fR is read in and verified for content; if the \fIPR\fR is valid as an initial \fIPR\fR, it is then added to the database. .P .RS 0.5i A zero exit code is returned if the submission was successful. Otherwise, the reason(s) for the \fIPR\fR being rejected are printed to stdout, and a non-zero exit code is returned. .RE .P The following options require a \fIPR number\fR to be given. .TP 0.5i \fB\-\-delete\-pr\fR Deletes the specified \fIPR\fR from the database. The \fIPR\fR must be in a closed state, and not locked. .LP .RS 0.5i Only the GNATS user (by default \fBgnats\fR) is permitted to delete \fIPR\fRs. .RE .TP 0.5i \fB\-\-lock\fR\=\fIusername\fR,\ \fB\-l\fR\ \fIusername\fR Locks the \fIPR\fR. \fIusername\fR is associated with the lock, so the system administrator can determine who actually placed the lock on the \fIPR\fR. However, anyone is permitted to remove locks on a \fIPR\fR. .P .RS 0.5i If the optional \fB\-\-process\-id\fR option is also given, that \fIprocess\-id\fR is associated with the lock. .RE .TP 0.5i \fB\-\-unlock\fR,\ \fB\-u\fR Unlocks the \fIPR\fR. .TP \fB\-\-append\fR\=\fIfield\fR,\ \fB\-a\fR\ \fIfield\fR .TP \fB\-\-replace\fR\=\fIfield\fR,\ \fB\-r\fR\ \fIfield\fR \fB\-\-append\fR and \fB\-\-replace\fR are used to append or replace content of a specific field within a \fIPR\fR. The new field content is read in from stdin (or from the file specified with the \fB\-\-filename\fR option), and either appended or replaced to the specified field. The field contents are verified for correctness before the \fIPR\fR is rewritten. .P .RS 0.5i If the edit is successful, a zero exit status is returned. If the edit failed, a non-zero exit status is returned, and the reasons for the failure are printed to stdout. .RE .TP 0.5i \fB\fB\-\-reason\fR\=\fIreason\fR,\ \fB\-R\fR\ \fIreason\fR Certain PR fields are configured in the database configuration to require a short text describing the reason for every change that is made to them. If you edit a PR and change any such fields, you must provide a short text, the \fIreason\fR for the change, through this option. If the option is used and no change-reason requiring field is actually changed, the option has no effect. .RE .TP 0.5i \fI[PR]\fR If only a \fIPR\fR number is specified with no other options, a replacement \fIPR\fR is read in (either from stdin or the file specified with \fB\-\-filename\fR). If the \fIPR\fR contents are valid and correct, the existing \fIPR\fR is replaced with the new \fIPR\fR contents. .P .RS 0.5i If the edit is successful, a zero exit status is returned. If the edit failed, a non-zero exit status is returned, and the reasons for the failure are printed to stdout. .RE .TP 0.5i \fB\-\-database\fR\=\fIdatabase\fR,\ \fB\-d\fR\ \fIdatabase\fR Specifies the database which is to be manipulated. If no database is specified, the database named \fIdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .TP 0.5i \fB\-\-filename\fR\=\fIfilename\fR,\ \fB\-f\fR\ \fIfilename\fR For actions that require reading in a \fIPR\fR or field content, this specifies the name of a file to read. If \fB\-\-filename\fR is not specified, the \fIPR\fR or field content is read in from stdin. .TP 0.5i \fB\-\-version\fR,\ \fB\-V\fR Displays the version number of the program. .TP 0.5i \fB\-\-help\fR,\ \fB\-h\fR Prints a brief usage message. .TP 0.5i \fB\-\-host\fR\=\fIhost\fR,\ \fB\-H\fR\ \fIhost\fR Hostname of the GNATS server. .TP 0.5i \fB\-\-port\fR\=\fIport\fR,\ \fB\-P\fR\ \fIport\fR The port that the GNATS server runs on. .TP 0.5i \fB\-\-user\fR\=\fIusername\fR,\ \fB\-v\fR\ \fIusername\fR Username used when logging into the GNATS server. .TP 0.5i \fB\-\-passwd\fR\=\fIpassword\fR,\ \fB\-w\fR\ \fIpassword\fR Password used when logging into the GNATS server. .TP 0.5i \fB\-\-debug\fR,\ \fB\-D\fR Used to debug network connections. .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database, in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set and the --database option is not supplied, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 2000, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/query-pr.man0000644000175000017500000004504007712014071017165 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 94, 95, 96, 1997, 1999, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .in +0.9i .TH query-pr 1 "August 2003" "GNATS @VERSION@" "GNATS User Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME query-pr \- query problem reports in the GNATS database .SH SYNOPSIS .hy 0 .na .B query\-pr .RS [\fB\-\-output\fR\ \fIfile\fR\ |\ \fB\-o\fR\ \fIfile\fR] .br [\fB\-\-list\-databases\fR] [\fB\-\-list\-fields\fR] [\fB\-\-list\-input\-fields\fR] .br [\fB\-\-responsible\-address\fR\ \fIaddress\fR] .br [\fB\-\-field\-type\fR\ \fItype\fR] .br [\fB\-\-field\-description\fR\ \fIdescription\fR] .br [\fB\-\-valid\-values\fR\ \fIvalues\fR] .br [\fB\-\-format\fR\ \fIformat\fR\ |\ \fB\-f\fR\ \fIformat\fR] .br [\fB\-\-full\fR\ |\ \fB\-F\fR] [\fB\-\-summary\fR\ |\ \fB\-q\fR] .br [\fB\-\-database\fR\ \fIdatabase\fR\ |\ \fB\-d\fR\ \fIdatabase\fR] .br [\fB\-\-and\fR\ |\ \fB\-&\fR] [\fB\-\-or\fR\ |\ \fB\-|\fR] .br [\fB\-\-expr\fR\ \fIexpr\fR] .br [\fB\-\-debug\fR\ |\ \fB\-D\fR] .br [\fB\-\-help\fR\ |\ \fB\-h\fR] [\fB\-\-version\fR\ |\ \fB\-V\fR] .br [\fIPR .\|.\|.\fR] .SS Non-network-mode options: .RS [\fB\-\-print\-sh\-vars\fR] [\fB\-\-print\-directory\-for\-database\fR] .SS Network-mode-only options: .RS [\fB\-\-host\fR\ \fIhost\fR\ |\ \fB\-H\fR\ \fIhost\fR] [\fB\-\-port\fR\ \fIport\fR] [\fB\-\-user\fR\ \fIuser\fR\ |\ \fB\-v\fR\ \fIuser\fR] [\fB\-\-passwd\fR\ \fIpasswd\fR\ |\ \fB\-w\fR\ \fIpasswd\fR] .SS Deprecated Options .RS [\fB\-\-list\-categories\fR\ |\ \fB\-j\fR] [\fB\-\-list\-classes\fR\ |\ \fB\-J\fR] [\fB\-\-list\-responsible\fR\ |\ \fB\-k\fR] [\fB\-\-list\-submitters\fR\ |\ \fB\-l\fR] [\fB\-\-list\-states\fR\ |\ \fB\-T\fR] [\fB\-\-category\fR\ \fIcategory\fR\ |\ \fB\-c\fR\ \fIcategory\fR] [\fB\-\-synopsis\fR\ \fIsynopsis\fR\ |\ \fB\-y\fR\ \fIsynopsis\fR] [\fB\-\-confidential\fR\ \fIconfidential\fR\ |\ \fB\-C\fR\ \fIconfidential\fR] [\fB\-\-multitext\fR\ \fImultitext\fR\ |\ \fB\-m\fR\ \fImultitext\fR] [\fB\-\-originator\fR\ \fIoriginator\fR\ |\ \fB\-O\fR\ \fIoriginator\fR] [\fB\-\-release\fR\ \fIrelease\fR\ |\ \fB\-A\fR\ \fIrelease\fR] [\fB\-\-class\fR\ \fIclass\fR\ |\ \fB\-L\fR\ \fIclass\fR] [\fB\-\-cases\fR\ \fIcases\fR\ |\ \fB\-E\fR\ \fIcases\fR] [\fB\-\-quarter\fR\ \fIquarter\fR\ |\ \fB\-Q\fR\ \fIquarter\fR] [\fB\-\-keywords\fR\ \fIkeywords\fR\ |\ \fB\-K\fR\ \fIkeywords\fR] [\fB\-\-priority\fR\ \fIpriority\fR\ |\ \fB\-p\fR\ \fIpriority\fR] [\fB\-\-responsible\fR\ \fIresponsible\fR\ |\ \fB\-r\fR\ \fIresponsible\fR] [\fB\-\-restricted\fR\ |\ \fB\-R\fR] [\fB\-\-severity\fR\ \fIseverity\fR\ |\ \fB\-e\fR\ \fIseverity\fR] [\fB\-\-skip\-closed\fR\ |\ \fB\-x\fR] [\fB\-\-sql\fR\ |\ \fB\-i\fR] [\fB\-\-sql2\fR\ |\ \fB\-I\fR] [\fB\-\-state\fR\ \fIstate\fR\ |\ \fB\-s\fR\ \fIstate\fR] [\fB\-\-submitter\fR\ \fIsubmitter\fR\ |\ \fB\-S\fR\ \fIsubmitter\fR] [\fB\-\-text\fR\ \fItext\fR\ |\ \fB\-t\fR\ \fItext\fR] [\fB\-\-required\-before\fR\ \fIdate\fR\ |\ \fB\-u\fR\ \fIdate\fR] [\fB\-\-required\-after\fR\ \fIdate\fR\ |\ \fB\-U\fR\ \fIdate\fR] [\fB\-\-arrived\-before\fR\ \fIdate\fR\ |\ \fB\-b\fR\ \fIdate\fR] [\fB\-\-arrived\-after\fR\ \fIdate\fR\ |\ \fB\-a\fR\ \fIdate\fR] [\fB\-\-modified\-before\fR\ \fIdate\fR\ |\ \fB\-B\fR\ \fIdate\fR] [\fB\-\-modified\-after\fR\ \fIdate\fR\ |\ \fB\-M\fR\ \fIdate\fR] [\fB\-\-closed\-before\fR\ \fIdate\fR\ |\ \fB\-z\fR\ \fIdate\fR] [\fB\-\-closed\-after\fR\ \fIdate\fR\ |\ \fB\-Z\fR\ \fIdate\fR] .ad b .hy 1 .SH DESCRIPTION Queries the .B GNATS database according to options and returns either selected Problem Reports (\fIPR\fRs) or other requested information. \fBquery-pr\fR can query \fIPR\fRs located in either a local database or via \fBgnatsd\fR. .LP \fIPR\fRs may be selected via the use of the \fB\-\-expr\fR option, directly by number, or by the use of the (now deprecated) field-specific query operators. .LP By default, query options are connected with a logical .BR AND . For example, .RS \fBquery\-pr\fR \fB\-\-category=\fIfoo\fR \fB\-\-responsible=\fIbar\fR .RE only prints PRs which have a \fBCategory\fR field of \fIfoo\fR and a \fBResponsible\fR field of \fIbar\fR. .LP The .B \-\-or option may be used to connect query options with a logical \fBOR\fR. For example, .RS \fBquery\-pr\fR \fB\-\-category=\fIbaz\fR \fB\-\-or\fR \fB\-\-responsible=\fIblee\fR .RE prints PRs which have either a \fBCategory\fR field of \fIbaz\fR \fIor\fR a \fBResponsible\fR field of \fIblee\fR. .LP The use of these options is strongly discouraged, as they will be deleted in the next release. The expressions specified by the \fB\-\-expr\fR option are much more flexible. .SH OPTIONS .TP 0.5i \fB\-\-help\fR,\ \fB\-h\fR Prints a (rather longish) help message. .TP \fB\-\-version\fR,\ \fB\-V\fR Displays the program version to stdout. .TP \fB\-\-output\fR\ \fIfile\fR,\ \fB\-o\fR\ \fIfile\fR The results of the query will be placed in this file. .TP \fB\-\-database\fR\ \fIdatabase\fR,\ \fB\-d\fR\ \fIdatabase\fR Specifies the database to be used for the query. If no database is specified, the database named \fIdefault\fR is assumed. (This option overrides the database specified in the \fBGNATSDB\fR environment variable; see the \fBENVIRONMENT VARIABLES\fR section for more information.) .TP \fB\-\-list\-categories\fR,\ \fB\-j\fR Lists the available \fIPR\fR categories for the selected database. .TP \fB\-\-list\-classes\fR,\ \fB\-J\fR Lists the available \fIPR\fR classes for the selected database. .TP \fB\-\-list\-responsible\fR,\ \fB\-k\fR Lists the users that appear in the database's responsible list. .TP \fB\-\-list\-submitters\fR,\ \fB\-l\fR Lists the valid submitters for this database. .TP \fB\-\-list\-states\fR,\ \fB\-T\fR Lists the valid \fIPR\fR states for \fIPR\fRs in this database. .PP The previous \fB\-\-list-*\fR options are deprecated and will be removed in the next release; their functionality can be replaced with .RE .PP .RS 1.5i \fBquery-pr\fR \fB\-\-valid-values\fR \fIfield\fR .RE .PP where \fIfield\fR is one of \fBCategory\fR, \fBClass\fR, \fBResponsible\fR, \fBSubmitter-Id\fR, or \fBState\fR. .TP \fB\-\-list\-databases\fR Lists the known databases. .TP \fB\-\-list\-fields\fR Lists the entire set of field names for \fIPR\fRs in the selected database. .TP \fB\-\-list\-input\-fields\fR Lists the fields that should be provided when creating a new \fIPR\fR for the currently-specified database. The fields are listed in an order that would make sense when used in a template or form. .TP \fB\-\-field\-type\fR\ \fIfield\fR Returns the data type contained in \fIPR\fR field \fIfield\fR. The current set of data types includes \fBtext\fR, \fBmultitext\fR, \fBenum\fR, \fBmultienum\fR, \fBinteger\fR, \fBdate\fR, and \fBtext-with-regex-qualifier\fR. .TP \fB\-\-field\-description\fR\ \fIfield\fR Returns a human-readable description of the intended purpose of \fIfield\fR. .TP \fB\-\-valid\-values\fR\ \fIfield\fR For fields of type \fBenum\fR, a list of valid values (one per line) is returned. Otherwise, a regular expression is returned that describes the legal values in \fIfield\fR. .TP \fB\-\-responsible\-address\fR\ \fIname\fR The mail address of \fIname\fR is returned; \fIname\fR is assumed to be a name either appearing in the database's \fBresponsible\fR list, or is otherwise a user on the system. .TP \fB\-\-print\-sh\-vars\fR A set of \fI/bin/sh\fR variables is returned that describe the selected database. They include: .RS .TP GNATSDB The name of the currently-selected database. .TP GNATSDB_VALID Set to 1 if the selected database is valid. .TP GNATSDBDIR The directory where the database contents are stored. .TP DEBUG_MODE Set to 1 if debug mode has been enabled for the database. .TP DEFAULTCATEGORY The default category for \fIPR\fRs in the database. .TP DEFAULTSTATE The default state for \fIPR\fRs in the database. .RE .TP \fB\-\-print\-directory\-for\-database\fR Returns the directory where the selected database is located. .TP \fB\-\-format\fR\ \fIformat\fR,\ \fB\-f\fR\ \fIformat\fR Used to specify the format of the output \fIPR\fRs, See FORMATS below for a complete description. .TP \fB\-\-full\fR,\ \fB\-F\fR When printing \fIPR\fRs, the entre PR is displayed. This is exactly equivalent to .PP .RS 1i \fBquery-pr\fR \fB\-\-format\fR \fBfull\fR .RE .TP \fB\-\-summary\fR,\ \fB\-q\fR When printing \fIPR\fRs, a summary format is used. This is exactly equivalent to .PP .RS 1i \fBquery-pr\fR \fB\-\-format\fR \fBsummary\fR .RE .TP \fB\-\-debug\fR,\ \fB\-D\fR Enables debugging output for network queries. .TP \fB\-\-host\fR\ \fIhost\fR,\ \fB\-H\fR\ \fIhost\fR Specifies the hostname of the \fBgnatsd\fR server to communicate with. This overrides the value in the \fBGNATSDB\fR environment variable. .TP \fB\-\-port\fR\ \fIport\fR Specifies the port number of the \fBgnatsd\fR server to communicate with. This overrides the value in the \fBGNATSDB\fR environment variable. .TP \fB\-\-user\fR\ \fIuser\fR,\ \fB\-v\fR\ \fIuser\fR Specifies the username to login with when connecting to the \fBgnatsd\fR server. This overrides the value in the \fBGNATSDB\fR environment variable. .TP \fB\-\-passwd\fR\ \fIpasswd\fR,\ \fB\-w\fR\ \fIpasswd\fR Specifies the password to login with when connecting to the \fBgnatsd\fR server. This overrides the value in the \fBGNATSDB\fR environment variable. .TP \fB\-\-and\fR,\ \fB\-&\fR, \fB\-\-or\fR,\ \fB\-|,\fR These options are used when connecting multiple query operators together. They specify whether the previous and subsequent options are to be logically \fBAND\fRed or logically \fBOR\fRed. .TP \fB\-\-expr\fR\ \fIexpr\fR Specifies a query expression to use when searching for PRs. See the \fBQUERY EXPRESSIONS\fR section. .PP The remaining deprecated options are not described here, since their use is fairly obvious and their functionality is completely replaced by the use of the \fB\-\-expr\fR option. (Some sort of shorthand option for querying fields may appear in the next release.) .SH FORMATS Printing formats for \fIPR\fRs are in one of three forms: .TP \fBformatname\fR This is a \fInamed format\fR which is described by the database (specifically, these formats are described in the \fIdbconfig\fR file associated with the database). The default configuration contains five such formats: \fIstandard\fR, \fIfull\fR, \fIsummary\fR, \fIsql\fR, and \fIsql2\fR. .PP .RS The first three are the ones most commonly used when performing queries. \fIstandard\fR is the format used by default if no other format is specified. .PP Use of the latter two are discouraged; they are merely kept for historical purposes. .PP Other named formats may have been added by the database administrator. .RE .TP \fBfieldname\fR A single field name may appear here. Only the contents of this field will be displayed. .TP \'"\fIprintf string\fR" \fIfieldname\fR \fIfieldname\fR . . .\' This provides a rather flexible mechanism for formatting \fIPR\fR output. (The formatting is identical to that provided by the named formats described by the database configuration.) The printf string can contain the following % sequences: .PP .RS \fB%[positionalspecifiers]s\fR: Prints the field as a string. The positional specifiers are similar to those of printf, as +, - and digit qualifiers can be used to force a particular alignment of the field contents. .PP \fB%[positionalspecifiers]S\fR: Similar to %s, except that the field contents are terminated at the first space character. .PP \fB%[positionalspecifiers]d\fR: Similar to %s, except that the field contents are written as a numeric value. For integer fields, the value is written as a number. For enumerated fields, the field is converted into a numeric equivalent (i.e. if the field can have two possible values, the result will be either 1 or 2). For date fields, the value is written as seconds since Jan 1, 1970. .PP \fB%F\fR: The field is written as it would appear within a \fIPR\fR, complete with field header. .PP \fB%D\fR: For date fields, the date is written in a standard GNATS format. .PP \fB%Q\fR: For date fields, the date is written in an arbitrary "SQL" format. .PP An example printf formatted query (note the quoting of the whole format specification): .PP query-pr --format '"%s, %s" Synopsis State' .RE .SH QUERY EXPRESSIONS Query expressions are used to select specific \fIPR\fRs based on their field contents. The general form is .P .RS \fIfieldname\fR|"\fIvalue\fR" \fIoperator\fR \fIfieldname\fR|"\fIvalue\fR" [\fIbooleanop\fR ...] .RE .P \fIvalue\fR is a literal string or regular expression; it must be surrounded by double quotes, otherwise it is interpreted as a \fIfieldname\fR. .P \fIfieldname\fR is the name of a field in the \fIPR\fR. .P \fIoperator\fR is one of: .TP \fI=\fR The value of the left-hand side of the expression must exactly match the regular expression on the right-hand side of the expression. .TP \fI~\fR Some portion of the left-hand side of the expression must match the regular expression on the right-hand side. .TP \fI==\fR The value of the left-hand side must be equal to the value on the right-hand side of the expression. .RS .PP The equality of two values depends on what type of data is stored in the field(s) being queried. For example, when querying a field containing integer values, literal strings are interpreted as integers. The query expression .P .RS Number == "0123" .RE .P is identical to .P .RS Number == "123" .RE .P as the leading zero is ignored. If the values were treated as strings instead of integers, then the two comparisons would return different results. .RE .TP \fI!=\fR The not-equal operator. Produces the opposite result of the \fI==\fR operator. .TP \fI<\fR,\fI>\fR The left-hand side must have a value less than or greater than the right-hand side. Comparisons are done depending on the type of data being queried; in particular, integer fields and dates use a numeric comparison, and enumerated fields are ordered depending on the numeric equivalent of their enumerated values. .PP \fIbooleanop\fR is either | [or], or & [and]. The query expression .RS Category="baz" | Responsible="blee" .RE is identical to the second query example with \fB\-\-or\fR given earlier; it selects all \fIPR\fRs with a Category field of \fIbaz\fR or a Responsible field of \fIblee\fR. .PP The not operator \fI!\fR may be used to negate a test: .RS ! Category="foo" .RE searches for \fIPR\fRs where the category is \fInot\fR equal to the regular expression \fIfoo\fR. .PP Parenthesis may be used to force a particular interpretation of the expression: .RS !(Category="foo" & Submitter-Id="blaz") .RE skips \fIPR\fRs where the \fBCategory\fR field is equal to \fIfoo\fR and the \fBSubmitter-Id\fR field is equal to \fIblaz\fR. Parenthesis may be nested to any arbitrary depth. .P Fieldnames can be specified in several ways. The simplest and most obvious is just a name: .RS Category="foo" .RE checks the value of the category field for the value "foo". .P A fieldname qualifier may be prepended to the name of the field; a colon is used to separate the qualifier from the name. To refer directly to a builtin field name: .P .RS builtin:Number="123" .RE .P In this case, \fINumber\fR is interpreted as the builtin name of the field to check. (This is useful if the fields have been renamed. For more discussion of builtin field names, see dbconfig(5).) .P To scan all fields of a particular type, the \fIfieldtype\fR qualifier may be used: .P .RS fieldtype:Text="bar" .RE .P searches all text fields for the regular expression \fIbar\fR. .P Note that it is not necessary that the right-hand side of the expression be a literal string. To query all \fIPR\fRs where the \fIPR\fR has been modified since it was closed, the expression .P .RS Last-Modified != Closed-Date .RE .P will work; for each \fIPR\fR, it compares the value of its Last-Modified field against its Closed-Date field, and returns those \fIPR\fRs where the values differ. However, this query will also return all \fIPR\fRs with empty Last-Modified or Closed-Date fields. To further narrow the search: .P .RS Last-Modified != Closed-Date & Last-Modified != "" & Closed-Date != "" .RE .P In general, comparing fields of two different types (an integer field against a date field, for example) will probably not do what you want. .P Also, a field specifier may be followed by the name of a subfield in braces: .P .RS State[type] != "closed" .RE .P or even .P .RS builtin:State[type] != "closed" .RE .P Subfields are further discussed in dbconfig(5). .SH QUERY BY MAIL .B query-pr can also be accessed by electronic mail, if your version of GNATS is configured for this. To use this feature, simply send mail to the address .BI query-pr@ your-site with command line arguments or options in the .B Subject: line of the mail header. GNATS replies to your mail with the results of your query. The default settings for the .B query-pr mail server are shown below; to override the .B \-\-state parameter, specify .BI \-\-state= state in the .B Subject: line of the mail header. You can not query on confidential Problem Reports by mail. .TP 1i .B \-\-restricted \-\-state="open|analyzed|feedback|suspended" .SH ENVIRONMENT VARIABLES The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. .P For network access via \fIgnatsd\fR, it contains a colon-separated list of strings that describe the remote database in the form .TP \fIserver\fR:\fIport\fR:\fIdatabasename\fR:\fIusername\fR:\fIpassword\fR .P Any of the fields may be omitted except for \fIserver\fR, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. .P If \fBGNATSDB\fR is not set, it is assumed that the database is local and that its name is \fIdefault\fR. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 94, 95, 96, 1997, 1999, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/queue-pr.man0000644000175000017500000000705407712014071017147 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH queue-pr 8 "August 2003" "GNATS @VERSION@" "GNATS Administration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME queue-pr \- incoming mail control for GNATS .SH SYNOPSIS .hy 0 .na .TP 1i .B queue-pr [ .B \-q \fR|\fB\ \-\-queue ] [ .B \-r \fR|\fB \-\-run ] .br [ .B \-f \fIfilename\fB \fR|\fB \-\-file=\fIfilename\fR ] .br [ .B \-m \fIkbytes\fB \fR|\fB \-\-max-size=\fIkbytes\fR ] .br [ .B \-d \fIdatabase\fB \fR|\fB \-\-database=\fIdatabase\fR ] .br [ .B \-h \fR|\fB \-\-help ] [ .B \-V \fR|\fB \-\-version ] .ad b .hy 1 .SH DESCRIPTION .B `queue-pr -q' should run through a .BR pipe (2V) via the mail .BR aliases (5) mechanism to automatically place incoming bug reports in a queue directory for .B GNATS. .LP Run .B `queue-pr -r' via .BR cron (8) to periodically empty the .B GNATS queue, filing new bug reports in the database. .LP Always use one of .B \-q \fR|\fB \-\-queue or .B \-r \fR|\fB \-\-run (but not both), in each call to .B queue-pr. These are mutually exclusive functions in order to avoid collisions. .SH OPTIONS .TP 1i .B \-q, \-\-queue Accept standard input as an incoming mail message, placing this message in an incrementally numbered file in the database subdirectory \fBgnats-queue\fR for future handling. .TP .B \-r, \-\-run Redirect files from the database subdirectory \fBgnats-queue\fR to .BR file-pr (8) which files and creates index entries for each. .TP .B \-f \fIfilename\fR or \fB\-\-file=\fIfilename\fR Treat .I filename as input rather than reading from standard input (used with the .B \-\-queue option). .TP .B \-m \fIkbytes\fR, \fB\-\-max-size\fR=\fIkbytes\fR Do not process messages larger than \fikbytes\fR kilobytes in size. Files larger than the limit are left for human intervention. .TP .B \-d \fIdatabase\fR or \fB\-\-database=\fIdatabasename\fR Used with the .B \-\-queue or .B \-\-run options, use the database named .I database rather than the database \fIdefault\fR or the database specified by the .B GNATSDB environment variable. .TP .B -h\fR,\fB --help Displays a short usage message. .TP .B -V\fR,\fB --version Displays the \fBqueue-pr\fR version number. .SH "ENVIRONMENT VARIABLES" The \fBGNATSDB\fR environment variable is used to determine which database to use. For a local database, it contains the name of the database to access. If \fBGNATSDB\fR is not set, the database named \fIdefault\fR is used. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/man/rmcat.man0000644000175000017500000000343107712014071016505 0ustar chewiechewie00000000000000.\" Copyright (c) 1993, 2000, 2003 Free Software Foundation, Inc. .\" See section COPYING for conditions for redistribution .TH rmcat 8 "August 2003" "GNATS @VERSION@" "GNATS Admininstration Utilities" .de BP .sp .ti -.2i \(** .. .SH NAME rmcat \- remove GNATS categories .SH SYNOPSIS .hy 0 .na .TP .B rmcat .I category [ .I category... ] .ad b .hy 1 .SH DESCRIPTION Removes any named .I category from the .B GNATS installation. Before calling .BR rmcat , you must first remove .I category from the list of categories in the database. You must also reclassify or remove all problem reports associated with .I category (i.e., .IR category 's subdirectory must be empty). .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH COPYING Copyright (c) 1993, 2000, 2003, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/doc/ChangeLog0000600000175000017500000005205310212661676015705 0ustar chewiechewie000000000000002005-03-06 Chad Walstrom * gnats-faq.texi: Updated reference to latest release and copyright notice. Added "or greater" to version references to 4.0. 2004-11-18 Chad Walstrom * Makefile.in: Fixed VERSION environment variable assignment, using @PACKAGE_VERSION@ 2004-11-17 Chad Walstrom * configure.in, configure.ac: configure.in renamed to configure.ac. Updated to 2.59 format. Updated version to 4.1.0. * configure: Regenerated. 2004-09-05 Hans-Albert Schneider * gnats-faq.texi: Replace mailto: links to the lists by links to lists.gnu.org. Let's hope this reduces spam a bit. 2004-06-11 Chad Walstrom * man/Makefile.in, man/getclose.man: Added new manpage * Makefile.in, man/Makefile.in: Prepended the $(DESTDIR) variable to all destination targets. This will help with building distribution packages. Moved mkinstalldir calls to install targets. 2004-06-03 Hans-Albert Schneider * gnats-faq.texi: Some remarks that 3.113.1 is deprecated, and that 4.0 has been released. Encourage upgrading. New section on upgrading. 2003-08-30 Andrew J. Gray * gnats.texi: Update for changes in SUBM command responses. * p-admin.texi: Add description of --show-prnum option for pr-edit. 2003-07-30 Yngve Svendsen * man/Makefile.in, man/databases.man, man/dbconfig.man, man/delete-pr.man, man/edit-pr.man, man/file-pr.man, man/gen-index.man, man/gnats.man, man/gnatsd.man, man/mkcat.man, man/mkdb.man, man/pr-edit.man, man/query-pr.man, man/queue-pr.man, man/rmcat.man: Replace 2002 in all copyright notices with 2003 (there were no official releases of GNATS in 2002). Change publication date of all man pages to August 2003. * gnats.texi: Change year in copyright notices from 2002 to 2003, change publication date to August 2003, remove the table showing which chapters have been rewritten for GNATS 4. 2003-07-27 Andrew J. Gray * Makefile.in (VERSION): Increased to 4.0. 2003-06-11 Hans-Albert Schneider * gnats-faq.texi: Some cleanup and polishing: Make sure there is something after every "::". (Mailing lists): Removed references to old mailing-list addresses. (Append-only Audit-Trail): Removed this section; it is now in the manual. (Gnatsweb): added back reference from the cookies section to the "Login Not Remembered" problem. 2003-06-05 Hans-Albert Schneider * gnats-faq.texi: Gnatsweb 2.9.x and GNATS 3.999.x do not cooperate. Spell-checked the file. 2003-05-01 Yngve Svendsen * gnats.texi: "Overall access levels per host" and "Access levels per user": Explain why wildcard entries must be placed near the end of the gnatsd.xxxx_access files. 2003-03-07 Andrew J. Gray * p-usage.texi: Update subject header regular expression to match that used in code; patch by Lars Henriksen . 2003-01-27 Hans-Albert Schneider * gnats-faq.texi: Added example for the queue-pr cron job. 2002-12-12 Yngve Svendsen * fields-texi, p-usage.texi, s-usage-texi: Add a new section ``Following up via direct e-mail'' to the Editing existing Problem Reports section. Sprinkle references to it throughout. Change the node name belonging to ``The Problem Report template''. All due to Lars Henriksen. 2002-11-27 Yngve Svendsen * p-admin.texi: Update the list of builtin fields. Several were missing. * p-admin.texi: Emphasize the fact that all built-in fields must be have corresponding definitions in the dbconfig file. 2002-11-25 Yngve Svendsen * gnats.texi: Manual now dated November, add 2002 to copyright statement. 2002-11-24 Andrew J. Gray * Makefile.in (VERSION): Increased to 4.0-beta2. 2002-11-04 Yngve Svendsen * p-admin.texi: Fix indentation problem in gen-index usage summary. * man/ : Rewrite all man pages for GNATS 4. - man/Makefile.in (SRCS7, (SRCS8): Substitute @PREFIX@. 2002-11-03 Yngve Svendsen * categ.texi: Remove. No longer relevant. 2002-10-31 Yngve Svendsen * p-admin.texi: Warn people that they may need to set category dir permissions to 755 if they have users running query-pr etc. locally, i.e. not through gnatsd. 2002-10-29 Yngve Svendsen * gnats.texi, gnatsd.man: Document the new InitialRequiredFields argument to LIST. 2002-10-27 Hans-Albert Schneider * p-inst.texi: Mention renaming of gnatsd.access to gnatsd.user_access. 2002-10-27 Yngve Svendsen * p-inst.texi, p-admin.texi, gnats.texi: Cleanup, improved consistency in the ``Where GNATS lives'' chapter. Minor formatting fixes. Thanks to Lars Henriksen. 2002-10-26 Yngve Svendsen * Document the per-field on-change require functionality of dbconfig. Patch by Lars Henriksen. 2002-10-25 Yngve Svendsen * p-inst.texi: State that Texinfo v4.2 or newer is required to install GNATS. 2002-10-24 Yngve Svendsen * s-usage.texi (Invoking send-pr from the shell): Undocument the removed --cc | -c option. It is gone and has been replaced by the Notify-List functionality. * fields.texi (Problem Report fields): Describe the new Notify-List field. 2002-10-24 Andrew J. Gray * p-admin.texi (Initial PR input fields): Add "require" parameter to "initial-entry" fields; patch by Mel Hatzis . 2002-10-24 Yngve Svendsen * p-inst.texi: Tell upgraders from release-based GNATS 3 installations to add the field definitions mentioned below. * gnats.texi: Add definitions for the removed release-based GNATS 3 fields Quarter, Keywords and Required-Date to the dbconfig recipes appendix, together with the pre-release version 4 GNATS field Cases. * gnats.texi, p-usage.texi, fields.texi: Minor formatting fixes, changed all field names from being typeset as @samp to @code -- too many apostrophes make my eyes hurt. * s-usage.texi: Fully cleaned up and updated for GNATS 4.0. 2002-10-23 Yngve Svendsen * p-usage: Minor formatting corrections. * fields.texi: Cross reference send-pr.conf section. * s-usage.texi: Finally started work on cleaning it up for GNATS4. 2002-10-21 Yngve Svendsen * gnats.texi: Add a new appendix, `dbconfig recipes'. 2002-10-15 Yngve Svendsen * p-inst.texi (Installing the user tools): Flesh out the instructions. * p-inst.texi (Installing the daemon): Remove the server_args line from the xinetd config, as suggested by Anders Johnson. Add spaces around the equals signs between keywords and values. 2002-10-14 Yngve Svendsen * p-admin.texi (The states file): Rewrite this section to comply with the way states are defined in GNATS 4. Fix some typos. * gnats.texi: Rephrase some of the treatment of states. * gnats.texi (Regexps): Fix typo in example query with 'State="open"' vs. 'State="o"'. Fix due to Tom Koelman. * gnatsd.man, gnats.texi: Remove `Classes' as a valid argument to the LIST command. This parameter was removed because "class" is no longer a built-in field. In order to list classes, you have to use the command "fvld class", just as for all other non-builtin fields. * gnatsd.man: Amend descriptions of CHDB and USER commands to allow for blank passwords. Correct the stated CODE_OK number from 220 to 210. Say that CHDB now also returns the user access level. 2002-10-02 Hans-Albert Schneider * gnats-faq.texi: New sections 'How to pronounce it', 'Append-only Audit-Trail', 'Outgoing mail bounces' 2002-09-25 Yngve Svendsen * p-usage.texi (query-pr): Explicitly say that the whole format string must be quoted. Provide a very simple example. 2002-09-24 Yngve Svendsen * query-pr.man (FORMATS): Explicitly say that the whole format string must be quoted. 2002-07-28 Milan Zamazal * p-admin.texi (queue-pr): --max-size documented. 2002-07-21 Hans-Albert Schneider * gnats-faq.texi: New sections 'Changing Fields' and 'Upgrading' (the latter currently @ignore-d). 2002-07-14 Milan Zamazal * gnats-faq.texi: gnatsd.access -> gnatsd.user_access. * gnats.texi: Likewise. * p-admin.texi: Likewise. * p-inst.texi: Likewise. 2002-05-21 Milan Zamazal * Makefile.in (distclean): Remove '#*'. (mostlyclean): Remove backup files in `distclean'. (distclean): Call the clean on `man/' too. * man/Makefile.in (realclean): Renamed to `maintainer-clean'. (distclean): Remove backup files. 2002-05-20 Milan Zamazal * fields.texi: Colons removed from index entries. * s-usage.texi: Likewise. * p-usage.texi (Environment): Index entry for GNATSDB added. * gnats.texi (gnatsd environment variables): Index entry and a cross reference for GNATSDB added. 2002-04-01 Yngve Svendsen * p-inst.texi (Installing the user tools): Edited and fleshed out the sections on remote tool installation. 2002-03-31 Yngve Svendsen * p-inst.texi (Installing the user tools): Add "User tools on a local network" in complete form, and "User tools for remote users" in outline form. The latter needs more work, but should work as a stop-gap for now. 2002-03-31 Yngve Svendsen * p-admin.texi, p-inst.texi: Document the send-pr.conf file. 2002-03-31 Yngve Svendsen * p-admin.texi (Field datatypes, enumerated-in-file): Mention the Category field as an example of an enumerated-in-file field. * p-usage.texi (Invoking query-pr): Add descriptions of the field-flags, adm-field, adm-subfield and adm-key options. 2002-03-19 Yngve Svendsen * gnats-faq.texi (Add a database): Remove some garbage at the end of the @node line. This would prevent makeinfo from doing its thing properly. Also change @subsubheading to @subsection, so makeinfo won't get confused about document structure. 2002-02-17 Hans-Albert Schneider * gnats-faq.texi: New file. * Makefile.in: Added gnats-faq.* to various targets. 2002-01-13 Milan Zamazal * p-usage.texi (Invoking query-pr): Format the list of --print-sh-vars variables as a table. (Invoking query-pr): --print-server-addr documented. * emacs.texi (Other Emacs commands): gnats-show-connection documented. (Other Emacs commands): unlock-database documented. 2002-01-10 Milan Zamazal * Makefile.in (GNATS_SOURCES): Don't prefix `version.texi' with `srcdir'; fixes PR gnats/323. 2002-01-07 Milan Zamazal * emacs.texi (Emacs querying): gnats-query-reverse-listing documented. (Emacs submitting): Typo fixed. (Emacs submitting): User variables documented. (Emacs querying): New query-pr key documented. 2002-01-06 Milan Zamazal * Makefile.in (clean): Remove *.ps and *.pdf too. (DVIPS, TEXI2PDF): New variables. (ps, gnats.ps): New targets. (pdf, gnats.pdf): New targets. * man/Makefile.in ($(SRCS1), $(SRCS5), $(SRCS7), $(SRCS8)): Create the man directories. 2001-12-27 Milan Zamazal * Makefile.in (VERSION): Increased to 4.0-beta1. (clean): Don't remove Info files. (maintainer-clean): Remove Info files. (mostlyclean): Remove garbage files created by editors and patch. (distclean): Remove `Makefile'. (Makefile): New target. (version.texi): Depend on `Makefile'. 2001-12-26 Milan Zamazal * gnats.texi (Support): Minor grammar fix. * emacs.texi (Emacs): Use @code instead of @kbd for command names. (Emacs querying, Emacs editing buffer): Written. (Emacs editing): gnats-edit-mode-hook moved to `Emacs editing buffer'. (Emacs): `GNATS [34]' wrapped by @w. (Other Emacs commands): Minor wording fix. 2001-12-23 Milan Zamazal * p-admin.texi (Audit-trail formats, Outgoing email formats): The source of $EditUserEmailAddr documented. * gnats.texi (Access Control): /usr/local/etc -> /etc. (gnatsd.access): A few clarifications about clear text passwords. (gnatsd.access): Relationship between user and host access levels documented. (gnatsd commands): EDITADDR documented. 2001-12-15 Milan Zamazal * emacs.texi: Document structure defined. Most subsections written. * gnats.texi (Suppport): New section. * Makefile.in (GNATS_SOURCES): emacs.texi added. 2001-12-12 Yngve Svendsen * p-admin.texi: Clean up the `defaults' stuff in the treatment of the multi-enumerated-in-file field type. Note that `separators' keyword has to come last. 2001-12-11 Milan Zamazal * Makefile.in: send-pr.texi vaporated. * emacs.texi: New manual part (to be written). * p-usage.texi (GNATS user tools): `view-pr' table item removed. (GNATS user tools): `Emacs' added to the menu and `emacs.texi' included. * send-pr.texi: Removed. * s-usage.texi (using send-pr): Emacs usage updated. (send-pr in Emacs): Updates, most of the text deleted and replace with the reference to the special Emacs manual section. * p-inst.texi (Configure and make): No longer mention send-pr.el. (Configure and make): Elisp files are not byte compiled. (Installing utils): Emacs installation code updated. * gnats.texi (Top): Removed the remark about old Emacs documentation. (defaults): Information about Emacs files updated. 2001-12-08 Lars Henriksen * Makefile.in (gnats.info, gnats.info): Include $(srcdir). (GNATS_SOURCES, SENDPR_SOURCES): Likewise. 2001-12-08 Milan Zamazal * p-admin.texi (Field datatypes): `default' added to `multi-enumerated-in-file'. 2001-12-07 Yngve Svendsen * p-admin.texi: Document where enumerated-in-file and multi-enumerated-in-file fields get their defaults. Be honest in saying that there is currently no way to set multiple default values for the latter type. * p-inst.texi: TkGnats now supports GNATS 4. * gnats.texi: Update chapter status. * gnats.texi (Access levels per user): Treat the different password encryption formats and mention gnats-pwconv. Mention that a gnats-passwd tool is planned. l2001-12-07 Yngve Svendsen * p-admin.texi: Document gnats-pwconv. - gnats.texi: Add gnats-pwconv to the Locations section. - p-inst.texi: Add cross reference to gnats-pwconv. 2001-12-04 Milan Zamazal * p-usage.texi (Invoking query-pr): The no longer pertinent option `--list-classes' removed. 2001-12-04 Yngve Svendsen * p-inst.texi: Provide full instructions for xinetd based systems. Thanks to Jamin W. Collins. * p-inst.texi: Revise installations instructions, based on suggestions by Jamin W. Collins. Specifically: - Say that Emacs is no longer a requirement. - Create the gnats user before configure and make. - Rewrite the mkdb instructions -- they were wrong. * p-admin.texi (dbconfig file): Clarify the use of `|' in mail address lines in mail format definitions. 2001-12-03 Milan Zamazal * p-admin.texi (dbconfig file): Cosmetic fixes of the menu. 2001-12-02 Milan Zamazal * p-admin.texi (mkdb): Change of the `mkdb' argument. (pr-edit): New option `reason'. 2001-11-28 Yngve Svendsen * p-admin.texi: Mention subfields in conjunction with enum-in-file types. 2001-11-19 Yngve Svendsen * p-admin.texi: Defaults in multienums clarified by a short example. 2001-11-15 Yngve Svendsen * p-admin.texi: Document upgrading from GNATS 3 to GNATS 4. 2001-11-09 Milan Zamazal * Makefile.in (install-gnats): The dirfile argument added to the INSTALL_INFO invocation. (uninstall): Likewise. 2001-11-09 Lars Henriksen * Makefile.in (prefix): Added. 2001-11-05 Yngve Svendsen * man/gnatsd.man: Document FTYPINFO. * p-admin.texi: Remove outdated reference to GNATS_ROOT, replace with DATABASEDIR. * p-inst.texi: Rewrite overview to match GNATS 4 installation more closely. * gnats.texi (gnatsd commands): Document FTYPINFO. 2001-10-29 Milan Zamazal * p-admin.texi (at-pr): Documented that the reminders only concern urgent problems. 2001-10-28 Milan Zamazal * gnats.texi (gnatsd commands): Missing dot appended (makeinfo complaint). 2001-10-16 Yngve Svendsen * gnats.texi: DBLS and CHDB were mixed up in the previous commit. Fixed. * gnats.texi (Privileged gnatsd commands, The GNATS network server - gnatsd): Update description of DBLS to mention listdb. 2001-10-14 Milan Zamazal * gnats.texi (Overview): Document the new `listdb' access level. 2001-10-04 Yngve Svendsen * gnats.texi: Fix some inconsistencies in the appendix "Where GNATS lives". 2001-09-18 Milan Zamazal * Makefile.in (install-gnats): Use `$(MAKE)', not `make'; fixes PR gnats/256. 2001-10-02 Yngve Svendsen * fields.texi: Fixes to cross references. 2001-10-01 Yngve Svendsen * gnats.texi, fields.texi, states.texi: Revised chapter 1 of the manual. fields.texi needs a bit more work, it currently does not mention the Cases, Keywords, Quarter and Release-Note fields. 2001-09-28 Yngve Svendsen * gnats.texi: New appendix documenting gnatsd added. Some cross references added all-round, and some minor formatting bugs and typos corrected 2001-09-17 Yngve Svendsen * p-usage.texi: The sections on edit-pr and query-pr rewritten for GNATS 4, the most important being the addition of query expression documentation. The send-pr part still needs rewriting, and Emacs documentation must be added to all relevant sections. Chapter renamed "The GNATS user tools". * p-admin.texi: Fixed a couple of typos. Inserted some useful cross-references to the new material in p-usage.texi. * gnats.texi: Regexp appendix rewritten for GNATS 4. Reorganized so that GNATS installation is now a chapter, not an appendix. The new organization is meant to more clearly separate the manual into a 'user' and an 'administrator' part. 2001-09-05 Milan Zamazal * Makefile.in (all): Don't depend on `dvi'. 2001-09-04 Milan Zamazal * configure.in: Check for install-info. * configure: Regenerated. * Makefile.in (install-gnats): Install an entry into `dir' file. (uninstall): Uninstall the info entry. (INSTALL_INFO): New variable. 2001-08-29 Milan Zamazal * Makefile.in (all-gnats): New target. (all-tools): New target. (distclean): Remove the files produced during the configure process. 2001-08-07 Milan Zamazal * p-admin.texi (databases file): mkdb with reference mentioned. 2001-08-05 Yngve Svendsen * gnats.texi: Change revision date of manual. * p-inst.texi: Make instructions for adding a new database more visible. Typos fixed. 2001-08-03 Milan Zamazal * p-inst.texi (Setting up the default database): Typos fixed. 2001-07-28 Milan Zamazal * p-inst.texi (Installing the daemon): "Advise" what to do when using other superserver than inetd. * p-admin.texi (check-db): The new option `--all' described. (check-db): The paragraph about locking made more clear. 2001-07-23 Milan Zamazal * p-admin.texi (Field datatypes): `multi-enumerated-in-file' documented. 2001-07-08 Milan Zamazal * gnats.texi: Put table of contents at the beginning of the manual. * p-admin.texi (mkdb): Typographical bug fixed. (addresses file): Use @samp, not @var, for the e-mail formats list. 2001-06-24 Milan Zamazal * man/Makefile.in (install): Replace @GNATS_INSTALL@ by a fixed target. (all): Replace @GNATS_ALL@ by a fixed target. * configure.in: AC_PROG_INSTALL added. * configure: Regenerated. * Makefile.in (.PHONY): `install-gnats' and `install-tools' added. (srcdir): New variable. (INSTALL): New variable. (INSTALL_DATA): New variable. (INSTALL_PROGRAM): New variable. (INSTALL_SCRIPT): New variable. 2001-06-21 Milan Zamazal * configure.in: New file. * configure: Generated. * Makefile.in: New file. * All Texinfo and man files moved here from the `gnats' and `send-pr' directories. gnats-4.1.0/doc/Makefile.in0000644000175000017500000000701210147276501016177 0ustar chewiechewie00000000000000# Makefile for GNU GNATS documentation # Copyright (C) 2001, 2002 Milan Zamazal # Copyright (C) 1993, 2001 Free Software Foundation, Inc. # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. prefix = @prefix@ infodir = @infodir@ srcdir = @srcdir@ INSTALL = $(srcdir)/../install-sh -c INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_INFO = @INSTALL_INFO@ TEXI2DVI = texi2dvi TEXI2PDF = texi2pdf TEXIDIR = $(srcdir)/../texinfo TEXINPUTS = $(srcdir):$(TEXIDIR) DVIPS = dvips VERSION = @PACKAGE_VERSION@ GNATS_SOURCES = $(srcdir)/gnats.texi $(srcdir)/emacs.texi \ $(srcdir)/p-admin.texi $(srcdir)/p-inst.texi \ $(srcdir)/p-usage.texi version.texi FAQ_SOURCES = $(srcdir)/gnats-faq.texi .PHONY: all install install-strip install-gnats install-tools uninstall \ clean distclean mostlyclean maintainer-clean TAGS info dvi dist check all: info man all-gnats: all all-tools: all install: install-gnats install-strip: $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install install-gnats: info man for i in gnats.info* gnats-faq.info*; do \ $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/$$i ; \ done -if [ -x "$(INSTALL_INFO)" ]; then \ $(INSTALL_INFO) $(DESTDIR)$(infodir)/gnats.info $(DESTDIR)$(infodir)/dir; \ $(INSTALL_INFO) $(DESTDIR)$(infodir)/gnats-faq.info $(DESTDIR)$(infodir)/dir; \ fi $(MAKE) -C man install-gnats install-tools: install-gnats uninstall: -if [ -x "$(INSTALL_INFO)" ]; then \ $(INSTALL_INFO) --delete $(DESTDIR)$(infodir)/gnats.info \ $(DESTDIR)$(infodir)/dir; \ $(INSTALL_INFO) --delete $(DESTDIR)$(infodir)/gnats-faq.info \ $(DESTDIR)$(infodir)/dir; \ fi $(MAKE) -C man uninstall mostlyclean: -rm -f *.toc *.log *.vr *.fn *.cp *.tp *.ky *.pg *.i *.s *.aux *.cps $(MAKE) -C man mostlyclean clean: mostlyclean -rm -f *.dvi *.ps *.pdf $(MAKE) -C man clean distclean: clean -rm -f Makefile config.cache config.status config.log -rm -f .\#* \#* *~ -rm -f *.orig *.rej $(MAKE) -C man distclean maintainer-clean: distclean -rm -f *.info* version.texi Makefile: $(srcdir)/Makefile.in config.status ./config.status TAGS: info: gnats.info gnats-faq.info gnats.info: $(GNATS_SOURCES) $(MAKEINFO) -I $(srcdir) -o $@ $< gnats-faq.info: $(FAQ_SOURCES) $(MAKEINFO) -I $(srcdir) -o $@ $< version.texi: Makefile echo "@set VERSION $(VERSION)" > $@-t mv $@-t $@ dvi: gnats.dvi gnats-faq.dvi gnats.dvi: $(GNATS_SOURCES) TEXINPUTS=$(TEXINPUTS) $(TEXI2DVI) $< gnats-faq.dvi: $(FAQ_SOURCES) TEXINPUTS=$(TEXINPUTS) $(TEXI2DVI) $< ps: gnats.ps gnats-faq.ps gnats.ps: gnats.dvi $(DVIPS) -o $@ $< gnats-faq.ps: gnats-faq.dvi $(DVIPS) -o $@ $< pdf: gnats.pdf gnats-faq.pdf gnats.pdf: $(GNATS_SOURCES) TEXINPUTS=$(TEXINPUTS) $(TEXI2PDF) $< gnats-faq.pdf: $(FAQ_SOURCES) TEXINPUTS=$(TEXINPUTS) $(TEXI2PDF) $< man: $(MAKE) -C man dist: check: gnats-4.1.0/doc/configure0000744000175000017500000021146610147021631016041 0ustar chewiechewie00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for gnats-doc 4.1.0. # # Report bugs to . # # Copyright (C) 2003 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 Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='gnats-doc' PACKAGE_TARNAME='gnats-doc' PACKAGE_VERSION='4.1.0' PACKAGE_STRING='gnats-doc 4.1.0' PACKAGE_BUGREPORT='bug-gnats@gnu.org' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA INSTALL_INFO LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # 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. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= 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 ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -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 | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$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 ;; -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 ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) 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 ;; -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=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 ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && 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'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac 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 echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 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 # 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 its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | 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 if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias # # 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 gnats-doc 4.1.0 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 \`..'] _ACEOF cat <<_ACEOF 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] --datadir=DIR read-only architecture-independent data [PREFIX/share] --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] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of gnats-doc 4.1.0:";; esac cat <<\_ACEOF Report bugs to . _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style 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 elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd "$ac_popdir" done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF gnats-doc configure 4.1.0 generated by GNU Autoconf 2.59 Copyright (C) 2003 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 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by gnats-doc $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { 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` hostinfo = `(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=. echo "PATH: $as_dir" done } >&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_sep= 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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$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 ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >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 # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" 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. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 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 `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 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 { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`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. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } 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 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 { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # 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. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_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 ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done 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. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$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' # Extract the first word of "install-info", so it can be a program name with args. set dummy install-info; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_INSTALL_INFO+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $INSTALL_INFO in [\\/]* | ?:[\\/]*) ac_cv_path_INSTALL_INFO="$INSTALL_INFO" # Let the user override the test with a path. ;; *) 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_INSTALL_INFO="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi INSTALL_INFO=$ac_cv_path_INSTALL_INFO if test -n "$INSTALL_INFO"; then echo "$as_me:$LINENO: result: $INSTALL_INFO" >&5 echo "${ECHO_T}$INSTALL_INFO" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi ac_config_files="$ac_config_files Makefile man/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, don't put newlines in cache variables' values. # 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. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *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 \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" 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}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ 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[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $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} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by gnats-doc $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet 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 Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ gnats-doc config.status 4.1.0 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. 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=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; 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 if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; 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 fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@INSTALL_INFO@,$INSTALL_INFO,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac # 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. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;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,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # 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 || { (exit 1); exit 1; } fi gnats-4.1.0/doc/configure.ac0000644000175000017500000000024510147021631016411 0ustar chewiechewie00000000000000AC_PREREQ(2.5) AC_INIT(gnats-doc,4.1.0,bug-gnats@gnu.org) AC_PROG_INSTALL AC_PATH_PROG(INSTALL_INFO,install-info) AC_CONFIG_FILES([Makefile man/Makefile]) AC_OUTPUT gnats-4.1.0/doc/emacs.texi0000644000175000017500000002746207431535606016136 0ustar chewiechewie00000000000000@ignore Copyright (C) 2001, 2002 Milan Zamazal Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to process this file through TeX and print the results, provided the printed document carries a copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions. @end ignore @c *************************************************************************** @node Emacs @section The Emacs interface to @sc{gnats} @cindex Emacs Emacs interface to @sc{gnats} provides basic access to @sc{gnats} databases, i.e. sending, editing, and querying Problem Reports. It also defines a simple major mode for editing @file{dbconfig} files. This section provides an overview of using @sc{gnats} with Emacs. It does not describe the use of Emacs itself, for detailed instructions on using Emacs, see @ref{Top,,,emacs,GNU Emacs}. For installation instructions of the @sc{gnats} Emacs mode, see @ref{Installing utils}. Please note the Emacs interface was completely rewritten between @w{@sc{gnats} 3} and @w{@sc{gnats} 4}. It now uses @code{gnatsd}, @ref{gnatsd}, exclusively for its operations and uses modern Emacs features like faces. Its features are not complete though, you can send your suggestions and patches to the appropriate @sc{gnats} mailing list, @ref{Support}. @menu * Emacs viewing:: Viewing PRs by their number. * Emacs querying:: Querying the database. * Emacs submitting:: Submitting new PRs. * Emacs editing:: Editing PRs. * Emacs editing buffer:: The editing buffer. * Emacs and databases:: Changing the working database. * dbconfig mode:: Major mode for dbconfig files. * Other Emacs commands:: Miscellaneous commands. * Emacs customization:: Customizing the Emacs interface. @end menu @node Emacs viewing @subsection Viewing Problem Reports @cindex @code{view-pr} To view a particular Problem Report, use the command @kbd{M-x view-pr}. It asks for a Problem Report number and displays that Problem Report. @cindex @code{gnats-view-edit-pr} The displayed buffer is put in the view mode, @ref{Misc File Ops,,,emacs,GNU Emacs}. If you decide to edit the displayed Problem Report, use the command @kbd{e} (@code{gnats-view-edit-pr}). @table @code @cindex @code{gnats-view-mode-hook} @item gnats-view-mode-hook Hook run when @code{gnats-view-mode} is entered. @end table @node Emacs querying @subsection Querying Problem Reports @cindex @code{query-pr} Querying the database is performed by the @kbd{M-x query-pr} command. The command prompts for the query expression, @ref{Query expressions}, and displays a buffer with the list of the matching Problem Reports. The list of the Problem Reports is displayed in the @samp{summary} query format, @ref{Formatting query-pr output}. Currently, the display format cannot be changed and it must output each Problem Report's number in the first column. The Problem Report list buffer is put in the view mode, @ref{Misc File Ops,,,emacs,GNU Emacs}. You can use most of the standard view mode commands in it. Additionally, the following special commands are available: @table @kbd @cindex @code{gnats-query-view-pr} @item v @itemx RET @itemx mouse-2 View the current Problem Report (@code{gnats-query-view-pr}), @ref{Emacs viewing}. @cindex @code{gnats-query-edit-pr} @item e Edit the current Problem Report (@code{gnats-query-edit-pr}), @ref{Emacs editing}. @cindex @code{gnats-query-reread} @item g Update the Problem Report list (@code{gnats-query-reread}). The last performed query is executed again and the buffer is filled with the new results. @cindex @code{query-pr} @item G Perform new query (@code{query-pr}). @cindex @code{send-pr} @item s Send new Problem Report (@code{send-pr}), @ref{Emacs submitting}. @cindex @code{gnats-change-database} @item D Change the current database (@code{gnats-change-database}), @ref{Emacs and databases}. @cindex @code{bury-buffer} @item q Bury buffer, the buffer is put at the end of the list of all buffers. This is useful for quick escape of the buffer, without killing it. @end table @cindex @var{gnats-query-reverse-listing} If the value of the variable @var{gnats-query-reverse-listing} is non-@code{nil}, the listing appears in the reversed order, i.e. with the Problem Reports of the highest number first, in the buffer. Similarly to other @sc{gnats} Emacs modes, there is a hook available for the Problem Report list. @table @code @cindex @code{gnats-query-mode-hook} @item gnats-query-mode-hook Hook run when @code{gnats-query-mode} is entered. @end table @node Emacs submitting @subsection Submitting new Problem Reports @cindex @code{send-pr} You can submit new Problem Reports with the command @kbd{M-x send-pr}. The command puts you to the problem editing buffer, @ref{Emacs editing}. The buffer is prefilled with the initial report fields and their default values, if defined. You can use the usual Problem Report editing commands, @ref{Emacs editing}. When you have filled in all the fields, you can send the Problem Report by presing @kbd{C-c C-c}. If you run @kbd{M-x send-pr} with a prefix argument, it runs the @code{gnats-change-database} command before putting you to the editing buffer, @ref{Emacs and databases}. You can set the following variables to get some fields pre-filled: @table @var @cindex @var{gnats-default-organization} @item gnats-default-organization Default value of the @samp{Organization} field used in new Problem Reports. @cindex @var{gnats-default-submitter} @item gnats-default-submitter Default value of the @samp{Submitter-Id} field used in new Problem Reports. @end table @node Emacs editing @subsection Editing Problem Reports @cindex @code{edit-pr} To edit a particular Problem Report, use the command @kbd{M-x edit-pr}. It asks for a Problem Report number and puts the given Problem Report in the editing buffer. @xref{Emacs editing buffer}, for information how to edit the Problem Report in the buffer and how to submit your changes. Note you can also start editing of a selected Problem Report directly from within the viewing buffer, @ref{Emacs viewing}, or the query result buffer, @ref{Emacs querying}. @node Emacs editing buffer @subsection The Problem Report editing buffer When you invoke a Problem Report editing command, the Problem Report is put into a special editing buffer. The Problem Report is formatted similarly to the @code{query-pr -F} output, @ref{Formatting query-pr output}. Field identifiers are formatted as @example >Field: @end example with the text of the field following the identifier on the same line for single-line fields or starting on the next line for multi-line fields. The Problem Report editing mode tries to prevent you from violating the Problem Report format and the constraints put on the possible field values. Generally, you can use usual editing commands, some of them have a slightly modified behavior though. (If you encounter a very strange behavior somewhere, please report it as a bug, @ref{Support}.) @cindex @code{gnats-next-field} @cindex @code{gnats-previous-field} You can move between fields easily by pressing the @kbd{TAB} (@code{gnats-next-field}) or @kbd{M-TAB} (@code{gnats-previous-field}) keys. The field tags are read-only and you cannot edit them nor delete them. If you want to ``remove'' a field, just make its value empty. Editing a field value depends on the type of the edited field, @ref{Field datatypes}. For text fields, you can edit the value directly, assuming you preserve the rule about single-line and multi-line values mentioned above. For enumerated fields, you cannot edit the value directly. You can choose it from the list of the allowed values, either from the menu popped up by pressing the middle mouse button or from within minibuffer by pressing any key on the field's value. If the pressed key matches any of the allowed field values, that value is put as the default value after the minibuffer prompt. You can also cycle through the allowed field values directly in the editing buffer using the @code{SPACE} key. Enumerated field values are marked by a special face to not confuse you; you must have enabled font lock mode to benefit from this feature, @ref{Font Lock,,,emacs,GNU Emacs}. Some field values can be read-only, you cannot edit them at all. @cindex @code{gnats-apply-or-submit} Once you have edited the Problem Report as needed, you can send it to the server with the @kbd{C-c C-c} command (@code{gnats-apply-or-submit}). Successful submission is reported by a message and the buffer modification flag in mode line is cleared. Then you can either kill the buffer or continue with further modifications. @table @code @cindex @code{gnats-edit-mode-hook} @item gnats-edit-mode-hook Hook run when @code{gnats-edit-mode} is entered. @end table @node Emacs and databases @subsection Changing the database @cindex @code{gnats-change-database} By default, the Emacs interface connects to the default database, @ref{databases file}. If you want to connect to another database, use the command @kbd{M-x gnats-change-database}. It will ask you for the database name to use, server and port it can be accessed on, and your login name. @cindex gnatsd, Emacs If you want to use the @command{gnatsd} command, @ref{gnatsd}, directly, without connecting to a remote server or the localhost connection port, provide your local file system full path to @command{gnatsd} as the server name. Port number does not matter in this case. @cindex password, Emacs If the database requires a password to allow you the access to it, you are prompted for the password the first time you connect to the database. If you provide an invalid password, you cannot connect to the database anymore and you have to run the @kbd{M-x gnats-change-database} command again. @node dbconfig mode @subsection dbconfig mode @cindex dbconfig mode @cindex @code{gnats-dbconfig-mode} The Emacs interface defines a simple major mode @code{gnats-dbconfig-mode} for editing @file{dbconfig} files, @ref{dbconfig file}. It defines basic mode attributes like character syntax and font lock keywords, it does not define any special commands now. @table @code @cindex @code{gnats-dbconfig-mode-hook} @item gnats-dbconfig-mode-hook Hook run when @code{gnats-dbconfig-mode} is entered. @end table @node Other Emacs commands @subsection Other commands @table @kbd @cindex @code{unlock-pr} @item M-x unlock-pr Ask for a Problem Report number and unlock that Problem Report. This function is useful if connection to a @sc{gnats} server was interrupted during an editing operation and further modifications of the Problem Report are blocked by a stealth lock. @cindex @code{unlock-database} @item M-x unlock-database Unlock the whole @sc{gnats} database. This function is useful in situations similar to when @code{unlock-pr} is used. @cindex @code{gnats-show-connection} @item M-x gnats-show-connection Show the connection buffer associated with the current buffer. You can view the Emacs communication with @sc{gnatsd} in it. This is useful when something strange happens during the communication with the server, e.g. when sending a Problem Report with @kbd{C-c C-c} from a Problem Report editing buffer. @end table @node Emacs customization @subsection Customization All the user variables can be customized in the customization group @code{gnats}, @ref{Easy customization,,,emacs,GNU Emacs}. gnats-4.1.0/doc/fields.texi0000644000175000017500000004127707576116306016316 0ustar chewiechewie00000000000000@node Fields @section Problem Report format @cindex Problem Report format @cindex format @cindex database similarities @cindex fields The format of a PR is designed to reflect the nature of @sc{gnats} as a database. Information is arranged into @dfn{fields}, and kept in individual records (Problem Reports). A Problem Report contains two different types of fields: @dfn{Mail Header} fields, which are used by the mail handler for delivery, and @dfn{Problem Report} fields, which contain information relevant to the Problem Report and its submitter. A Problem Report is essentially a specially formatted electronic mail message. Problem Report fields are denoted by a keyword which begins with @samp{>} and ends with @samp{:}, as in @samp{>Confidential:}. Fields belong to one of eight data types as listed in @ref{Field datatypes reference}. As of version 4 of @sc{gnats} all characteristics of fields, such as field name, data type, allowed values, permitted operations, on-change actions etc. are configurable. @ifclear SENDPR For details, see @pxref{dbconfig file,,The @code{dbconfig} file}. @end ifclear @ifclear SENDPR @subheading Example Problem Report @end ifclear The following is an example Problem Report with the fields that would be present in a standard @sc{gnats} configuration. Mail headers are at the top, followed by @sc{gnats} fields, which begin with @samp{>} and end with @samp{:}. The @samp{Subject:} line in the mail header and the @code{Synopsis} field are usually duplicates of each other. @cindex sample Problem Report @cindex example Problem Report @cindex Problem Report template @cartouche @smallexample @group Message-Id: @var{message-id} Date: @var{date} From: @var{address} Reply-To: @var{address} To: @var{bug-address} Subject: @var{subject} >Number: @var{gnats-id} >Category: @var{category} >Synopsis: @var{synopsis} >Confidential: yes @emph{or} no >Severity: critical, serious, @emph{or} non-critical >Priority: high, medium @emph{or} low >Responsible: @var{responsible} >State: open, analyzed, suspended, feedback, @emph{or} closed >Class: sw-bug, doc-bug, change-request, support, @ifset SENDPR @emph{or} duplicate @end ifset @ifclear SENDPR duplicate, @emph{or} mistaken @end ifclear >Submitter-Id: @var{submitter-id} >Arrival-Date: @var{date} >Originator: @var{name} >Organization: @var{organization} >Release: @var{release} >Environment: @var{environment} >Description: @var{description} >How-To-Repeat: @var{how-to-repeat} >Fix: @var{fix} >Audit-Trail: @var{appended-messages@dots{}} State-Changed-From-To: @var{from}-@var{to} State-Changed-When: @var{date} State-Changed-Why: @var{reason} Responsible-Changed-From-To: @var{from}-@var{to} Responsible-Changed-When: @var{date} Responsible-Changed-Why: @var{reason} >Unformatted: @var{miscellaneous} @end group @end smallexample @end cartouche @menu * Field datatypes reference:: * Mail header fields:: * Problem Report fields:: @end menu @node Field datatypes reference @subsection Field datatypes reference The following is a short reference to the characteristics of the different field types. @ifclear SENDPR For details, see @ref{Field datatypes}. @end ifclear @table @code @item text A one-line text string. @item multitext Multiple lines of text. @item enum The value in this field is required to be from a list of specified values, defined at the Support Site. @ifclear SENDPR (@xref{dbconfig file,,The @code{dbconfig} file}, for details. @end ifclear @item multienum Similar to the @code{enum} datatype, except that the field can contain multiple values. @item enumerated-in-file Similar to @code{enum}, but the allowed field values are listed in a separate file on the @sc{gnats} server. @item multi-enumerated-in-file Similar to @code{enumerated-in-file}, except that the field can contain multiple values. @item date Used to hold dates. @item integer Used to hold integer numbers. @end table @c ---------------------- @node Mail header fields @subsection Mail header fields @cindex mail header fields @cindex Internet standard RFC-822 A Problem Report may contain any mail header field described in the Internet standard RFC-822. The @code{send-pr} tool can be configured either to submit PRs to the support site by e-mail or by talking directly to the @code{gnatsd} network daemon on the @sc{gnats} server. This is also true for other client tools such as Gnatsweb. Even when these tools are set up submit PRs directly to @code{gnatsd}, they will still include mail header fields that identify the sender and the subject in the submitted PR: @table @code @cindex @code{To} header @item To: The mail address for the Support Site, automatically supplied by the tool used to submit the PR or by the originator if plain e-mail was used. @cindex @code{Subject} header @item Subject: A terse description of the problem. This field normally contains the same information as the @code{Synopsis} field. @cindex @code{From} header @item From: Supplied automatically when PRs are submitted by plain e-mail and when well-behaved tools such as @code{send-pr} are used; should always contain the originator's e-mail address. @cindex @code{Reply-To} header @item Reply-To: A return address to which electronic replies can be sent; in most cases, the same address as the @code{From:} field. @end table @ifclear SENDPR @cindex @code{Received-By} headers One of the configurable options for @sc{gnats} is whether or not to retain @w{@code{Received-By}} headers, which often consume a lot of space and are not often used. @xref{dbconfig file,,The dbconfig file}. @end ifclear @c ---------------------- @node Problem Report fields @subsection Problem Report fields @cindex GNATS database fields @cindex field format @c FIXME - this node is loooooooooooooooong... In a standard @sc{gnats} installation, certain fields will always be present in a Problem Report. If a PR arrives without one or more of these fields, @sc{gnats} will add them, and if they have default values set by the configuration at the Support Site, they will be filled in with these values. Certain tools such as @code{send-pr} are set up to provide sensible defaults for most fields (@pxref{send-pr.conf file,,The send-pr.conf configuration file}.) In the list below, the field type (@code{text}, @code{multitext}, @code{enumerated}, etc.) is supplied in parantheses. The different field types are explained briefly in @ref{Field datatypes reference}. @cindex fields - list @cindex GNATS fields - list @table @code @cindex @code{Submitter-Id} field @item Submitter-Id (@code{enumerated-in-file}) A unique identification code assigned by the Support Site. It is used to identify all Problem Reports coming from a particular site. Submitters without a value for this field can invoke @code{send-pr} with the @code{--request-id} option to apply for one from the support organization. Problem Reports from those not affiliated with the support organization should use the default value of @samp{net} for this field. @ifclear SENDPR @xref{submitters file,,The @code{submitters} file}, for details. @end ifclear @cindex @code{Notify-List} field @item Notify-List (@code{text}) Comma-separated list of e-mail-addresses of people to notify when the PR changes significantly, i.e. when the Audit-Trail changes. This list is independent from the Notify subfield of entries in the @file{categories} file of the @sc{gnats} database. @cindex @code{Originator} field @item Originator (@code{text}) Originator's real name. Note that the Submitter and Originator might not be the same person/entity in all cases. @cindex @code{Organization} field @item Organization (@code{multitext}) The originator's organization. @cindex @code{Confidential} field @cindex confidentiality in PRs @cindex PR confidentiality @item Confidential (@code{enum}) Use of this field depends on the originator's relationship with the support organization; contractual agreements often have provisions for preserving confidentiality. Conversely, a lack of a contract often means that any data provided will not be considered confidential. Submitters should be advised to contact the support organization directly if this is an issue. If the originator's relationship to the support organization provides for confidentiality, then if the value of this field is @samp{yes} the support organization treats the PR as confidential; any code samples provided are not made publicly available. @cindex @code{Synopsis} field @item Synopsis (@code{text}) One-line summary of the problem. @w{@code{send-pr}} copies this information to the @code{Subject} line when you submit a Problem Report. @cindex @code{Severity} field @item Severity (@code{enum}) The severity of the problem. By default, accepted values include: @table @code @cindex @emph{critical} severity problems @item critical The product, component or concept is completely non-operational or some essential functionality is missing. No workaround is known. @cindex @emph{serious} severity problems @item serious The product, component or concept is not working properly or significant functionality is missing. Problems that would otherwise be considered @samp{critical} are usually rated @samp{serious} when a workaround is known. @cindex @emph{non-critical} severity problems @item non-critical The product, component or concept is working in general, but lacks features, has irritating behavior, does something wrong, or doesn't match its documentation. @end table @cindex @code{Priority} field @item Priority (@code{enumerated}) How soon the originator requires a solution. Accepted values include: @table @code @cindex @emph{high} priority problems @item high A solution is needed as soon as possible. @cindex @emph{medium} priority problems @item medium The problem should be solved in the next release. @cindex @emph{low} priority problems @item low The problem should be solved in a future release. @end table @cindex @code{Category} field @item Category (@code{enumerated-in-file}) The name of the product, component or concept where the problem lies. The values for this field are defined by the Support Site. @ifclear SENDPR @xref{categories file,,The @code{categories} file}, for details. @end ifclear @cindex @code{Class} field @item Class (@code{enumerated-in-file}) The class of a problem in a default @sc{gnats} installation can be one of the following: @table @code @cindex @emph{sw-bug} class @item sw-bug A general product problem. (@samp{sw} stands for ``software''.) @cindex @emph{doc-bug} class @item doc-bug A problem with the documentation. @cindex @emph{change-request} class @item change-request A request for a change in behavior, etc. @cindex @emph{support} class @item support A support problem or question. @cindex @emph{duplicate} class @item duplicate (@var{pr-number}) Duplicate PR. @var{pr-number} should be the number of the original PR. @ifclear SENDPR @cindex @emph{mistaken} class @item mistaken No problem, user error or misunderstanding. This value can only be set by tools at the Support Site, since it has no meaning for ordinary submitters. @end ifclear @end table @ifclear SENDPR @xref{classes file,,The @code{classes} file}, for details. @end ifclear @cindex @code{Release} field @item Release (@code{text}) Release or version number of the product, component or concept. @cindex @code{Environment} field @item Environment (@code{multitext}) Description of the environment where the problem occurred: machine architecture, operating system, host and target types, libraries, pathnames, etc. @cindex @code{Description} field @item Description (@code{multitext}) Precise description of the problem. @cindex @code{How-To-Repeat} field @item How-To-Repeat (@code{multitext}) Example code, input, or activities to reproduce the problem. The support organization uses example code both to reproduce the problem and to test whether the problem is fixed. Include all preconditions, inputs, outputs, conditions after the problem, and symptoms. Any additional important information should be included. Include all the details that would be necessary for someone else to recreate the problem reported, however obvious. Sometimes seemingly arbitrary or obvious information can point the way toward a solution. See also @ref{Helpful hints,,Helpful hints}. @cindex @code{Fix} field @item Fix (@code{multitext}) A description of a solution to the problem, or a patch which solves the problem. (This field is most often filled in at the Support Site; we provide it to the submitter in case he or she has solved the problem.) @end table @noindent @sc{gnats} adds the following fields when the PR arrives at the Support Site: @table @code @cindex @code{Number} field @item Number (@code{enumerated}) The incremental identification number for this PR. @ifclear SENDPR This is included in the automated reply to the submitter (if that feature of @sc{gnats} is activated; @pxref{dbconfig file,,The @file{dbconfig} file}). It is also included in the copy of the PR that is sent to the maintainer. @end ifclear The @code{Number} field is often paired with the @code{Category} field as @smallexample @var{category}/@var{number} @end smallexample @noindent in subsequent email messages. This is @sc{gnats}' way of tracking followup messages that arrive by mail so that they are filed as part of the original PR. @cindex @code{State} field @item State (@code{enumerated}) The current state of the PR. In default @sc{gnats} installations, accepted values are: @table @code @item open The PR has been filed and the responsible person notified. @item analyzed The responsible person has analyzed the problem. @item feedback The problem has been solved, and the originator has been given a patch or other fix. Support organizations may also choose to temporarily ''park'' PRs that are awaiting further input from the submitter under this state. @item closed The changes have been integrated, documented, and tested, and the originator has confirmed that the solution works. @item suspended Work on the problem has been postponed. @end table @noindent The initial state of a PR is @samp{open}. @xref{States,,States of Problem Reports}. @cindex @code{Responsible} field @item Responsible (@code{text}) The person at the Support Site who is responsible for this PR. @ifclear SENDPR @sc{gnats} retrieves this information from the @file{categories} file (@pxref{categories file,,The @code{categories} file}). @end ifclear @cindex @code{Arrival-Date} field @item Arrival-Date (@code{date}) The time that this PR was received by @sc{gnats}. The date is provided automatically by @sc{gnats}. @cindex @code{Date-Required} @cindex @code{Date-Required} field @item Date-Required (@code{date}) The date by which a fix is required. This is up to the maintainers at the Support Site to determine, so this field is not available until after the PR has been submitted. @cindex @code{Audit-Trail} field @item Audit-Trail (@code{multitext}) Tracks related electronic mail as well as changes in the @code{State} and @code{Responsible} fields with the sub-fields: @table @code @cindex @code{State-Changed--} in @code{Audit-Trail} @item @w{State-Changed--: @var{oldstate}>-<@var{newstate}} The old and new @code{State} field values. @cindex @code{Responsible-Changed--} in @code{Audit-Trail} @item @w{Responsible-Changed--: @var{oldresp}>-<@var{newresp}} The old and new @code{Responsible} field values. @cindex @code{State-Changed-By} in @code{Audit-Trail} @cindex @code{Responsible-Changed-By} in @code{Audit-Trail} @item State-Changed-By: @var{name} @itemx Responsible-Changed-By: @var{name} The name of the maintainer who effected the change. @cindex @code{State-Changed-When} in @code{Audit-Trail} @cindex @code{Responsible-Changed-When} in @code{Audit-Trail} @item State-Changed-When: @var{timestamp} @itemx Responsible-Changed-When: @var{timestamp} The time the change was made. @cindex @code{State-Changed-Why} in @code{Audit-Trail} @cindex @code{Responsible-Changed-Why} in @code{Audit-Trail} @item State-Changed-Why: @var{reason@dots{}} @itemx Responsible-Changed-Why: @var{reason@dots{}} The reason for the change. @end table @cindex follow-up via email @cindex subsequent mail @cindex related mail @noindent The @code{Audit-Trail} field also contains any mail messages received by @sc{gnats} related to this PR, in the order received. @sc{gnats} needs to find a reference to the PR in the Subject field of received email in order to be able to file it correctly, see @ref{follow-up via email,, Following up via direct email}. @cindex @code{Unformatted} field @item Unformatted (@code{multitext}) Any random text found outside the fields in the original Problem Report. @end table During a Problem Report's journey from @samp{open} to @samp{closed}, two more fields, @code{Last-Modified} and @code{Closed Date} (both of type @code{date}) will be added. gnats-4.1.0/doc/flowchart.eps0000644000175000017500000004547307314462227016655 0ustar chewiechewie00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: flowchart.eps %%Creator: fig2dev Version 3.2 Patchlevel 3c %%CreationDate: Sun Feb 25 16:43:39 2001 %%For: pdm@blackbird (Milan Zamazal) %%BoundingBox: 0 0 312 407 %%Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save newpath 0 407 moveto 0 0 lineto 312 0 lineto 312 407 lineto closepath clip newpath -38.0 419.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /reencdict 12 dict def /ReEncode { reencdict begin /newcodesandnames exch def /newfontname exch def /basefontname exch def /basefontdict basefontname findfont def /newfont basefontdict maxlength dict def basefontdict { exch dup /FID ne { dup /Encoding eq { exch dup length array copy newfont 3 1 roll put } { exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall newfont /FontName newfontname put newcodesandnames aload pop 128 1 255 { newfont /Encoding get exch /.notdef put } for newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat newfontname newfont definefont pop end } def /isovec [ 8#055 /minus 8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde 8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis 8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron 8#220 /dotlessi 8#230 /oe 8#231 /OE 8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling 8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis 8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot 8#255 /hyphen 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus 8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph 8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine 8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf 8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute 8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring 8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute 8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute 8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve 8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply 8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex 8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave 8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring 8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute 8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute 8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve 8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide 8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex 8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def /Times-Roman /Times-Roman-iso isovec ReEncode /Courier /Courier-iso isovec ReEncode /Times-Bold /Times-Bold-iso isovec ReEncode /Times-BoldItalic /Times-BoldItalic-iso isovec ReEncode /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def $F2psBegin %%Page: 1 1 10 setmiterlimit 0.06299 0.06299 sc % % Fig objects follow % % Polyline 15.000 slw n 735 2160 m 630 2160 630 6510 105 arcto 4 {pop} repeat 630 6615 5385 6615 105 arcto 4 {pop} repeat 5490 6615 5490 2265 105 arcto 4 {pop} repeat 5490 2160 735 2160 105 arcto 4 {pop} repeat cp gs col7 0.90 shd ef gr gs col0 s gr % Polyline n 2523 225 m 2418 225 2418 1245 105 arcto 4 {pop} repeat 2418 1350 3686 1350 105 arcto 4 {pop} repeat 3791 1350 3791 330 105 arcto 4 {pop} repeat 3791 225 2523 225 105 arcto 4 {pop} repeat cp gs col7 0.75 shd ef gr gs col0 s gr % Polyline n 768 225 m 663 225 663 1245 105 arcto 4 {pop} repeat 663 1350 1931 1350 105 arcto 4 {pop} repeat 2036 1350 2036 330 105 arcto 4 {pop} repeat 2036 225 768 225 105 arcto 4 {pop} repeat cp gs col7 0.75 shd ef gr gs col0 s gr % Polyline n 4255 225 m 4150 225 4150 1245 105 arcto 4 {pop} repeat 4150 1350 5418 1350 105 arcto 4 {pop} repeat 5523 1350 5523 330 105 arcto 4 {pop} repeat 5523 225 4255 225 105 arcto 4 {pop} repeat cp gs col7 0.75 shd ef gr gs col0 s gr % Polyline 7.500 slw n 870 2700 m 765 2700 765 6375 105 arcto 4 {pop} repeat 765 6480 5250 6480 105 arcto 4 {pop} repeat 5355 6480 5355 2805 105 arcto 4 {pop} repeat 5355 2700 870 2700 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr /Times-Bold-iso ff 180.00 scf sf 4410 2925 m gs 1 -1 sc (GNATS) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline 15.000 slw n 2610 2857 m 3285 2857 l 3285 3105 l 2610 3105 l cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 150.00 scf sf 2947 3015 m gs 1 -1 sc (gnatsd) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 1080 3397 m 3150 3397 l 3150 3622 l 1080 3622 l cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 135.00 scf sf 2115 3547 m gs 1 -1 sc (DATABASEDIR/gnats-queue/) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 1140 2835 m 1035 2835 1035 3000 105 arcto 4 {pop} repeat 1035 3105 2010 3105 105 arcto 4 {pop} repeat 2115 3105 2115 2940 105 arcto 4 {pop} repeat 2115 2835 1140 2835 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 150.00 scf sf 1575 2992 m gs 1 -1 sc (queue-pr -q) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 1140 3915 m 1035 3915 1035 4080 105 arcto 4 {pop} repeat 1035 4185 2010 4185 105 arcto 4 {pop} repeat 2115 4185 2115 4020 105 arcto 4 {pop} repeat 2115 3915 1140 3915 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 150.00 scf sf 1575 4072 m gs 1 -1 sc (queue-pr -r) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 900 5895 m 5220 5895 l 5220 6345 l 900 6345 l cp gs col7 1.00 shd ef gr gs col0 s gr /Times-Bold-iso ff 150.00 scf sf 3060 6075 m gs 1 -1 sc (GNATS Database) dup sw pop 2 div neg 0 rm col0 sh gr /Courier-iso ff 135.00 scf sf 3060 6255 m gs 1 -1 sc (DATABASEDIR/category/PR-number) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 2295 3937 m 4815 3937 l 4815 4162 l 2295 4162 l cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 135.00 scf sf 3555 4087 m gs 1 -1 sc (DATABASEDIR/pending/PR-number) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 4470 5355 m 4365 5355 4365 5520 105 arcto 4 {pop} repeat 4365 5625 5070 5625 105 arcto 4 {pop} repeat 5175 5625 5175 5460 105 arcto 4 {pop} repeat 5175 5355 4470 5355 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 150.00 scf sf 4770 5512 m gs 1 -1 sc (query-pr) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 3255 5355 m 3150 5355 3150 5520 105 arcto 4 {pop} repeat 3150 5625 3765 5625 105 arcto 4 {pop} repeat 3870 5625 3870 5460 105 arcto 4 {pop} repeat 3870 5355 3255 5355 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 150.00 scf sf 3510 5527 m gs 1 -1 sc (edit-pr) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 3285 2295 m 4230 2295 l 4230 2565 l 3285 2565 l cp gs col7 1.00 shd ef gr gs col0 s gr /Times-BoldItalic-iso ff 150.00 scf sf 3757 2482 m gs 1 -1 sc (administrator) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 4410 2295 m 5265 2295 l 5265 2565 l 4410 2565 l cp gs col7 1.00 shd ef gr gs col0 s gr /Times-BoldItalic-iso ff 150.00 scf sf 4837 2482 m gs 1 -1 sc (maintainers) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 3840 4500 m 3735 4500 3735 4665 105 arcto 4 {pop} repeat 3735 4770 4350 4770 105 arcto 4 {pop} repeat 4455 4770 4455 4605 105 arcto 4 {pop} repeat 4455 4500 3840 4500 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 150.00 scf sf 4095 4672 m gs 1 -1 sc (edit-pr) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 810 2317 m 1890 2317 l 1890 2542 l 810 2542 l cp gs col7 1.00 shd ef gr gs col0 s gr /Courier-iso ff 135.00 scf sf 1350 2475 m gs 1 -1 sc (/etc/aliases) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline n 2019 2238 m 2886 2238 l 2886 2441 l 2019 2441 l cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 1005 4365 m 900 4365 900 5610 105 arcto 4 {pop} repeat 900 5715 2415 5715 105 arcto 4 {pop} repeat 2520 5715 2520 4470 105 arcto 4 {pop} repeat 2520 4365 1005 4365 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline 7.500 slw gs clippath 2910 4170 m 2850 4170 l 2850 4281 l 2880 4206 l 2910 4281 l cp eoclip n 2115 5040 m 2880 5040 l 2880 4185 l gs col0 s gr gr % arrowhead 15.000 slw n 2910 4281 m 2880 4206 l 2850 4281 l 2880 4266 l 2910 4281 l cp gs 0.00 setgray ef gr col0 s % Polyline 7.500 slw gs clippath 4065 4515 m 4125 4515 l 4125 4415 l 4095 4490 l 4065 4415 l cp eoclip n 4095 4185 m 4095 4500 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 4065 4415 m 4095 4490 l 4125 4415 l 4095 4430 l 4065 4415 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 4065 5910 m 4125 5910 l 4125 5810 l 4095 5885 l 4065 5810 l cp eoclip n 4095 4770 m 4095 5895 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 4065 5810 m 4095 5885 l 4125 5810 l 4095 5825 l 4065 5810 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 3525 5910 m 3585 5910 l 3585 5810 l 3555 5885 l 3525 5810 l cp eoclip n 3555 5625 m 3555 5895 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 3525 5810 m 3555 5885 l 3585 5810 l 3555 5825 l 3525 5810 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 4800 5610 m 4740 5610 l 4740 5710 l 4770 5635 l 4800 5710 l cp eoclip n 4770 5895 m 4770 5625 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 4800 5710 m 4770 5635 l 4740 5710 l 4770 5695 l 4800 5710 l cp gs 0.00 setgray ef gr col0 s % Polyline [60] 0 sd gs clippath 4440 4605 m 4440 4665 l 4540 4665 l 4465 4635 l 4540 4605 l cp eoclip n 3780 2565 m 3780 3825 l 4905 3825 l 4905 4635 l 4455 4635 l gs col0 s gr gr [] 0 sd % arrowhead n 4540 4605 m 4465 4635 l 4540 4665 l 4525 4635 l 4540 4605 l cp gs col7 1.00 shd ef gr col0 s % Polyline [60] 0 sd gs clippath 5070 2550 m 5010 2550 l 5010 2650 l 5040 2575 l 5070 2650 l cp eoclip n 5040 2565 m 5040 5355 l gs col0 s gr gr [] 0 sd % arrowhead n 5070 2650 m 5040 2575 l 5010 2650 l 5040 2635 l 5070 2650 l cp gs col7 1.00 shd ef gr col0 s % Polyline [60] 0 sd gs clippath 3525 5370 m 3585 5370 l 3585 5270 l 3555 5345 l 3525 5270 l cp eoclip n 5040 2565 m 5040 5040 l 3555 5040 l 3555 5355 l gs col0 s gr gr [] 0 sd % arrowhead n 3525 5270 m 3555 5345 l 3585 5270 l 3555 5285 l 3525 5270 l cp gs col7 1.00 shd ef gr col0 s /Times-Roman-iso ff 150.00 scf sf 1620 5625 m gs 1 -1 sc (Yes) col0 sh gr /Times-Roman-iso ff 150.00 scf sf 2250 4995 m gs 1 -1 sc (No) col0 sh gr /Courier-iso ff 150.00 scf sf 2070 4545 m gs 1 -1 sc (file-pr) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline 15.000 slw n 2767 427 m 3442 427 l 3442 652 l 2767 652 l cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 2664 894 m 2559 894 2559 1070 105 arcto 4 {pop} repeat 2559 1175 3546 1175 105 arcto 4 {pop} repeat 3651 1175 3651 999 105 arcto 4 {pop} repeat 3651 894 2664 894 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 1012 427 m 1687 427 l 1687 652 l 1012 652 l cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 909 894 m 804 894 804 1070 105 arcto 4 {pop} repeat 804 1175 1791 1175 105 arcto 4 {pop} repeat 1896 1175 1896 999 105 arcto 4 {pop} repeat 1896 894 909 894 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 1027 1575 m 922 1575 922 1785 105 arcto 4 {pop} repeat 922 1890 1627 1890 105 arcto 4 {pop} repeat 1732 1890 1732 1680 105 arcto 4 {pop} repeat 1732 1575 1027 1575 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 4499 427 m 5174 427 l 5174 652 l 4499 652 l cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 4396 894 m 4291 894 4291 1070 105 arcto 4 {pop} repeat 4291 1175 5278 1175 105 arcto 4 {pop} repeat 5383 1175 5383 999 105 arcto 4 {pop} repeat 5383 894 4396 894 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline n 4402 1575 m 4297 1575 4297 1785 105 arcto 4 {pop} repeat 4297 1890 5272 1890 105 arcto 4 {pop} repeat 5377 1890 5377 1680 105 arcto 4 {pop} repeat 5377 1575 4402 1575 105 arcto 4 {pop} repeat cp gs col7 1.00 shd ef gr gs col0 s gr % Polyline 7.500 slw gs clippath 3120 2850 m 3180 2850 l 3180 2750 l 3150 2825 l 3120 2750 l cp eoclip n 4275 1755 m 3150 1755 l 3150 2835 l gs col0 s gr gr % arrowhead n 3120 2750 m 3150 2825 l 3180 2750 l 3150 2765 l 3120 2750 l cp gs 0.00 setgray ef gr col0 s % Polyline [60] 0 sd gs clippath 4890 1875 m 4830 1875 l 4830 1975 l 4860 1900 l 4890 1975 l cp eoclip n 4860 2295 m 4860 1890 l gs col0 s gr gr [] 0 sd % arrowhead n 4890 1975 m 4860 1900 l 4830 1975 l 4860 1960 l 4890 1975 l cp gs col7 1.00 shd ef gr col0 s % Polyline [60] 0 sd gs clippath 4665 1875 m 4605 1875 l 4605 1975 l 4635 1900 l 4665 1975 l cp eoclip n 3780 2295 m 3780 2025 l 4635 2025 l 4635 1890 l gs col0 s gr gr [] 0 sd % arrowhead n 4665 1975 m 4635 1900 l 4605 1975 l 4635 1960 l 4665 1975 l cp gs col7 1.00 shd ef gr col0 s /Times-Roman-iso ff 150.00 scf sf 1569 4929 m gs 1 -1 sc (valid) dup sw pop 2 div neg 0 rm col0 sh gr /Times-Roman-iso ff 150.00 scf sf 1569 5280 m gs 1 -1 sc (?) dup sw pop 2 div neg 0 rm col0 sh gr /Courier-iso ff 120.00 scf sf 1569 5105 m gs 1 -1 sc (>Category:) dup sw pop 2 div neg 0 rm col0 sh gr /Times-Bold-iso ff 150.00 scf sf 2040 2385 m gs 1 -1 sc (Support Site) col0 sh gr % Polyline gs clippath 1545 2850 m 1605 2850 l 1605 2750 l 1575 2825 l 1545 2750 l cp eoclip n 1575 2565 m 1575 2835 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1545 2750 m 1575 2825 l 1605 2750 l 1575 2765 l 1545 2750 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 1545 3390 m 1605 3390 l 1605 3290 l 1575 3365 l 1545 3290 l cp eoclip n 1575 3105 m 1575 3375 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1545 3290 m 1575 3365 l 1605 3290 l 1575 3305 l 1545 3290 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 1545 3930 m 1605 3930 l 1605 3830 l 1575 3905 l 1545 3830 l cp eoclip n 1575 3645 m 1575 3915 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1545 3830 m 1575 3905 l 1605 3830 l 1575 3845 l 1545 3830 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 2895 3390 m 2955 3390 l 2955 3290 l 2925 3365 l 2895 3290 l cp eoclip n 2925 3105 m 2925 3375 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 2895 3290 m 2925 3365 l 2955 3290 l 2925 3305 l 2895 3290 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 1545 4695 m 1605 4695 l 1605 4595 l 1575 4670 l 1545 4595 l cp eoclip n 1575 4185 m 1575 4680 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1545 4595 m 1575 4670 l 1605 4595 l 1575 4610 l 1545 4595 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 1545 5910 m 1605 5910 l 1605 5810 l 1575 5885 l 1545 5810 l cp eoclip n 1575 5400 m 1575 5895 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1545 5810 m 1575 5885 l 1605 5810 l 1575 5825 l 1545 5810 l cp gs 0.00 setgray ef gr col0 s /Times-Bold-iso ff 150.00 scf sf 2820 592 m gs 1 -1 sc (User Site) col0 sh gr /Times-Roman-iso ff 180.00 scf sf 3104 1080 m gs 1 -1 sc (gnatsd client) dup sw pop 2 div neg 0 rm col0 sh gr /Times-Bold-iso ff 150.00 scf sf 1065 592 m gs 1 -1 sc (User Site) col0 sh gr /Courier-iso ff 180.00 scf sf 1349 1080 m gs 1 -1 sc (send-pr) dup sw pop 2 div neg 0 rm col0 sh gr /Times-Roman-iso ff 180.00 scf sf 1327 1800 m gs 1 -1 sc (E-mail) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline gs clippath 1320 1590 m 1380 1590 l 1380 1490 l 1350 1565 l 1320 1490 l cp eoclip n 1350 1350 m 1350 1575 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1320 1490 m 1350 1565 l 1380 1490 l 1350 1505 l 1320 1490 l cp gs 0.00 setgray ef gr col0 s /Times-Bold-iso ff 150.00 scf sf 4552 592 m gs 1 -1 sc (User Site) col0 sh gr /Times-Roman-iso ff 180.00 scf sf 4836 1080 m gs 1 -1 sc (Web client) dup sw pop 2 div neg 0 rm col0 sh gr /Times-Roman-iso ff 180.00 scf sf 4836 1800 m gs 1 -1 sc (Web server) dup sw pop 2 div neg 0 rm col0 sh gr % Polyline gs clippath 4830 1590 m 4890 1590 l 4890 1490 l 4860 1565 l 4830 1490 l cp eoclip n 4860 1350 m 4860 1575 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 4830 1490 m 4860 1565 l 4890 1490 l 4860 1505 l 4830 1490 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 1320 2310 m 1380 2310 l 1380 2210 l 1350 2285 l 1320 2210 l cp eoclip n 1350 1890 m 1350 2295 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 1320 2210 m 1350 2285 l 1380 2210 l 1350 2225 l 1320 2210 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 2985 2850 m 3045 2850 l 3045 2750 l 3015 2825 l 2985 2750 l cp eoclip n 3015 1350 m 3015 2835 l gs col7 1.00 shd ef gr gs col0 s gr gr % arrowhead n 2985 2750 m 3015 2825 l 3045 2750 l 3015 2765 l 2985 2750 l cp gs 0.00 setgray ef gr col0 s % Polyline n 1569 4679 m 2101 5033 l 1569 5388 l 1037 5033 l cp gs col0 s gr $F2psEnd rs gnats-4.1.0/doc/flowchart.fig0000644000175000017500000001517507314462227016627 0ustar chewiechewie00000000000000#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 6 585 2115 5535 6660 6 2565 2835 3330 3150 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 2610 2857 3285 2857 3285 3105 2610 3105 2610 2857 4 1 0 50 0 12 10 0.0000 4 135 540 2947 3015 gnatsd\001 -6 6 1035 3375 3195 3645 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 1080 3397 3150 3397 3150 3622 1080 3622 1080 3397 4 1 0 50 0 12 9 0.0000 4 120 1800 2115 3547 DATABASEDIR/gnats-queue/\001 -6 6 990 2790 2160 3150 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 2115 3105 2115 2835 1035 2835 1035 3105 2115 3105 4 1 0 50 0 12 10 0.0000 4 105 990 1575 2992 queue-pr -q\001 -6 6 990 3870 2160 4230 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 2115 4185 2115 3915 1035 3915 1035 4185 2115 4185 4 1 0 50 0 12 10 0.0000 4 105 990 1575 4072 queue-pr -r\001 -6 6 1000 4667 2140 5455 6 1175 4754 1965 5280 4 1 0 20 0 0 10 0.0000 4 105 315 1569 4929 valid\001 4 1 0 20 0 0 10 0.0000 4 105 60 1569 5280 ?\001 4 1 0 20 0 12 8 0.0000 4 120 750 1569 5105 >Category:\001 -6 2 3 0 1 0 0 0 0 -1 0.000 0 0 -1 0 0 5 1569 4679 2101 5033 1569 5388 1037 5033 1569 4679 -6 6 855 5850 5265 6390 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 900 5895 5220 5895 5220 6345 900 6345 900 5895 4 1 0 50 0 2 10 0.0000 4 105 1170 3060 6075 GNATS Database\001 4 1 0 50 0 12 9 0.0000 4 120 2250 3060 6255 DATABASEDIR/category/PR-number\001 -6 6 2250 3915 4860 4185 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 2295 3937 4815 3937 4815 4162 2295 4162 2295 3937 4 1 0 50 0 12 9 0.0000 4 120 2175 3555 4087 DATABASEDIR/pending/PR-number\001 -6 6 4320 5310 5220 5670 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 5175 5625 5175 5355 4365 5355 4365 5625 5175 5625 4 1 0 50 0 12 10 0.0000 4 105 720 4770 5512 query-pr\001 -6 6 3105 5310 3915 5670 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 3870 5625 3870 5355 3150 5355 3150 5625 3870 5625 4 1 0 50 0 12 10 0.0000 4 135 630 3510 5527 edit-pr\001 -6 6 3240 2250 4275 2610 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 3285 2295 4230 2295 4230 2565 3285 2565 3285 2295 4 1 0 50 0 3 10 0.0000 4 105 870 3757 2482 administrator\001 -6 6 4365 2250 5310 2610 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 4410 2295 5265 2295 5265 2565 4410 2565 4410 2295 4 1 0 50 0 3 10 0.0000 4 105 750 4837 2482 maintainers\001 -6 6 3690 4455 4500 4815 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 4455 4770 4455 4500 3735 4500 3735 4770 4455 4770 4 1 0 50 0 12 10 0.0000 4 135 630 4095 4672 edit-pr\001 -6 6 765 2295 1935 2565 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 810 2317 1890 2317 1890 2542 810 2542 810 2317 4 1 0 50 0 12 9 0.0000 4 105 900 1350 2475 /etc/aliases\001 -6 6 1980 2205 2925 2475 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 2019 2238 2886 2238 2886 2441 2019 2441 2019 2238 4 0 0 20 0 2 10 0.0000 4 150 825 2040 2385 Support Site\001 -6 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1575 2565 1575 2835 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1575 3105 1575 3375 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1575 3645 1575 3915 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 2925 3105 2925 3375 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1575 4185 1575 4680 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1575 5400 1575 5895 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 2520 5715 2520 4365 900 4365 900 5715 2520 5715 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 2 1 2.00 60.00 60.00 2115 5040 2880 5040 2880 4185 2 4 0 2 0 7 100 0 18 0.000 0 0 7 0 0 5 5490 6615 630 6615 630 2160 5490 2160 5490 6615 2 4 0 1 0 7 60 0 20 0.000 0 0 7 0 0 5 5355 6480 5355 2700 765 2700 765 6480 5355 6480 2 1 0 1 0 7 50 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 4095 4185 4095 4500 2 1 0 1 0 7 50 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 4095 4770 4095 5895 2 1 0 1 0 7 50 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 3555 5625 3555 5895 2 1 0 1 0 7 50 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 4770 5895 4770 5625 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 5 2 0 1.00 60.00 60.00 3780 2565 3780 3825 4905 3825 4905 4635 4455 4635 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 1 2 2 0 1.00 60.00 60.00 5040 2565 5040 5355 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 0 1.00 60.00 60.00 5040 2565 5040 5040 3555 5040 3555 5355 4 0 0 50 0 0 10 0.0000 4 105 240 1620 5625 Yes\001 4 0 0 50 0 0 10 0.0000 4 105 195 2250 4995 No\001 4 1 0 50 0 12 10 0.0000 4 135 630 2070 4545 file-pr\001 4 1 0 60 0 2 12 0.0000 4 135 645 4410 2925 GNATS\001 -6 6 2205 0 4005 1575 6 2655 225 3555 675 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 2767 427 3442 427 3442 652 2767 652 2767 427 4 0 0 20 0 2 10 0.0000 4 120 600 2820 592 User Site\001 -6 6 2475 810 3735 1260 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 3651 1175 3651 894 2559 894 2559 1175 3651 1175 4 1 0 20 0 0 12 0.0000 4 180 975 3104 1080 gnatsd client\001 -6 2 4 0 2 0 7 100 0 15 0.000 0 0 7 0 0 5 3791 1350 3791 225 2418 225 2418 1350 3791 1350 -6 6 585 0 2160 1935 6 585 0 2160 1575 6 810 225 1710 675 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 1012 427 1687 427 1687 652 1012 652 1012 427 4 0 0 20 0 2 10 0.0000 4 120 600 1065 592 User Site\001 -6 6 585 675 1935 1350 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 1896 1175 1896 894 804 894 804 1175 1896 1175 4 1 0 20 0 12 12 0.0000 4 180 735 1349 1080 send-pr\001 -6 2 4 0 2 0 7 100 0 15 0.000 0 0 7 0 0 5 2036 1350 2036 225 663 225 663 1350 2036 1350 -6 6 877 1530 1777 1935 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 1732 1890 1732 1575 922 1575 922 1890 1732 1890 4 1 0 20 0 0 12 0.0000 4 135 540 1327 1800 E-mail\001 -6 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1350 1350 1350 1575 -6 6 4005 0 5625 1935 6 4027 0 5602 1575 6 4477 225 5377 675 2 2 0 2 0 7 50 0 20 0.000 0 0 -1 0 0 5 4499 427 5174 427 5174 652 4499 652 4499 427 4 0 0 20 0 2 10 0.0000 4 120 600 4552 592 User Site\001 -6 6 4252 810 5422 1260 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 5383 1175 5383 894 4291 894 4291 1175 5383 1175 4 1 0 20 0 0 12 0.0000 4 135 825 4836 1080 Web client\001 -6 2 4 0 2 0 7 100 0 15 0.000 0 0 7 0 0 5 5523 1350 5523 225 4150 225 4150 1350 5523 1350 -6 6 4252 1530 5422 1935 2 4 0 2 0 7 50 0 20 0.000 0 0 7 0 0 5 5377 1890 5377 1575 4297 1575 4297 1890 5377 1890 4 1 0 20 0 0 12 0.0000 4 135 885 4836 1800 Web server\001 -6 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 4860 1350 4860 1575 -6 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 1350 1890 1350 2295 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 2 1 1.00 60.00 60.00 4275 1755 3150 1755 3150 2835 2 1 0 1 0 7 20 0 20 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 60.00 3015 1350 3015 2835 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 2 0 1.00 60.00 60.00 4860 2295 4860 1890 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 0 1.00 60.00 60.00 3780 2295 3780 2025 4635 2025 4635 1890 gnats-4.1.0/doc/flowchart.txt0000644000175000017500000000324607314462227016675 0ustar chewiechewie00000000000000+===========+ +===========+ +============+ # USER SITE # # USER SITE # # USER SITE # # # # # # # # *send-pr* # # *send-pr* # # Web client # +=====|=====+ +=====|=====+ +=====|======+ | V | `---------> Email/gnatsd... <-------' ,---> | +===============|=========|===================+ # SUPPORT SITE | `---> /etc/aliases # # *send-pr* | # # +-----------------------------V--------+# # | GNATS DATABASEDIR/gnats-queue/|# # | | |# # | _________ V |# # | |*file-pr*|<--- *queue-pr -r* |# # | | | |# # _ | | valid | |# # |M| | |Category?|N--. |# # |A| | |_________| | GNATS |# # |I| | Y| | ADMINISTRATOR |# # |N| | | | |# # |T|<----------------| | |# # |A| | | | .-> *edit-pr* |# # |I|--->*edit-pr*-. | V | | |# # |N| | | |DATABASEDIR/pending | |# # |E|<--*query-pr* | | | |# # |R| | | | | | |# # |S| | | V V V |# # |_| |+------------------------------------+|# # || GNATS Database ||# # || DATABASEDIR/CATEGORY/GNATS-ID ||# # |+------------------------------------+|# # +--------------------------------------+# +=============================================+ gnats-4.1.0/doc/gnats-faq.texi0000600000175000017500000012613710212657543016712 0ustar chewiechewie00000000000000\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename gnats-faq @ifinfo @format START-INFO-DIR-ENTRY * GNATS FAQ: (gnats-faq). FAQ for the GNU Problem Report Management System END-INFO-DIR-ENTRY @end format @end ifinfo @settitle @sc{gnats} Frequently Asked Questions @c %**end of header @c @setchapternewpage odd @ifinfo Copyright @copyright{} 2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries a copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the sections entitled ``Copying'' and ``@sc{gnu} General Public License'' are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. @end ifinfo @titlepage @title @sc{gnats} Frequently Asked Questions @c @subtitle whatever @author Hans-Albert Schneider @page @c Copyright notice @vskip 0pt plus 1filll Copyright @copyright{} 2002, 2005 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the sections entitled ``Copying'' and ``@sc{gnu} General Public License'' are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. @end titlepage @contents @node Top @comment node-name, next, previous, up @top @sc{gnats} Frequently Asked Questions This document answers some frequently asked questions concerning @sc{gnats}, the @sc{gnu} problem report management system, and related software. The most recent version of this FAQ can be found at @uref{http://www.gnu.org/software/gnats/doc/faq/gnats-faq.html}. The questions and answers have been compiled by @email{Gnats-FAQ@@HA-Schneider.de,Hans-Albert Schneider}, mainly using the help-gnats mailing list and the @sc{gnats} documentation as input. Please report any errors and suggestions to him. @menu * General:: General questions * Installation:: Problems during installation * Configuration:: Problems with @sc{gnats} configuration * Clients:: Ways to access a @sc{gnats} system * Glossary:: Abbreviations and definitions * Index:: Important things and where they are referenced @end menu @node General @comment node-name, next, previous, up @chapter General Questions @menu * What is GNATS:: A very short overview * How to pronounce it:: Pronunciation: with or without the "G"? * Get it:: Where to get @sc{gnats} * Versions:: Which versions are available? * Mailing Lists:: E-mail discussion lists * Bug Reporting:: How to report a bug * Upgrading:: Considerations for the 3.x to 4.0 transition @end menu @node What is GNATS @comment node-name, next, previous, up @section What is @sc{gnats}? @sc{gnats} is the @sc{gnu} problem report management system. Problem report management systems are also known as "bug-tracking systems", though the entries need not be bugs (e.g., think of change requests). The acronym stands for "GNats: A Tracking System". @sc{gnats} stores all information about the problem reports at a central site, and enables users to access this site by various means, including e-mail, WWW, and a network daemon. New problem reports can be created, and existing reports can be queried and updated, by most of these means. @sc{gnats} is widely customizable: Of course you can define report categories (is the report about tool A or service B?), responsibles (who takes care of this report?), and submitters (is it from customer1 or from the sales department?). You can also define possible states of a report (open, analyzed, closed, etc.) and classes (software bug, documentation bug, change request, @dots{}). Starting with @sc{gnats} 4.0, you can define your own custom fields, and customize many of the built-in fields; you can have fields automatically set to a certain value when another field changes its contents (e.g., set a "Closed-Date" field to the current date when the report goes to state "closed", and unset it when it goes back from "closed" to something else), or when the report is changed at all (e.g., to maintain a "Last-Modified" field). @menu * User view:: Short overview for users * Administrator View:: Short overview for system administrators @end menu @node User view @comment node-name, next, previous, up @subsection How it Works---User's View Users enter their problem reports (PRs) via some front-end. This front-end either directly contacts the @sc{gnats} server, or sends the report via e-mail. (The server is available since about version 3.90 of @sc{gnats}). For an incomplete list of front-ends see @ref{Clients}. Some front-ends (like TkGnats, see @ref{TkGnats}) are capable of contacting several @sc{gnats} servers, or several problem report databases managed by the same @sc{gnats} server. @node Administrator View @comment node-name, next, previous, up @subsection How it Works---Administrator's View @cindex starting gnatsd @cindex gnatsd, starting The server is started by a super-server like inetd or xinetd. It has a built-in access control mechanism based on IP addresses and username/password. For users sending their PRs via e-mail, some mail addresses must be configured. @node How to pronounce it @comment node-name, next, previous, up @section How is "@sc{gnats}" pronounced? Q: So, How can I pronounce "@sc{gnats}?" Should I pronounce "G"? It has been reported that the original developers pronounced the "G". (This is unlike the little insect called "gnat" where the "G" is not pronounced.) @node Get it @comment node-name, next, previous, up @section Where do I get it? See the @sc{gnats} home page at @uref{http://www.gnu.org/software/gnats/}. The current development version is available via CVS only, see the @uref{http://savannah.gnu.org/projects/gnats,@sc{gnu} savannah @sc{gnats} project page} for the instructions how to get it. @node Versions @comment node-name, next, previous, up @section What is the latest version? The version numbers of @sc{gnats} 3.x is somewhat confusing, because 3.1xx is newer than 3.2. Version 3.2 was released in 1993 (I never tried it, but it is said to be "really broken"). A lot of new features have been added since 3.2, including multiple database support and customized fields. Among the contributed software are comprehensive WWW and Tk based front-ends. The latest 3.x release is 3.113.1. It is deprecated due to security concerns and lack of maintenance. @sc{gnats} 4.0 was released in August 2003, and 4.1 was released in March 2005. All released versions are available for download at @uref{http://ftp.gnu.org/pub/gnu/gnats/}. @node Mailing Lists @comment node-name, next, previous, up @section Is there a Mailing List? Currently, the following @sc{gnats} mailing lists exist: @itemize @item @uref{http://lists.gnu.org/mailman/listinfo/info-gnats,info-gnats@@gnu.org} This is a low volume moderated mailing lists for @sc{gnats} related announcements, like new releases or important information. @item @uref{http://lists.gnu.org/mailman/listinfo/help-gnats,help-gnats@@gnu.org} A low-to-middle volume mailing list where anything related to @sc{gnats} can be discussed (development, help, questions, suggestions, etc.). @item @uref{http://lists.gnu.org/mailman/listinfo/bug-gnats,bug-gnats@@gnu.org} Bug reports can be sent there. Please note that it's preferred to submit bug reports via the bug tracking system (@pxref{Bug Reporting}), which automatically mirrors them to this list. @end itemize Lists that are of interest mainly for the @sc{gnats} developers: @itemize @item @uref{http://lists.gnu.org/mailman/listinfo/gnats-prs,gnats-prs@@gnu.org} Copies of the bug tracking system messages are sent there. Contrast to bug-gnats@@gnu.org which only gets new bug reports, this list also gets the follow-ups (Whatever goes into @sc{gnats}' @code{>Audit-Trail:} field). @item @uref{http://lists.gnu.org/mailman/listinfo/gnats-commit,gnats-commit@@gnu.org} CVS commit messages are sent there. @item @uref{http://lists.gnu.org/mailman/listinfo/gnats-diffs,gnats-diffs@@gnu.org} Diffs of committed files are sent automatically to this address. @end itemize @node Bug Reporting @comment node-name, next, previous, up @section How do I Report a Bug? @cindex bug reporting Before reporting a bug, make sure it really is a bug, not a simple misunderstanding or a misconfiguration. Please check the manual and this FAQ. You may also ask for help on the @uref{http://lists.gnu.org/mailman/listinfo/help-gnats,help-gnats@@gnu.org} mailing list (you may want to search the list archive first; it is available from @uref{http://lists.gnu.org/mailman/listinfo/help-gnats}). If it is a bug, please report it via the bug tracking system. It resides at @uref{http://bugs.gnu.org/cgi-bin/gnatsweb.pl?database=gnats}. This is a common bug database for @sc{gnats}, Gnatsweb and TkGnats. (And, yes, of course: It uses @sc{gnats} and Gnatsweb.) When you report problems concerning @sc{gnats} itself, please do not forget to provide especially the following information: @itemize @bullet @item The @sc{gnats} version you are using. If your problem involves Gnatsweb or TkGnats, please also report their versions. @item The @emph{exact} way how to reproduce the bug. @item Your configuration. @item If you encounter a compilation or build problem, it is especially important to mention the operating system, compiler and possibly other build utilities you use. @end itemize Providing this information in the initial report avoids further unnecessary communication, saves the limited resources of the developers (keep in mind that they are working on @sc{gnats} and friends in their spare time) and helps to track down and fix the problem soon. @node Upgrading @comment node-name, next, previous, up @section Upgrading Considerations See @ref{Upgrading,,Upgrading from older versions,gnats,Keeping Track} for the upgrade process from 3.x to 4.x. If you are running a 3.x version, @emph{please consider upgrading to 4.0.} There are some security concerns about the 3.1xx code that have gone with 4.0. Furthermore, the @sc{gnats} 3 branch is not maintained anymore due to lack of capacity. The default format of the reports has not changed during the transition from 3.113.1 to 4.0, though you may add more fields to 4.0 reports (and leave out others). The format of the index file is now binary. However, you have to change the e-mail aliases because the meaning of the @samp{-d} option to the client programs has changed: It took the @emph{directory} of the @sc{gnats} database in 3.1xx, and now takes its @emph{name} (plus, it is now installed into the @file{libexec} directory instead of the @file{lib} directory). I.e., you must change the aliases: @smallexample # GNATS 3 aliases: ourdb-query: "|/usr/local/lib/gnats/mail-query -d /usr/local/gnats/db2" ourdb-bugs: "|/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -q" @end smallexample to @smallexample # GNATS 4 aliases: ourdb-query: "|/usr/local/libexec/gnats/mail-query -d ourdb" ourdb-bugs: "|/usr/local/libexec/gnats/queue-pr -d ourdb -q" @end smallexample Also note that the client/server protocol has changed from 3.1xx to 4.0; you cannot run clients from one version with the server from the other version. @ignore One consideration is to migrate by running 4.x in parallel to 3.x, as a sort of mirror of the 3.x version. To the best of my knowledge, this has not yet been done practically. The idea is to have the mail aliases on the 3.x server also send the mails to the 4.x server. To avoid confusing submitters and responsibles by duplicate emails (one from 3.x and one from 4.x), the 4.x server could send its mails to the @sc{gnats} admin, or even to @code{nobody} (usually aliased to @w{@file{/dev/null}}). As the mail text sent by the 4.x server is configurable, another option is to include an explanatory statement. @smallexample # On the @sc{gnats} 3 server: GreatNewDB-bugs: GreatNewDB-bugs-3, GreatNewDB-bugs-4 GreatNewDB-query: "|/usr/local/lib/gnats/mail-query -d /usr/local/gnats/db2" GreatNewDB-bugs-3: "|/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -q" # If the @sc{gnats} 4 server is different: GreatNewDB-bugs-4: GreatNewDB-bugs-4@@gnats4-server @end smallexample @smallexample # On the @sc{gnats} 4 server: GreatNewDB-bugs-4: "|/usr/local/libexec/gnats/queue-pr -d GreatNewDB -q" nobody: /dev/null @end smallexample @end ignore @node Installation @comment node-name, next, previous, up @chapter Problems during Installation As installation and configuration problems often overlap, please check also @ref{Configuration}. @menu * Gnatsweb and GNATS:: Cooperation problems between @sc{gnats} and Gnatsweb @end menu @node Gnatsweb and GNATS, , Installation, Installation @comment node-name, next, previous, up @section Gnatsweb and @sc{gnats} do not like each other. @b{Q:} I have installed @sc{gnats} 3.999.x and Gnatsweb 2.9.x, and I cannot get them work together. Symptoms are that "make test" fails; if Gnatsweb is installed nevertheless, it hangs when trying to login into the @sc{gnats} server. @b{A:} The versions are incompatible. Gnatsweb 2.9.x is for use with @sc{gnats} 3.113.1. With @sc{gnats} 3.999.x, you must use Gnatsweb 3.99.x; it is in the contrib subdirectory of the @sc{gnats} distribution. (@sc{gnats} 3.999.x/Gnatsweb 3.99.x were pre-releases of the 4.0 releases. As 4.0 is out now, you may consider to upgrade to the non-pre versions.) For @sc{gnats} 4.x, use Gnatsweb 4.0 or greater. @node Configuration @comment node-name, next, previous, up @chapter Configuration Issues @menu * General configuration:: General questions about @sc{gnats} configuration * Gnatsd:: Configuration of the @sc{gnats} daemon * E-Mail:: Problems with the e-mail interface * Miscellaneous:: Other configuration problems @end menu @node General configuration @comment node-name, next, previous, up @section General Configuration Questions @menu * Add a database:: How to create a new database * Renaming a Category:: How to rename categories * Changing Fields:: Add, remove, or rename a PR field @end menu @node Add a database @comment node-name, next, previous, up @subsection How do I add a new database? @noindent @b{A: (@sc{gnats} 3.1xx)} (Please consider upgrading to @sc{gnats} 4.0 or greater.) @enumerate @item Create the base directory for the new database, say @w{@file{/usr/local/gnats/db2}}, and make sure it is owned by the @sc{gnats} user. @item In there, create subdirectories @w{@file{gnats-adm}}, @w{@file{gnats-adm/locks}}, and @w{@file{gnats-queue}}, and make sure they is owned by the @sc{gnats} user. @item Now you need to populate the new @w{@file{gnats-adm}} directory. The easiest way is to copy all files from @w{@file{gnats-db/gnats-adm}} to @w{@file{/usr/local/gnats/db2/gnats-adm}}, and edit them to reflect the needs of your new database. Again, make sure they are owned by the gnats user. Note that there @emph{must} be a category named @code{pending}. It is used when no category is given in a report, and when a report names an invalid category. Also note that each database needs its own mail address for submissions (see also step 8 below), and that you must enter it in the file @file{config}. @item As the @sc{gnats} user, run @samp{mkcat --directory=/usr/local/gnats/db2} to create the directories for the categories. Remove the files @file{current} and @file{index}, if they exist. @item If the new database is split off of another one, move or copy the existing reports to their new location. This is easiest if the categories have the same names as in the original database. (See @ref{Renaming a Category} if some of them changed names.) Run the program @code{gen-index} to create the index file (@pxref{gen-index,,Regenerating the index,gnats,Keeping Track}). Find the greatest report number and put it (or any larger number) into @file{/usr/local/gnats/db2/gnats-adm/current}. @strong{Caution:} E-mail updates to the PRs you moved to the new database may still arrive at the old database. You may want to contact everybody who knows about these PRs, asking them to use the mail address of the new database when sending a follow-up. @item Now add a line for the new database to @w{@file{gnats-db.conf}}, like this: @code{/usr/local/gnats/db2:GreatNewDB} Gnatsd reads it on startup (and as it is started by inetd, this means it becomes effective with the next connection to gnatsd). Gnatsweb (see @ref{Gnatsweb}) learns the database list from gnatsd, so it will offer you the new database "GreatNewDB" when it is invoked next time. If you do not know where @w{@file{gnats-db.conf}} lives, run: @samp{strings /where/ever/gnatsd | grep gnats-db.conf} @item Don't forget to setup a cron job to run through the additional @w{@file{gnats-queue}}. Note that you need to specify the database directory to @file{queue-pr}, i.e., @samp{/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -r} or, if you prefer the long options, @samp{/usr/local/lib/gnats/queue-pr --directory=/usr/local/gnats/db2 --run} @item Don't forget to create mail aliases for your new database (@pxref{Aliases,,Setting up mail aliases,gnats,Keeping Track}). Take care that the aliases have the right database, e.g., @smallexample GreatNewDB-bugs: "|/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -q" GreatNewDB-query: "|/usr/local/lib/gnats/mail-query -d /usr/local/gnats/db2" @end smallexample If you do not want to allow querying the database by mail, omit the @samp{GreatNewDB-query} alias. You usually need the cooperation of a system administrator for this step (if you are not a system administrator yourself, of course). Make sure that @file{/usr/local/gnats/db2/gnats-adm/config} gives the correct mail addresses for @var{GNATS_ADDR} (this @emph{must} be different for each database) and for @var{GNATS_ADMIN} (this is probably the same for all databases). @smallexample GNATS_ADDR="GreatNewDB-bugs@@bugs.example.com" GNATS_ADMIN="gnats-admin@@bugs.example.com" @end smallexample If your @sc{gnats} sits behind a firewall and needs to exchange mails with the outside world, see also @ref{Outgoing mail bounces}. @end enumerate @noindent @b{A: (@sc{gnats} 4.x)} With version 4, this has become much easier (@pxref{mkdb,,Adding another database,gnats,Keeping Track}): @enumerate @item Add a line for the new database to @w{@file{databases}}, like this: @code{GreatNewDB:Our great tools:/usr/local/gnats/db2} Then, as the @sc{gnats} user, run @samp{mkdb GreatNewDB} to create the database. Make sure that the directory (in our example, @w{@file{/usr/local/gnats/db2}}) can be created by the @sc{gnats} user. (Note that there @emph{must} be a database named @code{default}. It is used as a fallback by some tools if no database is specified. You need not use it actively, but you should have run @samp{mkdb default}.) Gnatsd reads the file @w{@file{databases}} on startup (and as it is started by inetd, this means it becomes effective with the next connection to gnatsd). Gnatsweb (see @ref{Gnatsweb}) learns the database list from gnatsd, so it will offer you the new database "GreatNewDB" when it is invoked next time. If you do not know where @w{@file{databases}} lives, run: @samp{strings /where/ever/gnatsd | grep databases} @item Now, as the @sc{gnats} user, edit the files in directory @w{@file{/usr/local/gnats/db2/gnats-adm}} to reflect the needs of your new database. @item Depending on the settings in the @w{@file{dbconfig}} file of the new database, you need not run @code{mkcat} anymore in order to create new category directories in your database---@sc{gnats} 4 creates them automatically when they are missing. @xref{dbconfig file,,The @code{dbconfig} file,gnats,Keeping Track}, for details. @item Don't forget to setup a cron job to run through the additional @w{@file{gnats-queue}}. Note that you need to specify the database to @file{queue-pr}, i.e., @samp{/usr/local/libexec/gnats/queue-pr -d GreatNewDB -r} or, if you prefer the long options, @samp{/usr/local/libexec/gnats/queue-pr --database=GreatNewDB --run} @item Don't forget to create mail aliases for your new database (@pxref{Aliases,,Setting up mail aliases,gnats,Keeping Track}). Take care that the aliases have the right database, e.g., @smallexample GreatNewDB-bugs: "|/usr/local/libexec/gnats/queue-pr -d GreatNewDB -q" GreatNewDB-query: "|/usr/local/libexec/gnats/mail-query -d GreatNewDB" @end smallexample If you are updating from @sc{gnats} 3.1xx, note that the @samp{-d} option has changed its meaning: it does not give the directory of the database, but its name. (In case you prefer the long form of the option, it is now @samp{--database} instead of @samp{--directory}.) If your @sc{gnats} sits behind a firewall and needs to exchange mails with the outside world, see also @ref{Outgoing mail bounces}. @end enumerate @node Renaming a Category @comment node-name, next, previous, up @subsection How do I rename a category? Renaming a category requires to touch every PR in that category, because each report contains the name of its category. To rename category @code{A} to @code{B}, proceed as follows: @enumerate @item Create a new category @code{B}. @item Edit every report in category @code{A}, changing its category to @code{B}. This can be done with any @sc{gnats} client; check the archives of the @sc{help-gnats} mailing list for hints about automating this step. @item Run @code{gen-index} (@pxref{gen-index,,Regenerating the index,gnats,Keeping Track}) to refresh the @file{index} file. @item If you are using @sc{gnats} 4 (or planning to upgrade soon), you should not remove the category @code{A}. When a follow-up to an existing PR arrives via e-mail, @sc{gnats} 4.x checks that both the category and the PR number indicated in the mail exist (this is a sanity check). To reduce the risk of new reports being filed to category @code{A}, change its description in the @file{categories} file to something like @samp{obsolete, use category @code{B} instead}. @end enumerate @node Changing Fields @comment node-name, next, previous, up @subsection How do I add, remove, or rename a PR field? @noindent @b{A: (@sc{gnats} 3.1xx)} The fields and their names are fixed in @sc{gnats} 3.1xx, so this is not possible. @noindent @b{A: (@sc{gnats} 4.x)} Edit the file @file{dbconfig} to reflect your changes. Note that the PR fields with the builtin-names @code{severity}, @code{priority} and @code{state} are required if you want automatic reminders (@code{notify-about-expired-prs = true}). In this case, the file @file{submitters} must also contain a response time. @c The reminder is filed if: @c - "response time" is not -1, and @c - @code{notify-about-expired-prs} = true, and @c - (@code{severity} = @code{critical}) @c or ( @code{severity} = @code{serious} @c and @code{priority} = @code{high} ) The @code{severity} field is checked for values @code{critical} and @code{serious}, and @code{priority} for value @code{high}. This is currently not configurable. @node Gnatsd @comment node-name, next, previous, up @section Gnatsd, the @sc{gnats} Daemon @cindex server, see gnatsd @cindex @sc{gnats} server, see gnatsd @cindex gnatsd @menu * Port Number:: How to connect to gnatsd * Starting gnatsd:: How to make gnatsd accept connections * Gnatsd messages:: Some error messages and what they mean @end menu @node Port Number @comment node-name, next, previous, up @subsection Gnatsd Port Number @cindex port @cindex server port In 3.xxx versions, gnatsd uses port 1529 by default; as this port is officially assigned to another application (see the @uref{http://www.iana.org/assignments/port-numbers,list of port numbers} maintained by the @uref{http://www.iana.org/,Internet Assigned Numbers Authority}) @c there is no default port @c anymore in 4.x (you have to create an entry in @w{@file{/etc/services}}). it will probably change in 4.x. If you want/need to run gnatsd on another port, you can change the default port at compile time (call @code{configure --help} to learn about compile time configuration options). Most clients also accept an option or configuration variable to change the port. Don't forget to tell inetd (or xinetd, or whatever super-server you use) to start gnatsd on the other port. @node Starting gnatsd @comment node-name, next, previous, up @subsection How to Start Gnatsd Gnatsd is intended to be started by some "super server", like @code{inetd} or @code{xinetd}. ("Super servers" are sometimes also called "super daemons".) This is also described in the @sc{gnats} manual; see @ref{Installing the daemon,,Installing the daemon,gnats,Keeping Track}. @menu * inetd configuration:: The traditional super server * xinetd configuration:: Another widespread super server @end menu @node inetd configuration @comment node-name, next, previous, up @subsubheading How to configure inetd to start gnatsd @cindex inetd If your gnatsd will be started by inetd (the "internet daemon"), add the following entry to your @w{@file{/etc/inetd.conf}}: @smallexample # port userid program support stream tcp nowait gnats /usr/local/libexec/gnats/gnatsd gnatsd @end smallexample @noindent and to @w{@file{/etc/services}}: @smallexample support 1529/tcp # GNATS @end smallexample @noindent (You may need to use tabulator characters to separate the fields of @w{@file{/etc/services}}.) Then send inetd a hangup signal (@w{@code{kill -HUP @emph{pid-of-inetd}}}). You may want to use another port instead of 1529 (@pxref{Port Number}). @node xinetd configuration @comment node-name, next, previous, up @subsubheading How to configure xinetd to start gnatsd @cindex xinetd If your gnatsd will be started by xinetd (the "extended internet daemon"), create a file @w{@file{/etc/xinetd.d/support}} with the following lines (@pxref{Installing the daemon,,Installing the daemon,gnats,Keeping Track}): @example @cartouche service support @{         disable = no         socket_type = stream         protocol = tcp         wait = no         user = gnats         server = /usr/local/libexec/gnats/gnatsd server_args = gnatsd @} @end cartouche @end example @noindent or add theses lines to your @w{@file{xinetd.conf}} file, whatever is appropriate. The equal signs seem to need spaces around them with some versions of xinetd. You need to add @smallexample support 1529/tcp # GNATS @end smallexample @noindent to @w{@file{/etc/services}} (it may be necessary to use tabulator characters to separate the fields), and to tell xinetd to reread its configuration (@code{kill -HUP @emph{pid-of-xinetd}}). @node Gnatsd messages @comment node-name, next, previous, up @subsection Gnatsd Messages @menu * No host access for stdin:: Error when starting gnatsd manually * No host access for remote:: Cannot connect from another machine @end menu @node No host access for stdin @comment node-name, next, previous, up @subsubheading You are not on the host access list: stdin (stdin) @b{Q:} When starting gnatsd manually (on the command line), I get @samp{520 You are not on the host access list: stdin (stdin)}. @b{A: (@sc{gnats} 3.1xx)} Gnatsd is not intended to be started manually, but via inetd, xinetd, or a similar "super server". When gnatsd is started this way, its stdin and stdout (standard input and standard output streams) are connected to a so called "TCP socket" (one end of the network connection), and from this socket gnatsd learns the IP address of the remote end (and from this it derives the remote host name). When you start gnatsd from the command line, its stdin and stdout are connected to the terminal, and thus gnatsd gets a nonsense value. You usually need @samp{root} privileges in order to change the configuration of your "super server". If you don't have them, contact your system administrator. See @ref{Starting gnatsd} for inetd and xinetd configuration. @b{A: (@sc{gnats} 4.0)} This error message should not occur with gnatsd 4.0 anymore, because gnatsd can be started from the command line. However, this probably only makes sense for debugging and diagnosing problems. Furthermore, you need to play the part of the client program yourself (i.e., you must "speak" the gnatsd client protocol). @node No host access for remote @comment node-name, next, previous, up @subsubheading You are not on the host access list @b{Q:} Gnatsd rejects connections from a remote host with the error message @samp{520 You are not on the host access list}. @b{A:} Check the file @w{@file{gnatsd.host_access}}; if you are using the default locations, this is @w{@file{/usr/local/etc/gnats/gnatsd.host_access}}. (If you are still using @sc{gnats} 3.xxx, the file is named @w{@file{gnatsd.conf}}; its default place is @w{@file{/usr/local/etc/gnatsd.conf}}.) Each line of the file names a host and its access level, separated by colons. Gnatsd tries the lines in turn to match the remote host, and the first line that matches wins. The first field specifies the host(s); it may be a host name (like @samp{goedel.example.com}), a partial domain (like @samp{*.example.com}), an IP address (like @samp{192.168.1.5}), or a partial IP address (like @samp{192.168.*}). If it is only @samp{*}, it matches all hosts. Depending on how IP addresses are mapped to hostnames on your gnatsd machine, you may be able to omit the domain (like in @samp{goedel}). You may even @emph{need} to omit the domain for some hosts. The second field is the access level granted to the remote host. This is usually increased by the access level granted to the user as soon as (s)he logs in. The third field is currently not used; just leave it empty (but supply the colon between the second and the third field). Example: @example @cartouche # # This is a comment # # Grant view access to all hosts with IP addresses # ranging from 192.168.0.0 to 192.168.255.255: 192.168.*:view: # Users on host goedel.example.com get (at least) edit access: goedel.example.com:edit: # Users from escher.example.com may view all reports, even # confidential ones: escher.example.com:viewconf: # Users from bach.example.com may only view all non-confidential # reports: bach.example.com:view: # Users from other example.com hosts # only get the access specified for them in gnatsd.user_access: *.example.com:none: # Same for domain our-users.example: *.our-users.example:none: # All other hosts are rejected # without even asking for username and password: *:deny: @end cartouche @end example The format is described in detail in the comments at the beginning of the file. @node E-Mail, Miscellaneous, Gnatsd, Configuration @comment node-name, next, previous, up @section E-Mail Issues @menu * queue-pr not available:: Sendmail refuses to run queue-pr * Outgoing mail bounces:: Mail system complains on outgoing mail @end menu @node queue-pr not available, Outgoing mail bounces, E-Mail, E-Mail @comment node-name, next, previous, up @subsubheading queue-pr not available for sendmail programs Your sendmail installation uses @samp{smrsh} to check programs that are invoked from a mail alias. @samp{smrsh} only allows the execution of programs of which it is told that they are save. To tell it that @file{queue-pr} is save, create a symbolic link in the directory @w{@file{/etc/smrsh}} to @file{queue-pr}, like this: @smallexample mkdir /etc/smrsh @r{# if it does not yet exist} cd /etc/smrsh ln -s /usr/local/libexec/gnats/queue-pr queue-pr @end smallexample @noindent Replace @w{@file{/usr/local/libexec/gnats/queue-pr}} by the real path to @file{queue-pr}. @node Outgoing mail bounces, , queue-pr not available, E-Mail @comment node-name, next, previous, up @subsubheading Mail from @sc{gnats} bounces You are getting bounce mails like this: @example ----- Transcript of session follows ----- ... while talking to mail.example.com.: >>> MAIL From: SIZE=334 <<< 501 5.1.8 ... Domain of sender address gnats@@mymachine.subdomain.example.com does not exist @end example Probably your @sc{gnats} sits behind a firewall, but it needs to exchange mails with the world outside the firewall. Make sure that @var{GNATS_ADDR} is valid outside. This is what probably happens behind the scenes: On its way to the outside world, the sender address of the mail gets rewritten to something "official" (like @code{Hans-Albert.Schneider@@example.com}, as opposed to @code{me@@mymachine.subdomain.example.com}). This is especially necessary if the internal hosts are not visible outside. If your outgoing mail gateway still sees the internal address, it complains with a message like the above (it has probably checked @code{mymachine.subdomain.example.com} with your organization's external DNS server, which does not know @code{mymachine}). To solve this problem, get an "official" address for your @sc{gnats} system, e.g., tool-bugs@@example.com, and use that one for @var{GNATS_ADDR}. @node Miscellaneous @comment node-name, next, previous, up @section Miscellaneous Configuration Issues @menu * No New Reports:: New reports do not show up in the database * Initially Assign Field Values:: If you want to set additional fields when entering a report @end menu @node No New Reports, Initially Assign Field Values, Miscellaneous, Miscellaneous @comment node-name, next, previous, up @subsubheading New reports do not show up in the database @enumerate @item Make sure you have set up the mail aliases for your database(s). (See @ref{Add a database} and @ref{mkdb,,Adding another database,gnats,Keeping Track}.) @item Try to send a PR using @samp{send-pr}. If you get error replies, investigate the causes. See @ref{E-Mail}. @item Does a new file show up in the @w{@file{gnats-queue}} directory of your database, with the report as its contents? If it does, make sure you have created the cron job for this database. @item If the report does not show up in the @w{@file{gnats-queue}} of the desired database, does it show up in the @w{@file{gnats-queue}} directory of another database? In this case, make sure your mail aliases are set up correctly; especially, make sure that you have specified the correct @samp{--directory} option (@samp{--database} for @sc{gnats} 4.x) for each @file{queue-pr}. @end enumerate @node Initially Assign Field Values, , No New Reports, Miscellaneous @comment node-name, next, previous, up @subsubheading Assigning responsible etc. when entering a report @b{Q:} When entering a new PR, I want to assign a value to some field (e.g., @code{Responsible}) which is normally assigned by @sc{gnats}. @b{A: (@sc{gnats} 3.1xx)} This is not possible in @sc{gnats} 3.1xx. @b{A: (@sc{gnats} 4.x)} This is done by adding the field name (in this example, @code{Responsible}) to the @w{@code{initial-entry}} item at the very end of the @file{dbconfig} file. Gnatsweb will pick this up and add a @code{Responsible} field to the Create PR form. @node Clients @comment node-name, next, previous, up @chapter Client Software Several client applications can be found in the @sc{gnats} distribution. The most important are Gnatsweb (a WWW interface to @sc{gnats}), TkGnats (a Tcl/Tk based interface), a @sc{gnats} mode for Emacs and XEmacs, and send-pr (the traditional command line interface that sends a PR by e-mail). @menu * Gnatsweb:: a WWW interface to @sc{gnats} * TkGnats:: a Tcl/Tk based client * Emacs mode:: for (X)Emacs enthusiasts * send-pr:: traditional command line interface @end menu @node Gnatsweb @comment node-name, next, previous, up @section Gnatsweb See also @ref{Gnatsweb and GNATS} in the chapter on @ref{Installation}. @menu * Gnatsweb Login Questions:: Problems logging in to Gnatsweb @end menu @c @node General Gnatsweb Questions @comment node-name, next, previous, up @c @subsection General Gnatsweb Questions @node Gnatsweb Login Questions @comment node-name, next, previous, up @subsection Login Questions @menu * What to enter:: What to enter at login * Login Not Remembered:: Reasons why Gnatsweb forgets your login * Cookies:: What Gnatsweb stores in its cookies @end menu @node What to enter @comment node-name, next, previous, up @subsubheading What should be entered as login information? @b{A:} If you get an HTML form asking you to enter username, password, and database, use what your gnats administrator has told you. In this case, your authentication data is checked with gnatsd's own user database. If your browser gives you a window asking for username and password (or for "credentials"), the authentication is done by the WWW server. You should have got the necessary data either from your gnats administrator, or from the webmaster of the site offering Gnatsweb access. @node Login Not Remembered @comment node-name, next, previous, up @subsubheading Login data are not remembered @b{Q:} After logging in via Gnatsweb, the main screen is displayed, but whatever action is selected (whatever button is clicked), the login screen gets displayed again. @b{A:} This is usually a problem of cookies getting ignored. Gnatsweb uses cookies to store the login information (see "Gnatsweb and Cookies" below). Configure your web browser to allow the cookies Gnatsweb tries to set. @b{Q:} There is not even the main screen, the user immediately gets the login screen when trying to log in. The login data entered is correct. It works fine on another machine and for other users. @b{A:} This has actually been reported only once; but as the effect is similar to the previous one, it is included in the FAQ. It apparently was related to very strict security settings, but has not been investigated in detail. @node Cookies @comment node-name, next, previous, up @subsubheading Gnatsweb and Cookies @cindex cookies @b{Q:} Wait a moment! Cookies? Can I eat them? @b{A:} No, not these. The cookies about which we are talking here are little data packages that a web-server sends to your browser (in our case, on behalf of Gnatsweb) and your browser sends them back to the server next time. Modern browsers give you the option to generally accept or reject cookies, or to be asked whenever a cookie arrives (some even can make this decision based on the web-server). To learn more about cookies, visit, e.g., @uref{http://www.cookiecentral.com/,the Cookie Central}. @b{Q:} So, which cookies does Gnatsweb send, and why? @b{A:} Gnatsweb uses a cookie @code{gnatsweb-db-}@emph{database_name} to store your login information (username, password), and a cookie @code{gnatsweb-global} to store the @sc{gnats} database you are working on, your e-mail address (to fill it in for you when you create a new report or reply to an existing report), a default list of fields to display in search results, and defaults for @code{Submitter-Id} and @code{Originator} fields. Gnatsweb also sets a cookie for each "saved query" (named @code{gnatsweb-query-}@emph{queryname}). It is therefore essential that you allow Gnatsweb to set its cookies. For a typical effect of rejecting them, see @ref{Login Not Remembered}. @node TkGnats @comment node-name, next, previous, up @section TkGnats To be completed. @node Emacs mode @comment node-name, next, previous, up @section @sc{gnats} Mode for Emacs The Emacs mode is in the file gnats.el @menu * XEmacs:: Does it also work for XEmacs? @end menu @node XEmacs, , Emacs mode, Emacs mode @comment node-name, next, previous, up @subsubheading Does it also work for XEmacs? @b{A: (@sc{gnats} 3.1xx)} Yes. @b{A: (@sc{gnats} 4.x)} Still to be tested. @node send-pr @comment node-name, next, previous, up @section send-pr A simple command line tool that sends a report via electronic mail. This is not contributed software, but part of @sc{gnats} itself. The 3.xxx versions do not support multiple databases. @c You can try to work around this by installing a separate send-pr for @c each database, with the appropriate e-mail address and category list. To be completed. @node Glossary @comment node-name, next, previous, up @appendix Glossary @table @dfn @item cookie A chunk of data that a WWW server stores in your browser. It is sent back to the server when you contact it again. Gnatsweb (see @ref{Gnatsweb}) uses cookies to store your login information, preferences, and named queries. @item gnats.el @sc{gnats} mode for (X)Emacs. @item gnatsd The @sc{gnats} daemon (server program). @item Gnatsweb A WWW interface to @sc{gnats}. @item port A communication endpoint of various IP based protocols, notably TCP and UDP. A server program waits for connections ("listens") on a port, and a client program connects to this port. @uref{http://www.iana.org/,IANA} (the Internet Assigned Numbers Authority) maintains a @uref{http://www.iana.org/assignments/port-numbers,list of port numbers} registered for certain purposes. @item PR Short for ``Problem Report''. An entry in a @sc{gnats} database. @item send-pr A command line tool that sends a new report by e-mail. @item super server A super server (sometimes also called "super daemon") is a daemon (= UNIX server process) that waits for connections on the ports of various server programs and starts the corresponding server when a connection is made. This way, there is only one server process for a set of services (instead of one for each service), but each service in the set is available to its clients. The most common super servers are @code{inetd} (the "InterNET Daemon" that comes with many UNIX installations) and @uref{http://www.xinetd.org,xinetd} (the "eXtended InterNET Daemon"). @item TkGnats A Tcl/Tk based interface to @sc{gnats}. @end table @node Index @comment node-name, next, previous, up @unnumbered Index @printindex cp @bye @c LocalWords: ifinfo savannah gnats-4.1.0/doc/gnats.texi0000644000175000017500000022705707724054132016157 0ustar chewiechewie00000000000000\input texinfo @c -*-texinfo-*- @setfilename gnats.info @include version.texi @ifinfo @format START-INFO-DIR-ENTRY * Keeping Track: (gnats). GNU Problem Report Management System END-INFO-DIR-ENTRY @end format @end ifinfo @ifinfo Copyright @copyright{} 1993, 1995, 2001, 2002, 2003 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries a copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions. @end ifinfo @c NOTE TO ANYONE FORMATTING THIS DOCUMENT FOR PRINTING... @c Comment the following line out if you don't have access to a @c PostScript printer or viewer @set POSTSCRIPT @settitle Keeping Track @setchapternewpage odd @finalout @titlepage @title Keeping Track @subtitle Managing Messages With @sc{gnats} @subtitle The @sc{gnu} Problem Report Management System @subtitle Version @value{VERSION} @subtitle August 2003 @author Jeffrey M. Osier @author Brendan Kehoe @author Cygnus Support @author Revised for GNATS 4 by Yngve Svendsen @page @vskip 0pt plus 1filll Copyright @copyright{} 1993, 1995, 2001, 2002, 2003 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions. @end titlepage @contents @node Top @top Overview @cindex overview to GNATS @cindex foreword This manual documents @sc{gnats}, the @sc{gnu} Problem Report Management System, version @value{VERSION}. @sc{gnats} is a bug-tracking tool designed for use at a central @dfn{Support Site}. Users who experience problems use electronic mail, web-based or other clients communicating with the @sc{gnats} network daemon running at the support site or direct database submissions to communicate these problems to @dfn{maintainers} at that Support Site. @sc{gnats} partially automates the tracking of these @dfn{Problem Reports} (@dfn{PR}s) by: @itemize @bullet @item organizing problem reports into a database and notifying responsible parties of suspected bugs; @item allowing support personnel and their managers to edit and query accumulated bugs; and @item providing a reliable archive of problems (and their subsequent solutions) with a given program. @end itemize @sc{gnats} offers many of the same features offered by more generalized databases, including editing, querying, and basic reporting. The @sc{gnats} database itself is an ordered repository for problem reports; each PR receives a unique, incremental @dfn{PR number} which identifies it throughout its lifetime. For a discussion on the working system adopted by @sc{gnats}, see @ref{Paradigm,,The database paradigm}. You can access the submitting, editing, and querying functions of @sc{gnats} from within @sc{gnu} Emacs. @xref{GNATS user tools,,The @sc{gnats} user tools}. @menu * Introduction:: Introducing GNATS. * GNATS user tools:: The GNATS user tools. * Installation:: Installing GNATS. * Management:: GNATS Administration. * Locations:: Where GNATS lives. * gnatsd:: The GNATS network server. * Access Control:: Controlling access to GNATS databases. * Regexps:: Querying using regular expressions. * dbconfig recipes:: Useful dbconfig tricks. * Support:: GNATS related sites and mailing lists. * Index:: @end menu @c =============================================================== @node Introduction @chapter Introducing @sc{gnats} @cindex introduction to GNATS @cindex rationale @cindex database rationale Any support organization realizes that a large amount of data flows back and forth between the maintainers and the users of their products. This data often takes the form of problem reports and communication via electronic mail. @sc{gnats} addresses the problem of organizing this communication by defining a database made up of archived and indexed problem reports. @sc{gnats} was designed as a tool for software maintainers. It consists of several utilities which, when used in concert, formulate and administer a database of Problem Reports grouped by site-defined @dfn{problem categories}. It allows a support organization to keep track of problems (hence the term @dfn{Problem Report}) in an organized fashion. Essentially, @sc{gnats} acts as an active archive for field-separated textual data. @menu * Paradigm:: The database paradigm * Flowchart:: Flowchart of GNATS activities * States:: States of Problem Reports * Fields:: Problem Report format @end menu @node Paradigm @section The database paradigm @cindex paradigm @cindex database paradigm @cindex why GNATS @cindex support site @cindex maintenance @cindex so what does it do It is in your best interest as the maintainer of a body of work to organize the feedback you receive on that work, and to make it easy for users of your work to report problems and suggestions. @sc{gnats} makes this easy by automatically filing incoming problem reports into appropriate places, by notifying responsible parties of the existence of the problem and (optionally) sending an acknowledgment to the submitter that the report was received, and by making these Problem Reports accessible to queries and easily editable. @sc{gnats} is a database specialized for a specific task. @sc{gnats} was designed for use at a Support Site that handles a high level of problem-related traffic. It maintains Problem Reports in the form of text files with defined @dfn{fields} (@pxref{Fields,,@sc{gnats} data fields}). The location of the database, as well as the categories it accepts as valid, the maintainers for whom it provides service, and the submitters from whom it accepts Problem Reports, are all definable by the @dfn{Support Site}. @xref{Management,,@sc{gnats} administration}. @cindex what is a PR Each PR is a separate file within a main repository (@pxref{Locations,,Where @sc{gnats} lives}). Editing access to the database is regulated to maintain consistency. To make queries on the database faster, an index is kept automatically (@pxref{index file,,The @code{index} file}). We provide several software tools so that users may submit new Problem Reports, edit existing Problem Reports, and query the database. @itemize @bullet @item @w{@code{send-pr}} is used by both product maintainers and the end users of the products they support to submit PRs to the database. @item @w{@code{edit-pr}} is used by maintainers when editing problem reports in the database. @item Maintainers, managers and administrators can use @w{@code{query-pr}} to make inquiries about individual PRs or groups of PRs. @end itemize Other interfaces to @sc{gnats} include Gnatsweb, a web-based tool which provides features for submitting and editing PRs and querying the database, and TkGnats, a Tcl/Tk-based frontend. These tools are distributed together with @sc{gnats}. @cindex GNATS administrator At the Support Site, a @sc{gnats} @dfn{administrator} is charged with the duty of maintaining @sc{gnats}. These duties are discussed in detail in @ref{Management,,@sc{gnats} Administration}, and generally include configuring @sc{gnats} for the Support Site, editing PRs that @sc{gnats} cannot process, pruning log files, setting up new problem categories, backing up the database, and distributing @code{send-pr} so that others may submit Problem Reports. Responsibility for a given Problem Report initially depends on the category of the problem. Optionally, an automated reminder can be sent to the responsible person if a problem report is neglected for a requisite time period. @xref{GNATS configuration,,Overview of @sc{gnats} configuration}. @cindex @code{pending} directory @cindex unparseable incoming PRs @cindex incoming PRs that @sc{gnats} cannot parse @sc{gnats} does not have the ability to decipher random text. If there is no default category set, any problem reports which arrive in a format @sc{gnats} does not recognize are placed in a separate directory pending investigation by the @sc{gnats} administrator (@pxref{Management,,@sc{gnats} Administration}). Once a problem is recorded in the database, work can begin toward a solution. A problem's initial @dfn{state} type is @dfn{open} (@pxref{States,,States of Problem Reports}). An acknowledgment may be sent to the originator of the bug report (depending on whether this feature has been switched on in the @sc{gnats} configuration). @sc{gnats} forwards copies of the report to the party responsible for that problem category and to the person responsible for problems arriving from that submitter. @c (@pxref{Glossary,,Glossary}). When a problem has been identified, the maintainer can change its state to @dfn{analyzed}, and then to @dfn{feedback} when a solution is found. @sc{gnats} may be configured so that each time the state of a PR changes, the submitter of the problem report is notified of the reason for the change. If the party responsible for the PR changes, the previous responsible party and the new responsible party receive notice of the change. The change and reason are also recorded in the @code{Audit-Trail} field of the Problem Report. (@xref{edit-pr,,Editing existing Problem Reports}. For information on the @code{Audit-Trail} field, see @ref{Fields,,Problem Report format}.) When the originator of the Problem Report confirms that the solution works, the maintainer can change the state to @dfn{closed}. If the PR cannot be closed, the maintainer can change its state to @dfn{suspended} as a last resort. (For a more detailed description of the standard states, see @ref{States,,States of Problem Reports}.) It should be emphasized that what we describe here is the default way that @sc{gnats} works, but as of version 4, @sc{gnats} is extremely customizable, allowing sites to tailor almost every aspect of its behavior. See for instance @ref{dbconfig file,,The @code{dbconfig} file} and @xref{States,,States of Problem Reports}.) @node Flowchart @section Flowchart of @sc{gnats} activities @cindex flowchart of GNATS activities @cindex visual map of data flow This informal flowchart shows the relationships of the @sc{gnats} tools to each other and to the files with which they interoperate. @sp 2 @ifset POSTSCRIPT @tex \input epsf \epsffile{flowchart.eps} @end tex @end ifset @ifinfo @clear POSTSCRIPT @end ifinfo @ifclear POSTSCRIPT @cartouche @smallexample @include flowchart.txt @end smallexample @end cartouche @end ifclear @sp 2 @c --------------------------------------------------------------- @include states.texi @c --------------------------------------------------------------- @include fields.texi @c =============================================================== @include p-usage.texi @c =============================================================== @node Installation @chapter Installing @sc{gnats} @include p-inst.texi @c =============================================================== @include p-admin.texi @c =============================================================== @node Locations @appendix Where @sc{gnats} lives @cindex locations @cindex where @sc{gnats} lives @cindex default installation locations We use a few conventions when referring to the installation structure @sc{gnats} uses. These values are adjustable when you build and install @sc{gnats} (@pxref{Installation,,Installing @sc{gnats}}). @menu * prefix:: * exec-prefix:: * gnats-adm:: * defaults:: Default installation locations @end menu @node prefix @section @var{prefix} @cindex @var{prefix} @var{prefix} corresponds to the variable @samp{prefix} for @code{configure}, which passes it on to the @file{Makefile} it creates. @var{prefix} sets the root installation directory for @dfn{host-independent} files as follows: @c FIXME - check these @table @asis @item the directory path of the default database @file{@var{prefix}/com}@* @item site-wide configuration files @file{@var{prefix}/etc/gnats}@* @item @code{man} pages @file{@var{prefix}/man} @item @code{info} documents @file{@var{prefix}/info} @item @code{include} files @file{@var{prefix}/include} @item @emph{etc@dots{}} @end table The default value for @var{prefix} is @w{@file{/usr/local}}, which can be changed on the command line to @code{configure} using @smallexample configure --prefix=@var{prefix} @dots{} @end smallexample @noindent @xref{Configure and make,,Configuring and compiling the software}. @node exec-prefix @section @var{exec-prefix} @cindex @var{exec-prefix} @var{exec-prefix} corresponds to the variable @samp{exec-prefix} for @code{configure}, which passes it on to the @file{Makefile} it creates. @w{@var{exec-prefix}} sets the root installation for @dfn{host-dependent} files as follows: @table @asis @item @sc{gnats} user tools @file{@var{exec-prefix}/bin} @item administrative and support utilities @file{@var{exec-prefix}/libexec/gnats} @item compiled libraries @file{@var{exec-prefix}/lib}@* @item @emph{etc@dots{}} @end table @code{configure} supports several more options which allow you to specify in great detail where different files are installed. The locations given in this appendix do not take into account highly customized installations, but fairly ordinary @sc{gnats} installations should be covered by the material here. For a complete list of options accepted by @code{configure}, run @code{./configure --help} in the @file{gnats} subdirectory of the distribution. Since most installations are not intended to be distributed around a network, the default value for @w{@var{exec-prefix}} is the value of @samp{prefix}, i.e., @w{@file{/usr/local}}. However, using @var{exec-prefix} saves space when you are installing a package on several different platforms for which many files are identical; rather than duplicate them for each host, these files can be shared in a common repository, and you can use symbolic links on each host to find the host-dependent files. Use @var{exec-prefix} in conjunction with @var{prefix} to share host-independent files, like libraries and @code{info} documents. For example: @smallexample @emph{for each host:} configure --prefix=/usr/gnu --exec-prefix=/usr/gnu/H-@var{host} make all install @dots{} @end smallexample @noindent Using this paradigm, all host-dependent binary files are installed into @w{@file{/usr/gnu/H-@var{host}/bin}}, while files which do not depend on the host type for which they were configured are installed into @w{@file{/usr/gnu}}. You can then use a different symbolic link for @w{@file{/usr/gnu}} on each host (@file{/usr} is usually specific to a particular machine; it is always specific to a particular architecture). @smallexample @emph{on host-1:} ln -s /usr/gnu/H-@var{host-1} /usr/gnu @emph{on host-2:} ln -s /usr/gnu/H-@var{host-2} /usr/gnu @end smallexample @noindent To the end user, then, placing @w{@file{/usr/gnu/bin}} in her or his @code{PATH} simply works transparently for each @var{host} type. You can change @w{@var{exec-prefix}} on the command line to @code{configure} using @smallexample configure --exec-prefix=@var{exec-prefix} @dots{} @end smallexample We recommend that you consult @ref{Using configure,,Using @code{configure},configure,Cygnus configure}, before attempting this. @node gnats-adm @section The @file{gnats-adm} directory @cindex @var{gnats-adm} Each @sc{gnats} database located on a server has its own directory, as listed in the @file{databases} (@pxref{databases file,,The @code{databases} file} and given when the @code{mkdb} utility is invoked to initialize the database (@pxref{mkdb,,Initializing a new database}). This directory has several subdirectories, one of which is named @file{gnats-adm}. This directory contains all configuration files related to this specific database, including the @file{categories}, @file{submitters}, @file{responsible}, @file{states}, @file{classes}, @file{dbconfig}, @file{addresses}, @file{states} and @file{gnatsd.user_access}, as well as two files generated and maintained by @sc{gnats}, @file{index} and @file{current}. @node defaults @section Default installation locations @cindex default installation locations @table @asis @item @var{prefix} defaults to @file{/usr/local}; change using @code{configure} (@pxref{Configure and make,,Configuring and compiling the software}). @item @var{exec-prefix} defaults to @var{prefix}; change using @code{configure} (@pxref{Configure and make,,Configuring and compiling the software}). @end table @noindent @sc{gnats} installs tools, utilities, and files into the following locations. @table @code @item @var{exec-prefix}/bin @table @code @item send-pr @xref{send-pr,,Submitting Problem Reports}. @item edit-pr @xref{edit-pr,,Editing existing Problem Reports}. @item query-pr @xref{query-pr,,Querying the database}. @end table @item @var{exec-prefix}/libexec/gnats @table @code @item at-pr @xref{at-pr,,Timely reminders}. @item check-db @xref{check-db,,Checking database health}. @item delete-pr Tool for deleting PRs. Deprecated. Use the --delete-pr option of @code{pr-edit} instead (@pxref{pr-edit,,The edit-pr driver}). @item diff-prs @xref{diff-prs,,The @code{diff-prs} tool}. @item file-pr @xref{file-pr,,Interface to pr-edit for filing new PRs}. @item gen-index @xref{gen-index,,Regenerating the index}. @item gnatsd The @sc{gnats} daemon. @item gnats-pwconv @xref{gnats-pwconv,,Converting old password files}. @item mail-query @xref{Aliases,,Setting up mail aliases}. @item mkcat @xref{mkcat,,Adding a problem category}. @item mkdb @xref{mkdb,,Script for creating new databases}. @item pr-age @xref{pr-age,,The @code{pr-age} tool}. @item pr-edit @xref{pr-edit,,The main PR processor}. @item queue-pr @xref{queue-pr,,Handling incoming traffic}. @item rmcat @xref{rmcat,,Removing categories}. @end table @item @var{exec-prefix}/lib/libiberty.a The @sc{gnu} @code{libiberty} library. @item @var{prefix}/etc/gnats @table @file @item databases @xref{databases file,,The @file{databases} file}. @item defaults @xref{GNATS configuration,,Overview of @sc{gnats} configuration}. @item gnatsd.host_access @xref{gnatsd.host_access,,The @file{gnatsd.host_access} file}. @item gnatsd.user_access @xref{gnatsd.user_access,,The @file{gnatsd.user_access} file}. @end table @item @var{prefix}/share/emacs/site-lisp @table @file @item gnats.el @itemx gnats.elc The Emacs versions of the programs @code{send-pr}, @code{query-pr}, @code{edit-pr}, and @code{view-pr}. @xref{GNATS user tools,,The @sc{gnats} user tools}. To change this directory you must change the @code{lispdir} variable in @file{Makefile.in}; see @ref{Configure and make,,Configuring and compiling the software}. @end table @item @var{prefix}/info @table @file @item gnats.info @itemx send-pr.info The @sc{gnats} manuals, in a form readable by @code{info} (the @sc{gnu} hypertext browser). @xref{Info,,Reading GNU Online Documentation,infoman,GNU Online Documentation}. @end table @item @var{prefix}/man/man1 @itemx @var{prefix}/man/man8 @table @asis @item @code{man} pages for all the @sc{gnats} tools and utilities. @xref{GNATS user tools,,The @sc{gnats} user tools}. @end table @item Per-database directory @table @file @item gnats-adm Administration and configuration data files that define behaviour of the particular database. The files @table @file @item categories @item submitters @item responsible @item states @item classes @item dbconfig @item addresses @item states @item gnatsd.user_access @item index (@emph{This file is created by @sc{gnats}.}) @item current (@emph{This file is created by @sc{gnats}.}) @end table @noindent exist here. @xref{Other config files,,Other database-specific config files}, @ref{Admin files,,Administrative data files} and @ref{Access Control,,Controlling access to databases}. @item gnats-queue Incoming Problem Reports are queued here until the next iteration of @w{@samp{queue-pr -r}} (@pxref{queue-pr,,Handling incoming traffic}). @item pending If no default category is set, problem reports without a category are reassigned to the category @samp{pending} and placed here pending intervention by @sc{gnats} administrators. @xref{Management,,@sc{gnats} administration}. @item @var{category} Each valid category has a corresponding subdirectory in the database. All Problem Reports associated with that category are kept in that subdirectory. @end table @end table @c =============================================================== @node gnatsd @appendix The @sc{gnats} network server -- @code{gnatsd} @cindex @code{gnatsd} This section describes in details how the @sc{gnats} network daemon works. This information is mainly assumed to be useful for developers of @sc{gnats} client software. @menu * Description of gnatsd:: * gnatsd options:: * gnatsd command protocol:: * gnatsd commands:: * gnatsd environment variables:: @end menu @node Description of gnatsd @section Description of @code{gnatsd} @cindex @code{gnatsd} description The @code{gnatsd} network daemon is used to service remote @sc{gnats} requests such as querying PRs, PR creation, deletion, and editing, and miscellaneous database queries. It uses a simple ASCII-based command protocol (similar to SMTP or POP3) for communicating with remote clients. It also provides a security model based either on IP-based authentication (generally considered very weak) or username/passwords, where passwords may be in cleartext, UNIX crypt or MD5 hash format. Access through @code{gnatsd} is granted according to certain predefined @dfn{access levels}. Access levels are further discussed in @ref{Access Control,,Controlling access to databases}. It should be emphasized that security has not been a focus of development until now, but future versions are expected to address this more thoroughly. All of the @sc{gnats} clients are capable of communicating via the @sc{gnats} remote protocol to perform their functions. @c XXX Add reference to remote tool installation section here. @code{gnatsd} is usually started from the inetd facility and should run as the @code{gnats} user (the actual username of this user is configurable during installation, @pxref{Configure and make,,Configuring and compiling the software} for details.) @node gnatsd options @section @code{gnatsd} options @cindex @code{gnatsd} options The daemon supports the following command-line options: @smallexample gnatsd [--database database | -d database] [--not-inetd | -n] [--max-access-level @var{level} | -m @var{level}] [--version | -V] [--help | -h] @end smallexample @cindex @code{gnatsd} startup options @table @code @item -V, --version Prints the program version to stdout and exits. @item -h, --help Prints a short help text to stdout and exits. @item -d, --database Specifies the default database which is to be serviced by this invocation of @code{gnatsd}. (The selected database may be changed via the @code{CHDB} command; the name set with this option is simply the default if no @code{CHDB} command is issued.) If no database is specified, the database named default is assumed. This option overrides the database specified in the @code{GNATSDB} environment variable. @item -n, --not-inetd As its name suggests, indicates that @code{gnatsd} is not being invoked from inetd. This can be used when testing @code{gnatsd}, or if it is being run via ssh or some other mechanism. This has the effect of using the local hostname where @code{gnatsd} is being invoked for authentication purposes, rather than the remote address of the connecting client. @item --max-access-level, -m Specifies the maximum access level that the connecting client can authenticate to. Authentication is as normal but if the user or host authenticates at a higher level, access level is still forced to this level. See @ref{Access Control,,Controlling access to databases} for details on access levels. @end table @node gnatsd command protocol @section @code{gnatsd} command protocol @cindex @code{gnatsd} command protocol Commands are issued to @code{gnatsd} as one or more words followed by a carriage-return/linefeed pair. For example, the @code{CHDB} (change database) command is sent as @samp{CHDB database} (the @code{CRLF} will not be explicitly written for future examples.) Replies from @code{gnatsd} are returned as one or more response lines containing a 3-digit numeric code followed by a human-readable string; the line is terminated with a @code{} pair. For example, one possible response to the @code{CHDB} command above would be: @smallexample 210 Now accessing GNATS database 'database'. @end smallexample The three-digit code is normally followed by a single ASCII space (character 0x20). However, if additional response lines are to be returned from the server, there will be a single dash @samp{-} instead of the space character after the three-digit code. Response code values are divided into ranges. The first digit reflects the general type of response (such as ''successful'' or ''error''), and the subsequent digits identify the specific type of response. @table @var @item Codes 200-299 Positive response indicating that the command was successful. No subsequent data will be transmitted with the response. In particular, code 210 (@code{CODE_OK}) is used as the positive result code for most simple commands. Commands that expect additional data from the client (such as @code{SUBM} or @code{VFLD}) use a two-step mechanism for sending the data. The server will respond to the initial command with either a 211 (@code{CODE_SEND_PR}) or 212 (@code{CODE_SEND_TEXT}) response line, or an error code if an error occurred with the initial command. The client is then expected to send the remaining data using the same quoting mechanism as described for server responses in the 300-349 range. The server will then send a final response line to the command. @item Codes 300-399 Positive response indicating that the query request was successful, and that a PR or other data will follow. Codes 300-349 are used when transmitting PRs, and 350-399 are used for other responses. Codes in the 300-349 range are followed by a series of @code{CRLF}-terminated lines containing the command response, usually a PR. The final line of the result is a single period @samp{.}. Result lines that begin with a period have an extra period prepended to them. Codes in the 350-399 range use a different scheme for sending their responses. The three-digit numeric code will be followed by either a dash @samp{-} or a single space. If the code is followed by a dash, that indicates that another response line will follow. The final line of the response has a single space after the three-digit code. In previous versions of the protocol the first line of a @code{CODE_INFORMATION} (310) response was to be ignored. This is no longer the case. Instead, any lines marked with code @code{CODE_INFORMATION_FILLER} (351) are to be ignored. This allows the server to transmit additional headers or other human-readable text that can be safely ignored by the clients. @item Codes 400-599 An error occurred, usually because of invalid command parameters or invalid input from the client, missing arguments to the command, or a command was issued out of sequence. The human-readable message associated with the response line describes the general problem encountered with the command. Multiple error messages may be returned from a command; in this case the @samp{-} continuation character is used on all but the last response line. @item Codes 600-799 An internal error occurred on the server, a timeout occurred reading data from the client, or a network failure occurred. These errors are of the ''this should not occur'' nature, and retrying the operation may resolve the problem. Fortunately, most @sc{gnats} transactions are idempotent; unfortunately, locking the database or a PR are not repeatable actions (we cannot determine if an existing lock is the one we originally requested, or someone else's). @end table @node gnatsd commands @section @code{gnatsd} commands @cindex @code{gnatsd} commands @cindex @code{gnatsd} commands Note that the set of @sc{gnats} commands and their responses is somewhat inconsistent and is very much in flux. At present the @sc{gnats} clients are rather simple-minded and not very strict about processing responses. For example, if the server were to issue a code 300 (@code{CODE_PR_READY}) response to a @code{CHDB} command, the client would happily expect to see a PR appear (and would print it out if one was sent). It is thus suggested that any clients that use the @sc{gnats} protocol be equally flexible about the way received responses are handled; in particular, only the first digit of the response code should be assumed to be meaningful, although subsequent digits are needed in some cases (codes 300-399). No attempt should be made to parse the message strings on error response lines; they are only intended to be read by humans, and will be changed on a regular basis. Almost every command may result in the response 440 (@code{CODE_CMD_ERROR}). This indicates that there was a problem with the command arguments, usually because of insufficient or too many arguments being specified. Access to most @code{gnatsd} commands requires a certain @dfn{access level}. For details of this, see @ref{Privileged gnatsd commands,,Privileged @code{gnatsd} commands}. @table @code @item USER [@var{userid} @var{password}] Specifies the userid and password for database access. Either both a username and password must be specified, or they both may be omitted; in the latter case, the current access level is returned. The possible server responses are: @code{350 (CODE_INFORMATION)} @*The current access level is specified. @code{422 (CODE_NO_ACCESS)} @*A matching username and password could not be found. @code{200 (CODE_OK)} @*A matching username and password was found, and the login was successful. @item QUIT Requests that the connection be closed. Possible responses: @code{201 (CODE_CLOSING)} @*Normal exit. The @code{QUIT} command has the dubious distinction of being the only command that cannot fail. @item LIST @var{list type} Describes various aspects of the database. The lists are returned as a list of records, one per line. Each line may contain a number of colon-separated fields. Possible values for @var{list type} include @code{Categories} @*Describes the legal categories for the database. @code{Submitters} @*Describes the set of submitters for the database. @code{Responsible} @*Lists the names in the responsible administrative file, including their full names and email addresses. @code{States} @*Lists the states listed in the state administrative file, including the state type (usually blank for most states; the closed state has a special type). @code{FieldNames} @*Lists the entire set of PR fields. @code{InitialInputFields} @*Lists the fields that @emph{should} be present when a PR is initially entered. @code{InitialRequiredFields} @*Lists fields that @emph{have} to be present and nonempty when a PR is initially entered (fields containing only blank characters such as spaces or newlines are considered empty.) @code{Databases} @*Lists the set of databases. The possible responses are: @code{301 (CODE_TEXT_READY)} @*Normal response, followed by the records making up the list as described above. @code{416 (CODE_INVALID_LIST)} @*The requested list does not exist. @item FTYP @var{field} [@var{field} ...] Describes the type of data held in the field(s) specified with the command. The currently defined data types are: @code{Text} @*A plain text field, containing exactly one line. @code{MultiText} @*A text field possibly containing multiple lines of text. @code{Enum} @*An enumerated data field; the value is restricted to one entry out of a list of values associated with the field. @code{MultiEnum} @*The field contains one or more enumerated values. Values are separated with spaces or colons @samp{:}. @code{Integer} @*The field contains an integer value, possibly signed. @code{Date} @*The field contains a date. @code{TextWithRegex} @*The value in the field must match one or more regular expressions associated with the field. The possible responses are: @code{350 (CODE_INFORMATION)} @*The normal response; the supplied text is the data type. @code{410 (CODE_INVALID_FIELD_NAME)} @*The specified field does not exist. If multiple field names were given, multiple response lines will be sent, one for each field, using the standard continuation protocol; each response except the last will have a dash @samp{-} immedately after the response code. @item FTYPINFO @var{field} @var{property} Provides field-type-related information. Currently, only the property @samp{separators} for MultiEnum fields is supported. When @samp{separators} is specified, the possible return codes are: @code{350 (CODE_INFORMATION)} A proper MultiEnum @var{field} was specified and the returned text is the string of separators specified for the field in the dbconfig file (@pxref{Field datatypes}) quoted in @code{'}'s. @code{435 (CODE_INVALID_FTYPE_PROPERTY)} The @samp{separators} property is not defined for this field, i.e. the specified @var{field} is not of type MultiEnum. Currently, specifying a different property than @samp{separators} results in return code 435 as above. @item FDSC @var{field} [@var{field} ... ] Returns a human-readable description of the listed field(s). The possible responses are: @code{350 (CODE_INFORMATION)} The normal response; the supplied text is the field description. @code{410 (CODE_INVALID_FIELD_NAME)} The specified field does not exist. Like the @code{FVLD} command, the standard continuation protocol will be used if multiple fields were specified with the command. @item FIELDFLAGS @var{field} [@var{field} ... ] Returns a set of flags describing the specified field(s). The possible responses are either @code{410 (CODE_INVALID_FIELD_NAME)} @*meaning that the specified field is invalid or nonexistent, or @code{350 (CODE_INFORMATION)} @*which contains the set of flags for the field. The flags may be blank, which indicate that no special flags have been set for this field. Like the @code{FDSC} and @code{FTYP} commands, multiple field names may be listed with the command, and a response line will be returned for each one in the order that the fields appear on the command line. The flags include: @code{textsearch} @*The field will be searched when a text field search is requested. @code{allowAnyValue} @*For fields that contain enumerated values, any legal value may be used in the field, not just ones that appear in the enumerated list. @code{requireChangeReason} @*If the field is edited, a reason for the change must be supplied in the new PR text describing the reason for the change. The reason must be supplied as a multitext PR field in the new PR whose name is @code{field-Changed-Why} (where @code{field} is the name of the field being edited). @code{readonly} @*The field is read-only, and cannot be edited. @item FVLD @var{field} @*Returns one or more regular expressions or strings that describe the valid types of data that can be placed in field. Exactly what is returned is dependent on the type of data that can be stored in the field. For most fields a regular expression is returned; for enumerated fields, the returned values are the list of legal strings that can be held in the field. The possible responses are: @code{301 (CODE_TEXT_READY)} @*The normal response, which is followed by the list of regexps or strings. @code{410 (CODE_INVALID_FIELD_NAME)} The specified field does not exist. @item VFLD @var{field} @code{VFLD} can be used to validate a given value for a field in the database. The client issues the @code{VFLD} command with the name of the field to validate as an argument. The server will either respond with @code{212 (CODE_SEND_TEXT)}, or @code{410 (CODE_INVALID_FIELD_NAME)} if the specified field does not exist. Once the @code{212} response is received from the server, the client should then send the line(s) of text to be validated, using the normal quoting mechanism described for PRs. The final line of text is followed by a line containing a single period, again as when sending PR text. The server will then either respond with @code{210 (CODE_OK)}, indicating that the text is acceptable, or one or more error codes describing the problems with the field contents. @item INPUTDEFAULT @var{field} [@var{field} ... ] Returns the suggested default value for a field when a PR is initially created. The possible responses are either @code{410 (CODE_INVALID_FIELD_NAME)}, meaning that the specified field is invalid or nonexistent, or @code{350 (CODE_INFORMATION)} which contains the default value for the field. Like the @code{FDSC} and @code{FTYP} commands, multiple field names may be listed with the command, and a response line will be returned for each one in the order that the fields appear on the command line. @item RSET Used to reset the internal server state. The current query expression is cleared, and the index of PRs may be reread if it has been updated since the start of the session. The possible responses are: @code{200 (CODE_OK)} @*The state has been reset. @code{440 (CODE_CMD_ERROR)} @*One or more arguments were supplied to the command. @code{6xx (internal error)} @*There were problems resetting the state (usually because the index could not be reread). The session will be immediately terminated. @item LKDB Locks the main @sc{gnats} database. No subsequent database locks will succeed until the lock is removed. Sessions that attempt to write to the database will fail. The possible responses are: @code{200 (CODE_OK)} The lock has been established. @code{440 (CODE_CMD_ERROR)} One or more arguments were supplied to the command. @code{431 (CODE_GNATS_LOCKED)} The database is already locked, and the lock could not be obtained after 10 seconds. @code{6xx (internal error)} An internal error occurred, usually because of permission or other filesystem-related problems. The lock may or may not have been established. @item UNDB Unlocks the database. Any session may steal a database lock; no checking of any sort is done. The possible responses are: @code{200 (CODE_OK)} @*The lock has been removed. @code{432 (CODE_GNATS_NOT_LOCKED)} @*The database was not locked. @code{440 (CODE_CMD_ERROR)} @*One or more arguments were supplied to the command. @code{6xx (internal error)} @*The database lock could not be removed, usually because of permissions or other filesystem-related issues. @item LOCK @var{PR user} [@var{pid}] Locks the specified @var{PR}, marking the lock with the @var{user} name and the optional @var{pid}. (No checking is done that the @var{user} or @var{pid} arguments are valid or meaningful; they are simply treated as strings.) The @code{EDIT} command requires that the PR be locked before it may be successfully executed. However, it does not require that the lock is owned by the editing session, so the usefulness of the lock is simply as an advisory measure. The @code{APPN} and @code{REPL} commands lock the PR as part of the editing process, and they do not require that the PR be locked before they are invoked. The possible responses are: @code{440 (CODE_CMD_ERROR)} @*Insufficient or too many arguments were specified to the command. @code{300 (CODE_PR_READY)} @*The lock was successfully obtained; the text of the PR (using the standard quoting mechanism for PRs) follows. @code{400 (CODE_NONEXISTENT_PR)} @*The PR specified does not exist. @code{430 (CODE_LOCKED_PR)} @*The PR is already locked by another session. @code{6xx (internal error)} @*The PR lock could not be created, usually because of permissions or other filesystem-related issues. @item UNLK @var{PR} Unlocks @var{PR}. Any user may unlock a PR, as no checking is done to determine if the requesting session owns the lock. The possible responses are: @code{440 (CODE_CMD_ERROR)} @*Insufficient or too many arguments were specified to the command. @code{200 (CODE_OK)} @*The PR was successfully unlocked. @code{433 (CODE_PR_NOT_LOCKED)} @*The PR was not locked. @code{6xx (internal error)} @*The PR could not be unlocked, usually because of permission or other filesystem-related problems. @item DELETE @var{PR} Deletes the specified @var{PR}. The user making the request must have admin privileges (@pxref{Access Control,,Controlling access to databases}). If successful, the PR is removed from the filesystem and the index file; a gap will be left in the numbering sequence for PRs. No checks are made that the PR is closed. The possible responses are: @code{200 (CODE_OK)} @*The PR was successfully deleted. @code{422 (CODE_NO_ACCESS)} @*The user requesting the delete does not have admin privileges. @code{430 (CODE_LOCKED_PR)} @*The PR is locked by another session. @code{431 (CODE_GNATS_LOCKED)} @*The database has been locked, and no PRs may be updated until the lock is cleared. @code{6xx (internal error)} @*The PR could not be successfully deleted, usually because of permission or other filesystem-related problems. @item CHEK [initial] Used to check the text of an entire PR for errors. Unlike the @code{VFLD} command, it accepts an entire PR at once instead of the contents of an individual field. The @code{initial} argument indicates that the PR text to be checked is for a PR that will be newly created, rather than an edit or replacement of an existing PR. After the @code{CHEK} command is issued, the server will respond with either a @code{440 (CODE_CMD_ERROR)} response indicating that the command arguments were incorrect, or a @code{211 (CODE_SEND_PR)} response code will be sent. Once the @code{211} response is received from the server, the client should send the PR using the normal PR quoting mechanism; the final line of the PR is then followed by a line containing a single period, as usual. The server will then respond with either a @code{200 (CODE_OK)} response, indicating there were no problems with the supplied text, or one or more error codes listing the problems with the PR. @item EDIT @var{PR} Verifies the replacement text for @var{PR}. If the command is successful, the contents of @var{PR} are completely replaced with the supplied text. The PR must previously have been locked with the @code{LOCK} command. The possible responses are: @code{431 (CODE_GNATS_LOCKED)} @*The database has been locked, and no PRs may be updated until the lock is cleared. @code{433 (CODE_PR_NOT_LOCKED)} @*The PR was not previously locked with the @code{LOCK} command. @code{400 (CODE_NONEXISTENT_PR)} @*The specified PR does not currently exist. The @code{SUBM} command should be used to create new PRs. @code{211 (CODE_SEND_PR)} @*The client should now transmit the replacement PR text using the normal PR quoting mechanism. After the PR has been sent, the server will respond with either @code{200 (CODE_OK)} indicating that the edit was successful, or one or more error codes listing problems either with the replacement PR text or errors encountered while updating the PR file or index. @item EDITADDR @var{address} Sets the e-mail address of the person communicating with @code{gnatsd}. The command requires at least the @code{edit} access level. The possible responses are: @code{200 (CODE_OK)} @*The address was successfully set. @code{440 (CODE_CMD_ERROR)} @*Invalid number of arguments were supplied. @item APPN @var{PR} @var{field} @itemx REPL @var{PR} @var{field} Appends to or replaces the contents of @var{field} in @var{PR} with the supplied text. The command returns a @code{201 (CODE_SEND_TEXT)} response; the client should then transmit the new field contents using the standard PR quoting mechanism. After the server has read the new contents, it then attempts to make the requested change to the PR. The possible responses are: @code{200 (CODE_OK)} @*The PR field was successfully changed. @code{400 (CODE_NONEXISTENT_PR)} @*The PR specified does not exist. @code{410 (CODE_INVALID_FIELD_NAME)} @*The specified field does not exist. @code{402 (CODE_UNREADABLE_PR)} @*The PR could not be read. @code{431 (CODE_GNATS_LOCKED)} @*The database has been locked, and no PRs may be updated until the lock is cleared. @code{430 (CODE_LOCKED_PR)} @*The PR is locked, and may not be altered until the lock is cleared. @code{413 (CODE_INVALID_FIELD_CONTENTS)} @*The supplied (or resulting) field contents are not valid for the field. @code{6xx (internal error)} @*An internal error occurred, usually because of permission or other filesystem-related problems. The PR may or may not have been altered. @item SUBM Submits a new PR into the database. The supplied text is verified for correctness, and if no problems are found a new PR is created. The possible responses are: @code{431 (CODE_GNATS_LOCKED)} @*The database has been locked, and no PRs may be submitted until the lock is cleared. @code{211 (CODE_SEND_PR)} @*The client should now transmit the new PR text using the normal quoting mechanism. After the PR has been sent, the server will respond with either @code{351 (CODE_INFORMATION_FILLER)} and @code{350 (CODE_INFORMATION)} responses indicating that the new PR has been created and supplying the number assigned to it, or one or more error codes listing problems with the new PR text. @item CHDB @var{database} Switches the current database to the name specified in the command. The possible responses are: @code{422 (CODE_NO_ACCESS)} @*The user does not have permission to access the requested database. @code{417 (CODE_INVALID_DATABASE)} @*The database specified does not exist, or one or more configuration errors in the database were encountered. @code{220 (CODE_OK)} @*The current database is now @var{database}. Any operations performed will now be applied to @var{database}. @item DBLS Lists the known set of databases. The possible responses are: @code{6xx (internal error)} @*An internal error was encountered while trying to obtain the list of available databases, usually due to lack of permissions or other filesystem-related problems, or the list of databases is empty. @code{301 (CODE_TEXT_READY)} @*The list of databases follows, one per line, using the standard quoting mechanism. Only the database names are sent. The @code{gnatsd} access level @samp{listdb} denies access until the user has authenticated with the USER command. The only other command available at this access level is @code{DBLS}. This access level provides a way for a site to secure its @sc{gnats} databases while still providing a way for client tools to obtain a list of the databases for use on login screens etc. @xref{Access Control,,Controlling access to databases}. @item DBDESC @var{database} Returns a human-readable description of the specified @var{database}. Responses include: @code{6xx (internal error)} @*An internal error was encountered while trying to read the list of available databases, usually due to lack of permissions or other filesystem-related problems, or the list of databases is empty. @code{350 (CODE_INFORMATION)} @*The normal response; the supplied text is the database description. @code{417 (CODE_INVALID_DATABASE)} @*The specified database name does not have an entry. @item EXPR @var{query expression} Specifies a @var{query expression} used to limit which PRs are returned from the @code{QUER} command. The expression uses the normal query expression syntax, (@pxref{Query expressions}). Multiple @code{EXPR} commands may be issued; the expressions are boolean ANDed together. Expressions are cleared by the @code{RSET} command. Possible responses include: @code{415 (CODE_INVALID_EXPR)} @*The specified expression is invalid, and could not be parsed. @code{200 (CODE_OK)} @*The expression has been accepted and will be used to limit the results returned from @code{QUER}. @item QFMT @var{query format} Use the specified @var{query format} to format the output of the @code{QUER} command. The query format may be either the name of a query format known to the server (@pxref{Named query definitions}), or an actual query format (@pxref{Formatting query-pr output}). The possible responses are: @code{200 (CODE_OK)} @*The normal response, which indicates that the query format is acceptable. @code{440 (CODE_CMD_ERROR)} @*No query format was supplied. @code{418 (CODE_INVALID_QUERY_FORMAT)} @*The specified query format does not exist, or could not be parsed. @item QUER [@var{PR}] [@var{PR}] [...] Searches the contents of the database for PRs that match the (optional) specified expressions with the @code{EXPR} command. If no expressions were specified with @code{EXPR}, the entire set of PRs is returned. If one or more PRs are specified on the command line, only those PRs will be searched and/or output. The format of the output from the command is determined by the query format selected with the @code{QFMT} command. The possible responses are: @code{418 (CODE_INVALID_QUERY_FORMAT)} @*A valid format was not specified with the @code{QFMT} command prior to invoking @code{QUER}. @code{300 (CODE_PR_READY)} @*One or more PRs will be output using the requested query format. The PR text is quoted using the normal quoting mechanisms for PRs. @code{220 (CODE_NO_PRS_MATCHED)} @*No PRs met the specified criteria. @item ADMV @var{field key} [@var{subfield}] Returns an entry from an administrative data file associated with @var{field}. @var{key} is used to look up the entry in the data file. If @var{subfield} is specified, only the value of that subfield is returned; otherwise, all of the fields in the adm data file are returned, separated by colons @samp{:}. The responses are: @code{410 (CODE_INVALID_FIELD_NAME)} The specified field does not exist. @code{221 (CODE_NO_ADM_ENTRY)} An adm entry matching the key was not found, or the field does not have an adm file associated with it. @code{350 (CODE_INFORMATION)} The normal response; the supplied text is the requested field(s). @end table @node gnatsd environment variables @section @code{gnatsd} environment variables @cindex @code{gnatsd} environment variables @cindex @code{GNATSDB} @code{gnatsd} supports the @code{GNATSDB} environment varable, @xref{Environment}, in almost the same way as the @sc{gnats} tools do. This variable is used to determine which database to use. For a local database, it contains the name of the database to access. @code{gnatsd} cannot service remote databases (though it might be interesting if it could) so the database is always assumed to be local. If @code{GNATSDB} is not set and the @code{--database} option is not supplied, it is assumed that the database is local and that its name is @samp{default}. @c =============================================================== @node Access Control @appendix Controlling access to databases @menu * Overview:: * Overall gnatsd access level:: * gnatsd.host_access:: Per-host access settings * gnatsd.user_access:: Access levels per user * Privileged gnatsd commands:: @end menu @node Overview @section Overview @sc{gnats} supports granting various levels of access to the @sc{gnats} databases served by the network daemon, @code{gnatsd}. @sc{gnats} access can be controlled at these levels: @table @code @item deny gnatsd closes the connection @item none no further access until userid and password given @item listdb only listing of available databases is allowed @item view query and view PRs with Confidential=no only @item viewconf query and view PRs with Confidential=yes @item edit full edit access @item admin full admin access @end table @noindent These access levels are used in the following settings: @itemize @bullet @item overall gnatsd access level @item overall access level set by host name or IP address @item overall access level set by userid and password @item per-database access level set by userid and password @end itemize @node Overall gnatsd access level @section Overall @code{gnatsd} access level @noindent The overall @code{gnatsd} access level is set by starting @code{gnatsd} with the option @example @code{-m} @var{level} or @code{--maximum-access-level}=@var{level}, @end example @noindent where @var{level} is one of the six access levels listed above. This restricts any access to the @sc{gnats} daemon to levels up to and including @var{level}, regardless of the settings in the access control files discussed below. If this option is left out, any access levels set in the access control files will be allowed. The discussion below assumes that the pre-build configure of @sc{gnats} was done without altering the default values for the @code{--with-gnatsd-user-access-file} and @code{--with-gnatsd-host-access-file} options. If non-default values were given, substitute as appropriate below. @node gnatsd.host_access @section Overall access levels per host @cindex @file{gnatsd.host_access} The host access file (by default @file{/usr/local/etc/gnats/gnatsd.host_access}) controls overall access levels on a per-host basis, meaning that settings in this file apply across all databases on the server. Entries in this file are in the following format: @var{host:access-level:whatever} @noindent @var{host} is the hostname or IP address of the host contacting gnatsd. Wildcard characters are supported: @samp{*} matches anything; @samp{?} matches any single character. By using wildcards, you can specify access levels for entire network subnets and domains. Note that when @sc{gnats} authenticates hosts, it reads the entries in this file in sequence until a match is found. This means that wildcard entries must be placed near the end of the file, otherwise, they will override non-wildcard entries appearing after the wildcard ones. The second field is the access level of @var{host}. The default is @code{deny}. If the user's hostname isn't in the file or its access level is set to @code{deny}, the connection is closed immediately. @sc{gnats} currently doesn't make use of the third field. Remember to still include the second @samp{:} on the line if you choose to leave the third field empty. Whenever a @code{CHDB} command is processed (or defaulted), the user's access level is set to the level for their host, as determined by the values in the @file{gnatsd.host_access} file. However, even if a host is given the @code{none} access level, an individual can still give the @code{USER} command to possibly gain a higher (but never lower) access than is set for their host. The gnatsd @code{USER} command takes two arguments: @code{USER }. @node gnatsd.user_access @section Access levels per user @cindex @file{gnatsd.user_access} Access levels per user can be set both across all databases on the server or on a per-database basis. The @file{gnatsd.user_access} file in a database's @file{gnats-adm} directory specifies the user access rules for that database. If it doesn't exist, or doesn't contain the user name given to @code{gnatsd}, then the overall user access file (by default @w{@file{/usr/local/etc/gnats/gnatsd.user_access}}) specifying the per-user access levels across all the databases on the server is checked. The user access files can only @emph{increase} the access level defined in the host access files for the given host, they can never lower it. If the access level is @code{none} after processing the userid and password, the connection is closed. The @file{gnatsd.user_access} files can contain plain text passwords, in such a case they should be owned by the @sc{gnats} user with file permission 600. Wildcard characters are supported for the userid and password with plain text passwords. A null string or @samp{*} matches anything; @samp{?} matches any one character. Note that when @sc{gnats} authenticates users, it reads the entries in this file in sequence until a match is found. This means that wildcard entries must be placed near the end of the file, otherwise, they will override non-wildcard entries appearing after the wildcard ones. Entries in the database-specific @file{gnatsd.user_access} user access file in the @file{gnats-adm} directory of the database have the following general format: @var{userid:password:access-level} The overall @file{gnatsd.user_access} user access file adds a fourth @var{databases} field: @var{userid:password:access-level:databases} @noindent @var{password} should either be in plain text, DES @code{crypt()}@footnote{DES crypt is the standard password encryption format used by most UNIX systems} or MD5 hash format@footnote{MD5 is only supported on platforms that have a @code{crypt()} function that supports MD5. Among others, this currently includes @sc{gnu} Linux and OpenBSD.}. If the password is in plain text format, it must be prefixed by @samp{$0$} and if it is in MD5 format, it needs to be prefixed by the string @samp{$1$}.@footnote{Some systems support even more encryption methods. In FreeBSD, for instance, a prefix of @samp{$2$} implies Blowfish encoding. @sc{gnats} will happily accept any encryption that the OS supports.} Passwords encrypted by @code{crypt()} should have no prefix. If no password is given then users can login with an empty password string. A @code{gnats-passwd} tool to manage @file{gnatsd.user_access} files is planned. In the meantime, @code{crypt()} passwords can be generated by using standard UNIX passwords tools, while MD5 passwords can be generated with the following little Perl snippet: @example perl -e 'use Crypt::PasswdMD5 ; print Crypt::PasswdMD5::unix_md5_crypt "@var{password}" , time() % 100000000' @end example @noindent If your Perl installation doesn't have the Crypt module installed, you need to install it. On most systems, the following command achieves this: @example perl -MCPAN -e 'install Crypt::PasswdMD5' @end example A tool for conversion of pre-version 4 @file{gnatsd.user_access} files is distributed with @sc{gnats} 4. @xref{gnats-pwconv,,Converting old password files}. @noindent The @var{access-level} field should contain one of the values listed at the beginning of this appendix. This overrides (increases but never lowers) the access level given as the default for the user's host in the global gnatsd.host_access file. The following shows an example @file{gnatsd.user_access} file with plain text passwords: @example rickm:$0$ruckm:edit pablo:$0$pueblo:view *::none @end example @noindent And this is the same file with MD5-encrypted passwords: @example rickm:$1$92388613$D7ZIYikzTUqd./dODTFrI.:edit pablo:$1$92388652$QRfAhIBG5elT.FQjQKhj80:view *::none @end example @noindent In these examples, anybody other than rickm and pablo get denied access, assuming that the host access level is also @code{none}. You could set the catch-all rule at the end to be @code{*::view} to allow view access to anyone who does not supply a password. Note the important detail that such a rule would allow view access only to persons who do not supply a password at all, i.e. if rickm or pablo tries to log in but mistypes his password, this rule would not apply and they would be denied access entirely. This is by design, since people might be surprised if they suddenly found themselves logged in, but with a lower access level than they usually have. The @var{databases} field contains a comma-separated list of database names, as defined in the @file{databases} file (@pxref{databases file,,The @code{databases} file}. Wildcard characters are supported. The databases listed in this field are the ones to which the other settings on the same line will be applied. @node Privileged gnatsd commands @section Privileged @code{gnatsd} commands Every @code{gnatsd} command has a minimum access level attached to it. If your access level is too low for a command, you get this response: @example LOCK 12 422 You are not authorized to perform this operation (LOCK). @end example @noindent The commands @code{CHDB}, @code{USER} and @code{QUIT} are unrestricted. @noindent The @code{DBLS} command requires at least @code{listdb} access. @noindent A user must have at least @code{edit} access for these commands: @table @code @item LKDB lock the main @sc{gnats} database. @item UNDB unlock the main @sc{gnats} database. @item LOCK @var{PR user pid} lock @var{PR} for @var{user} and optional @var{pid} and return PR text. @item UNLK @var{PR} unlock @var{PR}. @item EDIT @var{PR} check in edited @var{PR}. @item APPN @var{PR} @var{field}, REPL @var{PR} @var{field} Appends to or replaces the contents of @var{field} in @var{PR}. @end table The @code{DELETE} @var{PR} command is special in that it requires @code{admin} access. @noindent All other commands require @code{view} access. @code{edit-pr} and @code{query-pr} accept the command line arguments @code{-v|--user} and @code{-w|--passwd}. @xref{GNATS user tools,,The @sc{gnats} User Tools}. @c =============================================================== @node Regexps @appendix Querying using regular expressions @cindex querying using regexps @cindex regular expressions @cindex syntax of regexps See also @ref{Query expressions}. Unfortunately, we do not have room in this manual for a complete exposition on regular expressions. The following is a basic summary of some regular expressions you might wish to use. @emph{NOTE: When you use query expressions containing regular expressions as part of an ordinary query-pr shell command line, you need to quote them with @code{''}, otherwise the shell will try to interpret the special characters used, yielding highly unpredictable results.} @xref{Regular Expression Syntax,,Regular Expression Syntax,regex,Regex}, for details on regular expression syntax. Also see @ref{Regexps,,Syntax of Regular Expressions,emacs,GNU Emacs Manual}, but beware that the syntax for regular expressions in Emacs is slightly different. All search criteria options to @code{query-pr} rely on regular expression syntax to construct their search patterns. For example, @smallexample query-pr --expr 'State="open"' --format full @end smallexample @noindent matches all PRs whose @code{State} values match with the regular expression @samp{open}. We can substitute the expression @samp{o} for @samp{open}, according to @sc{gnu} regular expression syntax. This matches all values of @code{State} which begin with the letter @samp{o}. We see that @smallexample query-pr --expr 'State="o"' --format full @end smallexample is equivalent to @smallexample query-pr --expr 'State="open"' --format full @end smallexample @noindent in this case, since the only value for @code{State} which matches the expression @samp{o} in a standard installation is @samp{open}. @samp{State="o"} also matches @samp{o}, @samp{oswald}, and even @samp{oooooo}, but none of those values are valid states for a Problem Report in default @sc{gnats} installations. We can also use the expression operator @samp{|} to signify a logical @code{OR}, such that @smallexample query-pr --expr 'State="o|a"' --format full @end smallexample @noindent matches all @samp{open} or @samp{analyzed} Problem Reports. Regular expression syntax considers a regexp token surrounded with parentheses, as in @w{@samp{(@var{regexp})}}, to be a @dfn{group}. This means that @w{@samp{(ab)*}} matches any number (including zero) of contiguous instances of @samp{ab}. Matches include @samp{}, @samp{ab}, and @samp{ababab}. Regular expression syntax considers a regexp token surrounded with square brackets, as in @w{@samp{[@var{regexp}]}}, to be a @dfn{list}. This means that @w{@samp{Char[(ley)(lene)(broiled)}} matches any of the words @samp{Charley}, @samp{Charlene}, or @samp{Charbroiled} (case is significant; @samp{charbroiled} is not matched). Using groups and lists, we see that @smallexample query-pr --expr 'Category="gcc|gdb|gas"' --format full @end smallexample @noindent is equivalent to @smallexample query-pr --expr 'Category="g(cc|db|as)"' --format full @end smallexample @noindent and is also very similar to @smallexample query-pr --expr 'Category="g[cda]"' --format full @end smallexample @noindent with the exception that this last search matches any values which begin with @samp{gc}, @samp{gd}, or @samp{ga}. The @samp{.} character is known as a @dfn{wildcard}. @samp{.} matches on any single character. @samp{*} matches the previous character (except newlines), list, or group any number of times, including zero. Therefore, we can understand @samp{.*} to mean ``match zero or more instances of any character.'' @smallexample query-pr --expr 'State=".*a"' --format full @end smallexample @noindent matches all values for @code{State} which contain an @samp{a}. (These include @samp{analyzed} and @samp{feedback}.) Another way to understand what wildcards do is to follow them on their search for matching text. By our syntax, @samp{.*} matches any character any number of times, including zero. Therefore, @samp{.*a} searches for any group of characters which end with @samp{a}, ignoring the rest of the field. @samp{.*a} matches @samp{analyzed} (stopping at the first @samp{a}) as well as @samp{feedback}. @emph{Note:} When using @samp{fieldtype:Text} or @samp{fieldtype:Multitext} (@pxref{Query expressions}), you do not have to specify the token @samp{.*} at the beginning of your expression to match the entire field. For the technically minded, this is because these queries use @samp{re_search} rather than @samp{re_match}. @samp{re_match} @dfn{anchors} the search at the beginning of the field, while @samp{re_search} does not anchor the search. For example, to search in the @code{>Description:} field for the text @smallexample The defrobulator component returns a nil value. @end smallexample @noindent we can use @smallexample query-pr --expr 'fieldtype:Multitext="defrobulator.*nil"' --format full @end smallexample To also match newlines, we have to include the expression @samp{(.|^M)} instead of just a dot (@samp{.}). @samp{(.|^M)} matches ``any single character except a newline (@samp{.}) @emph{or} (@samp{|}) any newline (@samp{^M}).'' This means that to search for the text @smallexample The defrobulator component enters the bifrabulator routine and returns a nil value. @end smallexample @noindent we must use @smallexample query-pr --expr 'fieldtype:Multitext="defrobulator(.|^M)*nil"' --format full @end smallexample To generate the newline character @samp{^M}, type the following depending on your shell: @table @code @item csh @samp{@emph{control}-V @emph{control}-M} @item tcsh @samp{@emph{control}-V @emph{control}-J} @item sh (@emph{or} bash) Use the @key{RETURN} key, as in @smallexample (.| ) @end smallexample @end table Again, see @ref{Regular Expression Syntax,,Regular Expression Syntax,regex,Regex}, for a much more complete discussion on regular expression syntax. @c =============================================================== @node dbconfig recipes @appendix @file{dbconfig} recipes @cindex dbconfig @cindex @file{dbconfig} recipes The @file{dbconfig} file (@ref{dbconfig file,,The @file{dbconfig} file}) is the heart of any @sc{gnats} installation. It contains some very powerful machinery, something which this appendix tries to illustrate. We provide a range of examples that are both intended to be useful in their own right and to serve as starting points or building blocks for your own modifications. @subsubheading Provide Gnatsweb URL in initial response Sites that have Gnatsweb installed may wish to modify the response e-mail which is sent to the submitter of a PR so that it includes a URL where the status of the PR can be monitored. In order to allow this, you should first create an entry in @file{gnatsd.user_access} which allows viewing of PRs in your database (@xref{gnatsd.user_access,,The @file{gnatsd.user_access} file}.) Next, locate the entry @code{mail-format "initial-response-to-submitter"} in the @file{dbconfig} file of your database and add the following @emph{before} the line reading ``The individual assigned...'' in the @code{body} section: @verbatim \nYou can follow the status of this report on\n\ http://hostname/cgi-bin/scriptname?\n\ cmd=view&database=dbname&user=username&\n\ password=passwd&pr=%s\n\n\ @end verbatim @noindent Substitute @code{hostname}, @code{cgi-bin} and @code{scriptname} as appropriate for the setup of your web server. The part before the @samp{?} would typically look something like @code{http://www.example.com/cgi-bin/gnatsweb.pl}. Substitute the name of your database for @code{dbname}, and the username and password of the user with @code{view} rights for @code{username} and @code{passwd}. @noindent Next, add a @code{Number} to the @code{fields} list statement inside the @code{body} so it reads as follows: @verbatim fields { "Category" "Number" "Number" "Responsible" "Category" "Responsible" "Synopsis" "Arrival-Date" } @end verbatim @subsubheading State full name of responsible in initial response The initial e-mail response to the submitter of a PR identifies the responsible person assigned to the PR as follows: ``The individual assigned to look at your report is: @var{GNATS username}''. Some sites may wish to modify this so that the full name of the responsible person is used instead of the @sc{gnats} user name. The full name is contained in the @code{fullname} subfield of the user's entry in the @file{responsible} file and can be accessed as @code{Responsible[fullname]} (@pxref{administrative files,,Enumerated field administrative files}.) The change is achieved by editing the @file{dbconfig} item @code{mail-format "initial-response-to-submitter"} and changing the @code{fields} part of the @code{Body} from @verbatim fields { "Category" "Number" "Responsible" "Category" "Responsible" "Synopsis" "Arrival-Date" } @end verbatim @noindent to @verbatim fields { "Category" "Number" "Responsible[fullname]" "Category" "Responsible" "Synopsis" "Arrival-Date" } @end verbatim @subsubheading Append-only Audit-Trail The Audit-Trail of a PR is by default editable. For some applications, one might want to make the Audit-Trail append-only, so it provides a full and unchangeable case history. Also by default, only certain changes, such as change of state and change of responsible gets recorded in the Audit-Trail. In some cases, it might also be convenient to have a way of inserting comments directly into the Audit-Trail. The following procedure creates such an append-only Audit-Trail and adds a PR field which makes it possible to register comments in the Audit-Trail. @noindent First, add the keyword @code{read-only} to the Audit-Trail field definition in @file{dbconfig}. @noindent Then, add the following field definition to @file{dbconfig}: @verbatim field "Add-To-Audit-Trail" { description "Add a log entry to the Audit Trail" multitext { default "\n" } on-change { add-audit-trail audit-trail-format { format "**** Comment added by %s on %s ****\n %s\n\n" fields { "$EditUserEmailAddr" "$CurrentDate" "$NewValue" } } } on-change { set-field "Add-To-Audit-Trail" { "\n" } } } @end verbatim @anchor{release-based support} @subsubheading Supporting @sc{gnats} ``release-based'' fields When installing @sc{gnats} version 3.x, it was possible to choose whether to enable three optional fields: @code{Quarter}, @code{Keywords} and @code{Date-Required}. Default installations had these fields switched off, and installations which had them were called ``release-based''. The default @file{dbconfig} shipped with @sc{gnats} version 4 or newer does not have these fields, so if you are upgrading from an old release-based system, you need to add the following field definitions to your @file{dbconfig} file: @verbatim field "Quarter" { description "What quarter does the PR fall into?" text query-default inexact-regexp textsearch } field "Keywords" { description "Keywords used to index this PR" text query-default inexact-regexp textsearch } field "Date-Required" { description "Date that the PR must be fixed by" date } @end verbatim A side note: Pre-release versions of @sc{gnats} 4 also had a field named @code{Cases}. For those who may need it, here is the field definition of @code{Cases}: @verbatim field "Cases" { text query-default inexact-regexp textsearch } @end verbatim @c =============================================================== @node Support @appendix @sc{gnats} support @cindex @sc{gnats} support The @sc{gnats} home page is located at @url{http://www.gnu.org/software/gnats}. It contains all the important references to the available information about @sc{gnats} and the related software. There is also a special page dedicated to the @sc{gnats} development at @url{http://savannah.gnu.org/projects/gnats}. @cindex mailing lists There are several @sc{gnats} mailing lists. The most important ones are: @table @email @item info-gnats@@gnu.org Announcements and other important information about @sc{gnats} and the related software. This is a very low volume moderated list. @item bug-gnats@@gnu.org The bug reporting mailing list on the @sc{gnats} itself. Please note that the preferred way to report @sc{gnats} bugs is to submit them via the web interface at @url{http://bugs.gnu.org/cgi-bin/gnatsweb.pl?database=gnats}. New bug reports submitted via the web interface are copied to the mailing list automatically. @item help-gnats@@gnu.org General discussion about @sc{gnats}. Anything related to @sc{gnats} (user questions, development, suggestions, etc.) can be discussed there. @end table The complete list of @sc{gnats} related mailing lists is available from the web page at @url{http://savannah.gnu.org/project/gnats}. @cindex bug reporting When you report problems concerning @sc{gnats} itself, please do not forget to provide especially the following information: @itemize @bullet @item The @sc{gnats} version you are using. @item The @emph{exact} way how to reproduce the bug. @item Your configuration. @item If you encounter a compilation or build problem, it is especially important to mention the operating system, compiler and possibly other build utilities you use. @end itemize Providing this information in the initial report avoids further unnecessary communication, saves our limited development resources and helps to track down and fix the problem soon. @c =============================================================== @ignore @c complete this someday... @node Glossary @unnumbered Glossary @table @strong @item PR Short for ``Problem Report''. An electronic mail message which reports a problem. A @dfn{record} in the @sc{gnats} database. @item Support Site A central site that provides resources for maintainers of a body of work, such as a software package. We refer to the Support Site as the location where @sc{gnats} is installed and functional. @item Database An organized collection of information. @item @sc{gnats} The @sc{gnu} Problem Report Management System. @item Field A location for specific information. A group of fields make up a Problem Report. @item Mail header Defined by the Internet Internet standard RFC-822 @item Category @item Submitter @item Originator @item Query @item Report @item Site @item Edit @item Submit @item Bug @item State @item ID Number @item Synopsis @item Confidential @item Severity @item Priority @item Responsible @item Configuration @item Class @item Environment @item Description @item Audit-Trail @item Unformatted @item Fix @item Release @item Makefile @item gnats-admin @item pending @item send-pr @item edit-pr @item Maintainers @item timestamp @item utility @item tool @end table @end ignore @node Index @unnumbered Index @printindex cp @bye gnats-4.1.0/doc/p-admin.texi0000644000175000017500000024507107724054132016364 0ustar chewiechewie00000000000000@node Management @chapter @sc{gnats} Administration @cindex administering @sc{gnats} @cindex managing @sc{gnats} @cindex GNATS management @cindex duties for @code{gnats-admin} In daily usage, @sc{gnats} is self-maintaining. However, there are various administrative duties which need to be performed periodically. Also, requirements may change with time, so it may be necessary to make changes to the @sc{gnats} configuration at some point: @table @emph @item emptying the @code{pending} directory @cindex emptying the @code{pending} directory If a Problem Report arrives with a @code{Category} value that is unrecognized by the @file{categories} file, or if that field is missing, @sc{gnats} places the PR in the @w{@file{pending}} directory (@pxref{Locations,,Where @sc{gnats} lives}). PRs submitted in free-form by email will always be filed in the @w{@file{pending}} directory. If so configured, @sc{gnats} sends a notice to the @code{gnats-admin} and to the party responsible for that submitter (as listed in the @file{submitters} file) when this occurs. To have these "categoryless" PRs filed correctly, you can then use a @sc{gnats} tool such as @code{edit-pr} to set the correct category of each PR in the @file{pending} directory. In order to protect yourself from problems caused by full disks, you should arrange to have all mail that is sent to the @sc{gnats} database copied to a log file (@ref{Aliases,,Setting up mail aliases}). Then, should you run out of disk space, and an empty file ends up in the database's @file{pending} directory, you need only look in the log file, which should still contain the full message that was submitted. @item adding another database @cindex adding another database @cindex @code{mkdb} @sc{gnats} supports multiple databases. If you find at some point that you need to add another database to your server, the @code{mkdb} tool does most of the work for you. @xref{mkdb,,Adding another database}. @item adding new categories @cindex adding a problem category @cindex @code{mkcat} Most installations of @sc{gnats} will only require you to add a new line to the @w{@file{categories}} file. The category directory will then be created automatically as needed. However, if automatic directory creation has been switched off in the @file{dbconfig} file (@pxref{dbconfig file,,The @code{dbconfig} file}), you need to use the @file{mkcat} program. @item removing categories @cindex removing a problem category @cindex @code{rmcat} To remove a category, you need to make sure the relevant subdirectory is empty (in other words, make sure no PRs exist for the category you wish to remove). You can then remove the category listing from the @file{categories} file, and invoke @smallexample rmcat @var{category@dots{}} @end smallexample @noindent to remove @var{category} (any number of categories may be specified on the command line to @code{rmcat}, so long as they abide by the above constraints). @item adding and removing maintainers @cindex adding and removing maintainers Edit the @file{responsible} file to add a new maintainer or to remove an existing maintainer. @xref{responsible file,,The @code{responsible} file}. @item building a new index @cindex building a new index @cindex @code{gen-index} If your index becomes corrupted, or if you wish to generate a new one for some reason, use the program @code{gen-index} (@pxref{gen-index,,Regenerating the index}). @item pruning log files @cindex pruning log files Log files often grow to unfathomable proportions. As with gardening, it is best to prune these as they grow, lest they take over your disk and leave you with no room to gather more Problem Reports. If you keep log files, be sure to keep an eye on them. (@xref{Aliases,,Setting up mail aliases}.) @c "gather ye rosebugs while ye may..." @item BACKING UP YOUR DATA @cindex BACK UP YOUR DATA Any database is only useful if its data remains uncorrupted and safe. Performing periodic backups ensures that problems like disk crashes and data corruption are reversible. @end table @xref{Locations,,Where @sc{gnats} lives}. @menu * GNATS configuration:: Overview of GNATS configuration * databases file:: The databases file * dbconfig file:: The dbconfig file * Other config files:: Configuration files * send-pr.conf file:: The send-pr.conf file * Admin files:: Administrative data files * Admin utils:: Administrative utilities * Internal utils:: Internal utilities @end menu @node GNATS configuration @section Overview of @sc{gnats} configuration @cindex @sc{gnats} configuration @cindex Overview of @sc{gnats} configuration @xref{Locations,,Where @sc{gnats} lives}. @sc{gnats} has two, well, actually three, different kinds of configuration file. The @dfn{site-wide} configuration files determine overall behaviour across all the databases on your machine, while the @dfn{database-specific} configuration files determine how @sc{gnats} behaves when dealing with a specific database. In addition, there is a single file that needs to be set up for the @code{send-pr} tool to work properly. These files can be edited at any time --- the next time a @sc{gnats} tool is invoked, the new parameters will take effect. These are the site-wide configuration files used by @sc{gnats}: @cindex Site wide configuration files @table @code @item databases @cindex @file{databases} Specifies database names and their associated parameters, such as in which directory they are located. This file is used by the @sc{gnats} clients to determine the location of a database referred to by name. @xref{databases file,,The @code{databases} file}. @item defaults @cindex @file{defaults} This directory contains the set of default per-database configuration files used when a new database is created with @code{mkdb}. @item gnatsd.host_access @cindex @file{gnatsd.host_access} Controls access levels for the different machines that will do lookups in the databases on this machine. @xref{Access Control,,@sc{gnats} access control}. @item gnatsd.user_access @cindex @file{gnatsd.user_access} Controls user access levels for the databases on this server. The settings apply to all databases (there is also a database-specific user access level file). @xref{Access Control,,@sc{gnats} access control}. @end table @noindent The database-specific configuration is determined by the following files in the @file{gnats-adm} subdirectory of the database directory. @table @code @cindex @code{dbconfig} file @item dbconfig Controls most aspects of how @sc{gnats} behaves when dealing with your database. @xref{dbconfig file,,The @code{dbconfig} file}. @cindex @code{categories} file @item categories The list of categories that @sc{gnats} accepts as valid for the @code{Category} field, and the maintainers responsible for each category. Update this file whenever you have a new category, or whenever a category is no longer valid. You must also update this file whenever responsibility for a category changes, or if a maintainer is no longer valid. @xref{categories file,,The @code{categories} file}. @cindex @code{responsible} file @item responsible An alias list mapping names to their associated mailing addresses. The names in this list can have multiple email addresses associated with them. If a responsible user does not show up in this list, they are assumed to be a user local to the system. This list is not associated with just the responsible user field; all email addresses are mapped through this file whenever mail is sent from @sc{gnats}. @xref{responsible file,,The @code{responsible} file}. @cindex @code{submitters} file @item submitters Lists sites from whom @sc{gnats} accepts Problem Reports. The existence of this file is mandatory, although the feature it provides is not; see @ref{submitters file,,The @code{submitters} file}. @cindex @code{addresses} file @item addresses Mappings between submitter IDs and submitters' e-mail addresses. Use of this file is optional. If you get Problem reports where the @code{Submitter} field is not filled in, @sc{gnats} will use entries in this file to try to derive the submitter ID from the e-mail headers. @xref{addresses file,,The @code{addresses} file}. @cindex @code{states} file @item states Lists the possible states for Problem Reports, typically ranging from @dfn{open} to @dfn{closed}. @xref{addresses file,,The @code{states} file}. @cindex @code{classes} file @item classes Lists the possible classes of Problem Report. This provides an easy way to have ``subcategories'', for example by setting up classes such as @code{sw-bug}, @code{doc-bug}, @code{change-request} etc. @xref{classes file,,The @code{classes} file}. @cindex @code{gnatsd.user_access} file @item gnatsd.user_access Specify the access levels for different users to your database. @xref{Access Control,,@sc{gnats} access control}. @end table The last file in this menagerie is the @code{send-pr} configuration file @file{send-pr.conf}. This file contains some defaults that need to be known in order for @code{send-pr} to work. The file needs to be present on all hosts where @code{send-pr} is to be used. @xref{send-pr.conf file,,the @file{send-pr.conf} file}. @node databases file @section The @code{databases} file @cindex @code{databases} file The @file{databases} configuration file is a site-wide configuration file containing the list of @sc{gnats} databases that are available either on the host itself or remotely over the network, together with some parameters associated with each database. The file contains one line for each database. For databases located on the host itself, each line consists of three fields separated by colons: @var{database name:short description of database:path/to/database} The first field is the database name. This is the name used to identify the database when invoking programs such as @code{query-pr} or @code{send-pr}, either by using the @code{--database} option of the program or by setting the @var{GNATSDB} environment variable to the name of the database. The second field is a short human-readable description of the database contents, and the final field is the directory where the database contents are kept. For a database that is located across a network, but which should be accessible from this host, the entry for the database should look like this: @var{database name:short description of database::hostname:port} The first two fields are the same as for local databases, the third field is empty (notice the two adjacent @samp{:} symbols, indicating an empty field), the fourth field is the hostname of the remote @sc{gnats} server, and the fifth field is the port number that the remote @sc{gnats} is running on. If @sc{gnats} was built with default options, the @file{databases} file will be located in the @w{@file{/usr/local/etc/gnats}} directory. However, if the option @code{--with-gnats-dblist-file} was used during building of @sc{gnats}, the @file{databases} file has the name and location given to this option. A sample @file{databases} file is installed together with @sc{gnats}. Note that if you add a new local database, you must create its data directory, including appropriate subdirectories and administrative files. This is best done using the @code{mkdb} tool, @xref{mkdb}. @node dbconfig file @section The @code{dbconfig} file @cindex @code{dbconfig} file The @file{dbconfig} configuration file controls the configuration of a @sc{gnats} database. Each database has its own individual copy of this file, which is located in the @file{gnats-adm} subdirectory of the database. The file consists of standard plain text. Whitespace is completely optional and is ignored. Sets of braces @samp{@@} are used to delimit the different sections, and all non-keyword values must be surrounded with double quotes. The values in @file{dbconfig} can be changed at any time; the new values take effect for all subsequent iterations of @sc{gnats} tools. The @file{dbconfig} file contains 6 major sections, which must appear in the following order: @itemize @bullet @item Overall database configuration @item Individual field configuration @item Named query definitions @item Audit-trail and outgoing email formats @item Index file description @item Initial Problem Report input fields @end itemize The different sections are described below. While reading the following sections, it will be useful to refer to the sample @file{dbconfig} file which is installed when a new database is initialized with the @code{mkdb} tool. In fact, the sample file provides a configuration that should be usable for a great range of sites, since it reproduces the behaviour of the older, less customizable 3.x versions of @sc{gnats}. @menu * Overall database configuration:: Overall database configuration. * Individual field configuration:: Individual field configuration. * Field datatypes:: Field datatypes. * Edit controls:: Trigger on certain edit actions. * Named query definitions:: Define and name standard queries. * Audit-trail formats:: Specify formatting of the audit-trail. * Outgoing email formats:: Specify contents and formatting of messages sent out by GNATS. * Index file description:: Specify the general format and contents of the database index. * Initial PR input fields:: Which fields should be present on initial PR entry. @end menu @node Overall database configuration @subsection Overall database configuration @cindex Overall database configuration The overall database options are controlled by settings in the @code{database-info} section of the @file{dbconfig} file. The following is the general format of this section: @example database-info @{ [options] @} @end example The following options and values may be used in the @code{database-info} section: @table @code @cindex @code{debug-mode} @item debug-mode@ @ @var{true | false} If set to @code{true}, the database is placed into debug mode. This causes all outgoing email to be sent to the @dfn{gnats-admin} user listed in the @file{responsible} file of the database. The default value is @code{false}. @cindex @code{keep-all-received-headers} @item keep-all-received-headers@ @ @var{true | false} If set to @code{true}, all of the Received: headers for PRs submitted via email are kept in the PR. Otherwise, only the first one is kept. The default value is @code{false}. @cindex @code{notify-about-expired-prs} @item notify-about-expired-prs@ @ @var{true | false} If set to @code{true}, notification email about expired PRs is sent via the @code{at-pr} command. Otherwise, required times for PR fixes are not used. The default value is @code{false}. @cindex @code{send-submitter-ack} @item send-submitter-ack@ @ @var{true | false} When new PRs are submitted to the database, an acknowledgment email will be sent to the submitter of send-submitter-ack is set to @code{true}. This is in addition to the normal notification mail to the person(s) responsible for the new PR. The default value is @code{false}. @cindex @code{libexecdir} @item libexecdir@ @ @var{"directory"} Specifies the directory where the @sc{gnats} administrative executables are located. In particular, @code{at-pr} and @code{mail-pr} are invoked from this directory. The default value is the empty string, which is unlikely to be useful. @cindex @code{business-day-hours} @item business-day-hours@ @ @var{day-start - day-end} Used to specify the hours that define a business day. The values are inclusive and should be given in 24-hour format, with a dash separating them. @sc{gnats} uses these values to determine whether the required completion time for a PR has passed. The default values are 8 for @code{day-start} and 17 for @code{day-end}. @cindex @code{business-week-days} @item business-week-days@ @ @var{week-start - week-end} Specifies the start and ending days of the business week, where 0 is Sunday, 1 is Monday, etc. The days are inclusive, and the values should be given with a dash separating them. @sc{gnats} uses these values to determine whether the required completion time for a PR has passed. The default values are 1 for @code{week-start} and 5 for @code{week-end}. @cindex @code{create-category-dirs} @item create-category-dirs@ @ @var{true | false} If set to @code{true}, database directories for categories are automatically created as needed. Otherwise, they must be created manually (usually with the @code{mkcat} script). It is recommended that the default value of @code{true} be kept. @cindex @code{category-dir-perms} @item category-dir-perms@ @ @var{mode} Standard octal mode-specification specifying the permissions to be set on auto-created category directories. Default is @code{0750}, yielding user read, write and execute, and group read and execute. Note that if you have local users on the @sc{gnats} server itself, running for instance @code{query-pr}, you may need to change the permissions to @code{0755}. @end table @node Individual field configuration @subsection Individual field configuration @cindex Individual field configuration Each type of field in a PR must be described with a @code{field} section in the @file{dbconfig} file. These sections have the following general structure: @example field "fieldname" @{ description "string" [ field-options ... ] datatype [ datatype-options ... ] [ on-change @{ edit-options ... @} ] @} @end example @code{fieldname} is used as the field header in the PR. The characters @code{>} and @code{:} are used internally as field markers by @sc{gnats}, so they must not be used in fieldnames. The order in which the @code{field} sections appear in the @file{dbconfig} file determines the order in which they appear in the PR text. There is no required order, unlike previous versions of @sc{gnats} --- the Unformatted field and multitext fields may appear anywhere in the PR. The following @code{field-options} may be present within a @code{field} section: @table @code @cindex @code{builtin-name} @item builtin-name@ @ @var{"name"} Indicates that this field corresponds to one of the @sc{gnats} built-in fields. @sc{gnats} has several fields which are required to be present in a PR, and this option is used to map their external descriptions to their internal usage. The external field names are: @table @code @item arrival-date @cindex @code{arrival-date} The arrival date of the PR @item audit-trail @cindex @code{audit-trail} The audit-trail recording changes to the PR @item category @cindex @code{category} The category that the PR falls into @item closed-date @cindex @code{closed-date} The date that the PR was closed @item confidential @cindex @code{confidential} If set to @code{yes}, the PR is confidential @item description @cindex @code{description} A description of the problem @item last-modified @cindex @code{last-modified} The date the PR was last modified @item number @cindex @code{number} The PR's unique numeric identifier @item originator @cindex @code{originator} The originator of the PR @item priority @cindex @code{priority} Priority of the PR @item responsible @cindex @code{responsible} The person responsible for handling the PR @item severity @cindex @code{severity} Severity of the problem described by the PR @item state @cindex @code{state} The current state of the PR @item submitter-id @cindex @code{submitter-id} The user that submitted the PR @item synopsis @cindex @code{synopsis} The one-line description of the PR @item unformatted @cindex @code{unformatted} PR text which cannot be parsed and associated with other fields. @end table For these built-in fields, a matching field description @emph{must} appear in the @file{dbconfig} file. Otherwise, the configuration will be considered invalid, and errors will be generated from the @sc{gnats} clients and @code{gnatsd}. We also recommend that you leave the actual fieldnames of these fields at their default values (i.e. capitalized versions of their built-in names), since some clients may depend on these names. @item description@ @ @var{"description text"} A one-line human-readable description of the field. Clients can use this string to describe the field in a help dialog. The string is returned from the FDSC command in gnatsd and is also available via the @code{--field-description} option in @code{query-pr}. This entry must be present in the field description, and there is no default value. @item query-default@ @ @var{exact-regexp | inexact-regexp} Used to specify the default type of searches performed on this field. This is used when the @code{^} search operator appears in a query, and is also used for queries in @code{query-pr} that use the old @code{--field} query options. If the option is not given, the default search is @code{exact-regexp}. @item textsearch If this option is present, the field will be searched when the user performs a @code{--text} search from @code{query-pr}. The field is also flagged as a @code{textsearch} field in the set of field flags returned by the @code{FIELDFLAGS} command in gnatsd. By default, fields are not marked as @code{textsearch} fields. @item read-only When this option is present, the field contents may not be edited --- they must be set when the PR is initially created. In general, this should only be used for fields that are given as internal values rather than fields supplied by the user. By default, editing is allowed. @end table @node Field datatypes @subsection Field datatypes @cindex Field datatypes Each field description has to contain a datatype declaration which describes what data are to be store in the field. The general format for such a declaration is @table @code @cindex @code{datatype} @item datatype@ @ [ options ... ] @end table The available datatypes are: @table @code @cindex @code{text} @item text@ @ [ matching @{ "regexp" [ "regexp" ... ] @} ] The @code{text} datatype is the most commonly used type; it is a one-line text string. If the @code{matching} qualifier is present, the data in the field must match at least one of the specified regexps. This provides an easy and flexible way to limit what text is allowed in a field. If no @code{matching} qualifier is present, no restriction is placed on what values may appear in the field. @cindex @code{multitext} @item multitext@ @ [ @{ default "string" @} ] The field can contain multiple lines of text. If the @code{default} option is present, the field will default to the specified @code{string} if the field is not given a value when the PR is initially created. Otherwise, the field will be left empty. @cindex @code{enum} @item enum@ @ @{ @itemx @ @ values @{ @itemx @ @ @ @ "string" [ "string" ... ] @itemx @ @ @} @itemx @ @ [ default "string" ] @itemx @} Defines an enumerated field, where the values in the PR field must match an entry from a list of specified values. The list of allowed values is given with the @code{values} option. The @code{values} option is required for an enumerated field. If a @code{default} option is present, it is used to determine the initial value of the field if no entry for the field appears in an initial OR (or if the value in the initial PR is not one of the acceptable values). However, the value in the @code{default} statement is not required to be one of the accepted values; this can be used to allow the field to be initially empty, for example. If no @code{default} option is specified, the default value for the field is the first value in the @code{values} section. @cindex @code{multienum} @item multienum@ @ @{ @itemx @ @ values @{ @itemx @ @ @ @ "string" [ "string" ... ] @itemx @ @ @} @itemx @ @ [ separators "string" ] @itemx @ @ [ default "string" ] @itemx @} The @code{multienum} datatype is similar to the @code{enum} datatype, except that the field can contain multiple values, separated by one or more characters from the @code{separators} list. If no @code{separators} option is present, the default separators are space (@samp{ }) and colon (@samp{:}). The values in the @code{default} string for this field type should be separated by one of the defined separators. An example clarifies this. If we have a field named @code{ingredients} where the default values should be @samp{sugar}, @samp{flour} and @samp{baking powder} and the separator is a colon @samp{:}, the following sets these defaults: @smallexample default "sugar:flour:baking powder" @end smallexample @cindex @code{enumerated-in-file} @item enumerated-in-file@ @{ @itemx @ @ path "filename" @itemx @ @ fields @{ @itemx @ @ @ @ "name" [ "name" ... ] @itemx @ @ @} key "name" @itemx @ @ [ allow-any-value ] @itemx @} @anchor{administrative files}The @code{enumerated-in-file} type is used to describe an enumerated field with an associated @dfn{administrative file} which lists the legal values for the field, and may optionally contain additional fields that can be examined by query clients or used for other internal purposes. It is similar to the @code{enum} datatype, except that the list of legal values is stored in a separate file. An example of this kind of field is the built-in Category field with its associeted @file{categories} administrative file. @code{filename} is the name of a file in the @file{gnats-adm} administrative directory for the database. The format of the administrative file should be simple ASCII. @dfn{Subfields} within the file are separated with colons (@samp{:}). Lines beginning with a hash sign (@samp{#}) are ignored as comments. Records within the file are separated with newlines. The @code{field} option is used to name the subfields in the administrative file. There must be at least one subfield, which is used to list the legal values for the field. If the administrative file is empty (or does not contain any non-empty non-comment lines), the PR field must be empty. The @code{key} option is used to designate which field in the administrative file should be used to list the legal values for the PR field. The value must match one of the field names in the @code{field} option. If the @code{allow-any-value} option is present, the value of the PR field is not required to appear in the administrative file --- any value will be accepted. Note that there is no @code{default} keyword for @code{enumerated-in-file}. These fields get their default value from the @emph{first} entry in the associated administrative file. @cindex @code{multi-enumerated-in-file} @item multi-enumerated-in-file@ @{ @itemx @ @ path "filename" @itemx @ @ fields @{ @itemx @ @ @ @ "name" [ "name" ... ] @itemx @ @ @} key "name" @itemx @ @ [ default "string" ] @itemx @ @ [ allow-any-value ] @itemx @ @ [ separators "string" ] @itemx @} @code{multi-enumerated-in-file} is to @code{multienum} what @code{enumerated-in-file} is to @code{enum}. Its options have the same meaning as their counterparts in the @code{multienum} and @code{enumerated-in-file} fields. @emph{NOTE}: Keywords may appear in any sequence, with one exception -- the @code{separators} keyword, if present, has to come last. This rule only applies to fields of type @code{multi-enumerated-in-file}. @cindex @code{date} @item date The @code{date} datatype is used to hold dates. Date fields must either be empty or contain a correctly formatted date. No defaults or other options are available. The field is left empty if no value for the field is given in the initial PR. @cindex @code{integer} @item integer@ @ [ @{ default "integer" @} ] Integer fields are used to hold numbers. They must either be empty or contain a value composed entirely of digits, with an optional leading sign. If the @code{default} option is present, the field will have the value of @code{integer} if the field is not given a value when the PR is initially created. Otherwise, the field will be left empty. @end table @node Edit controls @subsection Edit controls @cindex edit controls The @code{on-change} subsection of a @code{fields} section specifies one or more actions to be performed when the field value is edited by the user. It has the general form @example on-change [ "query-expression" ] @{ @ @ [ add-audit-trail ] @ @ [ audit-trail-format @{ @ @ @ @ format "formatstring" @ @ @ @ [ fields @{ "fieldname" ... @} ] @ @ @} ] @ @ [ require-change-reason ] @ @ [ set-field | append-to-field "fieldname" @{ @ @ @ @ "format-string" [ fieldlist ] @ @ @} ] @ @ [ require @{ "fieldname" ... @} ] @} @end example The optional @code{query-expression} controls whether or not the actions in the @code{on-change} section are taken. If the expression fails to match, the actions are skipped. The @code{add-audit-trail} option indicates that an entry should be appended to the PR's audit-trail when this field is changed. The format of the entry is controlled by the optional @code{audit-trail-format} section within the field, or by the global @code{audit-trail-format} section. See @ref{Audit-trail formats} and @ref{Outgoing email formats}. The @code{require-change-reason} option specifies that a change reason must be present in the PR when this field is edited. This option only makes sense if an audit-trail entry is required, as the change reason is otherwise unused. The @code{set-field} and @code{append-to-field} options are used to change the value of the field @code{fieldname} in the PR. The supplied format is used to format the value that will be placed in the field. @code{append-to-field} appends the resulting formatted string to the existing, while @code{set-field} completely replaces the contents. Any field may be edited by the @code{set-field} or @code{append-to-field} option (the @code{read-only} option on a field is ignored). However, the changes are subject to the usual field content checks. The @code{require} option specifies that one or more fields must have a (non-blank) value when this field is changed. A field may be enforced to have a (non-blank) value at all times by including it in the set of fields required for the initial PR, see @ref{Initial PR input fields}, as well as in the set of fields required on change of the field itself. There is also a global @code{on-change} section that is executed once for each PR edit. A typical use for such a section is to set the last-modified date of the PR. @node Named query definitions @subsection Named query definitions @cindex Named query definitions When queries are performed via @code{query-pr}, they can refer to a query format described by a @code{query} section in the @file{dbconfig} file: @example query "queryname" @{ @ @ format "formatstring" @ @ [fields @{ "fieldname" [ "fieldname" ... ] @} ] @} @end example @code{formatstring} is as described in @ref{Formatting query-pr output}. It basically contains a string with printf-like % escapes. The output of the query is formatted as specified by this format string. The @code{fields} option lists the fields to be used with the format string. If the @code{fields} option is present without a @code{format} option, the contents of the listed fields are printed out, separated by newlines. The named query formats @emph{full}, @emph{standard} amd @emph{summary} must be present in the @file{dbconfig} file. @emph{full} and @emph{summary} correspond to the @code{query-pr} options @code{--full} and @code{--summary}, while @emph{standard} is used when no format option is given to @code{query-pr}. @node Audit-trail formats @subsection Audit-trail formats @cindex Audit-trail format These formats are similar to the named query formats, but they include more options. They are used for formatting audit-trail entries and for outgoing email messages. There is currently only one audit-trail format, defined by the @code{audit-trail-format} option: @example audit-trail-format @{ @ @ format "formatstring" @ @ [ fields @{ "fieldname" [ "fieldname" ... ] @} ] @} @end example For those fields that require an audit-trail entry, the audit-trail text to be appended is formatted as described by this format. The per-field @code{audit-trail-format} is used in preference to this one, if it exists. @code{formatstring} and @code{fieldname} are similar to those used by the named query format. @code{fieldname} may also be a @dfn{format parameter}, which is a context-specific value. (Format parameters are distinguished from fieldnames by a leading dollar sign (@samp{$})). The following format parameters are defined for @code{audit-trail-format} entries: @table @code @cindex format parameters @item $Fieldname The name of the field for which an audit-trail entry is being created. @item $OldValue The old value of the field. @item $NewValue The new field value. @item $EditUserEmailAddr The email address of the user editing the field. Set by the @code{EDITADDR} @code{gnatsd} command or from the @file{responsible} file; if not available, user's local address is used. @item $CurrentDate The current date. @item $ChangeReason The reason for the change; may be blank if no reason was supplied. @end table These parameters may be used anywhere a @code{fieldname} can appear. @node Outgoing email formats @subsection Outgoing email formats @cindex Outgoing email formats During the life of a PR, @sc{gnats} can be configured to send out a range of email messages. When a PR first arrives, an acknowledgment message is sent out if the @code{send-submitter-ack} parameter above is set to @code{true}. Certain edits to the PR may also cause email to be sent out to the various parties, and if a PR is deleted, @sc{gnats} may send notification email. The formats of the email messages are controlled by @code{mail-format} sections in the @file{dbconfig} file. The general structure of a @code{mail-format} section is as follows: @c XXX The use of | and []'s below needs to be cleaned up @example mail-format "format-name" @{ @ @ from-address @{ @ @ @ @ [ fixed-address "address" ] @ @ @ @ [ email-header-name | [ mail-header-name | ... ] ] @ @ @} @ @ to-address @{ @ @ @ @ [ fixed-address "address" ] @ @ @ @ [ "email-header-name" | [ "mail-header-name" | ... ] ] @ @ @} @ @ reply-to @{ @ @ @ @ [ fixed-address "address" ] @ @ @ @ [ "email-header-name" | ... ] | [ "gnats-field-name" | ... ] @ @ @} @ @ header @{ @ @ @ @ format "formatstring" @ @ @ @ [ fields @{ "fieldname" [ "fieldname" ... ] @} ] @ @ @} @ @ body @{ @ @ @ @ format "formatstring" @ @ @ @ [ fields @{ "fieldname" [ "fieldname" ... ] @} ] @ @ @} @} @end example @code{gnats} recognizes and uses 6 different @code{format-name} values: @table @code @cindex @code{format-name} @item initial-response-to-submitter @cindex @code{initial-response-to-submitter} Format of the message used when mailing an initial response back to the PR submitter. This message will only be sent if @code{send-submitter-ack} in the overall database configuration is set to @code{true}. @item initial-pr-notification @cindex @code{initial-pr-notification} Format of the message sent to the responsible parties when a new PR with category different from ``pending'' arrives. @item initial-pr-notification-pending @cindex @code{initial-pr-notification-pending} Format of the message sent to the responsible parties when a new PR that ends up with category ``pending'' arrives. @item appended-email-response @cindex @code{appended-email-response} Format of the notification message sent out when a response to a PR is received via email. @item audit-mail @cindex @code{audit-mail} Format of the message sent out when a PR edit generates an Audit-Trail entry. @item deleted-pr-mail @cindex @code{deleted-pr-mail} Format of the message sent out when a PR is deleted. @end table The @code{from-address}, @code{to-address} and @code{reply-to} subsections of a mail-format section specify the contents of the @code{To:}, @code{From:} and @code{Reply-To:} headers in outgoing email. There are two ways to specify the contents: by using a @code{fixed-address} specification, or by specifying @code{email-header-name}s or @code{gnats-field-name}s. When an @code{email-header-name} or @code{gnats-field-name} value is given, @sc{gnats} will attempt to extract an email address from the specified location. If several values are given on the same line, separated by @samp{|} characters, @sc{gnats} will try to extract an address from each location in turn until it finds a header or field which is nonempty. The following example should clarify this: @example mail-format "initial-response-to-submitter" @{ @ @ from-address @{ @ @ @ @ fixed-address "gnats-admin" @ @ @} @ @ to-addresses @{ @ @ @ @ "Reply-To:" | "From:" | "Submitter-Id" @ @ @} @dots{} @end example This partial @code{mail-format} section specifies the format of the address headers in the email message that is sent out as an acknowledgment of a received PR. The @code{From:} field of the message will contain the email address of the @sc{gnats} administrator, as specified by the @code{gnats-admin} line in the @file{responsible} file. To fill in the @code{To:} header, @sc{gnats} will first look for the mail header @code{Reply-To:} in the PR and use the contents of that, if any. If that header doesn't exist or is empty, it will look for the contents of the @code{From:} email header, and if that yields nothing, it will look for the @sc{gnats} @code{Submitter-Id} field and use the contents of that. Other email headers to be included in messages sent out by @sc{gnats} can be specified by @code{header} subsections of the @code{mail-header} section. @code{formatstring} and @code{fieldname} are similar to those used by the named query format. Each header line must have a newline character (@samp{\n}) at the end. The email message body is specified in the @code{body} subsection of the @code{mail-format} section. Just as for a @code{header} section, the @code{body} section must contain a @code{formatstring} and @code{fieldname} values. For some of the formats that @sc{gnats} recognizes, special variables are available for use. The following table lists the formats that provide special variables. See the example below for an illustration of how they are used. @table @code @item appended-email-response @table @code @item $MailFrom The From: line of the original message. @item $MailTo The To: line of the original message. @item $MailSubject The Subject: line of the original message. @item $MailCC The CC: line of the original message. @item $NewAuditTrail The text of the new audit trail entry (corresponds to the body of the message). @end table @item audit-mail @table @code @item $EditUserEmailAddr The email address of the user editing the PR. Set by the @code{EDITADDR} @code{gnatsd} command or from the @file{responsible} file; if not available, user's local address is used. @item $OldResponsible The previous Responsible field entry, if it was changed. @item $NewAuditTrail The Audit-Trail: entries that have been appended by the edits. @end table @item deleted-pr-mail @table @code @item $EditUserEmailAddr The email address of the user deleting the PR. Set by the @code{EDITADDR} @code{gnatsd} command or from the @file{responsible} file; if not available, user's local address is used. @item $PRNum The number of the PR that was deleted. @end table @end table The following example illustrates the use of these special variables: @example mail-format "deleted-pr-mail" @{ @ @ from-address @{ @ @ @ @ "$EditUserEmailAddr" @ @ @} @ @ to-addresses @{ @ @ @ @ fixed-address "gnats-admin" @ @ @} @ @ header @{ @ @ @ @ format "Subject: Deleted PR %s\n" @ @ @ @ fields @{ "$PRNum" @} @ @ @} @ @ body @{ @ @ @ @ format "PR %s was deleted by user %s.\n" @ @ @ @ fields @{ "$PRNum" "$EditUserEmailAddr" @} @ @ @} @} @end example This @code{mail-format} section specifies the format of the email message that is sent out when a PR is deleted. The @code{From:} field is set to the email address field of the user who deleted the PR, the subject of the message contains the number of the deleted PR, and the message body contains both the PR number and the user's email address. @node Index file description @subsection Index file description @cindex Index file description The @code{index} section of the @file{dbconfig} file lists the fields that appear in the database index. The index is always keyed by PR number. The general format for the @code{index} section is @example index @{ @ @ path "file" @ @ fields @{ "fieldname" [ "fieldname" ... ] @} @ @ binary-index true | false @ @ [ separator "symbol" ] @} @end example The @code{path} parameter gives the name of the index file in the @file{gnats-adm} directory of the database. Only one index is allowed per database, so only one @code{path} entry is allowed. The @code{fields} parameter controls what fields will appear, and in what order, in the index. Fields are listed by their names, separated by spaces (@samp{ }). Fields will appear in the order they are listed. The @code{binary-index} parameter controls whether the index is supposed to be in plaintext or binary format. Binary format is recommended, as it avoids potential problems when field separators appear as bona-fide field contents. When plaintext format is used, by setting @code{binary-index false}, the symbol (@samp{|}) is used as a field separator in the index, unless the optional @code{separator} parameter is used to redefine the separator character. @node Initial PR input fields @subsection Initial PR input fields @cindex Initial PR input fields An @code{initial-entry} section in the @file{dbconfig} file is used to describe which fields should be present on initial PR entry; this is used by tools such as send-pr to determine which fields to include in a ``blank'' PR template. An optional @code{require} parameter can be defined to specify a subset of the @code{intial-entry} fields which must be assigned a value upon initial creation of the PR. The general format for the @code{initial-entry} section is @example initial-entry @{ @ @ fields @{ "fieldname" [ "fieldname" ... ] @} @ @ [ require @{ "fieldname" [ "fieldname" ... ] @} ] @} @end example @node Other config files @section Other database-specific config files @menu * categories file:: * responsible file:: * submitters file:: * states file:: * addresses file:: * classes file:: @end menu @node categories file @subsection The @code{categories} file @cindex @code{categories} file The @file{categories} file contains a list of problem categories, specific to the database, which @sc{gnats} tracks. This file also matches responsible people with these categories. You must edit this file initially, creating valid categories. In most installations, @sc{gnats} is configured to create directories on disk for valid categories automatically as needed (@pxref{Overall database configuration,,Overall database configuration}). If @sc{gnats} isn't set up to do this, you need to run @code{mkcat} to create the corresponding subdirectories of the database directory. For instructions on running @code{mkcat}, see @ref{mkcat,,Adding a problem category}. To create a new category, log in as @sc{gnats}, add a line to this file, and run @code{mkcat} if applicable. Lines beginning with @samp{#} are ignored. A line in the @file{categories} file consists of four fields delimited by colons, as follows: @smallexample @var{category}:@var{description}:@var{responsible}:@var{notify} @end smallexample @noindent @table @var @item category A unique category name, made up of text characters. This name cannot contain spaces or any of the following characters: @smallexample ! $ & * ( ) @{ @} [ ] ` ' " ; : < > ~ @end smallexample @noindent Ideally, category names should not contain commas or begin with periods. Each line has a corresponding subdirectory in the database directory. @item description A terse textual description of the category. @item responsible The name tag of the party responsible for this category of problems, as listed in the @file{responsible} file (@pxref{responsible file,,The @code{responsible} file}). @item notify One or more other parties which should be notified when a Problem Report with this category arrives, such as a project manager, other members of the same project, other interested parties, or even log files. These should be separated with commas. @end table A good strategy for configuring this file is to have a different category for each product your organization supports or wishes to track information for. @smallexample rock:ROCK program:me:myboss,fred stone:STONE utils:barney:fred iron:IRON firewall:me:firewall-log @end smallexample In the above example, the nametags @samp{myboss}, @samp{me}, @samp{fred}, and @samp{barney} must be defined in the @file{responsible} file (@pxref{responsible file,,The @code{responsible} file}). Problem Reports with a category of @samp{rock} are sent to the local mail address (or alias) @samp{me}, and also sent to the addresses @samp{myboss} and @samp{fred}. PRs with a category of @samp{stone} are sent to the local addresses @samp{barney} and @samp{fred} only, while PRs with the category @samp{iron} are sent only to @samp{me}, and are also filed in @code{firewall-log} (in this case, a mail alias should be set up, @pxref{Aliases,,Setting up mail aliases}. If you want to separate PRs in each problem category into specific subsets, say @emph{documentation} and @emph{software bugs}, using the @file{classes} file is recommended. @xref{classes file,,The @file{classes} file}. Only one category @emph{must} be present for @sc{gnats} to function: @smallexample pending:Non-categorized PRs:gnats-admin: @end smallexample @cindex @code{pending} file The @file{pending} directory is created automatically when you run @code{mkdb} to initialize a new database. (@pxref{Configure and make,,Configuring and compiling the software}). @node responsible file @subsection The @code{responsible} file @cindex @code{responsible} file This file contains a list of the responsible parties. Lines beginning with @samp{#} are ignored. Each entry contains three fields, separated by colons: @smallexample @var{responsible}:@var{full-name}:@var{mail-address} @end smallexample @noindent @table @var @item responsible A name-tag description of the party in question, such as her or his user name, or the name of the group. This name is listed in the PR in the @code{Responsible} field. @item full-name The full name of the party (``Charlotte Bronte''; ``Compiler Group''). @item mail-address The full, valid mail address of the party. This field is only necessary if the responsible party has no local mail address or alias. @end table @noindent A sample @file{responsible} listing might be: @smallexample ren:Ren Hoek: stimpy:Stimpson J. Cat:stimpy@@lederhosen.org @end smallexample @noindent Here, @code{ren} is a local user. @code{stimpy} is remote, so his full address must be specified. @noindent The following entry @emph{must} be present for @sc{gnats} to function: @smallexample gnats-admin:GNATS administrator: @end smallexample @noindent @code{gnats-admin} is usually defined as a mail alias when @sc{gnats} is installed, so for this purpose @code{gnats-admin} is a local address. However, this line can alos be used to redefine the email address of the @sc{gnats} administrator, by adding the desired address at the end of the line. @node submitters file @subsection The @code{submitters} file @cindex @code{submitters} file This is a database of sites which submit bugs to your support site. It contains six fields delineated by colons. Lines beginning with @samp{#} will be ignored. Entries are of the format: @smallexample @var{submitter-id}:@var{name}:@var{type}:@var{resp-time}:@var{contact}:@var{notify} @end smallexample @noindent @table @var @item submitter-id A unique identifier for a specific site or other entity who submits Problem Reports. The first @code{submitter-id} listed in the file will be the default for PRs that arrive with invalid or empty submitter fields. @item name The full name or a description of this entity. @item type Optional description for the type of relationship of this submitter to your support site. This could indicate a contract type, a level of expertise, etc., or it can remain blank. @item resp-time Optional quoted response time in @dfn{business hours}. If the database @file{dbconfig} file has the @code{notify-about-expired-prs} entry set to @var{true} (@pxref{Overall database configuration,,Overall database configuration}, @sc{gnats} will use this field to schedule when it should notify the gnats-admin, responsible person and submitter contact that the PR wasn't analyzed within the agreed response time. Business hours and business-week days are set in the @file{dbconfig} file. For information on @code{at-pr}, the program which sends out this reminder, see @ref{at-pr,,Timely Reminders}. @item contact The name tag of the main @dfn{contact} at the Support Site for this submitter. This contact should be in the @file{responsible} file (@pxref{responsible file,,The @code{responsible} file}). Incoming bugs from @var{submitter} are sent to this contact. Optionally, this field can be left blank. @item notify Any other parties who should receive copies of Problem Reports sent in by @var{submitter}. They need not be listed in the @file{responsible} file. @end table A few example entries in the @file{submitters} file: @smallexample univ-hell:University of Hades:eternal:3:beelzebub:lucifer tta:Telephones and Telegraphs of America:support:720:dave: @end smallexample @noindent In this example, when a PR comes in from the University of Hades (who has an eternal contract), it should have @samp{univ-hell} in its @code{Submitter-Id} field. This Problem Report goes to @code{beelzebub} (who should be in the @file{responsible} file), and if it is not analyzed within three business hours a reminder message is sent. @code{lucifer} also receives a copy of the bug, and a copy of the reminder message as well (if it is sent). When Telephones and Telegraphs of America utilizes their support contract and submits a bug, a copy is sent only to @code{dave}, who has 720 business hours to return an analysis before a reminder is sent. @cindex disabling @var{submitter-id} To disable the feature of @sc{gnats} which tracks the @code{Submitter-Id}, simply alter the @file{submitters} file to only contain one @var{submitter-id} value, and instruct your submitters to ignore the field. @node states file @subsection The @code{states} file @cindex @code{states} file This file lists the possible states for Problem Reports. Each entry has up to three fields, separated by colons. Lines beginning with @samp{#} will be ignored. @smallexample @var{state}:@var{type}:@var{description} @end smallexample @noindent @table @var @item state The name of the state. It may contain alphanumerics as well as @samp{-} (hyphen), @samp{_} (underscore), or @samp{.} (period), but no other characters. @item type This is the type of the state. This field is optional and it may contain alphanumerics as well as @samp{-} (hyphen), @samp{_} (underscore), or @samp{.} (period), but no other characters. The concept of the type of a state recognizes that there may for instance be several possible states for a Problem Report which effectively means that the PR is closed and that there may be certain actions that need to be taken when a PR reaches a ``closed state''. The problem may have been resolved, it might have been decided that the problem is unsolvable or simply that it won't be solved. Some organizations may for instance wish to consider the ``suspended'' state as a state of type ``closed''. Currently, the only defined state types are ``open'' and ``closed'', the ``open'' type isn't currently used for anything while the ``closed'' type is only used to control the Closed-Date field of PRs. Changing the state of a PR to any state of type ``closed'' will set the Closed-Date field with a time stamp and changing the state of a PR from one ``closed'' state to another will leave the Closed-Date field as it was. Changing the state of a PR from any state of type ``closed'' to a non-closed state will clear the Closed-Date field. The @code{--skip-closed} option of @code{query-pr} refers to all states of type ``closed'', not to a specific state name of ``closed''. @item description This is is an optional one-line description of what the state means. Any character is okay in the description; a newline ends it. @sc{gnats} itself does not currently use the description for anything, but certain external tools (such as TkGnats and Gnatsweb) look for it, so it's a good idea to include one for every state. @end table The first state listed will be the state automatically assigned to Problem Reports when they arrive; by default this is named ``open''. The last state listed is the end state for Problem Reports --- one should usually assume that a PR in this state is not being actively worked on; by default this state is named ``closed''. Even if a different name has been chosen for this state, @sc{gnats} will force this state to be of type ``closed''. It is recommended that you keep the default names of ``open'' and ``closed'' for the first and last states respectively, since there may be external tools that depend on these names. @node addresses file @subsection The @code{addresses} file @cindex @code{addresses} file This file contains mappings between submitter IDs and corresponding e-mail addresses. When a PR comes in without a submitter ID (if someone sends unformatted e-mail to the PR submission email address), @sc{gnats} will try to derive the submitter ID from the address in the "From:" header. The entries in this file consist of two fields, separated by a colon: @smallexample @var{submitter-id}:@var{address-fragment} @end smallexample @noindent @table @var @item @var{submitter-id} A valid submitter ID @item @var{address-fragment} Part of, or all of the e-mail address to be matched @end table Here is an example of an @code{addresses} file: @smallexample # Addresses for Yoyodine Inc yoyodine:yoyodine.com yoyodine:yoyodine.co.uk # Addresses for Foobar Inc. foobar1:sales.foobar.com foobar2:admin.foobar.com foobar3:clark@@research.foobar.com @end smallexample @sc{gnats} checks each line in the @code{addresses} file, comparing @var{address-fragment} to the end of the "From:" header, until it finds a match. If no match is found, @sc{gnats} uses the default submitter ID. You can only have one address fragment per line, but you can have more than one line for a given submitter ID. An address fragment can be a domain (i.e. yoyodine.com), a machine location (admin.foobar.com), or a full e-mail address (clark@@research.foobar.com). @sc{gnats} can match addresses in three e-mail formats: @table @samp @item From: name@@address.com The address by itself without a full name, not enclosed in brackets @item From: Real Person A full name (optional, with or without quotation marks), followed by the address enclosed in angle brackets @item From: name@@address.com (Real Person) An address, followed by a name or comment in parentheses @end table If @sc{gnats} sees other e-mail address formats, it uses the default submitter ID. @node classes file @subsection The @code{classes} file @cindex @code{classes} file This file lists the possible classes of Problem Reports. Each line consists of a class name, followed by a colon and an optional class type name (the class type name is not used for anything in the current implementation of @sc{gnats}, so it may be left blank. The @code{class} and @code{class-type-name} fields may only contain alphanumerics, @samp{-}, @samp{_}, and @samp{.}, but no other characters. Then comes another colon, followed by an optional one-line description of the class. @sc{gnats} itself does not use the class description, but external tools such as Gnatsweb and TkGnats may use it. Therefore, a line in this file should at least contain the following: @smallexample class::class description @end smallexample Lines beginning with @samp{#} will be ignored, and the first listed class is the default class for an incoming Problem Report. @node send-pr.conf file @section The @file{send-pr.conf} file @cindex @code{send-pr.conf} file This file contains some default values that need to be known in order for @code{send-pr} to work properly. This file needs to be copied to all hosts where @code{send-pr} will be used. If @sc{gnats} was built with default options, the @file{send-pr.conf} file should be placed in the @w{@file{/usr/local/etc/gnats}} directory. However, if the option @code{--sysconfdir} was used during building of @sc{gnats}, the @file{send-pr.conf} file resides at the location given to this option. Entries in this file are on the format @smallexample variable=@var{value} @end smallexample The valid variables are: @table @code @item SUBMITTER The default value to be used for the Submitter-Id field when @code{send-pr} is invoked. @item DEFAULT_RELEASE The default value to be used for the Release field (only applicable if the Release field is defined in the @file{dbconfig} file. @item DEFAULT_ORGANIZATION The default value to be used for the Organization field. (only applicable if the Organization field is defined in the @file{dbconfig} file. @item MAILPROG If the @sc{gnats} server can't be reached directly over the network, i.e. it is behind a firewall or suchlike, @code{send-pr} can be set up to submit Problem Reports by e-mail. This is done by setting the @code{MAILPROG} variable to point to a mailer such as Sendmail. If @code{MAILPROG} needs to have the address that the mail is being sent to specified on the command line, it should be specified here as well (for example, @samp{MAILPROG=''mail bugs@@foo.bar.com''} should work). If Sendmail is used, use @samp{MAILPROG=''/usr/lib/sendmail -oi -t''}. See also @code{MAILADDR} and @code{TEMPLATE} below. @item MAILADDR If using e-mail to submit PRs, this is the address that PRs should be sent to. @item TEMPLATE When invoked, @code{send-pr} communicates directly over the network with the @sc{gnats} server to determine what fields to include in a correctly formatted Problem Report so that it can present the user with a template. If the @sc{gnats} server can't be reached directly over the network, a template must be provided. Set the @code{TEMPLATE} variable to point to a template file created on the @sc{gnats} server by using the command @command{send-pr -p}. @xref{Installing tools,,Installing the user tools}. @end table @node Admin files @section Administrative data files @cindex admin files @cindex files used for @sc{gnats} administration The following files are database-specific and are located in the @file{gnats-adm} subdirectory of the database directory. These files are maintained by @sc{gnats}; you should never need to touch them. @menu * index file:: The `index' file * current file:: The `current' file @end menu @node index file @subsection The @code{index} file @cindex @code{index} file The index is used to accelerate searches on the database by @code{query-pr} and @code{edit-pr}. This file is not created until the first PR comes in. It is then kept up to date by @sc{gnats}; you should never touch this file. Searches on subjects contained in the index are much faster than searches which depend on data not in the index. Inexes come in two different formats: @dfn{binary} and @dfn{plain-text}. Binary indexes are safer, in that they avoid certain problems that may crop up if the field separators used by plain-text indexes appear in field data. A plain-text index contains single-line entries for all PR fields except for the multitext fields such as Description, How-To-Repeat, etc. Fields are separated by bars (@samp{|}) except for @code{Category} and @code{Number}, which are separated by a slash (@samp{/}). Binary indexes are not meant to be human-readable, but they are safer than the plain-text variety, in that they avoid certain problems that may crop up if the field separators used by plain-text indexes appear in field data. The format of the index for a database is set in the @file{dbconfig} file. @xref{Index file description,,Index file description}. Should the @file{index} file become corrupted, the @code{gen-index} utility can be used to regenerate it. @xref{gen-index,,Regenerating the index}. @node current file @subsection The @code{current} file @cindex @code{current} file This file contains the last serial number assigned to an incoming PR. It is used internally by @sc{gnats}; you need never touch this file. @node Admin utils @section Administrative utilities @cindex administrative utilities These tools are used by the @sc{gnats} administrator as part of the periodic maintenance and configuration of @sc{gnats}. @xref{Management,,@sc{gnats} Administration}. @menu * mkdb:: Adding another database * mkcat:: Adding a problem category * rmcat:: Removing a problem category * gen-index:: Regenerating the index * check-db:: Checking database health * gnats-pwconv:: Managing user passwords @end menu @node mkdb @subsection Adding another database @cindex @code{mkdb} @cindex initializing a database @cindex new database To initialize a new @sc{gnats} database: @enumerate 1 @item Add a line for the new database in the @file{databases} file (@pxref{Locations,,Where @sc{gnats} lives}. @item Run @code{mkdb}, using @smallexample mkdb @var{database} @end smallexample where @var{database} is the database you specified in the @file{databases} file. @code{mkdb} creates the database directory and populates it with the directories @file{pending}, @file{gnats-queue} and @file{gnats-adm}. A full set of sample configuration files is copied to the @file{gnats-adm} directory. @end enumerate @node mkcat @subsection Adding a problem category @cindex @code{mkcat} @cindex adding a problem category @cindex new problem categories @cindex @code{categories} file To add new categories to the database: @enumerate 1 @item Add a line to for each new category to the @file{categories} file in the gnats-adm directory of the database. @xref{categories file,,The @code{categories} file}. @item Run @code{mkcat} If applicable. If @code{create-category-dirs} is set to @code{false} in the database @file{dbconfig} file, you need to create category directories with @code{mkcat}. @code{mkcat} creates a subdirectory under the database directory for any new categories which appear in the @file{categories} file. @end enumerate @node rmcat @subsection Removing a problem category @cindex @code{rmcat} @cindex removing a problem category @cindex @code{categories} file To remove a category from the database: @enumerate 1 @item Remove the Problem Reports from the subdirectories corresponding to the categories you wish to remove, or assign the PRs to new categories. All PRs for a given category reside in a subdirectory of the database directory, with the same name as the category. @item Run @code{rmcat} using @smallexample rmcat @var{category} [ @var{category@dots{}} ] @end smallexample @noindent where @var{category} is the category you wish to remove. You can specify as many categories as you wish as long as each category has no PRs associated with it. @code{rmcat} removes the directory where the Problem Reports for that category had been stored. @end enumerate @c FIXME! Should we suggest this? @ignore To reassign a group of categories.... (The idea is to call "query-pr --full", run the output through sed, and then throw it at pr-edit. This approach is untested, and may be unhealthy.) @end ignore @node gen-index @subsection Regenerating the index @cindex @code{gen-index} @cindex @code{index} file If your @file{index} file becomes corrupted, or if you need a copy of the current index for some reason, use @smallexample gen-index [ -n | --numeric ] [ -d @var{databasename} | --database=@var{databasename} ] [ -o @var{filename} | --outfile=@var{filename} ] [ -i | --import ] [ -e | --export ] [ -h | --help] [ -V | --version ] @end smallexample @noindent With no options, @code{gen-index} generates an index that is sorted by the order that the categories appear in the @file{categories} file. The index is generated in plaintext or binary format according to the value of @code{binary-index} in the @file{dbconfig} file (@pxref{Index file description,,Index file description}). The results are printed to standard output. The options are: @table @code @item -n @itemx --numeric Sorts index entries numerically. @item -d @var{databasename} @itemx --database=@var{databasename} Specifies the database to index. If this option is left out, @code{gen-index} attempts to index the database with name taken from the the @var{GNATSDB} environment variable, and if that is undefined, the default database, as set when @sc{gnats} was built (usually @code{default}). @item -o @var{filename} @itemx --outfile=@var{filename} Places output in @var{filename} rather than sending it to standard output. @item -i @itemx --import Import the existing index file instead of re-indexing the database. @item -e @itemx --export Force plaintext output. @item -h @itemx --help Prints the usage for @code{gen-index}. @item -V @itemx --version Prints the version number for @code{gen-index}. @end table @node check-db @subsection Checking database health @cindex @code{check-db} The @file{check-db} script is useful for performing periodic checks on database health. It accepts the following options: @table @code @item -d @var{databasename} @itemx --database=@var{databasename} Determines the database which to operate on. @item --all-databases Check all @sc{gnats} databases on the system. This option takes precedence over the @code{--database} option. @end table If no option is given, the default database is checked. During its operation, @code{check-db} first attempts to lock @var{database}. If this is not possible, it repeats the locking attempts for five minutes; if it fails, it sends a mail message notifying the administrator of the failure and exits. Once the database is locked, the script searches the database for lock files that are more than 24 hours old. Any old lock files are reported to the administrator in a mail message. After checking for old lock files, it calls @code{gen-index} (@pxref{gen-index,,Regenerating the index}) and compares the results with the current @file{index} file of the database; any inconsistencies are reported to the administrators in a mail message. After checking the index file for inconsistencies, the script unlocks the database and exits. @node gnats-pwconv @subsection Managing user passwords @cindex @code{gnats-pwconv} Older versions of @sc{gnats}, up to and including version 3.x, stored user passwords in plaintext in the @file{gnatsd.user_access} files. Version 4 has the options of storing the password as MD5 or standard DES @code{crypt()} hashes (as most UNIX versions do in the system password files) as well as in plaintext. Since the password strings require a prefix to indicate how they are encrypted, one is forced to convert the old password files to a new format when upgrading to @sc{gnats} version 4. @xref{Upgrading,,Upgrading from older versions}. The @code{gnats-pwconv} tool takes care of converting the old password files to the new format: @smallexample gnats-pwconv [ -c | --crypt ] [ -m | --md5 ] [ -p | --plaintext ] [ -h | --help] [ -V | --version ] @var{INFILE} [@var{OUTFILE}] @end smallexample Unless the @code{--version} or @code{--help} options are given, exactly one encryption method must be specified, as well as an input file. The output file parameter is optional. If one is not specified, results will be printed on standard output. @node Internal utils @section Internal utilities @cindex internal utilities These tools are used internally by @sc{gnats}. You should never need to run these by hand; however, a complete understanding may help you locate problems with the @sc{gnats} tools or with your local implementation. @menu * queue-pr:: Handling incoming traffic * file-pr:: Processing incoming traffic * at-pr:: Timely reminders * pr-edit:: The edit-pr driver * diff-prs:: The @code{diff-prs} tool * pr-age:: The @code{pr-age} tool @end menu @node queue-pr @subsection Handling incoming traffic @cindex @code{queue-pr} @cindex handling incoming traffic The program @code{queue-pr} handles traffic coming into @sc{gnats}. @code{queue-pr} queues incoming Problem Reports in the @file{gnats-queue} directory of the database, and then periodically (via @code{cron}) passes them on to @code{file-pr} to be filed in the @sc{gnats} database. @xref{Installation,,Installing @sc{gnats}}. The usage for @code{queue-pr} is as follows: @smallexample queue-pr [ -q | --queue ] [ -r | --run ] [ -f @var{filename} | --file=@var{filename} ] [ -m @var{kbytes} | --max-size=@var{kbytes} ] [ -d @var{databasename} | --database=@var{databasename} ] [ -h | --help] [ -V | --version ] @end smallexample One of @samp{-q} or @samp{-r} (or their longer-named counterparts) must be present upon each call to @code{queue-pr}. These options provide different functions, as described below. @table @code @item -q @itemx --queue Accepts standard input as an incoming mail message, placing this message in an incrementally numbered file in the @w{@file{gnats-queue}} directory under the database directory (@pxref{Locations,,Where @sc{gnats} lives}). @item -r @itemx --run Redirects files in the @file{gnats-queue} directory into the program @code{file-pr} one by one. @item -f @var{filename} @itemx --file=@var{filename} Used with @samp{-q} (or @samp{--queue}), accepts the file denoted by @var{filename} as input rather than reading from standard input. @item -m @var{kbytes} @itemx --max-size=@var{kbytes} Do not process messages larger then @var{kbytes} kilobytes. Files larger than the limit are left for human intervention. @item -d @var{databasename} @itemx --directory=@var{databasename} Specifies database to operate on. If this option is left out, the value of the @var{GNATSDB} environment variable is used, and if that is undefined, the default database name set when @sc{gnats} was built is used (usually @code{default}). @item -h @itemx --help Prints the usage for @code{gen-index}. @item -V @itemx --version Prints the version number for @code{gen-index}. @end table @node file-pr @subsection Processing incoming traffic @cindex @code{file-pr} @cindex processing incoming traffic @code{queue-pr} hands off queued Problem Reports to @code{file-pr} one at a time. @code{file-pr} checks each Problem Report for correct information in its fields (particularly a correct @code{Category}), assigns it an identification number, and files it in the database under the appropriate category. If the @code{Category} field does not contain a valid category value (i.e., matching a line in the @code{categories} file; @pxref{categories file,,The @code{categories} file}), the PR is assigned to the default category, as set in the @code{dbconfig} file. If there is no default category defined, the PR is given a @code{Category} value of @samp{pending} and is placed in the @file{pending} directory. The @sc{gnats} administrator is notified of the unplaceable PR. @code{file-pr} assigns the Problem Report an identification number, files it in the @sc{gnats} database (under the default, if the @code{Category} field contains an invalid category), and sends acknowledgments to appropriate parties. For the default @sc{gnats} configuration, the person responsible for that category of problem (@pxref{categories file,,The @code{categories} file}) and the person responsible for the submitter site where the PR originated (@pxref{submitters file,,The @code{submitters} file}) receive a copy of the PR in its entirety. Optionally, the originator of the PR receives an acknowledgment that the PR arrived and was filed (@pxref{GNATS configuration,,Changing your @sc{gnats} configuration}). The usage for @code{file-pr} is as follows: @smallexample file-pr [ -f @var{filename} | --file=@var{filename} ] [ -d @var{databasename} | --database=@var{databasename} ] [ -h | --help ] [ -V | --version ] network options: [ -H @var{host} | --host=@var{host} ] [ -P @var{port} | --port=@var{port} ] [ -v @var{username} | --user=@var{username} ] [ -w @var{password} | --passwd=@var{password} ] @end smallexample @code{file-pr} requires no options in order to operate, and takes input from standard input (normally, the output of @w{@samp{queue-pr -r}}) unless otherwise specified. The options include: @table @code @item -f @var{filename} @itemx --filename=@var{filename} Uses @var{filename} as input rather than standard input. @item -d @var{databasename} @itemx --database=@var{databasename} Performs refiling operations on @var{database}. If this option is left out, the value of the @var{GNATSDB} environment variable is used, and if that is undefined, the default database name set when @sc{gnats} was built is used (usually @code{default}). @item -h @itemx --help Prints the usage for @code{file-pr}. @item -V @itemx --version Prints the version number for @code{file-pr}. @end table @noindent @code{file-pr} can file PRs across a network, talking to a remote gnatsd. The following options relate to network access: @table @code @item -H @var{host} @itemx --host=@var{host} Hostname of the @sc{gnats} server. @item -P @var{port} @itemx --port=@var{port} The port that the @sc{gnats} server runs on. @item -v @var{username} @itemx --username=@var{username} Username used to log into the @sc{gnats} server. @item -w @var{password} @itemx --passwd=@var{password} Password used to log into the @sc{gnats} server. @end table @node at-pr @subsection Timely reminders @cindex @code{at-pr} @cindex timely reminders @cindex automatic notification @cindex notification of overdue PRs @code{at-pr} creates a queued job using @code{at} which, after an allotted @dfn{response time} is past, checks the PR to see if its state has changed from @samp{open}. When the PR is originally filed, @code{file-pr} checks the @code{notify-about-expired-prs} parameter in the @file{dbconfig} file. If this parameter is set to @code{true}, @code{file-pr} calls @code{at-pr}, which sets up the expiry check. The @file{submitters} file contains the response time for each @w{@code{>Submitter-Id:}} (@pxref{submitters file,,The @code{submitters} file}). The time is determined in @dfn{business hours}, which are defined in the database's @file{dbconfig} file (@pxref{Overall database configuration,,Overall database configuration}). If the PR is urgent and is still open after the requisite time period has passed, @code{at-pr} sends a reminder to the @sc{gnats} administrator, to the maintainer responsible for that submitter, and to the maintainer responsible for the PR with the following message: @cindex reminder message @cindex @code{at-pr} @smallexample To: @var{submitter-contact} @var{responsible} @var{gnats-admin} Subject: PR @var{gnats-id} not analyzed in @var{#hours} hours PR @var{gnats-id} was not analyzed within the acknowledgment period of @var{#hours} business hours. The pertinent information is: Submitter-Id: @var{submitter} Originator: @var{full name of the submitter} Synopsis: @var{synopsis} Person responsible for the PR: @var{responsible} -- The GNU Problem Report Management System (GNATS) @end smallexample The PR is @dfn{urgent} if its priority is @samp{critical} or if its priority is @samp{serious} and the severity is @samp{high}. @node pr-edit @subsection The @code{edit-pr} driver @cindex @code{pr-edit} @cindex @code{edit-pr} driver @cindex driver for @code{edit-pr} @code{pr-edit} does the background work for @code{edit-pr}, including error-checking and refiling newly edited Problem Reports, handling file and database locks and deletion of PRs. It can be called interactively, though it has no usable editing interface. The usage for @code{pr-edit} is: @smallexample pr-edit [ -l @var{username} | --lock=@var{username} ] [ -u | --unlockdb ] [ -L | --lockdb ] [ -U | --unlockdb ] [ -c | --check ] [ -C | --check-initial ] [ -s | --submit [ --show-prnum ] ] [ -a @var{field} | --append field=@var{field} ] [ -r @var{field} | --replace=@var{field} ] [ --delete-pr ] [ -R @var{reason} | --reason=@var{reason} ] [ -p @var{process-id} | --process=@var{process-id} ] [ -d @var{databasename} | --database=@var{databasename} ] [ -f @var{filename} | --filename=@var{filename} ] [ -V | --version ] [ -h | --help ] [ -v @var{username} | --user=@var{username} ] [ -w @var{passwd} | --passwd=@var{passwd} ] [ -H @var{host} | --host=@var{host} ] [ -P @var{port} | --port=@var{port} ] [ -D | --debug ] [ @var{PR number} ] @end smallexample @cindex PR locks @cindex locks A @dfn{lock} is placed on a Problem Report while the PR is being edited. The lock is simply a file in the @file{locks} subdirectory of the @file{gnats-adm} directory of the database, with the name @w{@file{@var{gnats-id}.lock}}, which contains the name of the user who created the lock. @var{user} then ``owns'' the lock, and must remove it before the PR can be locked again, even by the same @var{user}@footnote{This approach may seem heavy-handed, but it ensures that changes are not overwritten.}. If a PR is already locked when you attempt to edit it, @code{pr-edit} prints an error message giving the name of the user who is currently editing the PR. If you do not specify @w{@var{PR number}}, @code{pr-edit} reads from standard input. You must specify @w{@var{PR number}} for the functions which affect PR locks, @samp{--lock=@var{username}} and @samp{--unlock}. @table @code @item -L @itemx --lockdb Locks the database specified with the @code{--database} or @code{-d} option. No PRs may be edited, created or deleted while the database is locked. This option is generally used when editing the index file. @item -U @itemx --unlockdb Unlocks the specified database. No check is made that the invoking user actually had locked the database in the first place; hence, it is possible for anyone to steal a database lock. @item -c @itemx --check @itemx -C @itemx --check-initial The @code{--check} options are used to verify that a proposed PR's field contents are valid. The PR is read in (either from stdin or a file specified with @code{--filename}), and its fields are compared against the rules specified by the database configuration of the selected database. Warnings are given for enumerated fields whose contents do not contain one of the required values or fields that do not match required regexps. @code{--check-initial} is used to verify initial PRs, rather than proposed edits of existing PRs. @item -s @itemx --submit Used to submit a new PR to the database. The PR is read in and verified for content; if the PR is valid as an initial PR, it is then added to the database. If the submission is successful a zero exit code is returned. Otherwise, the reason(s) for the PR being rejected are printed, and a non-zero exit code is returned. @item --show-prnum This option is used with the @code{--submit} option to display the PR number associated with the submitted PR. @end table @noindent The following options require a PR number to be given. @table @code @item --delete-pr Deletes the specified PR from the database. The PR must be in a closed state, and not locked. Only the user @emph{gnats} (or the user name specified instead of @emph{gnats} during the building of @sc{gnats}) is permitted to delete PRs. @item -l @var{username} @itemx --lock=@var{username} Locks the PR. @var{username} is associated with the lock, so the system administrator can determine who actually placed the lock on the PR. However, anyone is permitted to remove locks on a PR. If the optional @code{--process} or @code{-p} option is also given, that process-id is associated with the lock. @item -u @itemx --unlock Unlocks the specified PR. @item -a @var{field} @itemx --append=@var{field} @item -r @var{field} @itemx --replace=@var{field} @code{--append} and @code{--replace} are used to append or replace content of a specific field within a PR. The new field content is read in from stdin (or from the file specified with the @code{--filename} option), and either appended or replaced to the specified field. The field contents are verified for correctness before the PR is rewritten. If the edit is successful, a zero exit status is returned. If the edit failed, a non-zero exit status is returned, and the reasons for the failure are printed to stdout. @item -R @var{reason} @itemx --reason=@var{reason} Certain PR fields are configured in the database configuration to require a short text describing the reason of every change that happens to them, @xref{dbconfig file}. If you edit a problem and change any of such fields, you must issue a short text, the @var{reason} of the change, through this option. If the option is used and no change-reason requiring field is actually changed, the option has no effect. @item PR number If only a @code{PR number} is specified with no other options, a replacement PR is read in (either from stdin or the file specified with @code{--filename}). If the PR contents are valid and correct, the existing PR is replaced with the new PR contents. If the edit is successful, a zero exit status is re turned. If the edit failed, a non-zero exit status is returned, and the reasons for the failure are printed to stdout. @item -d @var{database} @itemx --database=@var{database} Specifies the database which is to be manipulated. If no database is specified, the default database name set when @sc{gnats} was built is used (usually @code{default}). This option overrides the database specified in the GNATSDB environment variable. @item -f @var{filename} @itemx --filename=@var{filename} For actions that require reading in a PR or field content, this specifies the name of a file to read. If @code{--filename} is not specified, the PR or field content is read in from stdin. @item -h @itemx --help Prints the usage for @code{pr-edit}. @item -V @itemx --version Prints the version number for @code{pr-edit}. @end table @noindent @code{pr-edit} can edit PRs across a network, talking to a remote gnatsd. The following options relate to network access: @table @code @item -H @var{host} @itemx --host=@var{host} Hostname of the @sc{gnats} server. @item -P @var{port} @itemx --port=@var{port} The port that the @sc{gnats} server runs on. @item -v @var{username} @itemx --username=@var{username} Username used to log into the @sc{gnats} server. @item -w @var{password} @itemx --passwd=@var{password} Password used to log into the @sc{gnats} server. @item -D @itemx --debug Used to debug network connections. @end table @node diff-prs @subsection The @code{diff-prs} tool @cindex @code{diff-prs} The @code{diff-prs} tool is invoked as follows: @example diff-prs @var{prfile1} @var{prfile2} @end example @code{diff-prs} simply reads the PRs contained in @var{prfile1} and @var{prfile2} and returns a list of the fields that are different between the two. No output is produced if the PRs are identical. @node pr-age @subsection The @code{pr-age} tool @cindex @code{pr-age} @cindex age of PR The @code{pr-age} tool reports the time, in days and hours, since the PR arrived. Usage is @smallexample pr-age [ -d @var{databasename} | --database=@var{databasename} ] [ -H @var{host} | --host=@var{host} ] [ -P @var{port} | --port=@var{port} ] [ -v @var{username} | --user=@var{username} ] [ -w @var{password} | --passwd=@var{password} ] [ -h | --help ] [ -V | --version ] @end smallexample For an explanation of the arguments listed above, please refer to the usage description for @code{file-pr} (@ref{file-pr,,@code{file-pr}}). gnats-4.1.0/doc/p-inst.texi0000644000175000017500000010775607557041141016260 0ustar chewiechewie00000000000000@c This file is included as a chapter in gnats.texi. @cindex installing GNATS @cindex configuring GNATS @cindex setting up GNATS @cindex building GNATS See also @ref{Locations,,Where the tools and utilities reside}. There are several steps you need to follow to fully configure and install @sc{gnats} on your system. You need @code{root} access in order to create a new account for @code{gnats} and to install the @sc{gnats} utilities. You may need @code{root} access on some systems in order to set up mail aliases and to allow this new account access to @code{cron} and @code{at}. If you are updating an older version of @sc{gnats} rather than installing from scratch, see @ref{Upgrading,,Upgrading from older versions}. @sc{gnats} installation relies on two other freely available software packages, which should be installed before you go on to configure and build @sc{gnats}. These are @sc{gnu} @code{make} and @code{Texinfo} (version 4.2 or higher). Both are available from the @sc{gnu} FTP site at @url{ftp://ftp.gnu.org}. To build and install @sc{gnats}, you must: @itemize @bullet @item Run @code{configure}, with correct options if the defaults are unsuitable for your site. @xref{Configure and make,,Configuring and compiling the software}. Default installation locations are in @ref{Locations,,Where @sc{gnats} lives}. @item Compile the @sc{gnats} programs on your system. @xref{Configure and make,,Configuring and compiling the software}. @item Create an initial database by using the @code{mkdb} command. @xref{Setting up the default database}. @item Set up periodic jobs, using cron, to handle Problem Reports arriving by mail. @xref{Setting up periodic jobs}. @item Set up mail aliases for @sc{gnats}. @xref{Aliases,,Setting up mail aliases}. @item Install the @sc{gnats} tools and utilities locally, and install the user tools (@code{query-pr}, @code{edit-pr}, @code{send-pr}) on every machine in your local network. @xref{Installing tools,,Installing the user tools}. @item Install the @sc{gnats} daemon @file{gnatsd}. @xref{Installing the daemon}. @item If there are people outside your organization who will be submitting PRs or who are supposed to be able to query and/or edit PRs, you may need to instruct them to obtain and build the @sc{gnats} tools @code{query-pr}, @code{edit-pr} and @code{send-pr} for their systems. However, for many sites, setting up a remote access interface to @sc{gnats}, such as Gnatsweb is a better solution since this requires no configuration on the remote side. @end itemize @menu * Configure and make:: Configuring and compiling the software * Installing utils:: Installing the utilities * Setting up the default database:: Setting up the default database * Setting up periodic jobs:: Setting up periodic jobs * Aliases:: Setting up mail aliases * Installing the daemon:: Installing the daemon * Installing tools:: Installing the user tools * Upgrading:: Upgrading from older versions @end menu @node Configure and make @section Configuring and compiling the software @cindex unpacking the distribution @cindex configuring and compiling the software @cindex compiling the software @cindex @code{configure} @cindex @code{make} @enumerate 1 @item First, unpack your distribution. We provide source code in a @code{tar} file which was compressed using @code{gzip}. The code can be extracted into a directory @var{unpackdir} using @smallexample cd @var{unpackdir} gunzip gnats-@value{VERSION}.tar.gz tar xvf gnats-@value{VERSION}.tar @end smallexample The sources reside in a directory called @file{gnats-@value{VERSION}} when unpacked. We call this the @dfn{top level} of the source directory, or @dfn{srcdir}. The sources for the @sc{gnats} tools are in the subdirectory @file{gnats-@value{VERSION}/gnats/*}. Lists of files included in the distribution are in each directory in the file @file{MANIFEST}. @cindex lisp file installation @cindex Emacs lisp file installation @item As of @sc{gnats} version 4, having Emacs installed on the @sc{gnats} server is no longer a requirement. If you do not have Emacs installed, disregard this step altogether. You may wish to alter the installation directory for the Emacs lisp files. If your Emacs lisp library is not in @w{@file{@var{prefix}/share/emacs/site-lisp}}, edit the file @code{@var{srcdir}/gnats/Makefile.in}. Change the variable @code{lispdir} from @w{@file{@var{prefix}/emacs/site-lisp}} to the directory containing your Emacs lisp library. For information on @var{prefix}, see @ref{prefix,,@var{prefix}}. @item @cindex creating an account for the @sc{gnats} user Create an account for the @code{gnats} user. You can actually name this user whatever you want to, as long as it is a valid username on your system, but we strongly recommend that you call the user @code{gnats}. If you do decide to give it some other name, remember to use the option @code{--with-gnats-user} when running @code{configure} below. Below, we will anyway refer to this user by the name @code{gnats}. This user must have an entry in the file @w{@file{/etc/passwd}}. As for ordinary users, create a standard home directory for the @code{gnats} user. The default @code{PATH} for this user should contain @w{@file{@var{exec-prefix}/bin}} and @w{@file{@var{exec-prefix}/libexec/gnats}}. The @var{exec-prefix} value is configurable with the @code{--exec-prefix} configure option described below, but for standard installations, these two directories correspond to @w{@file{/usr/local/bin}} and @w{@file{/usr/local/libexec/gnats}}. @item Run @code{configure}. You can nearly always run @code{configure} with the simple command @example ./configure @end example @noindent and the ``Right Thing'' happens: @itemize @bullet @item @sc{gnats} is configured in the same directory you unpacked it in; @item when built, @sc{gnats} runs on the machine you're building it on; @item when installed, files are installed under @file{/usr/local} (@pxref{Locations,,Where @sc{gnats} lives}). @item all @sc{gnats} utilities operate on the @dfn{default database}, assumed to be named @emph{default} and to be located in @w{@file{/usr/local/com/default}}, unless you invoke the utilities with @code{-d} @var{databasename} or @code{--directory=}@var{databasename}, or set the @var{GNATSDB} environment variable to point to some other database. @end itemize @cindex @code{configure} The most common options to @code{configure} are listed below: @smallexample configure [ --prefix=@var{prefix} ] [ --exec-prefix=@var{exec-prefix} ] [ --with-gnats-service=@w{@var{service-name}} ] [ --with-gnats-user=@w{@var{username}} ] [ --with-gnatsd-user-access-file=@w{@var{path}} ] [ --with-gnatsd-host-access-file=@w{@var{path}} ] [ --with-gnats-dblist-file=@w{@var{path}} ] [ --with-gnats-default-db=@w{@var{path}} ] [ --with-kerberos ] [ --with-krb4 ] [ --verbose ] @end smallexample @table @code @cindex @var{prefix} @item --prefix=@var{prefix} All host-independent programs and files are to be installed under @var{prefix}. (Host-dependent programs and files are also installed in @var{prefix} by default.) The default for @var{prefix} is @w{@file{/usr/local}}. @xref{Locations,,Where @sc{gnats} lives}. @cindex @var{exec-prefix} @item --exec-prefix=@var{exec-prefix} All host-dependent programs and files are to be installed under @var{exec-prefix}. The default for @var{exec-prefix} is @var{prefix}. @xref{Locations,,Where @sc{gnats} lives}. @cindex --with-gnats-service @item --with-gnats-service=@w{@var{service-name}} Set @var{service-name} to be the @sc{gnats} network service. Default name is @var{support}. @cindex --with-gnats-user @item --with-gnats-user=@w{@var{username}} Set @var{username} to be the user name for @sc{gnats}. Default username is @var{gnats}. @cindex --with-gnatsd-user-access-file @item --with-gnatsd-user-access-file=@w{@var{path}} Set global (across all databases) gnatsd user access file to @var{path}. Default is @file{@var{/usr/local/etc/gnats/gnatsd.user_access}}. Per-database user access permissions are set in a @file{gnatsd.user_access} file in the @file{gnats-adm} subdirectory of each database. @cindex --with-gnatsd-host-access-file @item --with-gnatsd-host-access-file=@w{@var{path}} Set global (across all databases) gnatsd host access file to @var{path}. Default is @file{/usr/local/etc/gnats/gnatsd_host.access}. There is currently no way to specify host access permissions on a per-database basis. @cindex --with-gnats-dblist-file @item --with-gnats-dblist-file=@w{@var{path}} Specify the file containing the list of databases. Default is @w{@file{@var{prefix}/etc/gnats/databases}}. @cindex --with-gnats-default-db @item --with-gnats-default-db=@w{@var{path}} Specify the default database to use when @sc{gnats} tools are invoked without the @code{-d} or @code{--databasename} option, and when the @var{GNATSDB} envrionment variable hasn't been set. Default is @file{/@var{prefix}/com/gnatsdb}. @cindex --with-kerberos @item --with-kerberos Include code for Kerberos authentication. @cindex --with-krb4 @item --with-krb4 Support Kerberos 4. @item --verbose Give verbose output while @code{configure} runs. @end table @code{configure} supports several more options which allow you to specify in great detail where files are installed. For a complete list of options, run @code{./configure --help} in the source directory. @cindex building in a different directory @cindex @var{objdir} You can build @sc{gnats} in a different directory (@var{objdir}) from the source code by calling the @code{configure} program from the new directory, as in @smallexample mkdir @var{objdir} cd @var{objdir} @var{srcdir}/configure @dots{} @end smallexample By default, @code{make} compiles the programs in the same directory as the sources (@var{srcdir}). @item Make sure you have @sc{gnu} @code{make}, then run @smallexample make all info @end smallexample @noindent from the directory where @code{configure} created a @file{Makefile} (this is @var{objdir} if you used it, otherwise @var{srcdir}.) These targets indicate: @table @code @item all Compile all programs @item info Create @samp{info} files using @code{makeinfo}. @end table @end enumerate @node Installing utils @section Installing the utilities @cindex installing the utilities The following steps are necessary for a complete installation. You may need @code{root} access for these. @enumerate 1 @item Install the utilities by invoking @smallexample make install install-info @end smallexample These targets indicate: @table @code @item install Installs all programs into their configured locations (@pxref{Locations,,Where @sc{gnats} lives}). @item install-info Installs @samp{info} files into their configured locations (@pxref{Locations,,Where @sc{gnats} lives}). @end table After you have installed @sc{gnats}, you can remove the object files with @smallexample make clean @end smallexample @cindex @code{autoload} commands @cindex loading @code{.el} files @cindex Emacs functions @item If you do not have Emacs installed on your @sc{gnats} server, this step should be skipped. Place the following lines in the file @file{default.el} in your Emacs lisp library, or instruct your local responsible parties to place the lines in their @file{.emacs}: @smallexample (autoload 'send-pr "gnats" "Command to create and send a problem report." t) (autoload 'edit-pr "gnats" "Command to edit a problem report." t) (autoload 'view-pr "gnats" "Command to view a problem report." t) (autoload 'query-pr "gnats" "Command to query information about problem reports." t) (autoload 'unlock-pr "gnats" "Unlock a problem report." t) (autoload 'gnats-dbconfig-mode "gnats" "Major mode for editing the `dbconfig' GNATS configuration file." t) (add-to-list 'auto-mode-alist '("\\ @file{filename} @end smallexample The file @file{filename} now contains a PR template for your database. Copy this file to the client. Then edit the @file{send-pr.conf} file that you created on the client, set the @code{TEMPLATE} variable to point to the template file (@pxref{send-pr.conf file,,The send-pr.conf configuration file}) and make sure that the @code{MAILPROG} and @code{MAILADDR} varables in @file{send-pr.conf} are correctly set. You should now have a working remote tool installation. For clients that have no direct network access to your @sc{gnats} server, such as those that are located behind strict firewalls, you either need to set up a web interface such as Gnatsweb (provided that the firewall lets web traffic through) or use the procedure above which sets up @code{send-pr} to submit Problem Reports by e-mail. In order to query PRs, users on the remote machines will then have to use the the e-mail functionality of @code{query-pr} (@pxref{Invoking query-pr}. Editing PRs by e-mail is not possible, so clients in this group who need edit access have to get access through a web interface if possible. Note that when @code{send-pr} is set up to work over e-mail, the @code{GNATSDB} environment variable and the @code{-d} command line option have no effect since @code{send-pr} is tied to a specific database by way of the value of @code{MAILADDR} in the @file{send-pr.conf} file. @c --------------------------------------------------------------- @node Upgrading @section Upgrading from older versions @cindex upgrading from older versions The following procedure covers an upgrade from all @sc{gnats} 3 versions newer than 3.108. If your installation is an older 3.10x version, or even the ancient 3.2 version, you need to review the @file{UPGRADING.old} file in the @sc{gnats} distribution before carrying out the steps detailed here. @subsection Overview @cindex upgrading, overview Although almost all of the @sc{gnats} internals have been redesigned and rewritten for @sc{gnats} 4, little has changed in the format and structure of the database data. The only change that needs to be taken into account when upgrading is the fact that the database index format is binary in a default installation of @sc{gnats} 4. Thus, you will need to regenerate your database index by using the @code{gen-index} tool. In addition, if your old @sc{gnats} installation was so-called ``release-based'', you need to make some simple modifications to the database setup file @file{dbconfig}. See below for details. Apart from building and installing new binaries, the major changes which impinge on the upgrade procedure are all on the configuration side. The main database configuration file, @file{dbconfig}, is far more complex and powerful than the old @file{config} file, and while the installation process creates a sensible set of default values which are similar to @sc{gnats} 3.11x's defaults, you still need to migrate any changes you may have made to your own local configuration. Another aspect which needs consideration are remote submitter sites. Such sites either need to be instructed to upgrade their locally installed copies of the @sc{gnats} user tools (@code{send-pr}, @code{edit-pr} and @code{query-pr}), or they should be given access through interfaces such as Gnatsweb. Since the @sc{gnats} network daemon has been completely reworked, with an entirely new command set, all network-based interfaces, such as Gnatsweb and TkGnats need to be upgraded to versions that support @sc{gnats} 4. The @file{contrib} directory of this distribution contains some third-party interfaces, and the @file{README} file contains pointers to where you can obtain the newest versions of these tools. This document only deals with upgrading @sc{gnats} itself. Third-party tools should have separate upgrading instructions in their distributions. @subsection Upgrading @cindex upgrade, procedure @enumerate @item Before you begin, make a backup of your entire @sc{gnats} database directory hierarchy, the @sc{gnats} executables directory and the @sc{gnats} user tools (@code{send-pr}, @code{query-pr} etc.) The locations of these may vary, but in a default @sc{gnats} 3 installation, the database(s) reside under @w{@file{/usr/local/share/gnats}}, the executables are located in @w{@file{/usr/local/libexec/gnats}} and the user tools reside in @w{@file{/usr/local/bin}}. @item (optional) In order to avoid confusing your users, you may want to remove the old @sc{gnats} 3 executables and tools, escpecially if you plan to install @sc{gnats} 4 in a different location than version 3. @item Build and install @sc{gnats} 4. @xref{Installation,, Installing @sc{gnats}}. It is recommended that you use the @w{@code{--with-gnats-default-db}} option when running @code{configure}, in order to set the default database to be one of your already existing @sc{gnats} 3 databases. @item Edit the @sc{gnats} @file{databases} file and add entries for all your old @sc{gnats} 3 databases. In a default @sc{gnats} 4 installation the file is in @w{@file{/usr/local/etc/gnats}}. @xref{databases file,,The @file{databases} file}. @item In @sc{gnats} 3, the file @file{gnatsd.conf} specifies minimum access levels for the different hosts accessing the @sc{gnats} daemon, @code{gnatsd}. There is one @file{gnatsd.conf} for each database. In @sc{gnats} 4, these files have been replaced by a single file named @file{gnatsd.host_access} which contains settings that apply across all the databases on the server. This file is located in the same directory as the @file{databases} file. You need to combine the host access settings from all your @sc{gnats} 3 databases and add them to the @file{gnatsd.host_access} file. Note that you are no longer able to control host access on a per-database basis. Optionally, you may delete the old @file{gnatsd.conf} files. @xref{Access Control,,Controlling access to @sc{gnats} databases}. @item Next, you need to migrate the settings in the old @file{config} files of your databases to corresponding @file{dbconfig} files. The database you specified with the @w{@code{--with-gnats-default-db}} configure option got a default @file{dbconfig} installed. This default file contains field definitions etc. which makes this version of @sc{gnats} behave almost exactly like older versions. Copy this default file to the @w{@file{gnats-adm}} directories of any other @sc{gnats} databases that you may have on your host before you proceed to migrate your old configuration settings. The following is a list of the configuration directives that may be present in a @file{config} file and their counterparts (if any) in @sc{gnats} 4. @table @var @item GNATS_ADDR This setting has no counterpart in @sc{gnats} 4, since @sc{gnats} no longer needs to know its own mail address. @item GNATS_ADMIN This setting is now set in the @file{responsible} file in the @w{@file{gnats-adm}} directory of your database(s). @item GNATS_SITE @sc{gnats} 4 has no concept of a named `site', so this directive is obsolete. @item SUBMITTER Obsolete, since it relates to @var{GNATS_SITE}. @item DEFAULT_RELEASE @itemx DEFAULT_ORGANIZATION The @sc{gnats} 4 @file{dbconfig} file has separate configuration sections for each defined field. Field defaults are set with the @code{default} keyword in these sections. @xref{dbconfig file,,The @file{dbconfig} file}. @item NOTIFY Controlled by the @code{notify-about-expired-prs} setting in the @file{dbconfig} file. @item ACKNOWLEDGE Controlled by the @code{send-submitter-ack} setting in the @file{dbconfig} file. @item DEFAULT_SUBMITTER The default submitter is now always the first entry in the @file{submitters} file of your database. @item KEEP_RECEIVED_HEADERS Controlled by the @code{keep-all-received-headers} setting in the @file{dbconfig} file. @item DEBUG_MODE Controlled by the @code{debug-mode} setting in the @file{dbconfig} file. @item BDAY_START @itemx BDAY_END @itemx BWEEK_START @itemx BWEEK_END Controlled by the settings @code{business-day-hours} and @code{business-week-days} in the @file{dbconfig} file. @item DEFINE_CATEGORY The default category for PRs that arrive without one is now the first category listed in the @file{categories} file of your database. @end table After your are done migrating the settings, you may optionally delete the old @file{config} files. Since there are many more configuration settings available in the @sc{gnats} 4 @file{dbconfig} file, you should take some time to review them all before proceeding. @xref{dbconfig file,,The @file{dbconfig} file}. If your old @sc{gnats} installations was release-based, i.e. it included the fields Quarter, Keywords and Date-Required, you need to define those fields in the @file{dbconfig} file by following the instructions in @ref{release-based support,,Supporting old @sc{gnats} ``release-based'' fields}. @item The file @file{gnatsd.access} has been renamed to @file{gnatsd.user_access}. Furthermore, @sc{gnats} 4 uses a different password format in the @file{gnatsd.user_access} file than older versions, since it supports @code{crypt()} and MD5 passwords (@pxref{Access Control,,Controlling access to @sc{gnats} databases}). You need to translate your old @w{@file{gnatsd.user_access}} files to the new format by using the @code{gnats-pwconv} tool which was installed in the @w{@file{@var{EXEC-PREFIX}/libexec/gnats}} directory, typically @w{@file{/usr/local/libexec/gnats}}. @xref{gnats-pwconv,,Managing user passwords}. @item The final step involves regenerating the indexes of your databases. For this, log in as the user @code{gnats}. Then run the @code{gen-index} command for each of your databases. See @ref{Admin utils,,Administrative Utilities} for details on how to use @w{@code{gen-index}}. @item Sit back and enjoy your new @sc{gnats} 4 setup... @end enumerate @c FIXME - anything else? gnats-4.1.0/doc/p-usage.texi0000644000175000017500000007053607632523454016410 0ustar chewiechewie00000000000000@node GNATS user tools @chapter The @sc{gnats} User Tools @cindex usage for the @sc{gnats} user tools @cindex invoking the @sc{gnats} user tools This chapter describes the user tools distributed with @sc{gnats}. The @sc{gnats} administrative and internal tools are described in @ref{Management,,@sc{gnats} Administration}. The user tools provide facilities for initial submission, querying and editing of Problem Reports: @table @code @item send-pr Used by anyone who has a problem with a body of work to submit a report of the problem to the maintainers of that work (@pxref{send-pr,,Submitting Problem Reports}). @item query-pr Used to query the @sc{gnats} database (@pxref{query-pr,,Querying the database}). @item edit-pr Used to edit Problem Reports (to record new data, to change the responsible party, etc.) (@pxref{edit-pr,,Editing existing Problem Reports}). @end table @menu * Environment:: Environment variables and GNATS tools * send-pr:: Submitting Problem Reports * edit-pr:: Editing existing Problem Reports * query-pr:: Querying the database * Emacs:: The Emacs interface @end menu @node Environment @section Environment variables and @sc{gnats} tools @cindex environment variables and GNATS tools @cindex @code{GNATSDB} All the @sc{gnats} user tools honor the @code{GNATSDB} environment variable which is used to determine which database to use. For a local database, it contains the name of the database to access. For network access via gnatsd, it contains a colon-separated list of strings that describe the remote database in the form @smalldisplay @var{server:port:databasename:username:password} @end smalldisplay Any of the fields may be omitted except for @var{server}, but at least one colon must appear; otherwise, the value is assumed to be the name of a local database. If @code{GNATSDB} is not set and no command-line options are used to specify the database, it is assumed that the database is local and that its name is @samp{default}. @node send-pr @section Submitting Problem Reports @cindex @code{send-pr} @cindex using @code{send-pr} @cindex invoking @code{send-pr} @cindex reporting problems with @code{send-pr} Use @code{send-pr} to submit Problem Reports to the database. @code{send-pr} is a shell script which composes a template for submitters to complete. @lowersections @include s-usage.texi @raisesections @c --------------------------------------------------------------- @node edit-pr @section Editing existing Problem Reports @cindex using @code{edit-pr} @cindex invoking @code{edit-pr} @cindex @code{edit-pr} Use @code{edit-pr} to make changes to existing PRs in the database. This tool can be invoked both from a shell prompt or from within GNU Emacs using @samp{M-x edit-pr}. @code{edit-pr} first examines the PR you wish to edit and locks it if it is not already locked. This is to prevent you from editing a PR at the same time as another user. If the PR you wish to edit is already in the process of being edited, @code{edit-pr} tells you the name of the person who owns the lock. You may edit any non-readonly fields in the database. We recommend that you avoid deleting any information in the @sc{Text} and @sc{MultiText} fields (such as @code{Description} and @code{How-To-Repeat} (@pxref{Fields,,Problem Report format}). We also recommend that you record the final solution to the problem in the @code{Fix} field for future reference. Note that heavily customized installations of @sc{gnats} may have differently named fields, and sites using such installations should provide their own set of routines and instructions regarding how PRs should be treated throughout their life span. After the PR has been edited, it is then resubmitted to the database, and the index is updated (@pxref{index file,,The @code{index} file}). For information on @code{pr-edit}, the main driver for @code{edit-pr}, see @ref{Internal utils,,Internal utilities}. If you change a field that requires a reason for the change, such as the @code{Responsible} or @code{State} fields in the default configuration, @code{edit-pr} prompts you to supply a reason for the change. A message is then appended to the @code{Audit-Trail} field of the PR with the changed values and the change reason. Depending on how the database is configured, editing various fields in the PR may also cause mail to be sent concerning these changes. In the default configuration, any fields that generate @samp{Audit-Trail} entries will also cause a copy of the new @samp{Audit-Trail} message to be sent. Mail received at the PR submission email address and recognized by @sc{gnats} as relating to an existing PR is also appended to the @samp{Audit-Trail} field, see @ref{follow-up via email}. @menu * edit-pr from the shell:: Invoking @code{edit-pr} from the shell * follow-up via email:: Following up via direct email @end menu @node edit-pr from the shell @subsection Invoking @code{edit-pr} from the shell @cindex @code{edit-pr} from the shell The usage for @code{edit-pr} is: @smallexample edit-pr [ -V | --version ] [ -h | --help ] [-d @var{database} | --database @var{database}] @var{PR Number} @end smallexample @noindent Network-mode-only options: @smallexample [--host @var{host} | -H @var{host}] [--port @var{port}] [--user @var{user} | -v @var{user}] [--passwd @var{passwd} | -w @var{passwd}] @end smallexample @noindent The options have the following meaning: @table @code @item -h, --help Prints a brief usage message for edit-pr. @item -V, --version Prints the version number for edit-pr. @item -d @var{database}, --database @var{database} Specifies the database containing the PR to be edited; if no database is specified, the database named @samp{default} is assumed. This option overrides the database specified in the @code{GNATSDB} environment variable. @item --host @var{host}, -H @var{host} Specifies the hostname of the gnatsd server to communicate with. This overrides the value in the @code{GNATSDB} environment variable. @item --port @var{port} Specifies the port number of the gnatsd server to communicate with. This overrides the value in the @code{GNATSDB} environment variable. @item --user @var{user}, -v @var{user} Specifies the username to login with when connecting to the gnatsd server. This overrides the value in the @code{GNATSDB} environment variable. @item --passwd @var{passwd}, -w @var{passwd} Specifies the password to login with when connecting to the gnatsd server. This overrides the value in the @code{GNATSDB} environment variable. @end table @code{edit-pr} calls the editor specified in your environment variable @code{EDITOR} on a temporary copy of that PR. (If you don't have the variable @code{EDITOR} defined in your environment, the default editor @code{vi} is used.) Edit the PR, changing any relevant fields or adding to existing information. When you exit the editor, @code{edit-pr} prompts you on standard input for a reason if you have changed a field that requires specifying a reason for the change. @node follow-up via email @subsection Following up via direct email @cindex follow-up via email @cindex subsequent mail @cindex related mail If you have some additional information for a PR and for some reason do not want to (or cannot) edit the PR directly, you may append the information to the Audit-Trail field by mailing it to the PR submission address. In order for GNATS to be able to recognize the mail as pertaining to an existing PR (as opposed to a new PR, see @ref{Submitting via e-mail,,}), the Subject mail header field must contain a reference to the PR. GNATS matches the Subject header against the regular expression @smallexample \<(PR[ \t#/]?|[-[:alnum:]+.]+/)[0-9]+ @end smallexample @noindent to determine whether such a reference is present. Any text may precede or follow the reference in the Subject header. If more than one reference is present, the first is used and the rest ignored. A PR reference matching the regular expression above has two parts. The second is the PR number (one or more digits). The first is either the capital letters 'PR' optionally followed by a separator character (blank, tab, hash mark or forward slash) or the category name followed by a forward slash. Following are some examples which match the regular expression: @smallexample PR 123 PR4567 PR#890 gnats/4711 @end smallexample The PR number and the category (if present) are checked for existence, and if the outcome is positive, the mail is appended to the Audit-Trail field of the PR. Note that the PR need not belong to the category because PRs may move between categories. Outgoing emails sent by GNATS itself may be configured to have a Subject header field that refers to the PR in question: @smallexample Subject: Re: PR @var{category}/@var{gnats-id}: @var{original message subject} @end smallexample This makes it extremely easy to follow up on a PR by replying to such an email, see @ref{dbconfig file,,The @code{dbconfig} file} and the sample, default @code{dbconfig} file installed by @code{mkdb}. @c --------------------------------------------------------------- @node query-pr @section Querying the database @cindex using @code{query-pr} @cindex invoking @code{query-pr} @cindex @code{query-pr} @cindex querying individual problem reports Obtain information from the database by using the program @w{@code{query-pr}}. @code{query-pr} uses search parameters you provide to find matching Problem Reports in the database. You can invoke @code{query-pr} from the shell or from within Emacs. @code{query-pr} uses the same arguments whether it is invoked from the shell or from Emacs. PRs may be selected via the use of the @code{--expr} option, directly by number, or by the use of the (now deprecated) field-specific query operators. By default, query options are connected with a logical AND. For example, @smallexample query-pr --category=foo --responsible=bar @end smallexample @noindent only prints PRs which have a Category field of @samp{foo} and a Responsible field of @samp{bar}. The @code{--or} option may be used to connect query options with a logical OR. For example, @smallexample query-pr --category=baz --or --responsible=blee @end smallexample @noindent prints PRs which have either a Category field of @samp{baz} or a Responsible field of @samp{blee}. It should be emphasized, however, that the use of these field-specific options is strongly discouraged, since they exist only for compatibility with older versions of @sc{gnats} and are likely to be deleted in the next release. The expressions specified by the @code{--expr} option are much more flexible (see below). @menu * Invoking query-pr:: * Formatting query-pr output:: * Query expressions:: * Example queries:: @end menu @node Invoking query-pr @subsection Invoking @code{query-pr} From the shell, simply type @kbd{query-pr}, followed by any search parameters you wish to exercise. From Emacs, type @w{@kbd{M-x query-pr}}. @code{query-pr} prompts you for search parameters in the minibuffer. @cindex @code{query-pr} by mail @code{query-pr} can also be accessed by electronic mail, if your version of @sc{gnats} is configured for this. To use this feature, simply send mail to the address @w{@samp{query-pr@@@var{your-site}}} with command line arguments or options in the @code{Subject} line of the mail header. @sc{gnats} replies to your mail with the results of your query. The default settings for the @code{query-pr} mail server are @cindex the section on query-by-mail needs to be relocated @smallexample --restricted --state="open|analyzed|feedback|suspended" @end smallexample @noindent To override the @code{--state} parameter, specify @w{@code{--state=@var{state}}} in the @code{Subject} line of the mail header. You can not query on confidential Problem Reports by mail. The usage for @code{query-pr} is: @smallexample query-pr [--debug | -D] [--help | -h] [--version | -V] [--output @var{file} | -o @var{file}] [--list-databases] [--list-fields] [--list-input-fields] [--responsible-address @var{name}] [--field-type @var{field}] [--field-description @var{field}] [--field-flags @var{field}] [--adm-field @var{field}] [--adm-subfield @var{subfield}] [--adm-key @var{key}] [--valid-values @var{field}] [--format @var{format} | -f @var{format}] [--full | -F] [--summary | -q] [--database @var{database} | -d @var{database}] [--and | -&] [--or | -|] [--expr @var{expr}] [PR Number] @end smallexample Non-network-mode options: @smallexample [--print-sh-vars] [--print-directory-for-database] @end smallexample Network-mode-only options: @smallexample [--host @var{host} | -H @var{host}] [--port @var{port}] [--user @var{user} | -v @var{user}] [--passwd @var{passwd} | -w @var{passwd}] [--print-server-addr] @end smallexample Deprecated Options: @smallexample [--list-categories | -j] [--list-states | -T] [--list-responsible | -k] [--list-submitters | -l] [--category @var{category} | -c @var{category}] [--synopsis @var{synopsis} | -y @var{synopsis}] [--confidential @var{confidential} | -C @var{confidential}] [--multitext @var{multitext} | -m @var{multitext}] [--originator @var{originator} | -O @var{originator}] [--release @var{release} | -A @var{release}] [--class @var{class} | -L @var{class}] [--cases @var{cases} | -E @var{cases}] [--quarter @var{quarter} | -Q @var{quarter}] [--keywords @var{keywords} | -K @var{keywords}] [--priority @var{priority} | -p @var{priority}] [--responsible @var{responsible} | -r @var{responsible}] [--restricted | -R] [--severity @var{severity} | -e @var{severity}] [--skip-closed | -x] [--sql | -i] [--sql2 | -I] [--state @var{state} | -s @var{state}] [--submitter @var{submitter} | -S @var{submitter}] [--text @var{text} | -t @var{text}] [--required-before @var{date} | -u @var{date}] [--required-after @var{date} | -U @var{date}] [--arrived-before @var{date} | -b @var{date}] [--arrived-after @var{date} | -a @var{date}] [--modified-before @var{date} | -B @var{date}] [--modified-after @var{date} | -M @var{date}] [--closed-before @var{date} | -z @var{date}] [--closed-after @var{date} | -Z @var{date}] @end smallexample The options have the following meaning: @table @code @item --help, -h Prints a help message. @item --version, -V Displays the program version to stdout. @item --output @var{file}, -o @var{file} The results of the query will be placed in this file. @item --database @var{database}, -d @var{database} Specifies the database to be used for the query. If no database is specified, the database named default is assumed. (This option overrides the database specified in the @code{GNATSDB} environment variable; see @ref{Environment} for more information.) @item --list-categories, -j Lists the available PR categories for the selected database. @item --list-states, -T Lists the valid PR states for PRs in this database. @item --list-responsible, -k Lists the users that appear in the database's responsible list. @item --list-submitters, -l Lists the valid submitters for this database. @end table The previous --list-* options are deprecated and may be removed in future releases of @sc{gnats}; their functionality can be replaced with @smallexample query-pr --valid-values @var{field} @end smallexample @noindent where @var{field} is one of @code{Category}, @code{Class}, @code{Responsible}, @code{Submitter-Id}, or @code{State}. @table @code @item --list-databases Lists the known databases. @item --list-fields Lists the entire set of field names for PRs in the selected database. @item --list-input-fields Lists the fields that should be provided when creating a new PR for the currently-specified database. The fields are listed in an order that would make sense when used in a template or form. @item --field-type @var{field} Returns the data type contained in PR field @var{field}. The current set of data types includes @samp{text}, @samp{multitext}, @samp{enum}, @samp{multienum}, @samp{enumerated-in-file}, @samp{multi-enumerated-in-file}, @samp{date} and @samp{integer}. @item --field-description @var{field} Returns a human-readable description of the intended purpose of @var{field}. @item --field-flags @var{field} Returns the flags set for the field in the @file{dbconfig} file associated with the database, such as @code{textsearch} and @code{readonly}. @xref{Individual field configuration}. @item --adm-field @var{field} Used together with the @code{--adm-key} option, this returns a record from the administrative file (if any) associated with the field. For more material on administrative files, see @ref{administrative files,,Enumerated field administrative files}. @item --adm-subfield @var{subfield} Used together with the @code{--adm-field} and @code{--adm-key} options, this returns the contents of a particular subfield from the record specified by @code{--adm-field} and @code{--adm-key}. Subfields are treated in @ref{administrative files,,Enumerated field administrative files}. @item --adm-key @var{key} Used together with @code{--adm-field} to select a record from the administrative file associated with the field specified by @code{--adm-field}. @xref{administrative files,,Enumerated field administrative files}. @item --valid-values @var{field} For fields of type @samp{enum}, a list of valid values (one per line) is returned. Otherwise, a regular expression is returned that describes the legal values in @var{field}. @item --responsible-address @var{name} The mail address of @var{name} is returned; @var{name} is assumed to be a name either appearing in the database's responsible list, or is otherwise a user on the system. @item --print-sh-vars A set of @file{/bin/sh} variables is returned that describe the selected database. They include: @table @code @item GNATSDB The name of the currently-selected database. @item GNATSDB_VALID Set to 1 if the selected database is valid. @item GNATSDBDIR The directory where the database contents are stored. @item DEBUG_MODE Set to 1 if debug mode has been enabled for the database. @item DEFAULTCATEGORY The default category for PRs in the database. @item DEFAULTSTATE The default state for PRs in the database. @end table @item --print-server-addr Prints the information about a remote server database in the format suitable for the @code{GNATSDB} environment variable. This option works only in the network mode. @item --print-directory-for-database Returns the directory where the selected database is located. @item --format @var{format}, -f @var{format} Used to specify the format of the output PRs, See @ref{Formatting query-pr output} for a complete description. @item --full, -F When printing PRs, the entre PR is displayed. This is exactly equivalent to @smallexample query-pr --format full @end smallexample @item --summary, -q When printing PRs, a summary format is used. This is exactly equivalent to @smallexample query-pr --format @var{summary} @end smallexample @item --debug, -D Enables debugging output for network queries. @item --host @var{host}, -H @var{host} Specifies the hostname of the gnatsd server to communicate with. This overrides the value in the @code{GNATSDB} environment variable. @item --port @var{port} Specifies the port number of the gnatsd server to communicate with. This overrides the value in the @code{GNATSDB} environment variable. @item --user @var{user}, -v @var{user} Specifies the username to login with when connecting to the gnatsd server. This overrides the value in the @code{GNATSDB} environment variable. @item --passwd @var{passwd}, -w @var{passwd} Specifies the password to login with when connecting to the gnatsd server. This overrides the value in the @code{GNATSDB} environment variable. @item --and, -&, --or, -| These options are used when connecting multiple query operators together. They specify whether the previous and subsequent options are to be logically ANDed or logically ORed. @item --expr @var{expr} Specifies a query expression to use when searching for PRs. @xref{Query expressions}. @end table The remaining deprecated options are not described here, since their use is fairly obvious and their functionality is completely replaced by the use of the @code{--expr} option. @node Formatting query-pr output @subsection Formatting @code{query-pr} output @cindex query-pr output format Printing formats for PRs are in one of three forms: @table @var @item formatname This is a named format which is described by the database (specifically, these formats are described in the @file{dbconfig} file associated with the database). The default configuration contains five such formats: @samp{standard}, @samp{full}, @samp{summary}, @samp{sql}, and @samp{sql2}. The first three are the ones most commonly used when performing queries. standard is the format used by default if no other format is specified. Use of the latter two are discouraged; they are merely kept for historical purposes. Other named formats may have been added by the database administrator. @item fieldname A single field name may appear here. Only the contents of this field will be displayed. @item '"printf string" fieldname fieldname ...' This provides a very flexible mechanism for formatting PR output. (The formatting is identical to that provided by the named formats described by the database configuration, @xref{Named query definitions}. The @var{printf string} can contain the following % sequences: @code{%[positionalspecifiers]s}: Prints the field as a string. The positional specifiers are similar to those of printf, as +, - and digit qualifiers can be used to force a particular alignment of the field contents. @code{%[positionalspecifiers]S}: Similar to @code{%s}, except that the field contents are terminated at the first space character. @code{%[positionalspecifiers]d}: Similar to @code{%s}, except that the field contents are written as a numeric value. For integer fields, the value is written as a number. For enumerated fields, the field is converted into a numeric equivalent (i.e. if the field can have two possible values, the result will be either 1 or 2). For date fields, the value is written as seconds since Jan 1, 1970. @code{%F}: The field is written as it would appear within a PR, complete with field header. @code{%D}: For date fields, the date is written in a standard @sc{gnats} format. @code{%Q}: For date fields, the date is written in an arbitrary "SQL" format. @end table An example formatted query looks as follows (note that the whole format specification should be quoted): @smallexample query-pr --format '"%s, %s" Synopsis State' @end smallexample @node Query expressions @subsection Query expressions @cindex query expressions @noindent Query expressions are used to select specific PRs based on their field contents. The general form is @smallexample fieldname|"value" operator fieldname|"value" [booleanop ...] @end smallexample @var{value} is a literal string or regular expression; it must be surrounded by double quotes, otherwise it is interpreted as a fieldname. @var{fieldname} is the name of a field in the PR. @var{operator} is one of: @table @code @item = The value of the left-hand side of the expression must exactly match the regular expression on the right-hand side of the expression. @xref{Regexps,,Querying using regular expressions}. @item ~ Some portion of the left-hand side of the expression must match the regular expression on the right-hand side. @item == The value of the left-hand side must be equal to the value on the right-hand side of the expression. The equality of two values depends on what type of data is stored in the field(s) being queried. For example, when querying a field containing integer values, literal strings are interpreted as integers. The query expression @smallexample Number == "0123" @end smallexample @noindent is identical to @smallexample Number == "123" @end smallexample @noindent as the leading zero is ignored. If the values were treated as strings instead of integers, then the two comparisons would return different results. @item != The not-equal operator. Produces the opposite result of the == operator. @item <,> The left-hand side must have a value less than or greater than the right-hand side. Comparisons are done depending on the type of data being queried; in particular, integer fields and dates use a numeric comparison, and enumerated fields are ordered depending on the numeric equivalent of their enumerated values. @end table @var{booleanop} is either @samp{|} (logical or), or @samp{&} (logical and). The query expression @smallexample Category="baz" | Responsible="blee" @end smallexample @noindent selects all PRs with a Category field of @samp{baz} or a Responsible field of @samp{blee}. The not operator @samp{!} may be used to negate a test: @smallexample ! Category="foo" @end smallexample @noindent searches for PRs where the category is not equal to the regular expression foo. Parentheses may be used to force a particular interpretation of the expression: @smallexample !(Category="foo" & Submitter-Id="blaz") @end smallexample @noindent skips PRs where the Category field is equal to @samp{foo} and the Submitter-Id field is equal to @samp{blaz}. Parentheses may be nested to any arbitrary depth. Fieldnames can be specified in several ways. The simplest and most obvious is just a name: @smallexample Category="foo" @end smallexample @noindent which checks the value of the category field for the value @var{foo}. A fieldname qualifier may be prepended to the name of the field; a colon is used to separate the qualifier from the name. To refer directly to a builtin field name: @smallexample builtin:Number="123" @end smallexample In this case, @samp{Number} is interpreted as the builtin name of the field to check. (This is useful if the fields have been renamed. For further discussion of builtin field names, see @ref{dbconfig file,,The @code{dbconfig} file}. To scan all fields of a particular type, the @var{fieldtype} qualifier may be used: @smallexample fieldtype:Text="bar" @end smallexample @noindent This searches all text fields for the regular expression @samp{bar}. Note that it is not required that the right-hand side of the expression be a literal string. To query all PRs where the PR has been modified since it was closed, the expression @smallexample Last-Modified != Closed-Date @end smallexample @noindent will work; for each PR, it compares the value of its Last-Modified field against its Closed-Date field, and returns those PRs where the values differ. However, this query will also return all PRs with empty Last-Modified or Closed-Date fields. To further narrow the search: @smallexample Last-Modified != Closed-Date & Last-Modified != "" & Closed-Date != "" @end smallexample @noindent In general, comparing fields of two different types (an integer field against a date field, for example) will probably not do what you want. Also, a field specifier may be followed by the name of a subfield in braces: @smallexample State[type] != "closed" @end smallexample @noindent or even @smallexample builtin:State[type] != "closed" @end smallexample @noindent Subfields are further discussed in @ref{dbconfig file,,The @code{dbconfig} file}. @c -------------------------------------------------------- @node Example queries @subsection Example queries @cindex example queries @noindent The following simple query: @smallexample query-pr --expr 'Category~"rats" & State~"analyzed" & Responsible~"fred"' @end smallexample @noindent yields all PRs in the database which contain the field values: @smallexample >Category: rats @emph{and} >Responsible: fred @emph{and} >State: analyzed @end smallexample The following query: @smallexample query-pr --expr 'State~"open|analyzed"' @end smallexample @noindent yields all PRs in the database whose @code{State} values match either @samp{open} or @samp{analyzed} (@pxref{Regexps,,Querying using regular expressions}. This search is useful as a daily report that lists all Problem Reports which require attention. The following query: @smallexample query-pr --expr 'fieldtype:Text="The quick.*brown fox"' @end smallexample @noindent yields all PRs whose @sc{Text} fields contain the text @samp{The quick} followed by @samp{brown fox} within the same field. @xref{Regexps,,Querying using regular expressions}, which also contains further useful examples of query expressions. @include emacs.texi gnats-4.1.0/doc/s-usage.texi0000644000175000017500000003373607576116306016415 0ustar chewiechewie00000000000000You can invoke @code{send-pr} from a shell prompt, or from within @sc{gnu} Emacs using @w{@samp{M-x send-pr}} (@pxref{Emacs submitting,,Submitting Problem Reports from Emacs}.) @menu * PR template:: The Problem Report template * send-pr in Emacs:: Using send-pr from within Emacs * send-pr from the shell:: Invoking send-pr from the shell * Submitting via e-mail:: Submitting a Problem Report via direct e-mail * Helpful hints:: @end menu @node send-pr from the shell @section Invoking @code{send-pr} from the shell @cindex command line options @cindex invoking @code{send-pr} from the shell @cindex shell invocation @smallexample send-pr [ -b | --batch ] [ -d @var{database} | --database @var{database} ] [ -f @var{file} | --file @var{file} ] [ -p | --print ] [ --request-id ] [ -s @var{severity} | --severity @var{severity} ] [ -V | --version ] [ -h | --help ] @end smallexample Invoking @code{send-pr} with no options assumes that you want to submit to the local @sc{gnats} database named @var{default} and calls the editor named in your environment variable @code{EDITOR} on a PR template for this database. @table @code @item -b @itemx --batch Suppresses printing of most of the messages @code{send-pr} usually prints while running. @item -d @var{database}, --database @var{database} Specifies the database to which the PR is to be submitted; if no database is specified, the local database named @code{default} is assumed. This option overrides the database specified in the @code{GNATSDB} environment variable. @var{database} can also be set to a remote database by using the format for @code{GNATSDB} described in @ref{Environment,,Environment variables and @sc{gnats} tools}. @item -f @var{problem-report} @itemx --file @var{problem-report} Specifies a file, @var{problem-report}, where a completed Problem Report or a PR template exists. @code{send-pr} verifies that the contents of the file constitute a valid PR and asks you if you want to edit it or send it directly. If the PR text is invalid you will be told what is wrong and be given the option to edit it. If @var{problem-report} is @samp{-}, @w{@code{send-pr}} reads from standard input. @item -p @itemx --print Displays the PR template for the specified database, or if the @code{-d} or @code{--database} options aren't specified, print the template for the local @var{default} database. No PR is submitted. @item --request-id Sends a request for a @code{Submitter-Id} to the Support Site. @item -s @var{severity} @itemx --severity @var{severity} @cindex @code{send-pr} fields Sets the initial value of the @code{Severity} field to @var{severity}. @item -V @itemx --version Displays the @code{send-pr} version number and a usage summary. No mail is sent. @item -h @itemx --help Displays a usage summary for @code{send-pr}. No mail is sent. @end table @c --------------------------------------------------------------- @node send-pr in Emacs @section Using @code{send-pr} from within Emacs @cindex using @code{send-pr} from within Emacs @cindex @code{send-pr} within Emacs @cindex invoking @code{send-pr} from Emacs @cindex interactive interface You can use an interactive @code{send-pr} interface from within @sc{gnu} Emacs to fill out your Problem Report. We recommend that you familiarize yourself with Emacs before using this feature (@pxref{Introduction,,Introduction,emacs,GNU Emacs}). Call @code{send-pr} with @w{@samp{M-x send-pr}}.@footnote{If typing @w{@samp{M-x send-pr}} doesn't work, see your system administrator for help loading @file{gnats.el} into Emacs.} @code{send-pr} responds with a preconfigured Problem Report template. The Emacs interface is described in more detail in a separate section, @xref{Emacs,,The Emacs interface to @sc{gnats}}. @node PR template @section The Problem Report template Invoking @code{send-pr} presents a PR @dfn{template} with a number of fields already filled in with default values for the database you are submitting to. Complete the template as thoroughly as possible to make a useful bug report. Submit only one bug with each PR. @cindex template A template consists of three sections: @itemize @bullet @item Comments @item Mail Header @item @sc{gnats} fields @end itemize The @strong{Comments section} at the top of the template contains basic instructions for completing the Problem Report, as well as a list of valid entries for the @code{Category} field. One (and only one) of these values should be placed in the @code{Category} field further down in the Problem Report. @cindex template comment section @cindex comment section in the PR template @smallexample @group SEND-PR: -*- send-pr -*- SEND-PR: Lines starting with `SEND-PR' will be removed SEND-PR: automatically as well as all comments (the text SEND-PR: below enclosed in `<' and `>'). SEND-PR: SEND-PR: Please consult the document `Reporting Problems SEND-PR: Using send-pr' if you are not sure how to fill out SEND-PR: a problem report. SEND-PR: SEND-PR: Choose from the following categories: @end group @end smallexample @ifset SENDPR A complete sample bug report, from template to completed PR, is shown in @ref{An Example}. For a complete list of valid categories, type @w{@samp{send-pr -L}} at your prompt. @xref{Valid Categories,,Valid Categories}, for a sample list of categories, . @end ifset The comments lines are all preceded by the string @samp{SEND-PR:} and are erased automatically when the PR is submitted. The instructional comments within @samp{<} and @samp{>} are also removed. (Only these comments are removed; lines you provide that happen to have those characters in them, such as examples of shell-level redirection, are not affected.) The @strong{Mail Header} section of the template contains a standard mail header constructed by @code{send-pr}. @code{send-pr} can be set up to submit PRs by e-mail or by speaking directly to the @sc{gnats} server, but since this header is part of the standard format of Problem Reports, @code{send-pr} includes it even when it is set up to speak directly to the server. @cindex mail header section @smallexample @group To: @var{PR submission address} Subject: @emph{complete this field} From: @var{your-login}@@@var{your-site} Reply-To: @var{your-login}@@@var{your-site} X-send-pr-version: send-pr @value{VERSION} @end group @end smallexample @noindent @code{send-pr} automatically completes all the mail header fields except the @code{Subject} line with default values. (@xref{Fields,,Problem Report format}.) The @strong{@sc{gnats} fields} below the mail header form the bulk of a @sc{gnats} Problem Report. Each field is either automatically completed with valid information (such as your @code{Submitter-Id}) or contains a one-line instruction specifying the information that field requires in order to be correct. For example, the @code{Confidential} field expects a value of @samp{yes} or @samp{no}, and the answer must fit on one line; similarly, the @code{Synopsis} field expects a short synopsis of the problem, which must also fit on one line. Fill out the fields as completely as possible. @xref{Helpful hints,,Helpful hints}, for suggestions as to what kinds of information to include. The mechanisms @code{send-pr} uses to fill in default values is as follows: Your preconfigured @code{Submitter-Id} is taken from the local @file{send-pr.conf} configuration file. @code{send-pr} will set the @code{Originator} field to the value of the @code{NAME} environment variable if it has been set; similarly, @code{Organization} will be set to the value of @code{ORGANIZATION}. If these variables aren't set in you environment, @code{send-pr} uses the values set in the local @file{send-pr.conf} configuration file, if that exists. If not, these values are left blank in the template. @code{send-pr} also attempts to find out some information about your system and architecture, and places this information in the @code{Environment} field if it finds any. In this example, words in @emph{italics} are filled in with pre-configured information: @cindex @code{send-pr} fields @smallexample >Submitter-Id: @emph{your submitter-id} >Originator: @emph{your name here} >Organization: @emph{your organization} >Confidential:<[ yes | no ] (one line)> >Synopsis: >Severity: <[non-critical | serious | critical](one line)> >Priority: <[ low | medium | high ] (one line)> >Category: >Class: <[sw-bug | doc-bug | change-request | support]> >Release: >Environment: >Description: >How-To-Repeat: >Fix: @end smallexample @cindex @code{Submitter-Id} field @cindex @code{>Submitter-Id} When you finish editing the Problem Report, @code{send-pr} validates the contents and if it looks OK either submits it directly to the @sc{gnats} server or submits it by mail to the address named in the @code{To} field in the mail header. @cindex bad Problem Reports @cindex errors @cindex invalid Problem Reports If your PR contains one or more invalid field values, @code{send-pr} places the PR in a temporary file named @file{/tmp/pbad@var{nnnn}} on your machine. @var{nnnn} is the process identification number given to your current @code{send-pr} session. If you are running @code{send-pr} from the shell, you are prompted as to whether or not you wish to try editing the same Problem Report again. If you are running @code{send-pr} from Emacs, the Problem Report is placed in the buffer @w{@samp{*gnats-send*}}; you can edit this file and then submit it with @kbd{C-c C-c}. @c ------------------------------------------------------------------------- @node Submitting via e-mail @section Submitting a Problem Report via direct e-mail @cindex Direct e-mail @cindex Submitting a PR via e-mail In addition to using @code{send-pr}, there is another way to submit a problem report. You can simply send an e-mail message to the PR submission e-mail address of the support site (This address should be published by the support site.) When you send unformatted e-mail to this address, @sc{gnats} processes the message as a new problem report, filling in as many fields from defaults as it can: @table @code @item Synopsis The @code{Synopsis} field is filled in by the @code{Subject} header of the e-mail message. @item Submitter ID @sc{gnats} will try to derive the @code{Submitter} field from the address in the @code{From} header of the e-mail. @item Description All of the text in the body of the e-mail message is put into the @code{Description} field. @end table Other fields, such as @code{Category}, @code{Version}, @code{Severity}, etc. are set to default values as defined by the @sc{gnats} administrator. @c -------------------------------------------------------------------------- @node Helpful hints @section Helpful hints @cindex helpful hints @cindex Using and Porting @sc{gnu} CC @cindex effective problem reporting @cindex kinds of helpful information @cindex information to submit @cindex Report all the facts! There is no orthodox standard for submitting effective bug reports, though you might do well to consult the section on submitting bugs for @sc{gnu} @code{gcc} in @ref{Bugs, , Reporting Bugs, gcc, Using and Porting GNU CC}, by Richard Stallman. This section contains instructions on what kinds of information to include and what kinds of mistakes to avoid. In general, common sense (assuming such an animal exists) dictates the kind of information that would be most helpful in tracking down and resolving problems in software. @itemize @bullet @item Include anything @emph{you} would want to know if you were looking at the report from the other end. There's no need to include every minute detail about your environment, although anything that might be different from someone else's environment should be included (your path, for instance). @item Narratives are often useful, given a certain degree of restraint. If a person responsible for a bug can see that A was executed, and then B and then C, knowing that sequence of events might trigger the realization of an intermediate step that was missing, or an extra step that might have changed the environment enough to cause a visible problem. Again, restraint is always in order (``I set the build running, went to get a cup of coffee (Columbian, cream but no sugar), talked to Sheila on the phone, and then THIS happened@dots{}'') but be sure to include anything relevant. @item Richard Stallman writes, ``The fundamental principle of reporting bugs usefully is this: @strong{report all the facts}. If you are not sure whether to state a fact or leave it out, state it!'' This holds true across all problem reporting systems, for computer software or social injustice or motorcycle maintenance. It is especially important in the software field due to the major differences seemingly insignificant changes can make (a changed variable, a missing semicolon, etc.). @item Submit only @emph{one} problem with each Problem Report. If you have multiple problems, use multiple PRs. This aids in tracking each problem and also in analyzing the problems associated with a given program. @item It never hurts to do a little research to find out if the bug you've found has already been reported. Most software releases contain lists of known bugs in the Release Notes which come with the software; see your system administrator if you don't have a copy of these. @item The more closely a PR adheres to the standard format, the less interaction is required by a database administrator to route the information to the proper place. Keep in mind that anything that requires human interaction also requires time that might be better spent in actually fixing the problem. It is therefore in everyone's best interest that the information contained in a PR be as correct as possible (in both format and content) at the time of submission. @end itemize gnats-4.1.0/doc/states.texi0000644000175000017500000000360107356175547016350 0ustar chewiechewie00000000000000@node States @section States of Problem Reports @cindex life-cycle of a Problem Report @cindex states of Problem Reports @cindex Problem Report states @cindex automatic notification Each PR goes through a defined series of states between origination and closure. By default, the originator of a PR receives notification automatically of any state changes. Unless your site has customized states (@pxref{states file,,,gnats}), @sc{gnats} uses these states: @table @dfn @cindex @emph{open} state @cindex initial state (@dfn{open}) @cindex state---@dfn{open} @item open The initial state of a Problem Report. This means the PR has been filed and the responsible person(s) notified. @cindex @emph{analyzed} state @cindex state---@dfn{analyzed} @item analyzed The responsible person has analyzed the problem. The analysis should contain a preliminary evaluation of the problem and an estimate of the amount of time and resources necessary to solve the problem. It should also suggest possible workarounds. @cindex @emph{feedback} state @cindex state---@dfn{feedback} @item feedback The problem has been solved, and the originator has been given a patch or other fix. The PR remains in this state until the originator acknowledges that the solution works. @cindex @emph{closed} state @cindex state---@dfn{closed} @cindex final state (@dfn{closed}) @item closed A Problem Report is closed (``the bug stops here'') only when any changes have been integrated, documented, and tested, and the submitter has confirmed the solution. @cindex @emph{suspended} state @cindex state---@dfn{suspended} @item suspended Work on the problem has been postponed. This happens if a timely solution is not possible or is not cost-effective at the present time. The PR continues to exist, though a solution is not being actively sought. If the problem cannot be solved at all, it should be closed rather than suspended. @end table gnats-4.1.0/doc/version.texi0000600000175000017500000000002310212665130016466 0ustar chewiechewie00000000000000@set VERSION 4.1.0 gnats-4.1.0/doc/gnats.info0000600000175000017500000107757710212665130016134 0ustar chewiechewie00000000000000This is gnats.info, produced by makeinfo version 4.7 from gnats.texi. START-INFO-DIR-ENTRY * Keeping Track: (gnats). GNU Problem Report Management System END-INFO-DIR-ENTRY Copyright (C) 1993, 1995, 2001, 2002, 2003 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.  File: gnats.info, Node: Top, Next: Introduction, Up: (dir) Overview ******** This manual documents GNATS, the GNU Problem Report Management System, version 4.1.0. GNATS is a bug-tracking tool designed for use at a central "Support Site". Users who experience problems use electronic mail, web-based or other clients communicating with the GNATS network daemon running at the support site or direct database submissions to communicate these problems to "maintainers" at that Support Site. GNATS partially automates the tracking of these "Problem Reports" ("PR"s) by: * organizing problem reports into a database and notifying responsible parties of suspected bugs; * allowing support personnel and their managers to edit and query accumulated bugs; and * providing a reliable archive of problems (and their subsequent solutions) with a given program. GNATS offers many of the same features offered by more generalized databases, including editing, querying, and basic reporting. The GNATS database itself is an ordered repository for problem reports; each PR receives a unique, incremental "PR number" which identifies it throughout its lifetime. For a discussion on the working system adopted by GNATS, see *Note The database paradigm: Paradigm. You can access the submitting, editing, and querying functions of GNATS from within GNU Emacs. *Note The GNATS user tools: GNATS user tools. * Menu: * Introduction:: Introducing GNATS. * GNATS user tools:: The GNATS user tools. * Installation:: Installing GNATS. * Management:: GNATS Administration. * Locations:: Where GNATS lives. * gnatsd:: The GNATS network server. * Access Control:: Controlling access to GNATS databases. * Regexps:: Querying using regular expressions. * dbconfig recipes:: Useful dbconfig tricks. * Support:: GNATS related sites and mailing lists. * Index::  File: gnats.info, Node: Introduction, Next: GNATS user tools, Prev: Top, Up: Top 1 Introducing GNATS ******************* Any support organization realizes that a large amount of data flows back and forth between the maintainers and the users of their products. This data often takes the form of problem reports and communication via electronic mail. GNATS addresses the problem of organizing this communication by defining a database made up of archived and indexed problem reports. GNATS was designed as a tool for software maintainers. It consists of several utilities which, when used in concert, formulate and administer a database of Problem Reports grouped by site-defined "problem categories". It allows a support organization to keep track of problems (hence the term "Problem Report") in an organized fashion. Essentially, GNATS acts as an active archive for field-separated textual data. * Menu: * Paradigm:: The database paradigm * Flowchart:: Flowchart of GNATS activities * States:: States of Problem Reports * Fields:: Problem Report format  File: gnats.info, Node: Paradigm, Next: Flowchart, Up: Introduction 1.1 The database paradigm ========================= It is in your best interest as the maintainer of a body of work to organize the feedback you receive on that work, and to make it easy for users of your work to report problems and suggestions. GNATS makes this easy by automatically filing incoming problem reports into appropriate places, by notifying responsible parties of the existence of the problem and (optionally) sending an acknowledgment to the submitter that the report was received, and by making these Problem Reports accessible to queries and easily editable. GNATS is a database specialized for a specific task. GNATS was designed for use at a Support Site that handles a high level of problem-related traffic. It maintains Problem Reports in the form of text files with defined "fields" (*note GNATS data fields: Fields.). The location of the database, as well as the categories it accepts as valid, the maintainers for whom it provides service, and the submitters from whom it accepts Problem Reports, are all definable by the "Support Site". *Note GNATS administration: Management. Each PR is a separate file within a main repository (*note Where GNATS lives: Locations.). Editing access to the database is regulated to maintain consistency. To make queries on the database faster, an index is kept automatically (*note The `index' file: index file.). We provide several software tools so that users may submit new Problem Reports, edit existing Problem Reports, and query the database. * `send-pr' is used by both product maintainers and the end users of the products they support to submit PRs to the database. * `edit-pr' is used by maintainers when editing problem reports in the database. * Maintainers, managers and administrators can use `query-pr' to make inquiries about individual PRs or groups of PRs. Other interfaces to GNATS include Gnatsweb, a web-based tool which provides features for submitting and editing PRs and querying the database, and TkGnats, a Tcl/Tk-based frontend. These tools are distributed together with GNATS. At the Support Site, a GNATS "administrator" is charged with the duty of maintaining GNATS. These duties are discussed in detail in *Note GNATS Administration: Management, and generally include configuring GNATS for the Support Site, editing PRs that GNATS cannot process, pruning log files, setting up new problem categories, backing up the database, and distributing `send-pr' so that others may submit Problem Reports. Responsibility for a given Problem Report initially depends on the category of the problem. Optionally, an automated reminder can be sent to the responsible person if a problem report is neglected for a requisite time period. *Note Overview of GNATS configuration: GNATS configuration. GNATS does not have the ability to decipher random text. If there is no default category set, any problem reports which arrive in a format GNATS does not recognize are placed in a separate directory pending investigation by the GNATS administrator (*note GNATS Administration: Management.). Once a problem is recorded in the database, work can begin toward a solution. A problem's initial "state" type is "open" (*note States of Problem Reports: States.). An acknowledgment may be sent to the originator of the bug report (depending on whether this feature has been switched on in the GNATS configuration). GNATS forwards copies of the report to the party responsible for that problem category and to the person responsible for problems arriving from that submitter. When a problem has been identified, the maintainer can change its state to "analyzed", and then to "feedback" when a solution is found. GNATS may be configured so that each time the state of a PR changes, the submitter of the problem report is notified of the reason for the change. If the party responsible for the PR changes, the previous responsible party and the new responsible party receive notice of the change. The change and reason are also recorded in the `Audit-Trail' field of the Problem Report. (*Note Editing existing Problem Reports: edit-pr. For information on the `Audit-Trail' field, see *Note Problem Report format: Fields.) When the originator of the Problem Report confirms that the solution works, the maintainer can change the state to "closed". If the PR cannot be closed, the maintainer can change its state to "suspended" as a last resort. (For a more detailed description of the standard states, see *Note States of Problem Reports: States.) It should be emphasized that what we describe here is the default way that GNATS works, but as of version 4, GNATS is extremely customizable, allowing sites to tailor almost every aspect of its behavior. See for instance *Note The `dbconfig' file: dbconfig file. and *Note States of Problem Reports: States.)  File: gnats.info, Node: Flowchart, Next: States, Prev: Paradigm, Up: Introduction 1.2 Flowchart of GNATS activities ================================= This informal flowchart shows the relationships of the GNATS tools to each other and to the files with which they interoperate. +===========+ +===========+ +============+ # USER SITE # # USER SITE # # USER SITE # # # # # # # # *send-pr* # # *send-pr* # # Web client # +=====|=====+ +=====|=====+ +=====|======+ | V | `---------> Email/gnatsd... <-------' ,---> | +===============|=========|===================+ # SUPPORT SITE | `---> /etc/aliases # # *send-pr* | # # +-----------------------------V--------+# # | GNATS DATABASEDIR/gnats-queue/|# # | | |# # | _________ V |# # | |*file-pr*|<--- *queue-pr -r* |# # | | | |# # _ | | valid | |# # |M| | |Category?|N--. |# # |A| | |_________| | GNATS |# # |I| | Y| | ADMINISTRATOR |# # |N| | | | |# # |T|<----------------| | |# # |A| | | | .-> *edit-pr* |# # |I|--->*edit-pr*-. | V | | |# # |N| | | |DATABASEDIR/pending | |# # |E|<--*query-pr* | | | |# # |R| | | | | | |# # |S| | | V V V |# # |_| |+------------------------------------+|# # || GNATS Database ||# # || DATABASEDIR/CATEGORY/GNATS-ID ||# # |+------------------------------------+|# # +--------------------------------------+# +=============================================+  File: gnats.info, Node: States, Next: Fields, Prev: Flowchart, Up: Introduction 1.3 States of Problem Reports ============================= Each PR goes through a defined series of states between origination and closure. By default, the originator of a PR receives notification automatically of any state changes. Unless your site has customized states (*note states file: (gnats)states file.), GNATS uses these states: "open" The initial state of a Problem Report. This means the PR has been filed and the responsible person(s) notified. "analyzed" The responsible person has analyzed the problem. The analysis should contain a preliminary evaluation of the problem and an estimate of the amount of time and resources necessary to solve the problem. It should also suggest possible workarounds. "feedback" The problem has been solved, and the originator has been given a patch or other fix. The PR remains in this state until the originator acknowledges that the solution works. "closed" A Problem Report is closed ("the bug stops here") only when any changes have been integrated, documented, and tested, and the submitter has confirmed the solution. "suspended" Work on the problem has been postponed. This happens if a timely solution is not possible or is not cost-effective at the present time. The PR continues to exist, though a solution is not being actively sought. If the problem cannot be solved at all, it should be closed rather than suspended.  File: gnats.info, Node: Fields, Prev: States, Up: Introduction 1.4 Problem Report format ========================= The format of a PR is designed to reflect the nature of GNATS as a database. Information is arranged into "fields", and kept in individual records (Problem Reports). A Problem Report contains two different types of fields: "Mail Header" fields, which are used by the mail handler for delivery, and "Problem Report" fields, which contain information relevant to the Problem Report and its submitter. A Problem Report is essentially a specially formatted electronic mail message. Problem Report fields are denoted by a keyword which begins with `>' and ends with `:', as in `>Confidential:'. Fields belong to one of eight data types as listed in *Note Field datatypes reference::. As of version 4 of GNATS all characteristics of fields, such as field name, data type, allowed values, permitted operations, on-change actions etc. are configurable. For details, see *note The `dbconfig' file: dbconfig file. Example Problem Report ---------------------- The following is an example Problem Report with the fields that would be present in a standard GNATS configuration. Mail headers are at the top, followed by GNATS fields, which begin with `>' and end with `:'. The `Subject:' line in the mail header and the `Synopsis' field are usually duplicates of each other. Message-Id: MESSAGE-ID Date: DATE From: ADDRESS Reply-To: ADDRESS To: BUG-ADDRESS Subject: SUBJECT >Number: GNATS-ID >Category: CATEGORY >Synopsis: SYNOPSIS >Confidential: yes _or_ no >Severity: critical, serious, _or_ non-critical >Priority: high, medium _or_ low >Responsible: RESPONSIBLE >State: open, analyzed, suspended, feedback, _or_ closed >Class: sw-bug, doc-bug, change-request, support, duplicate, _or_ mistaken >Submitter-Id: SUBMITTER-ID >Arrival-Date: DATE >Originator: NAME >Organization: ORGANIZATION >Release: RELEASE >Environment: ENVIRONMENT >Description: DESCRIPTION >How-To-Repeat: HOW-TO-REPEAT >Fix: FIX >Audit-Trail: APPENDED-MESSAGES... State-Changed-From-To: FROM-TO State-Changed-When: DATE State-Changed-Why: REASON Responsible-Changed-From-To: FROM-TO Responsible-Changed-When: DATE Responsible-Changed-Why: REASON >Unformatted: MISCELLANEOUS * Menu: * Field datatypes reference:: * Mail header fields:: * Problem Report fields::  File: gnats.info, Node: Field datatypes reference, Next: Mail header fields, Up: Fields 1.4.1 Field datatypes reference ------------------------------- The following is a short reference to the characteristics of the different field types. For details, see *Note Field datatypes::. `text' A one-line text string. `multitext' Multiple lines of text. `enum' The value in this field is required to be from a list of specified values, defined at the Support Site. (*Note The `dbconfig' file: dbconfig file, for details. `multienum' Similar to the `enum' datatype, except that the field can contain multiple values. `enumerated-in-file' Similar to `enum', but the allowed field values are listed in a separate file on the GNATS server. `multi-enumerated-in-file' Similar to `enumerated-in-file', except that the field can contain multiple values. `date' Used to hold dates. `integer' Used to hold integer numbers.  File: gnats.info, Node: Mail header fields, Next: Problem Report fields, Prev: Field datatypes reference, Up: Fields 1.4.2 Mail header fields ------------------------ A Problem Report may contain any mail header field described in the Internet standard RFC-822. The `send-pr' tool can be configured either to submit PRs to the support site by e-mail or by talking directly to the `gnatsd' network daemon on the GNATS server. This is also true for other client tools such as Gnatsweb. Even when these tools are set up submit PRs directly to `gnatsd', they will still include mail header fields that identify the sender and the subject in the submitted PR: `To:' The mail address for the Support Site, automatically supplied by the tool used to submit the PR or by the originator if plain e-mail was used. `Subject:' A terse description of the problem. This field normally contains the same information as the `Synopsis' field. `From:' Supplied automatically when PRs are submitted by plain e-mail and when well-behaved tools such as `send-pr' are used; should always contain the originator's e-mail address. `Reply-To:' A return address to which electronic replies can be sent; in most cases, the same address as the `From:' field. One of the configurable options for GNATS is whether or not to retain `Received-By' headers, which often consume a lot of space and are not often used. *Note The dbconfig file: dbconfig file.  File: gnats.info, Node: Problem Report fields, Prev: Mail header fields, Up: Fields 1.4.3 Problem Report fields --------------------------- In a standard GNATS installation, certain fields will always be present in a Problem Report. If a PR arrives without one or more of these fields, GNATS will add them, and if they have default values set by the configuration at the Support Site, they will be filled in with these values. Certain tools such as `send-pr' are set up to provide sensible defaults for most fields (*note The send-pr.conf configuration file: send-pr.conf file.) In the list below, the field type (`text', `multitext', `enumerated', etc.) is supplied in parantheses. The different field types are explained briefly in *Note Field datatypes reference::. `Submitter-Id' (`enumerated-in-file') A unique identification code assigned by the Support Site. It is used to identify all Problem Reports coming from a particular site. Submitters without a value for this field can invoke `send-pr' with the `--request-id' option to apply for one from the support organization. Problem Reports from those not affiliated with the support organization should use the default value of `net' for this field. *Note The `submitters' file: submitters file, for details. `Notify-List' (`text') Comma-separated list of e-mail-addresses of people to notify when the PR changes significantly, i.e. when the Audit-Trail changes. This list is independent from the Notify subfield of entries in the `categories' file of the GNATS database. `Originator' (`text') Originator's real name. Note that the Submitter and Originator might not be the same person/entity in all cases. `Organization' (`multitext') The originator's organization. `Confidential' (`enum') Use of this field depends on the originator's relationship with the support organization; contractual agreements often have provisions for preserving confidentiality. Conversely, a lack of a contract often means that any data provided will not be considered confidential. Submitters should be advised to contact the support organization directly if this is an issue. If the originator's relationship to the support organization provides for confidentiality, then if the value of this field is `yes' the support organization treats the PR as confidential; any code samples provided are not made publicly available. `Synopsis' (`text') One-line summary of the problem. `send-pr' copies this information to the `Subject' line when you submit a Problem Report. `Severity' (`enum') The severity of the problem. By default, accepted values include: `critical' The product, component or concept is completely non-operational or some essential functionality is missing. No workaround is known. `serious' The product, component or concept is not working properly or significant functionality is missing. Problems that would otherwise be considered `critical' are usually rated `serious' when a workaround is known. `non-critical' The product, component or concept is working in general, but lacks features, has irritating behavior, does something wrong, or doesn't match its documentation. `Priority' (`enumerated') How soon the originator requires a solution. Accepted values include: `high' A solution is needed as soon as possible. `medium' The problem should be solved in the next release. `low' The problem should be solved in a future release. `Category' (`enumerated-in-file') The name of the product, component or concept where the problem lies. The values for this field are defined by the Support Site. *Note The `categories' file: categories file, for details. `Class' (`enumerated-in-file') The class of a problem in a default GNATS installation can be one of the following: `sw-bug' A general product problem. (`sw' stands for "software".) `doc-bug' A problem with the documentation. `change-request' A request for a change in behavior, etc. `support' A support problem or question. `duplicate (PR-NUMBER)' Duplicate PR. PR-NUMBER should be the number of the original PR. `mistaken' No problem, user error or misunderstanding. This value can only be set by tools at the Support Site, since it has no meaning for ordinary submitters. *Note The `classes' file: classes file, for details. `Release' (`text') Release or version number of the product, component or concept. `Environment' (`multitext') Description of the environment where the problem occurred: machine architecture, operating system, host and target types, libraries, pathnames, etc. `Description' (`multitext') Precise description of the problem. `How-To-Repeat' (`multitext') Example code, input, or activities to reproduce the problem. The support organization uses example code both to reproduce the problem and to test whether the problem is fixed. Include all preconditions, inputs, outputs, conditions after the problem, and symptoms. Any additional important information should be included. Include all the details that would be necessary for someone else to recreate the problem reported, however obvious. Sometimes seemingly arbitrary or obvious information can point the way toward a solution. See also *Note Helpful hints: Helpful hints. `Fix' (`multitext') A description of a solution to the problem, or a patch which solves the problem. (This field is most often filled in at the Support Site; we provide it to the submitter in case he or she has solved the problem.) GNATS adds the following fields when the PR arrives at the Support Site: `Number' (`enumerated') The incremental identification number for this PR. This is included in the automated reply to the submitter (if that feature of GNATS is activated; *note The `dbconfig' file: dbconfig file.). It is also included in the copy of the PR that is sent to the maintainer. The `Number' field is often paired with the `Category' field as CATEGORY/NUMBER in subsequent email messages. This is GNATS' way of tracking followup messages that arrive by mail so that they are filed as part of the original PR. `State' (`enumerated') The current state of the PR. In default GNATS installations, accepted values are: `open' The PR has been filed and the responsible person notified. `analyzed' The responsible person has analyzed the problem. `feedback' The problem has been solved, and the originator has been given a patch or other fix. Support organizations may also choose to temporarily "park" PRs that are awaiting further input from the submitter under this state. `closed' The changes have been integrated, documented, and tested, and the originator has confirmed that the solution works. `suspended' Work on the problem has been postponed. The initial state of a PR is `open'. *Note States of Problem Reports: States. `Responsible' (`text') The person at the Support Site who is responsible for this PR. GNATS retrieves this information from the `categories' file (*note The `categories' file: categories file.). `Arrival-Date' (`date') The time that this PR was received by GNATS. The date is provided automatically by GNATS. `Date-Required' (`date') The date by which a fix is required. This is up to the maintainers at the Support Site to determine, so this field is not available until after the PR has been submitted. `Audit-Trail' (`multitext') Tracks related electronic mail as well as changes in the `State' and `Responsible' fields with the sub-fields: `State-Changed--: OLDSTATE>--: OLDRESP>-'). SEND-PR: SEND-PR: Please consult the document `Reporting Problems SEND-PR: Using send-pr' if you are not sure how to fill out SEND-PR: a problem report. SEND-PR: SEND-PR: Choose from the following categories: The comments lines are all preceded by the string `SEND-PR:' and are erased automatically when the PR is submitted. The instructional comments within `<' and `>' are also removed. (Only these comments are removed; lines you provide that happen to have those characters in them, such as examples of shell-level redirection, are not affected.) The *Mail Header* section of the template contains a standard mail header constructed by `send-pr'. `send-pr' can be set up to submit PRs by e-mail or by speaking directly to the GNATS server, but since this header is part of the standard format of Problem Reports, `send-pr' includes it even when it is set up to speak directly to the server. To: PR SUBMISSION ADDRESS Subject: _complete this field_ From: YOUR-LOGIN@YOUR-SITE Reply-To: YOUR-LOGIN@YOUR-SITE X-send-pr-version: send-pr 4.1.0 `send-pr' automatically completes all the mail header fields except the `Subject' line with default values. (*Note Problem Report format: Fields.) The *GNATS fields* below the mail header form the bulk of a GNATS Problem Report. Each field is either automatically completed with valid information (such as your `Submitter-Id') or contains a one-line instruction specifying the information that field requires in order to be correct. For example, the `Confidential' field expects a value of `yes' or `no', and the answer must fit on one line; similarly, the `Synopsis' field expects a short synopsis of the problem, which must also fit on one line. Fill out the fields as completely as possible. *Note Helpful hints: Helpful hints, for suggestions as to what kinds of information to include. The mechanisms `send-pr' uses to fill in default values is as follows: Your preconfigured `Submitter-Id' is taken from the local `send-pr.conf' configuration file. `send-pr' will set the `Originator' field to the value of the `NAME' environment variable if it has been set; similarly, `Organization' will be set to the value of `ORGANIZATION'. If these variables aren't set in you environment, `send-pr' uses the values set in the local `send-pr.conf' configuration file, if that exists. If not, these values are left blank in the template. `send-pr' also attempts to find out some information about your system and architecture, and places this information in the `Environment' field if it finds any. In this example, words in _italics_ are filled in with pre-configured information: >Submitter-Id: _your submitter-id_ >Originator: _your name here_ >Organization: _your organization_ >Confidential:<[ yes | no ] (one line)> >Synopsis: >Severity: <[non-critical | serious | critical](one line)> >Priority: <[ low | medium | high ] (one line)> >Category: >Class: <[sw-bug | doc-bug | change-request | support]> >Release: >Environment: >Description: >How-To-Repeat: >Fix: When you finish editing the Problem Report, `send-pr' validates the contents and if it looks OK either submits it directly to the GNATS server or submits it by mail to the address named in the `To' field in the mail header. If your PR contains one or more invalid field values, `send-pr' places the PR in a temporary file named `/tmp/pbadNNNN' on your machine. NNNN is the process identification number given to your current `send-pr' session. If you are running `send-pr' from the shell, you are prompted as to whether or not you wish to try editing the same Problem Report again. If you are running `send-pr' from Emacs, the Problem Report is placed in the buffer `*gnats-send*'; you can edit this file and then submit it with `C-c C-c'.  File: gnats.info, Node: Submitting via e-mail, Next: Helpful hints, Prev: send-pr from the shell, Up: send-pr 2.2.4 Submitting a Problem Report via direct e-mail --------------------------------------------------- In addition to using `send-pr', there is another way to submit a problem report. You can simply send an e-mail message to the PR submission e-mail address of the support site (This address should be published by the support site.) When you send unformatted e-mail to this address, GNATS processes the message as a new problem report, filling in as many fields from defaults as it can: `Synopsis' The `Synopsis' field is filled in by the `Subject' header of the e-mail message. `Submitter ID' GNATS will try to derive the `Submitter' field from the address in the `From' header of the e-mail. `Description' All of the text in the body of the e-mail message is put into the `Description' field. Other fields, such as `Category', `Version', `Severity', etc. are set to default values as defined by the GNATS administrator.  File: gnats.info, Node: Helpful hints, Prev: Submitting via e-mail, Up: send-pr 2.2.5 Helpful hints ------------------- There is no orthodox standard for submitting effective bug reports, though you might do well to consult the section on submitting bugs for GNU `gcc' in *Note Reporting Bugs: (gcc)Bugs, by Richard Stallman. This section contains instructions on what kinds of information to include and what kinds of mistakes to avoid. In general, common sense (assuming such an animal exists) dictates the kind of information that would be most helpful in tracking down and resolving problems in software. * Include anything _you_ would want to know if you were looking at the report from the other end. There's no need to include every minute detail about your environment, although anything that might be different from someone else's environment should be included (your path, for instance). * Narratives are often useful, given a certain degree of restraint. If a person responsible for a bug can see that A was executed, and then B and then C, knowing that sequence of events might trigger the realization of an intermediate step that was missing, or an extra step that might have changed the environment enough to cause a visible problem. Again, restraint is always in order ("I set the build running, went to get a cup of coffee (Columbian, cream but no sugar), talked to Sheila on the phone, and then THIS happened...") but be sure to include anything relevant. * Richard Stallman writes, "The fundamental principle of reporting bugs usefully is this: *report all the facts*. If you are not sure whether to state a fact or leave it out, state it!" This holds true across all problem reporting systems, for computer software or social injustice or motorcycle maintenance. It is especially important in the software field due to the major differences seemingly insignificant changes can make (a changed variable, a missing semicolon, etc.). * Submit only _one_ problem with each Problem Report. If you have multiple problems, use multiple PRs. This aids in tracking each problem and also in analyzing the problems associated with a given program. * It never hurts to do a little research to find out if the bug you've found has already been reported. Most software releases contain lists of known bugs in the Release Notes which come with the software; see your system administrator if you don't have a copy of these. * The more closely a PR adheres to the standard format, the less interaction is required by a database administrator to route the information to the proper place. Keep in mind that anything that requires human interaction also requires time that might be better spent in actually fixing the problem. It is therefore in everyone's best interest that the information contained in a PR be as correct as possible (in both format and content) at the time of submission.  File: gnats.info, Node: edit-pr, Next: query-pr, Prev: send-pr, Up: GNATS user tools 2.3 Editing existing Problem Reports ==================================== Use `edit-pr' to make changes to existing PRs in the database. This tool can be invoked both from a shell prompt or from within GNU Emacs using `M-x edit-pr'. `edit-pr' first examines the PR you wish to edit and locks it if it is not already locked. This is to prevent you from editing a PR at the same time as another user. If the PR you wish to edit is already in the process of being edited, `edit-pr' tells you the name of the person who owns the lock. You may edit any non-readonly fields in the database. We recommend that you avoid deleting any information in the TEXT and MULTITEXT fields (such as `Description' and `How-To-Repeat' (*note Problem Report format: Fields.). We also recommend that you record the final solution to the problem in the `Fix' field for future reference. Note that heavily customized installations of GNATS may have differently named fields, and sites using such installations should provide their own set of routines and instructions regarding how PRs should be treated throughout their life span. After the PR has been edited, it is then resubmitted to the database, and the index is updated (*note The `index' file: index file.). For information on `pr-edit', the main driver for `edit-pr', see *Note Internal utilities: Internal utils. If you change a field that requires a reason for the change, such as the `Responsible' or `State' fields in the default configuration, `edit-pr' prompts you to supply a reason for the change. A message is then appended to the `Audit-Trail' field of the PR with the changed values and the change reason. Depending on how the database is configured, editing various fields in the PR may also cause mail to be sent concerning these changes. In the default configuration, any fields that generate `Audit-Trail' entries will also cause a copy of the new `Audit-Trail' message to be sent. Mail received at the PR submission email address and recognized by GNATS as relating to an existing PR is also appended to the `Audit-Trail' field, see *Note follow-up via email::. * Menu: * edit-pr from the shell:: Invoking `edit-pr' from the shell * follow-up via email:: Following up via direct email  File: gnats.info, Node: edit-pr from the shell, Next: follow-up via email, Up: edit-pr 2.3.1 Invoking `edit-pr' from the shell --------------------------------------- The usage for `edit-pr' is: edit-pr [ -V | --version ] [ -h | --help ] [-d DATABASE | --database DATABASE] PR NUMBER Network-mode-only options: [--host HOST | -H HOST] [--port PORT] [--user USER | -v USER] [--passwd PASSWD | -w PASSWD] The options have the following meaning: `-h, --help' Prints a brief usage message for edit-pr. `-V, --version' Prints the version number for edit-pr. `-d DATABASE, --database DATABASE' Specifies the database containing the PR to be edited; if no database is specified, the database named `default' is assumed. This option overrides the database specified in the `GNATSDB' environment variable. `--host HOST, -H HOST' Specifies the hostname of the gnatsd server to communicate with. This overrides the value in the `GNATSDB' environment variable. `--port PORT' Specifies the port number of the gnatsd server to communicate with. This overrides the value in the `GNATSDB' environment variable. `--user USER, -v USER' Specifies the username to login with when connecting to the gnatsd server. This overrides the value in the `GNATSDB' environment variable. `--passwd PASSWD, -w PASSWD' Specifies the password to login with when connecting to the gnatsd server. This overrides the value in the `GNATSDB' environment variable. `edit-pr' calls the editor specified in your environment variable `EDITOR' on a temporary copy of that PR. (If you don't have the variable `EDITOR' defined in your environment, the default editor `vi' is used.) Edit the PR, changing any relevant fields or adding to existing information. When you exit the editor, `edit-pr' prompts you on standard input for a reason if you have changed a field that requires specifying a reason for the change.  File: gnats.info, Node: follow-up via email, Prev: edit-pr from the shell, Up: edit-pr 2.3.2 Following up via direct email ----------------------------------- If you have some additional information for a PR and for some reason do not want to (or cannot) edit the PR directly, you may append the information to the Audit-Trail field by mailing it to the PR submission address. In order for GNATS to be able to recognize the mail as pertaining to an existing PR (as opposed to a new PR, see *Note Submitting via e-mail::), the Subject mail header field must contain a reference to the PR. GNATS matches the Subject header against the regular expression \<(PR[ \t#/]?|[-[:alnum:]+.]+/)[0-9]+ to determine whether such a reference is present. Any text may precede or follow the reference in the Subject header. If more than one reference is present, the first is used and the rest ignored. A PR reference matching the regular expression above has two parts. The second is the PR number (one or more digits). The first is either the capital letters 'PR' optionally followed by a separator character (blank, tab, hash mark or forward slash) or the category name followed by a forward slash. Following are some examples which match the regular expression: PR 123 PR4567 PR#890 gnats/4711 The PR number and the category (if present) are checked for existence, and if the outcome is positive, the mail is appended to the Audit-Trail field of the PR. Note that the PR need not belong to the category because PRs may move between categories. Outgoing emails sent by GNATS itself may be configured to have a Subject header field that refers to the PR in question: Subject: Re: PR CATEGORY/GNATS-ID: ORIGINAL MESSAGE SUBJECT This makes it extremely easy to follow up on a PR by replying to such an email, see *Note The `dbconfig' file: dbconfig file. and the sample, default `dbconfig' file installed by `mkdb'.  File: gnats.info, Node: query-pr, Next: Emacs, Prev: edit-pr, Up: GNATS user tools 2.4 Querying the database ========================= Obtain information from the database by using the program `query-pr'. `query-pr' uses search parameters you provide to find matching Problem Reports in the database. You can invoke `query-pr' from the shell or from within Emacs. `query-pr' uses the same arguments whether it is invoked from the shell or from Emacs. PRs may be selected via the use of the `--expr' option, directly by number, or by the use of the (now deprecated) field-specific query operators. By default, query options are connected with a logical AND. For example, query-pr --category=foo --responsible=bar only prints PRs which have a Category field of `foo' and a Responsible field of `bar'. The `--or' option may be used to connect query options with a logical OR. For example, query-pr --category=baz --or --responsible=blee prints PRs which have either a Category field of `baz' or a Responsible field of `blee'. It should be emphasized, however, that the use of these field-specific options is strongly discouraged, since they exist only for compatibility with older versions of GNATS and are likely to be deleted in the next release. The expressions specified by the `--expr' option are much more flexible (see below). * Menu: * Invoking query-pr:: * Formatting query-pr output:: * Query expressions:: * Example queries::  File: gnats.info, Node: Invoking query-pr, Next: Formatting query-pr output, Up: query-pr 2.4.1 Invoking `query-pr' ------------------------- From the shell, simply type `query-pr', followed by any search parameters you wish to exercise. From Emacs, type `M-x query-pr'. `query-pr' prompts you for search parameters in the minibuffer. `query-pr' can also be accessed by electronic mail, if your version of GNATS is configured for this. To use this feature, simply send mail to the address `query-pr@YOUR-SITE' with command line arguments or options in the `Subject' line of the mail header. GNATS replies to your mail with the results of your query. The default settings for the `query-pr' mail server are --restricted --state="open|analyzed|feedback|suspended" To override the `--state' parameter, specify `--state=STATE' in the `Subject' line of the mail header. You can not query on confidential Problem Reports by mail. The usage for `query-pr' is: query-pr [--debug | -D] [--help | -h] [--version | -V] [--output FILE | -o FILE] [--list-databases] [--list-fields] [--list-input-fields] [--responsible-address NAME] [--field-type FIELD] [--field-description FIELD] [--field-flags FIELD] [--adm-field FIELD] [--adm-subfield SUBFIELD] [--adm-key KEY] [--valid-values FIELD] [--format FORMAT | -f FORMAT] [--full | -F] [--summary | -q] [--database DATABASE | -d DATABASE] [--and | -&] [--or | -|] [--expr EXPR] [PR Number] Non-network-mode options: [--print-sh-vars] [--print-directory-for-database] Network-mode-only options: [--host HOST | -H HOST] [--port PORT] [--user USER | -v USER] [--passwd PASSWD | -w PASSWD] [--print-server-addr] Deprecated Options: [--list-categories | -j] [--list-states | -T] [--list-responsible | -k] [--list-submitters | -l] [--category CATEGORY | -c CATEGORY] [--synopsis SYNOPSIS | -y SYNOPSIS] [--confidential CONFIDENTIAL | -C CONFIDENTIAL] [--multitext MULTITEXT | -m MULTITEXT] [--originator ORIGINATOR | -O ORIGINATOR] [--release RELEASE | -A RELEASE] [--class CLASS | -L CLASS] [--cases CASES | -E CASES] [--quarter QUARTER | -Q QUARTER] [--keywords KEYWORDS | -K KEYWORDS] [--priority PRIORITY | -p PRIORITY] [--responsible RESPONSIBLE | -r RESPONSIBLE] [--restricted | -R] [--severity SEVERITY | -e SEVERITY] [--skip-closed | -x] [--sql | -i] [--sql2 | -I] [--state STATE | -s STATE] [--submitter SUBMITTER | -S SUBMITTER] [--text TEXT | -t TEXT] [--required-before DATE | -u DATE] [--required-after DATE | -U DATE] [--arrived-before DATE | -b DATE] [--arrived-after DATE | -a DATE] [--modified-before DATE | -B DATE] [--modified-after DATE | -M DATE] [--closed-before DATE | -z DATE] [--closed-after DATE | -Z DATE] The options have the following meaning: `--help, -h' Prints a help message. `--version, -V' Displays the program version to stdout. `--output FILE, -o FILE' The results of the query will be placed in this file. `--database DATABASE, -d DATABASE' Specifies the database to be used for the query. If no database is specified, the database named default is assumed. (This option overrides the database specified in the `GNATSDB' environment variable; see *Note Environment:: for more information.) `--list-categories, -j' Lists the available PR categories for the selected database. `--list-states, -T' Lists the valid PR states for PRs in this database. `--list-responsible, -k' Lists the users that appear in the database's responsible list. `--list-submitters, -l' Lists the valid submitters for this database. The previous -list-* options are deprecated and may be removed in future releases of GNATS; their functionality can be replaced with query-pr --valid-values FIELD where FIELD is one of `Category', `Class', `Responsible', `Submitter-Id', or `State'. `--list-databases' Lists the known databases. `--list-fields' Lists the entire set of field names for PRs in the selected database. `--list-input-fields' Lists the fields that should be provided when creating a new PR for the currently-specified database. The fields are listed in an order that would make sense when used in a template or form. `--field-type FIELD' Returns the data type contained in PR field FIELD. The current set of data types includes `text', `multitext', `enum', `multienum', `enumerated-in-file', `multi-enumerated-in-file', `date' and `integer'. `--field-description FIELD' Returns a human-readable description of the intended purpose of FIELD. `--field-flags FIELD' Returns the flags set for the field in the `dbconfig' file associated with the database, such as `textsearch' and `readonly'. *Note Individual field configuration::. `--adm-field FIELD' Used together with the `--adm-key' option, this returns a record from the administrative file (if any) associated with the field. For more material on administrative files, see *Note Enumerated field administrative files: administrative files. `--adm-subfield SUBFIELD' Used together with the `--adm-field' and `--adm-key' options, this returns the contents of a particular subfield from the record specified by `--adm-field' and `--adm-key'. Subfields are treated in *Note Enumerated field administrative files: administrative files. `--adm-key KEY' Used together with `--adm-field' to select a record from the administrative file associated with the field specified by `--adm-field'. *Note Enumerated field administrative files: administrative files. `--valid-values FIELD' For fields of type `enum', a list of valid values (one per line) is returned. Otherwise, a regular expression is returned that describes the legal values in FIELD. `--responsible-address NAME' The mail address of NAME is returned; NAME is assumed to be a name either appearing in the database's responsible list, or is otherwise a user on the system. `--print-sh-vars' A set of `/bin/sh' variables is returned that describe the selected database. They include: `GNATSDB' The name of the currently-selected database. `GNATSDB_VALID' Set to 1 if the selected database is valid. `GNATSDBDIR' The directory where the database contents are stored. `DEBUG_MODE' Set to 1 if debug mode has been enabled for the database. `DEFAULTCATEGORY' The default category for PRs in the database. `DEFAULTSTATE' The default state for PRs in the database. `--print-server-addr' Prints the information about a remote server database in the format suitable for the `GNATSDB' environment variable. This option works only in the network mode. `--print-directory-for-database' Returns the directory where the selected database is located. `--format FORMAT, -f FORMAT' Used to specify the format of the output PRs, See *Note Formatting query-pr output:: for a complete description. `--full, -F' When printing PRs, the entre PR is displayed. This is exactly equivalent to query-pr --format full `--summary, -q' When printing PRs, a summary format is used. This is exactly equivalent to query-pr --format SUMMARY `--debug, -D' Enables debugging output for network queries. `--host HOST, -H HOST' Specifies the hostname of the gnatsd server to communicate with. This overrides the value in the `GNATSDB' environment variable. `--port PORT' Specifies the port number of the gnatsd server to communicate with. This overrides the value in the `GNATSDB' environment variable. `--user USER, -v USER' Specifies the username to login with when connecting to the gnatsd server. This overrides the value in the `GNATSDB' environment variable. `--passwd PASSWD, -w PASSWD' Specifies the password to login with when connecting to the gnatsd server. This overrides the value in the `GNATSDB' environment variable. `--and, -&, --or, -|' These options are used when connecting multiple query operators together. They specify whether the previous and subsequent options are to be logically ANDed or logically ORed. `--expr EXPR' Specifies a query expression to use when searching for PRs. *Note Query expressions::. The remaining deprecated options are not described here, since their use is fairly obvious and their functionality is completely replaced by the use of the `--expr' option.  File: gnats.info, Node: Formatting query-pr output, Next: Query expressions, Prev: Invoking query-pr, Up: query-pr 2.4.2 Formatting `query-pr' output ---------------------------------- Printing formats for PRs are in one of three forms: FORMATNAME This is a named format which is described by the database (specifically, these formats are described in the `dbconfig' file associated with the database). The default configuration contains five such formats: `standard', `full', `summary', `sql', and `sql2'. The first three are the ones most commonly used when performing queries. standard is the format used by default if no other format is specified. Use of the latter two are discouraged; they are merely kept for historical purposes. Other named formats may have been added by the database administrator. FIELDNAME A single field name may appear here. Only the contents of this field will be displayed. '"PRINTF STRING" FIELDNAME FIELDNAME ...' This provides a very flexible mechanism for formatting PR output. (The formatting is identical to that provided by the named formats described by the database configuration, *Note Named query definitions::. The PRINTF STRING can contain the following % sequences: `%[positionalspecifiers]s': Prints the field as a string. The positional specifiers are similar to those of printf, as +, - and digit qualifiers can be used to force a particular alignment of the field contents. `%[positionalspecifiers]S': Similar to `%s', except that the field contents are terminated at the first space character. `%[positionalspecifiers]d': Similar to `%s', except that the field contents are written as a numeric value. For integer fields, the value is written as a number. For enumerated fields, the field is converted into a numeric equivalent (i.e. if the field can have two possible values, the result will be either 1 or 2). For date fields, the value is written as seconds since Jan 1, 1970. `%F': The field is written as it would appear within a PR, complete with field header. `%D': For date fields, the date is written in a standard GNATS format. `%Q': For date fields, the date is written in an arbitrary "SQL" format. An example formatted query looks as follows (note that the whole format specification should be quoted): query-pr --format '"%s, %s" Synopsis State'  File: gnats.info, Node: Query expressions, Next: Example queries, Prev: Formatting query-pr output, Up: query-pr 2.4.3 Query expressions ----------------------- Query expressions are used to select specific PRs based on their field contents. The general form is fieldname|"value" operator fieldname|"value" [booleanop ...] VALUE is a literal string or regular expression; it must be surrounded by double quotes, otherwise it is interpreted as a fieldname. FIELDNAME is the name of a field in the PR. OPERATOR is one of: `=' The value of the left-hand side of the expression must exactly match the regular expression on the right-hand side of the expression. *Note Querying using regular expressions: Regexps. `~' Some portion of the left-hand side of the expression must match the regular expression on the right-hand side. `==' The value of the left-hand side must be equal to the value on the right-hand side of the expression. The equality of two values depends on what type of data is stored in the field(s) being queried. For example, when querying a field containing integer values, literal strings are interpreted as integers. The query expression Number == "0123" is identical to Number == "123" as the leading zero is ignored. If the values were treated as strings instead of integers, then the two comparisons would return different results. `!=' The not-equal operator. Produces the opposite result of the == operator. `<,>' The left-hand side must have a value less than or greater than the right-hand side. Comparisons are done depending on the type of data being queried; in particular, integer fields and dates use a numeric comparison, and enumerated fields are ordered depending on the numeric equivalent of their enumerated values. BOOLEANOP is either `|' (logical or), or `&' (logical and). The query expression Category="baz" | Responsible="blee" selects all PRs with a Category field of `baz' or a Responsible field of `blee'. The not operator `!' may be used to negate a test: ! Category="foo" searches for PRs where the category is not equal to the regular expression foo. Parentheses may be used to force a particular interpretation of the expression: !(Category="foo" & Submitter-Id="blaz") skips PRs where the Category field is equal to `foo' and the Submitter-Id field is equal to `blaz'. Parentheses may be nested to any arbitrary depth. Fieldnames can be specified in several ways. The simplest and most obvious is just a name: Category="foo" which checks the value of the category field for the value FOO. A fieldname qualifier may be prepended to the name of the field; a colon is used to separate the qualifier from the name. To refer directly to a builtin field name: builtin:Number="123" In this case, `Number' is interpreted as the builtin name of the field to check. (This is useful if the fields have been renamed. For further discussion of builtin field names, see *Note The `dbconfig' file: dbconfig file. To scan all fields of a particular type, the FIELDTYPE qualifier may be used: fieldtype:Text="bar" This searches all text fields for the regular expression `bar'. Note that it is not required that the right-hand side of the expression be a literal string. To query all PRs where the PR has been modified since it was closed, the expression Last-Modified != Closed-Date will work; for each PR, it compares the value of its Last-Modified field against its Closed-Date field, and returns those PRs where the values differ. However, this query will also return all PRs with empty Last-Modified or Closed-Date fields. To further narrow the search: Last-Modified != Closed-Date & Last-Modified != "" & Closed-Date != "" In general, comparing fields of two different types (an integer field against a date field, for example) will probably not do what you want. Also, a field specifier may be followed by the name of a subfield in braces: State[type] != "closed" or even builtin:State[type] != "closed" Subfields are further discussed in *Note The `dbconfig' file: dbconfig file.  File: gnats.info, Node: Example queries, Prev: Query expressions, Up: query-pr 2.4.4 Example queries --------------------- The following simple query: query-pr --expr 'Category~"rats" & State~"analyzed" & Responsible~"fred"' yields all PRs in the database which contain the field values: >Category: rats _and_ >Responsible: fred _and_ >State: analyzed The following query: query-pr --expr 'State~"open|analyzed"' yields all PRs in the database whose `State' values match either `open' or `analyzed' (*note Querying using regular expressions: Regexps. This search is useful as a daily report that lists all Problem Reports which require attention. The following query: query-pr --expr 'fieldtype:Text="The quick.*brown fox"' yields all PRs whose TEXT fields contain the text `The quick' followed by `brown fox' within the same field. *Note Querying using regular expressions: Regexps, which also contains further useful examples of query expressions.  File: gnats.info, Node: Emacs, Prev: query-pr, Up: GNATS user tools 2.5 The Emacs interface to GNATS ================================ Emacs interface to GNATS provides basic access to GNATS databases, i.e. sending, editing, and querying Problem Reports. It also defines a simple major mode for editing `dbconfig' files. This section provides an overview of using GNATS with Emacs. It does not describe the use of Emacs itself, for detailed instructions on using Emacs, see *Note Top: (emacs)Top. For installation instructions of the GNATS Emacs mode, see *Note Installing utils::. Please note the Emacs interface was completely rewritten between GNATS 3 and GNATS 4. It now uses `gnatsd', *Note gnatsd::, exclusively for its operations and uses modern Emacs features like faces. Its features are not complete though, you can send your suggestions and patches to the appropriate GNATS mailing list, *Note Support::. * Menu: * Emacs viewing:: Viewing PRs by their number. * Emacs querying:: Querying the database. * Emacs submitting:: Submitting new PRs. * Emacs editing:: Editing PRs. * Emacs editing buffer:: The editing buffer. * Emacs and databases:: Changing the working database. * dbconfig mode:: Major mode for dbconfig files. * Other Emacs commands:: Miscellaneous commands. * Emacs customization:: Customizing the Emacs interface.  File: gnats.info, Node: Emacs viewing, Next: Emacs querying, Up: Emacs 2.5.1 Viewing Problem Reports ----------------------------- To view a particular Problem Report, use the command `M-x view-pr'. It asks for a Problem Report number and displays that Problem Report. The displayed buffer is put in the view mode, *Note Misc File Ops: (emacs)Misc File Ops. If you decide to edit the displayed Problem Report, use the command `e' (`gnats-view-edit-pr'). `gnats-view-mode-hook' Hook run when `gnats-view-mode' is entered.  File: gnats.info, Node: Emacs querying, Next: Emacs submitting, Prev: Emacs viewing, Up: Emacs 2.5.2 Querying Problem Reports ------------------------------ Querying the database is performed by the `M-x query-pr' command. The command prompts for the query expression, *Note Query expressions::, and displays a buffer with the list of the matching Problem Reports. The list of the Problem Reports is displayed in the `summary' query format, *Note Formatting query-pr output::. Currently, the display format cannot be changed and it must output each Problem Report's number in the first column. The Problem Report list buffer is put in the view mode, *Note Misc File Ops: (emacs)Misc File Ops. You can use most of the standard view mode commands in it. Additionally, the following special commands are available: `v' `RET' `mouse-2' View the current Problem Report (`gnats-query-view-pr'), *Note Emacs viewing::. `e' Edit the current Problem Report (`gnats-query-edit-pr'), *Note Emacs editing::. `g' Update the Problem Report list (`gnats-query-reread'). The last performed query is executed again and the buffer is filled with the new results. `G' Perform new query (`query-pr'). `s' Send new Problem Report (`send-pr'), *Note Emacs submitting::. `D' Change the current database (`gnats-change-database'), *Note Emacs and databases::. `q' Bury buffer, the buffer is put at the end of the list of all buffers. This is useful for quick escape of the buffer, without killing it. If the value of the variable GNATS-QUERY-REVERSE-LISTING is non-`nil', the listing appears in the reversed order, i.e. with the Problem Reports of the highest number first, in the buffer. Similarly to other GNATS Emacs modes, there is a hook available for the Problem Report list. `gnats-query-mode-hook' Hook run when `gnats-query-mode' is entered.  File: gnats.info, Node: Emacs submitting, Next: Emacs editing, Prev: Emacs querying, Up: Emacs 2.5.3 Submitting new Problem Reports ------------------------------------ You can submit new Problem Reports with the command `M-x send-pr'. The command puts you to the problem editing buffer, *Note Emacs editing::. The buffer is prefilled with the initial report fields and their default values, if defined. You can use the usual Problem Report editing commands, *Note Emacs editing::. When you have filled in all the fields, you can send the Problem Report by presing `C-c C-c'. If you run `M-x send-pr' with a prefix argument, it runs the `gnats-change-database' command before putting you to the editing buffer, *Note Emacs and databases::. You can set the following variables to get some fields pre-filled: GNATS-DEFAULT-ORGANIZATION Default value of the `Organization' field used in new Problem Reports. GNATS-DEFAULT-SUBMITTER Default value of the `Submitter-Id' field used in new Problem Reports.  File: gnats.info, Node: Emacs editing, Next: Emacs editing buffer, Prev: Emacs submitting, Up: Emacs 2.5.4 Editing Problem Reports ----------------------------- To edit a particular Problem Report, use the command `M-x edit-pr'. It asks for a Problem Report number and puts the given Problem Report in the editing buffer. *Note Emacs editing buffer::, for information how to edit the Problem Report in the buffer and how to submit your changes. Note you can also start editing of a selected Problem Report directly from within the viewing buffer, *Note Emacs viewing::, or the query result buffer, *Note Emacs querying::.  File: gnats.info, Node: Emacs editing buffer, Next: Emacs and databases, Prev: Emacs editing, Up: Emacs 2.5.5 The Problem Report editing buffer --------------------------------------- When you invoke a Problem Report editing command, the Problem Report is put into a special editing buffer. The Problem Report is formatted similarly to the `query-pr -F' output, *Note Formatting query-pr output::. Field identifiers are formatted as >Field: with the text of the field following the identifier on the same line for single-line fields or starting on the next line for multi-line fields. The Problem Report editing mode tries to prevent you from violating the Problem Report format and the constraints put on the possible field values. Generally, you can use usual editing commands, some of them have a slightly modified behavior though. (If you encounter a very strange behavior somewhere, please report it as a bug, *Note Support::.) You can move between fields easily by pressing the `TAB' (`gnats-next-field') or `M-TAB' (`gnats-previous-field') keys. The field tags are read-only and you cannot edit them nor delete them. If you want to "remove" a field, just make its value empty. Editing a field value depends on the type of the edited field, *Note Field datatypes::. For text fields, you can edit the value directly, assuming you preserve the rule about single-line and multi-line values mentioned above. For enumerated fields, you cannot edit the value directly. You can choose it from the list of the allowed values, either from the menu popped up by pressing the middle mouse button or from within minibuffer by pressing any key on the field's value. If the pressed key matches any of the allowed field values, that value is put as the default value after the minibuffer prompt. You can also cycle through the allowed field values directly in the editing buffer using the `SPACE' key. Enumerated field values are marked by a special face to not confuse you; you must have enabled font lock mode to benefit from this feature, *Note Font Lock: (emacs)Font Lock. Some field values can be read-only, you cannot edit them at all. Once you have edited the Problem Report as needed, you can send it to the server with the `C-c C-c' command (`gnats-apply-or-submit'). Successful submission is reported by a message and the buffer modification flag in mode line is cleared. Then you can either kill the buffer or continue with further modifications. `gnats-edit-mode-hook' Hook run when `gnats-edit-mode' is entered.  File: gnats.info, Node: Emacs and databases, Next: dbconfig mode, Prev: Emacs editing buffer, Up: Emacs 2.5.6 Changing the database --------------------------- By default, the Emacs interface connects to the default database, *Note databases file::. If you want to connect to another database, use the command `M-x gnats-change-database'. It will ask you for the database name to use, server and port it can be accessed on, and your login name. If you want to use the `gnatsd' command, *Note gnatsd::, directly, without connecting to a remote server or the localhost connection port, provide your local file system full path to `gnatsd' as the server name. Port number does not matter in this case. If the database requires a password to allow you the access to it, you are prompted for the password the first time you connect to the database. If you provide an invalid password, you cannot connect to the database anymore and you have to run the `M-x gnats-change-database' command again.  File: gnats.info, Node: dbconfig mode, Next: Other Emacs commands, Prev: Emacs and databases, Up: Emacs 2.5.7 dbconfig mode ------------------- The Emacs interface defines a simple major mode `gnats-dbconfig-mode' for editing `dbconfig' files, *Note dbconfig file::. It defines basic mode attributes like character syntax and font lock keywords, it does not define any special commands now. `gnats-dbconfig-mode-hook' Hook run when `gnats-dbconfig-mode' is entered.  File: gnats.info, Node: Other Emacs commands, Next: Emacs customization, Prev: dbconfig mode, Up: Emacs 2.5.8 Other commands -------------------- `M-x unlock-pr' Ask for a Problem Report number and unlock that Problem Report. This function is useful if connection to a GNATS server was interrupted during an editing operation and further modifications of the Problem Report are blocked by a stealth lock. `M-x unlock-database' Unlock the whole GNATS database. This function is useful in situations similar to when `unlock-pr' is used. `M-x gnats-show-connection' Show the connection buffer associated with the current buffer. You can view the Emacs communication with GNATSD in it. This is useful when something strange happens during the communication with the server, e.g. when sending a Problem Report with `C-c C-c' from a Problem Report editing buffer.  File: gnats.info, Node: Emacs customization, Prev: Other Emacs commands, Up: Emacs 2.5.9 Customization ------------------- All the user variables can be customized in the customization group `gnats', *Note Easy customization: (emacs)Easy customization.  File: gnats.info, Node: Installation, Next: Management, Prev: GNATS user tools, Up: Top 3 Installing GNATS ****************** See also *Note Where the tools and utilities reside: Locations. There are several steps you need to follow to fully configure and install GNATS on your system. You need `root' access in order to create a new account for `gnats' and to install the GNATS utilities. You may need `root' access on some systems in order to set up mail aliases and to allow this new account access to `cron' and `at'. If you are updating an older version of GNATS rather than installing from scratch, see *Note Upgrading from older versions: Upgrading. GNATS installation relies on two other freely available software packages, which should be installed before you go on to configure and build GNATS. These are GNU `make' and `Texinfo' (version 4.2 or higher). Both are available from the GNU FTP site at `ftp://ftp.gnu.org'. To build and install GNATS, you must: * Run `configure', with correct options if the defaults are unsuitable for your site. *Note Configuring and compiling the software: Configure and make. Default installation locations are in *Note Where GNATS lives: Locations. * Compile the GNATS programs on your system. *Note Configuring and compiling the software: Configure and make. * Create an initial database by using the `mkdb' command. *Note Setting up the default database::. * Set up periodic jobs, using cron, to handle Problem Reports arriving by mail. *Note Setting up periodic jobs::. * Set up mail aliases for GNATS. *Note Setting up mail aliases: Aliases. * Install the GNATS tools and utilities locally, and install the user tools (`query-pr', `edit-pr', `send-pr') on every machine in your local network. *Note Installing the user tools: Installing tools. * Install the GNATS daemon `gnatsd'. *Note Installing the daemon::. * If there are people outside your organization who will be submitting PRs or who are supposed to be able to query and/or edit PRs, you may need to instruct them to obtain and build the GNATS tools `query-pr', `edit-pr' and `send-pr' for their systems. However, for many sites, setting up a remote access interface to GNATS, such as Gnatsweb is a better solution since this requires no configuration on the remote side. * Menu: * Configure and make:: Configuring and compiling the software * Installing utils:: Installing the utilities * Setting up the default database:: Setting up the default database * Setting up periodic jobs:: Setting up periodic jobs * Aliases:: Setting up mail aliases * Installing the daemon:: Installing the daemon * Installing tools:: Installing the user tools * Upgrading:: Upgrading from older versions  File: gnats.info, Node: Configure and make, Next: Installing utils, Up: Installation 3.1 Configuring and compiling the software ========================================== 1. First, unpack your distribution. We provide source code in a `tar' file which was compressed using `gzip'. The code can be extracted into a directory UNPACKDIR using cd UNPACKDIR gunzip gnats-4.1.0.tar.gz tar xvf gnats-4.1.0.tar The sources reside in a directory called `gnats-4.1.0' when unpacked. We call this the "top level" of the source directory, or "srcdir". The sources for the GNATS tools are in the subdirectory `gnats-4.1.0/gnats/*'. Lists of files included in the distribution are in each directory in the file `MANIFEST'. 2. As of GNATS version 4, having Emacs installed on the GNATS server is no longer a requirement. If you do not have Emacs installed, disregard this step altogether. You may wish to alter the installation directory for the Emacs lisp files. If your Emacs lisp library is not in `PREFIX/share/emacs/site-lisp', edit the file `SRCDIR/gnats/Makefile.in'. Change the variable `lispdir' from `PREFIX/emacs/site-lisp' to the directory containing your Emacs lisp library. For information on PREFIX, see *Note PREFIX: prefix. 3. Create an account for the `gnats' user. You can actually name this user whatever you want to, as long as it is a valid username on your system, but we strongly recommend that you call the user `gnats'. If you do decide to give it some other name, remember to use the option `--with-gnats-user' when running `configure' below. Below, we will anyway refer to this user by the name `gnats'. This user must have an entry in the file `/etc/passwd'. As for ordinary users, create a standard home directory for the `gnats' user. The default `PATH' for this user should contain `EXEC-PREFIX/bin' and `EXEC-PREFIX/libexec/gnats'. The EXEC-PREFIX value is configurable with the `--exec-prefix' configure option described below, but for standard installations, these two directories correspond to `/usr/local/bin' and `/usr/local/libexec/gnats'. 4. Run `configure'. You can nearly always run `configure' with the simple command ./configure and the "Right Thing" happens: * GNATS is configured in the same directory you unpacked it in; * when built, GNATS runs on the machine you're building it on; * when installed, files are installed under `/usr/local' (*note Where GNATS lives: Locations.). * all GNATS utilities operate on the "default database", assumed to be named _default_ and to be located in `/usr/local/com/default', unless you invoke the utilities with `-d' DATABASENAME or `--directory='DATABASENAME, or set the GNATSDB environment variable to point to some other database. The most common options to `configure' are listed below: configure [ --prefix=PREFIX ] [ --exec-prefix=EXEC-PREFIX ] [ --with-gnats-service=SERVICE-NAME ] [ --with-gnats-user=USERNAME ] [ --with-gnatsd-user-access-file=PATH ] [ --with-gnatsd-host-access-file=PATH ] [ --with-gnats-dblist-file=PATH ] [ --with-gnats-default-db=PATH ] [ --with-kerberos ] [ --with-krb4 ] [ --verbose ] `--prefix=PREFIX' All host-independent programs and files are to be installed under PREFIX. (Host-dependent programs and files are also installed in PREFIX by default.) The default for PREFIX is `/usr/local'. *Note Where GNATS lives: Locations. `--exec-prefix=EXEC-PREFIX' All host-dependent programs and files are to be installed under EXEC-PREFIX. The default for EXEC-PREFIX is PREFIX. *Note Where GNATS lives: Locations. `--with-gnats-service=SERVICE-NAME' Set SERVICE-NAME to be the GNATS network service. Default name is SUPPORT. `--with-gnats-user=USERNAME' Set USERNAME to be the user name for GNATS. Default username is GNATS. `--with-gnatsd-user-access-file=PATH' Set global (across all databases) gnatsd user access file to PATH. Default is `/USR/LOCAL/ETC/GNATS/GNATSD.USER_ACCESS'. Per-database user access permissions are set in a `gnatsd.user_access' file in the `gnats-adm' subdirectory of each database. `--with-gnatsd-host-access-file=PATH' Set global (across all databases) gnatsd host access file to PATH. Default is `/usr/local/etc/gnats/gnatsd_host.access'. There is currently no way to specify host access permissions on a per-database basis. `--with-gnats-dblist-file=PATH' Specify the file containing the list of databases. Default is `PREFIX/etc/gnats/databases'. `--with-gnats-default-db=PATH' Specify the default database to use when GNATS tools are invoked without the `-d' or `--databasename' option, and when the GNATSDB envrionment variable hasn't been set. Default is `/PREFIX/com/gnatsdb'. `--with-kerberos' Include code for Kerberos authentication. `--with-krb4' Support Kerberos 4. `--verbose' Give verbose output while `configure' runs. `configure' supports several more options which allow you to specify in great detail where files are installed. For a complete list of options, run `./configure --help' in the source directory. You can build GNATS in a different directory (OBJDIR) from the source code by calling the `configure' program from the new directory, as in mkdir OBJDIR cd OBJDIR SRCDIR/configure ... By default, `make' compiles the programs in the same directory as the sources (SRCDIR). 5. Make sure you have GNU `make', then run make all info from the directory where `configure' created a `Makefile' (this is OBJDIR if you used it, otherwise SRCDIR.) These targets indicate: `all' Compile all programs `info' Create `info' files using `makeinfo'.  File: gnats.info, Node: Installing utils, Next: Setting up the default database, Prev: Configure and make, Up: Installation 3.2 Installing the utilities ============================ The following steps are necessary for a complete installation. You may need `root' access for these. 1. Install the utilities by invoking make install install-info These targets indicate: `install' Installs all programs into their configured locations (*note Where GNATS lives: Locations.). `install-info' Installs `info' files into their configured locations (*note Where GNATS lives: Locations.). After you have installed GNATS, you can remove the object files with make clean 2. If you do not have Emacs installed on your GNATS server, this step should be skipped. Place the following lines in the file `default.el' in your Emacs lisp library, or instruct your local responsible parties to place the lines in their `.emacs': (autoload 'send-pr "gnats" "Command to create and send a problem report." t) (autoload 'edit-pr "gnats" "Command to edit a problem report." t) (autoload 'view-pr "gnats" "Command to view a problem report." t) (autoload 'query-pr "gnats" "Command to query information about problem reports." t) (autoload 'unlock-pr "gnats" "Unlock a problem report." t) (autoload 'gnats-dbconfig-mode "gnats" "Major mode for editing the `dbconfig' GNATS configuration file." t) (add-to-list 'auto-mode-alist '("\\ `filename' The file `filename' now contains a PR template for your database. Copy this file to the client. Then edit the `send-pr.conf' file that you created on the client, set the `TEMPLATE' variable to point to the template file (*note The send-pr.conf configuration file: send-pr.conf file.) and make sure that the `MAILPROG' and `MAILADDR' varables in `send-pr.conf' are correctly set. You should now have a working remote tool installation. For clients that have no direct network access to your GNATS server, such as those that are located behind strict firewalls, you either need to set up a web interface such as Gnatsweb (provided that the firewall lets web traffic through) or use the procedure above which sets up `send-pr' to submit Problem Reports by e-mail. In order to query PRs, users on the remote machines will then have to use the the e-mail functionality of `query-pr' (*note Invoking query-pr::. Editing PRs by e-mail is not possible, so clients in this group who need edit access have to get access through a web interface if possible. Note that when `send-pr' is set up to work over e-mail, the `GNATSDB' environment variable and the `-d' command line option have no effect since `send-pr' is tied to a specific database by way of the value of `MAILADDR' in the `send-pr.conf' file.  File: gnats.info, Node: Upgrading, Prev: Installing tools, Up: Installation 3.8 Upgrading from older versions ================================= The following procedure covers an upgrade from all GNATS 3 versions newer than 3.108. If your installation is an older 3.10x version, or even the ancient 3.2 version, you need to review the `UPGRADING.old' file in the GNATS distribution before carrying out the steps detailed here. 3.8.1 Overview -------------- Although almost all of the GNATS internals have been redesigned and rewritten for GNATS 4, little has changed in the format and structure of the database data. The only change that needs to be taken into account when upgrading is the fact that the database index format is binary in a default installation of GNATS 4. Thus, you will need to regenerate your database index by using the `gen-index' tool. In addition, if your old GNATS installation was so-called "release-based", you need to make some simple modifications to the database setup file `dbconfig'. See below for details. Apart from building and installing new binaries, the major changes which impinge on the upgrade procedure are all on the configuration side. The main database configuration file, `dbconfig', is far more complex and powerful than the old `config' file, and while the installation process creates a sensible set of default values which are similar to GNATS 3.11x's defaults, you still need to migrate any changes you may have made to your own local configuration. Another aspect which needs consideration are remote submitter sites. Such sites either need to be instructed to upgrade their locally installed copies of the GNATS user tools (`send-pr', `edit-pr' and `query-pr'), or they should be given access through interfaces such as Gnatsweb. Since the GNATS network daemon has been completely reworked, with an entirely new command set, all network-based interfaces, such as Gnatsweb and TkGnats need to be upgraded to versions that support GNATS 4. The `contrib' directory of this distribution contains some third-party interfaces, and the `README' file contains pointers to where you can obtain the newest versions of these tools. This document only deals with upgrading GNATS itself. Third-party tools should have separate upgrading instructions in their distributions. 3.8.2 Upgrading --------------- 1. Before you begin, make a backup of your entire GNATS database directory hierarchy, the GNATS executables directory and the GNATS user tools (`send-pr', `query-pr' etc.) The locations of these may vary, but in a default GNATS 3 installation, the database(s) reside under `/usr/local/share/gnats', the executables are located in `/usr/local/libexec/gnats' and the user tools reside in `/usr/local/bin'. 2. (optional) In order to avoid confusing your users, you may want to remove the old GNATS 3 executables and tools, escpecially if you plan to install GNATS 4 in a different location than version 3. 3. Build and install GNATS 4. *Note Installing GNATS: Installation. It is recommended that you use the `--with-gnats-default-db' option when running `configure', in order to set the default database to be one of your already existing GNATS 3 databases. 4. Edit the GNATS `databases' file and add entries for all your old GNATS 3 databases. In a default GNATS 4 installation the file is in `/usr/local/etc/gnats'. *Note The `databases' file: databases file. 5. In GNATS 3, the file `gnatsd.conf' specifies minimum access levels for the different hosts accessing the GNATS daemon, `gnatsd'. There is one `gnatsd.conf' for each database. In GNATS 4, these files have been replaced by a single file named `gnatsd.host_access' which contains settings that apply across all the databases on the server. This file is located in the same directory as the `databases' file. You need to combine the host access settings from all your GNATS 3 databases and add them to the `gnatsd.host_access' file. Note that you are no longer able to control host access on a per-database basis. Optionally, you may delete the old `gnatsd.conf' files. *Note Controlling access to GNATS databases: Access Control. 6. Next, you need to migrate the settings in the old `config' files of your databases to corresponding `dbconfig' files. The database you specified with the `--with-gnats-default-db' configure option got a default `dbconfig' installed. This default file contains field definitions etc. which makes this version of GNATS behave almost exactly like older versions. Copy this default file to the `gnats-adm' directories of any other GNATS databases that you may have on your host before you proceed to migrate your old configuration settings. The following is a list of the configuration directives that may be present in a `config' file and their counterparts (if any) in GNATS 4. GNATS_ADDR This setting has no counterpart in GNATS 4, since GNATS no longer needs to know its own mail address. GNATS_ADMIN This setting is now set in the `responsible' file in the `gnats-adm' directory of your database(s). GNATS_SITE GNATS 4 has no concept of a named `site', so this directive is obsolete. SUBMITTER Obsolete, since it relates to GNATS_SITE. DEFAULT_RELEASE DEFAULT_ORGANIZATION The GNATS 4 `dbconfig' file has separate configuration sections for each defined field. Field defaults are set with the `default' keyword in these sections. *Note The `dbconfig' file: dbconfig file. NOTIFY Controlled by the `notify-about-expired-prs' setting in the `dbconfig' file. ACKNOWLEDGE Controlled by the `send-submitter-ack' setting in the `dbconfig' file. DEFAULT_SUBMITTER The default submitter is now always the first entry in the `submitters' file of your database. KEEP_RECEIVED_HEADERS Controlled by the `keep-all-received-headers' setting in the `dbconfig' file. DEBUG_MODE Controlled by the `debug-mode' setting in the `dbconfig' file. BDAY_START BDAY_END BWEEK_START BWEEK_END Controlled by the settings `business-day-hours' and `business-week-days' in the `dbconfig' file. DEFINE_CATEGORY The default category for PRs that arrive without one is now the first category listed in the `categories' file of your database. After your are done migrating the settings, you may optionally delete the old `config' files. Since there are many more configuration settings available in the GNATS 4 `dbconfig' file, you should take some time to review them all before proceeding. *Note The `dbconfig' file: dbconfig file. If your old GNATS installations was release-based, i.e. it included the fields Quarter, Keywords and Date-Required, you need to define those fields in the `dbconfig' file by following the instructions in *Note Supporting old GNATS "release-based" fields: release-based support. 7. The file `gnatsd.access' has been renamed to `gnatsd.user_access'. Furthermore, GNATS 4 uses a different password format in the `gnatsd.user_access' file than older versions, since it supports `crypt()' and MD5 passwords (*note Controlling access to GNATS databases: Access Control.). You need to translate your old `gnatsd.user_access' files to the new format by using the `gnats-pwconv' tool which was installed in the `EXEC-PREFIX/libexec/gnats' directory, typically `/usr/local/libexec/gnats'. *Note Managing user passwords: gnats-pwconv. 8. The final step involves regenerating the indexes of your databases. For this, log in as the user `gnats'. Then run the `gen-index' command for each of your databases. See *Note Administrative Utilities: Admin utils. for details on how to use `gen-index'. 9. Sit back and enjoy your new GNATS 4 setup...  File: gnats.info, Node: Management, Next: Locations, Prev: Installation, Up: Top 4 GNATS Administration ********************** In daily usage, GNATS is self-maintaining. However, there are various administrative duties which need to be performed periodically. Also, requirements may change with time, so it may be necessary to make changes to the GNATS configuration at some point: _emptying the `pending' directory_ If a Problem Report arrives with a `Category' value that is unrecognized by the `categories' file, or if that field is missing, GNATS places the PR in the `pending' directory (*note Where GNATS lives: Locations.). PRs submitted in free-form by email will always be filed in the `pending' directory. If so configured, GNATS sends a notice to the `gnats-admin' and to the party responsible for that submitter (as listed in the `submitters' file) when this occurs. To have these "categoryless" PRs filed correctly, you can then use a GNATS tool such as `edit-pr' to set the correct category of each PR in the `pending' directory. In order to protect yourself from problems caused by full disks, you should arrange to have all mail that is sent to the GNATS database copied to a log file (*Note Setting up mail aliases: Aliases.). Then, should you run out of disk space, and an empty file ends up in the database's `pending' directory, you need only look in the log file, which should still contain the full message that was submitted. _adding another database_ GNATS supports multiple databases. If you find at some point that you need to add another database to your server, the `mkdb' tool does most of the work for you. *Note Adding another database: mkdb. _adding new categories_ Most installations of GNATS will only require you to add a new line to the `categories' file. The category directory will then be created automatically as needed. However, if automatic directory creation has been switched off in the `dbconfig' file (*note The `dbconfig' file: dbconfig file.), you need to use the `mkcat' program. _removing categories_ To remove a category, you need to make sure the relevant subdirectory is empty (in other words, make sure no PRs exist for the category you wish to remove). You can then remove the category listing from the `categories' file, and invoke rmcat CATEGORY... to remove CATEGORY (any number of categories may be specified on the command line to `rmcat', so long as they abide by the above constraints). _adding and removing maintainers_ Edit the `responsible' file to add a new maintainer or to remove an existing maintainer. *Note The `responsible' file: responsible file. _building a new index_ If your index becomes corrupted, or if you wish to generate a new one for some reason, use the program `gen-index' (*note Regenerating the index: gen-index.). _pruning log files_ Log files often grow to unfathomable proportions. As with gardening, it is best to prune these as they grow, lest they take over your disk and leave you with no room to gather more Problem Reports. If you keep log files, be sure to keep an eye on them. (*Note Setting up mail aliases: Aliases.) _BACKING UP YOUR DATA_ Any database is only useful if its data remains uncorrupted and safe. Performing periodic backups ensures that problems like disk crashes and data corruption are reversible. *Note Where GNATS lives: Locations. * Menu: * GNATS configuration:: Overview of GNATS configuration * databases file:: The databases file * dbconfig file:: The dbconfig file * Other config files:: Configuration files * send-pr.conf file:: The send-pr.conf file * Admin files:: Administrative data files * Admin utils:: Administrative utilities * Internal utils:: Internal utilities  File: gnats.info, Node: GNATS configuration, Next: databases file, Up: Management 4.1 Overview of GNATS configuration =================================== *Note Where GNATS lives: Locations. GNATS has two, well, actually three, different kinds of configuration file. The "site-wide" configuration files determine overall behaviour across all the databases on your machine, while the "database-specific" configuration files determine how GNATS behaves when dealing with a specific database. In addition, there is a single file that needs to be set up for the `send-pr' tool to work properly. These files can be edited at any time -- the next time a GNATS tool is invoked, the new parameters will take effect. These are the site-wide configuration files used by GNATS: `databases' Specifies database names and their associated parameters, such as in which directory they are located. This file is used by the GNATS clients to determine the location of a database referred to by name. *Note The `databases' file: databases file. `defaults' This directory contains the set of default per-database configuration files used when a new database is created with `mkdb'. `gnatsd.host_access' Controls access levels for the different machines that will do lookups in the databases on this machine. *Note GNATS access control: Access Control. `gnatsd.user_access' Controls user access levels for the databases on this server. The settings apply to all databases (there is also a database-specific user access level file). *Note GNATS access control: Access Control. The database-specific configuration is determined by the following files in the `gnats-adm' subdirectory of the database directory. `dbconfig' Controls most aspects of how GNATS behaves when dealing with your database. *Note The `dbconfig' file: dbconfig file. `categories' The list of categories that GNATS accepts as valid for the `Category' field, and the maintainers responsible for each category. Update this file whenever you have a new category, or whenever a category is no longer valid. You must also update this file whenever responsibility for a category changes, or if a maintainer is no longer valid. *Note The `categories' file: categories file. `responsible' An alias list mapping names to their associated mailing addresses. The names in this list can have multiple email addresses associated with them. If a responsible user does not show up in this list, they are assumed to be a user local to the system. This list is not associated with just the responsible user field; all email addresses are mapped through this file whenever mail is sent from GNATS. *Note The `responsible' file: responsible file. `submitters' Lists sites from whom GNATS accepts Problem Reports. The existence of this file is mandatory, although the feature it provides is not; see *Note The `submitters' file: submitters file. `addresses' Mappings between submitter IDs and submitters' e-mail addresses. Use of this file is optional. If you get Problem reports where the `Submitter' field is not filled in, GNATS will use entries in this file to try to derive the submitter ID from the e-mail headers. *Note The `addresses' file: addresses file. `states' Lists the possible states for Problem Reports, typically ranging from "open" to "closed". *Note The `states' file: addresses file. `classes' Lists the possible classes of Problem Report. This provides an easy way to have "subcategories", for example by setting up classes such as `sw-bug', `doc-bug', `change-request' etc. *Note The `classes' file: classes file. `gnatsd.user_access' Specify the access levels for different users to your database. *Note GNATS access control: Access Control. The last file in this menagerie is the `send-pr' configuration file `send-pr.conf'. This file contains some defaults that need to be known in order for `send-pr' to work. The file needs to be present on all hosts where `send-pr' is to be used. *Note the `send-pr.conf' file: send-pr.conf file.  File: gnats.info, Node: databases file, Next: dbconfig file, Prev: GNATS configuration, Up: Management 4.2 The `databases' file ======================== The `databases' configuration file is a site-wide configuration file containing the list of GNATS databases that are available either on the host itself or remotely over the network, together with some parameters associated with each database. The file contains one line for each database. For databases located on the host itself, each line consists of three fields separated by colons: DATABASE NAME:SHORT DESCRIPTION OF DATABASE:PATH/TO/DATABASE The first field is the database name. This is the name used to identify the database when invoking programs such as `query-pr' or `send-pr', either by using the `--database' option of the program or by setting the GNATSDB environment variable to the name of the database. The second field is a short human-readable description of the database contents, and the final field is the directory where the database contents are kept. For a database that is located across a network, but which should be accessible from this host, the entry for the database should look like this: DATABASE NAME:SHORT DESCRIPTION OF DATABASE::HOSTNAME:PORT The first two fields are the same as for local databases, the third field is empty (notice the two adjacent `:' symbols, indicating an empty field), the fourth field is the hostname of the remote GNATS server, and the fifth field is the port number that the remote GNATS is running on. If GNATS was built with default options, the `databases' file will be located in the `/usr/local/etc/gnats' directory. However, if the option `--with-gnats-dblist-file' was used during building of GNATS, the `databases' file has the name and location given to this option. A sample `databases' file is installed together with GNATS. Note that if you add a new local database, you must create its data directory, including appropriate subdirectories and administrative files. This is best done using the `mkdb' tool, *Note mkdb::.  File: gnats.info, Node: dbconfig file, Next: Other config files, Prev: databases file, Up: Management 4.3 The `dbconfig' file ======================= The `dbconfig' configuration file controls the configuration of a GNATS database. Each database has its own individual copy of this file, which is located in the `gnats-adm' subdirectory of the database. The file consists of standard plain text. Whitespace is completely optional and is ignored. Sets of braces `@' are used to delimit the different sections, and all non-keyword values must be surrounded with double quotes. The values in `dbconfig' can be changed at any time; the new values take effect for all subsequent iterations of GNATS tools. The `dbconfig' file contains 6 major sections, which must appear in the following order: * Overall database configuration * Individual field configuration * Named query definitions * Audit-trail and outgoing email formats * Index file description * Initial Problem Report input fields The different sections are described below. While reading the following sections, it will be useful to refer to the sample `dbconfig' file which is installed when a new database is initialized with the `mkdb' tool. In fact, the sample file provides a configuration that should be usable for a great range of sites, since it reproduces the behaviour of the older, less customizable 3.x versions of GNATS. * Menu: * Overall database configuration:: Overall database configuration. * Individual field configuration:: Individual field configuration. * Field datatypes:: Field datatypes. * Edit controls:: Trigger on certain edit actions. * Named query definitions:: Define and name standard queries. * Audit-trail formats:: Specify formatting of the audit-trail. * Outgoing email formats:: Specify contents and formatting of messages sent out by GNATS. * Index file description:: Specify the general format and contents of the database index. * Initial PR input fields:: Which fields should be present on initial PR entry.  File: gnats.info, Node: Overall database configuration, Next: Individual field configuration, Up: dbconfig file 4.3.1 Overall database configuration ------------------------------------ The overall database options are controlled by settings in the `database-info' section of the `dbconfig' file. The following is the general format of this section: database-info { [options] } The following options and values may be used in the `database-info' section: `debug-mode TRUE | FALSE' If set to `true', the database is placed into debug mode. This causes all outgoing email to be sent to the "gnats-admin" user listed in the `responsible' file of the database. The default value is `false'. `keep-all-received-headers TRUE | FALSE' If set to `true', all of the Received: headers for PRs submitted via email are kept in the PR. Otherwise, only the first one is kept. The default value is `false'. `notify-about-expired-prs TRUE | FALSE' If set to `true', notification email about expired PRs is sent via the `at-pr' command. Otherwise, required times for PR fixes are not used. The default value is `false'. `send-submitter-ack TRUE | FALSE' When new PRs are submitted to the database, an acknowledgment email will be sent to the submitter of send-submitter-ack is set to `true'. This is in addition to the normal notification mail to the person(s) responsible for the new PR. The default value is `false'. `libexecdir "DIRECTORY"' Specifies the directory where the GNATS administrative executables are located. In particular, `at-pr' and `mail-pr' are invoked from this directory. The default value is the empty string, which is unlikely to be useful. `business-day-hours DAY-START - DAY-END' Used to specify the hours that define a business day. The values are inclusive and should be given in 24-hour format, with a dash separating them. GNATS uses these values to determine whether the required completion time for a PR has passed. The default values are 8 for `day-start' and 17 for `day-end'. `business-week-days WEEK-START - WEEK-END' Specifies the start and ending days of the business week, where 0 is Sunday, 1 is Monday, etc. The days are inclusive, and the values should be given with a dash separating them. GNATS uses these values to determine whether the required completion time for a PR has passed. The default values are 1 for `week-start' and 5 for `week-end'. `create-category-dirs TRUE | FALSE' If set to `true', database directories for categories are automatically created as needed. Otherwise, they must be created manually (usually with the `mkcat' script). It is recommended that the default value of `true' be kept. `category-dir-perms MODE' Standard octal mode-specification specifying the permissions to be set on auto-created category directories. Default is `0750', yielding user read, write and execute, and group read and execute. Note that if you have local users on the GNATS server itself, running for instance `query-pr', you may need to change the permissions to `0755'.  File: gnats.info, Node: Individual field configuration, Next: Field datatypes, Prev: Overall database configuration, Up: dbconfig file 4.3.2 Individual field configuration ------------------------------------ Each type of field in a PR must be described with a `field' section in the `dbconfig' file. These sections have the following general structure: field "fieldname" { description "string" [ field-options ... ] datatype [ datatype-options ... ] [ on-change { edit-options ... } ] } `fieldname' is used as the field header in the PR. The characters `>' and `:' are used internally as field markers by GNATS, so they must not be used in fieldnames. The order in which the `field' sections appear in the `dbconfig' file determines the order in which they appear in the PR text. There is no required order, unlike previous versions of GNATS -- the Unformatted field and multitext fields may appear anywhere in the PR. The following `field-options' may be present within a `field' section: `builtin-name "NAME"' Indicates that this field corresponds to one of the GNATS built-in fields. GNATS has several fields which are required to be present in a PR, and this option is used to map their external descriptions to their internal usage. The external field names are: `arrival-date' The arrival date of the PR `audit-trail' The audit-trail recording changes to the PR `category' The category that the PR falls into `closed-date' The date that the PR was closed `confidential' If set to `yes', the PR is confidential `description' A description of the problem `last-modified' The date the PR was last modified `number' The PR's unique numeric identifier `originator' The originator of the PR `priority' Priority of the PR `responsible' The person responsible for handling the PR `severity' Severity of the problem described by the PR `state' The current state of the PR `submitter-id' The user that submitted the PR `synopsis' The one-line description of the PR `unformatted' PR text which cannot be parsed and associated with other fields. For these built-in fields, a matching field description _must_ appear in the `dbconfig' file. Otherwise, the configuration will be considered invalid, and errors will be generated from the GNATS clients and `gnatsd'. We also recommend that you leave the actual fieldnames of these fields at their default values (i.e. capitalized versions of their built-in names), since some clients may depend on these names. `description "DESCRIPTION TEXT"' A one-line human-readable description of the field. Clients can use this string to describe the field in a help dialog. The string is returned from the FDSC command in gnatsd and is also available via the `--field-description' option in `query-pr'. This entry must be present in the field description, and there is no default value. `query-default EXACT-REGEXP | INEXACT-REGEXP' Used to specify the default type of searches performed on this field. This is used when the `^' search operator appears in a query, and is also used for queries in `query-pr' that use the old `--field' query options. If the option is not given, the default search is `exact-regexp'. `textsearch' If this option is present, the field will be searched when the user performs a `--text' search from `query-pr'. The field is also flagged as a `textsearch' field in the set of field flags returned by the `FIELDFLAGS' command in gnatsd. By default, fields are not marked as `textsearch' fields. `read-only' When this option is present, the field contents may not be edited -- they must be set when the PR is initially created. In general, this should only be used for fields that are given as internal values rather than fields supplied by the user. By default, editing is allowed.  File: gnats.info, Node: Field datatypes, Next: Edit controls, Prev: Individual field configuration, Up: dbconfig file 4.3.3 Field datatypes --------------------- Each field description has to contain a datatype declaration which describes what data are to be store in the field. The general format for such a declaration is `datatype [ options ... ]' The available datatypes are: `text [ matching { "regexp" [ "regexp" ... ] } ]' The `text' datatype is the most commonly used type; it is a one-line text string. If the `matching' qualifier is present, the data in the field must match at least one of the specified regexps. This provides an easy and flexible way to limit what text is allowed in a field. If no `matching' qualifier is present, no restriction is placed on what values may appear in the field. `multitext [ { default "string" } ]' The field can contain multiple lines of text. If the `default' option is present, the field will default to the specified `string' if the field is not given a value when the PR is initially created. Otherwise, the field will be left empty. `enum {' ` values {' ` "string" [ "string" ... ]' ` }' ` [ default "string" ]' `}' Defines an enumerated field, where the values in the PR field must match an entry from a list of specified values. The list of allowed values is given with the `values' option. The `values' option is required for an enumerated field. If a `default' option is present, it is used to determine the initial value of the field if no entry for the field appears in an initial OR (or if the value in the initial PR is not one of the acceptable values). However, the value in the `default' statement is not required to be one of the accepted values; this can be used to allow the field to be initially empty, for example. If no `default' option is specified, the default value for the field is the first value in the `values' section. `multienum {' ` values {' ` "string" [ "string" ... ]' ` }' ` [ separators "string" ]' ` [ default "string" ]' `}' The `multienum' datatype is similar to the `enum' datatype, except that the field can contain multiple values, separated by one or more characters from the `separators' list. If no `separators' option is present, the default separators are space (` ') and colon (`:'). The values in the `default' string for this field type should be separated by one of the defined separators. An example clarifies this. If we have a field named `ingredients' where the default values should be `sugar', `flour' and `baking powder' and the separator is a colon `:', the following sets these defaults: default "sugar:flour:baking powder" `enumerated-in-file {' ` path "filename"' ` fields {' ` "name" [ "name" ... ]' ` } key "name"' ` [ allow-any-value ]' `}' The `enumerated-in-file' type is used to describe an enumerated field with an associated "administrative file" which lists the legal values for the field, and may optionally contain additional fields that can be examined by query clients or used for other internal purposes. It is similar to the `enum' datatype, except that the list of legal values is stored in a separate file. An example of this kind of field is the built-in Category field with its associeted `categories' administrative file. `filename' is the name of a file in the `gnats-adm' administrative directory for the database. The format of the administrative file should be simple ASCII. "Subfields" within the file are separated with colons (`:'). Lines beginning with a hash sign (`#') are ignored as comments. Records within the file are separated with newlines. The `field' option is used to name the subfields in the administrative file. There must be at least one subfield, which is used to list the legal values for the field. If the administrative file is empty (or does not contain any non-empty non-comment lines), the PR field must be empty. The `key' option is used to designate which field in the administrative file should be used to list the legal values for the PR field. The value must match one of the field names in the `field' option. If the `allow-any-value' option is present, the value of the PR field is not required to appear in the administrative file -- any value will be accepted. Note that there is no `default' keyword for `enumerated-in-file'. These fields get their default value from the _first_ entry in the associated administrative file. `multi-enumerated-in-file {' ` path "filename"' ` fields {' ` "name" [ "name" ... ]' ` } key "name"' ` [ default "string" ]' ` [ allow-any-value ]' ` [ separators "string" ]' `}' `multi-enumerated-in-file' is to `multienum' what `enumerated-in-file' is to `enum'. Its options have the same meaning as their counterparts in the `multienum' and `enumerated-in-file' fields. _NOTE_: Keywords may appear in any sequence, with one exception - the `separators' keyword, if present, has to come last. This rule only applies to fields of type `multi-enumerated-in-file'. `date' The `date' datatype is used to hold dates. Date fields must either be empty or contain a correctly formatted date. No defaults or other options are available. The field is left empty if no value for the field is given in the initial PR. `integer [ { default "integer" } ]' Integer fields are used to hold numbers. They must either be empty or contain a value composed entirely of digits, with an optional leading sign. If the `default' option is present, the field will have the value of `integer' if the field is not given a value when the PR is initially created. Otherwise, the field will be left empty.  File: gnats.info, Node: Edit controls, Next: Named query definitions, Prev: Field datatypes, Up: dbconfig file 4.3.4 Edit controls ------------------- The `on-change' subsection of a `fields' section specifies one or more actions to be performed when the field value is edited by the user. It has the general form on-change [ "query-expression" ] { [ add-audit-trail ] [ audit-trail-format { format "formatstring" [ fields { "fieldname" ... } ] } ] [ require-change-reason ] [ set-field | append-to-field "fieldname" { "format-string" [ fieldlist ] } ] [ require { "fieldname" ... } ] } The optional `query-expression' controls whether or not the actions in the `on-change' section are taken. If the expression fails to match, the actions are skipped. The `add-audit-trail' option indicates that an entry should be appended to the PR's audit-trail when this field is changed. The format of the entry is controlled by the optional `audit-trail-format' section within the field, or by the global `audit-trail-format' section. See *Note Audit-trail formats:: and *Note Outgoing email formats::. The `require-change-reason' option specifies that a change reason must be present in the PR when this field is edited. This option only makes sense if an audit-trail entry is required, as the change reason is otherwise unused. The `set-field' and `append-to-field' options are used to change the value of the field `fieldname' in the PR. The supplied format is used to format the value that will be placed in the field. `append-to-field' appends the resulting formatted string to the existing, while `set-field' completely replaces the contents. Any field may be edited by the `set-field' or `append-to-field' option (the `read-only' option on a field is ignored). However, the changes are subject to the usual field content checks. The `require' option specifies that one or more fields must have a (non-blank) value when this field is changed. A field may be enforced to have a (non-blank) value at all times by including it in the set of fields required for the initial PR, see *Note Initial PR input fields::, as well as in the set of fields required on change of the field itself. There is also a global `on-change' section that is executed once for each PR edit. A typical use for such a section is to set the last-modified date of the PR.  File: gnats.info, Node: Named query definitions, Next: Audit-trail formats, Prev: Edit controls, Up: dbconfig file 4.3.5 Named query definitions ----------------------------- When queries are performed via `query-pr', they can refer to a query format described by a `query' section in the `dbconfig' file: query "queryname" { format "formatstring" [fields { "fieldname" [ "fieldname" ... ] } ] } `formatstring' is as described in *Note Formatting query-pr output::. It basically contains a string with printf-like % escapes. The output of the query is formatted as specified by this format string. The `fields' option lists the fields to be used with the format string. If the `fields' option is present without a `format' option, the contents of the listed fields are printed out, separated by newlines. The named query formats _full_, _standard_ amd _summary_ must be present in the `dbconfig' file. _full_ and _summary_ correspond to the `query-pr' options `--full' and `--summary', while _standard_ is used when no format option is given to `query-pr'.  File: gnats.info, Node: Audit-trail formats, Next: Outgoing email formats, Prev: Named query definitions, Up: dbconfig file 4.3.6 Audit-trail formats ------------------------- These formats are similar to the named query formats, but they include more options. They are used for formatting audit-trail entries and for outgoing email messages. There is currently only one audit-trail format, defined by the `audit-trail-format' option: audit-trail-format { format "formatstring" [ fields { "fieldname" [ "fieldname" ... ] } ] } For those fields that require an audit-trail entry, the audit-trail text to be appended is formatted as described by this format. The per-field `audit-trail-format' is used in preference to this one, if it exists. `formatstring' and `fieldname' are similar to those used by the named query format. `fieldname' may also be a "format parameter", which is a context-specific value. (Format parameters are distinguished from fieldnames by a leading dollar sign (`$')). The following format parameters are defined for `audit-trail-format' entries: `$Fieldname' The name of the field for which an audit-trail entry is being created. `$OldValue' The old value of the field. `$NewValue' The new field value. `$EditUserEmailAddr' The email address of the user editing the field. Set by the `EDITADDR' `gnatsd' command or from the `responsible' file; if not available, user's local address is used. `$CurrentDate' The current date. `$ChangeReason' The reason for the change; may be blank if no reason was supplied. These parameters may be used anywhere a `fieldname' can appear.  File: gnats.info, Node: Outgoing email formats, Next: Index file description, Prev: Audit-trail formats, Up: dbconfig file 4.3.7 Outgoing email formats ---------------------------- During the life of a PR, GNATS can be configured to send out a range of email messages. When a PR first arrives, an acknowledgment message is sent out if the `send-submitter-ack' parameter above is set to `true'. Certain edits to the PR may also cause email to be sent out to the various parties, and if a PR is deleted, GNATS may send notification email. The formats of the email messages are controlled by `mail-format' sections in the `dbconfig' file. The general structure of a `mail-format' section is as follows: mail-format "format-name" { from-address { [ fixed-address "address" ] [ email-header-name | [ mail-header-name | ... ] ] } to-address { [ fixed-address "address" ] [ "email-header-name" | [ "mail-header-name" | ... ] ] } reply-to { [ fixed-address "address" ] [ "email-header-name" | ... ] | [ "gnats-field-name" | ... ] } header { format "formatstring" [ fields { "fieldname" [ "fieldname" ... ] } ] } body { format "formatstring" [ fields { "fieldname" [ "fieldname" ... ] } ] } } `gnats' recognizes and uses 6 different `format-name' values: `initial-response-to-submitter' Format of the message used when mailing an initial response back to the PR submitter. This message will only be sent if `send-submitter-ack' in the overall database configuration is set to `true'. `initial-pr-notification' Format of the message sent to the responsible parties when a new PR with category different from "pending" arrives. `initial-pr-notification-pending' Format of the message sent to the responsible parties when a new PR that ends up with category "pending" arrives. `appended-email-response' Format of the notification message sent out when a response to a PR is received via email. `audit-mail' Format of the message sent out when a PR edit generates an Audit-Trail entry. `deleted-pr-mail' Format of the message sent out when a PR is deleted. The `from-address', `to-address' and `reply-to' subsections of a mail-format section specify the contents of the `To:', `From:' and `Reply-To:' headers in outgoing email. There are two ways to specify the contents: by using a `fixed-address' specification, or by specifying `email-header-name's or `gnats-field-name's. When an `email-header-name' or `gnats-field-name' value is given, GNATS will attempt to extract an email address from the specified location. If several values are given on the same line, separated by `|' characters, GNATS will try to extract an address from each location in turn until it finds a header or field which is nonempty. The following example should clarify this: mail-format "initial-response-to-submitter" { from-address { fixed-address "gnats-admin" } to-addresses { "Reply-To:" | "From:" | "Submitter-Id" } ... This partial `mail-format' section specifies the format of the address headers in the email message that is sent out as an acknowledgment of a received PR. The `From:' field of the message will contain the email address of the GNATS administrator, as specified by the `gnats-admin' line in the `responsible' file. To fill in the `To:' header, GNATS will first look for the mail header `Reply-To:' in the PR and use the contents of that, if any. If that header doesn't exist or is empty, it will look for the contents of the `From:' email header, and if that yields nothing, it will look for the GNATS `Submitter-Id' field and use the contents of that. Other email headers to be included in messages sent out by GNATS can be specified by `header' subsections of the `mail-header' section. `formatstring' and `fieldname' are similar to those used by the named query format. Each header line must have a newline character (`\n') at the end. The email message body is specified in the `body' subsection of the `mail-format' section. Just as for a `header' section, the `body' section must contain a `formatstring' and `fieldname' values. For some of the formats that GNATS recognizes, special variables are available for use. The following table lists the formats that provide special variables. See the example below for an illustration of how they are used. `appended-email-response' `$MailFrom' The From: line of the original message. `$MailTo' The To: line of the original message. `$MailSubject' The Subject: line of the original message. `$MailCC' The CC: line of the original message. `$NewAuditTrail' The text of the new audit trail entry (corresponds to the body of the message). `audit-mail' `$EditUserEmailAddr' The email address of the user editing the PR. Set by the `EDITADDR' `gnatsd' command or from the `responsible' file; if not available, user's local address is used. `$OldResponsible' The previous Responsible field entry, if it was changed. `$NewAuditTrail' The Audit-Trail: entries that have been appended by the edits. `deleted-pr-mail' `$EditUserEmailAddr' The email address of the user deleting the PR. Set by the `EDITADDR' `gnatsd' command or from the `responsible' file; if not available, user's local address is used. `$PRNum' The number of the PR that was deleted. The following example illustrates the use of these special variables: mail-format "deleted-pr-mail" { from-address { "$EditUserEmailAddr" } to-addresses { fixed-address "gnats-admin" } header { format "Subject: Deleted PR %s\n" fields { "$PRNum" } } body { format "PR %s was deleted by user %s.\n" fields { "$PRNum" "$EditUserEmailAddr" } } } This `mail-format' section specifies the format of the email message that is sent out when a PR is deleted. The `From:' field is set to the email address field of the user who deleted the PR, the subject of the message contains the number of the deleted PR, and the message body contains both the PR number and the user's email address.  File: gnats.info, Node: Index file description, Next: Initial PR input fields, Prev: Outgoing email formats, Up: dbconfig file 4.3.8 Index file description ---------------------------- The `index' section of the `dbconfig' file lists the fields that appear in the database index. The index is always keyed by PR number. The general format for the `index' section is index { path "file" fields { "fieldname" [ "fieldname" ... ] } binary-index true | false [ separator "symbol" ] } The `path' parameter gives the name of the index file in the `gnats-adm' directory of the database. Only one index is allowed per database, so only one `path' entry is allowed. The `fields' parameter controls what fields will appear, and in what order, in the index. Fields are listed by their names, separated by spaces (` '). Fields will appear in the order they are listed. The `binary-index' parameter controls whether the index is supposed to be in plaintext or binary format. Binary format is recommended, as it avoids potential problems when field separators appear as bona-fide field contents. When plaintext format is used, by setting `binary-index false', the symbol (`|') is used as a field separator in the index, unless the optional `separator' parameter is used to redefine the separator character.  File: gnats.info, Node: Initial PR input fields, Prev: Index file description, Up: dbconfig file 4.3.9 Initial PR input fields ----------------------------- An `initial-entry' section in the `dbconfig' file is used to describe which fields should be present on initial PR entry; this is used by tools such as send-pr to determine which fields to include in a "blank" PR template. An optional `require' parameter can be defined to specify a subset of the `intial-entry' fields which must be assigned a value upon initial creation of the PR. The general format for the `initial-entry' section is initial-entry { fields { "fieldname" [ "fieldname" ... ] } [ require { "fieldname" [ "fieldname" ... ] } ] }  File: gnats.info, Node: Other config files, Next: send-pr.conf file, Prev: dbconfig file, Up: Management 4.4 Other database-specific config files ======================================== * Menu: * categories file:: * responsible file:: * submitters file:: * states file:: * addresses file:: * classes file::  File: gnats.info, Node: categories file, Next: responsible file, Up: Other config files 4.4.1 The `categories' file --------------------------- The `categories' file contains a list of problem categories, specific to the database, which GNATS tracks. This file also matches responsible people with these categories. You must edit this file initially, creating valid categories. In most installations, GNATS is configured to create directories on disk for valid categories automatically as needed (*note Overall database configuration: Overall database configuration.). If GNATS isn't set up to do this, you need to run `mkcat' to create the corresponding subdirectories of the database directory. For instructions on running `mkcat', see *Note Adding a problem category: mkcat. To create a new category, log in as GNATS, add a line to this file, and run `mkcat' if applicable. Lines beginning with `#' are ignored. A line in the `categories' file consists of four fields delimited by colons, as follows: CATEGORY:DESCRIPTION:RESPONSIBLE:NOTIFY CATEGORY A unique category name, made up of text characters. This name cannot contain spaces or any of the following characters: ! $ & * ( ) { } [ ] ` ' " ; : < > ~ Ideally, category names should not contain commas or begin with periods. Each line has a corresponding subdirectory in the database directory. DESCRIPTION A terse textual description of the category. RESPONSIBLE The name tag of the party responsible for this category of problems, as listed in the `responsible' file (*note The `responsible' file: responsible file.). NOTIFY One or more other parties which should be notified when a Problem Report with this category arrives, such as a project manager, other members of the same project, other interested parties, or even log files. These should be separated with commas. A good strategy for configuring this file is to have a different category for each product your organization supports or wishes to track information for. rock:ROCK program:me:myboss,fred stone:STONE utils:barney:fred iron:IRON firewall:me:firewall-log In the above example, the nametags `myboss', `me', `fred', and `barney' must be defined in the `responsible' file (*note The `responsible' file: responsible file.). Problem Reports with a category of `rock' are sent to the local mail address (or alias) `me', and also sent to the addresses `myboss' and `fred'. PRs with a category of `stone' are sent to the local addresses `barney' and `fred' only, while PRs with the category `iron' are sent only to `me', and are also filed in `firewall-log' (in this case, a mail alias should be set up, *note Setting up mail aliases: Aliases. If you want to separate PRs in each problem category into specific subsets, say _documentation_ and _software bugs_, using the `classes' file is recommended. *Note The `classes' file: classes file. Only one category _must_ be present for GNATS to function: pending:Non-categorized PRs:gnats-admin: The `pending' directory is created automatically when you run `mkdb' to initialize a new database. (*note Configuring and compiling the software: Configure and make.).  File: gnats.info, Node: responsible file, Next: submitters file, Prev: categories file, Up: Other config files 4.4.2 The `responsible' file ---------------------------- This file contains a list of the responsible parties. Lines beginning with `#' are ignored. Each entry contains three fields, separated by colons: RESPONSIBLE:FULL-NAME:MAIL-ADDRESS RESPONSIBLE A name-tag description of the party in question, such as her or his user name, or the name of the group. This name is listed in the PR in the `Responsible' field. FULL-NAME The full name of the party ("Charlotte Bronte"; "Compiler Group"). MAIL-ADDRESS The full, valid mail address of the party. This field is only necessary if the responsible party has no local mail address or alias. A sample `responsible' listing might be: ren:Ren Hoek: stimpy:Stimpson J. Cat:stimpy@lederhosen.org Here, `ren' is a local user. `stimpy' is remote, so his full address must be specified. The following entry _must_ be present for GNATS to function: gnats-admin:GNATS administrator: `gnats-admin' is usually defined as a mail alias when GNATS is installed, so for this purpose `gnats-admin' is a local address. However, this line can alos be used to redefine the email address of the GNATS administrator, by adding the desired address at the end of the line.  File: gnats.info, Node: submitters file, Next: states file, Prev: responsible file, Up: Other config files 4.4.3 The `submitters' file --------------------------- This is a database of sites which submit bugs to your support site. It contains six fields delineated by colons. Lines beginning with `#' will be ignored. Entries are of the format: SUBMITTER-ID:NAME:TYPE:RESP-TIME:CONTACT:NOTIFY SUBMITTER-ID A unique identifier for a specific site or other entity who submits Problem Reports. The first `submitter-id' listed in the file will be the default for PRs that arrive with invalid or empty submitter fields. NAME The full name or a description of this entity. TYPE Optional description for the type of relationship of this submitter to your support site. This could indicate a contract type, a level of expertise, etc., or it can remain blank. RESP-TIME Optional quoted response time in "business hours". If the database `dbconfig' file has the `notify-about-expired-prs' entry set to TRUE (*note Overall database configuration: Overall database configuration, GNATS will use this field to schedule when it should notify the gnats-admin, responsible person and submitter contact that the PR wasn't analyzed within the agreed response time. Business hours and business-week days are set in the `dbconfig' file. For information on `at-pr', the program which sends out this reminder, see *Note Timely Reminders: at-pr. CONTACT The name tag of the main "contact" at the Support Site for this submitter. This contact should be in the `responsible' file (*note The `responsible' file: responsible file.). Incoming bugs from SUBMITTER are sent to this contact. Optionally, this field can be left blank. NOTIFY Any other parties who should receive copies of Problem Reports sent in by SUBMITTER. They need not be listed in the `responsible' file. A few example entries in the `submitters' file: univ-hell:University of Hades:eternal:3:beelzebub:lucifer tta:Telephones and Telegraphs of America:support:720:dave: In this example, when a PR comes in from the University of Hades (who has an eternal contract), it should have `univ-hell' in its `Submitter-Id' field. This Problem Report goes to `beelzebub' (who should be in the `responsible' file), and if it is not analyzed within three business hours a reminder message is sent. `lucifer' also receives a copy of the bug, and a copy of the reminder message as well (if it is sent). When Telephones and Telegraphs of America utilizes their support contract and submits a bug, a copy is sent only to `dave', who has 720 business hours to return an analysis before a reminder is sent. To disable the feature of GNATS which tracks the `Submitter-Id', simply alter the `submitters' file to only contain one SUBMITTER-ID value, and instruct your submitters to ignore the field.  File: gnats.info, Node: states file, Next: addresses file, Prev: submitters file, Up: Other config files 4.4.4 The `states' file ----------------------- This file lists the possible states for Problem Reports. Each entry has up to three fields, separated by colons. Lines beginning with `#' will be ignored. STATE:TYPE:DESCRIPTION STATE The name of the state. It may contain alphanumerics as well as `-' (hyphen), `_' (underscore), or `.' (period), but no other characters. TYPE This is the type of the state. This field is optional and it may contain alphanumerics as well as `-' (hyphen), `_' (underscore), or `.' (period), but no other characters. The concept of the type of a state recognizes that there may for instance be several possible states for a Problem Report which effectively means that the PR is closed and that there may be certain actions that need to be taken when a PR reaches a "closed state". The problem may have been resolved, it might have been decided that the problem is unsolvable or simply that it won't be solved. Some organizations may for instance wish to consider the "suspended" state as a state of type "closed". Currently, the only defined state types are "open" and "closed", the "open" type isn't currently used for anything while the "closed" type is only used to control the Closed-Date field of PRs. Changing the state of a PR to any state of type "closed" will set the Closed-Date field with a time stamp and changing the state of a PR from one "closed" state to another will leave the Closed-Date field as it was. Changing the state of a PR from any state of type "closed" to a non-closed state will clear the Closed-Date field. The `--skip-closed' option of `query-pr' refers to all states of type "closed", not to a specific state name of "closed". DESCRIPTION This is is an optional one-line description of what the state means. Any character is okay in the description; a newline ends it. GNATS itself does not currently use the description for anything, but certain external tools (such as TkGnats and Gnatsweb) look for it, so it's a good idea to include one for every state. The first state listed will be the state automatically assigned to Problem Reports when they arrive; by default this is named "open". The last state listed is the end state for Problem Reports -- one should usually assume that a PR in this state is not being actively worked on; by default this state is named "closed". Even if a different name has been chosen for this state, GNATS will force this state to be of type "closed". It is recommended that you keep the default names of "open" and "closed" for the first and last states respectively, since there may be external tools that depend on these names.  File: gnats.info, Node: addresses file, Next: classes file, Prev: states file, Up: Other config files 4.4.5 The `addresses' file -------------------------- This file contains mappings between submitter IDs and corresponding e-mail addresses. When a PR comes in without a submitter ID (if someone sends unformatted e-mail to the PR submission email address), GNATS will try to derive the submitter ID from the address in the "From:" header. The entries in this file consist of two fields, separated by a colon: SUBMITTER-ID:ADDRESS-FRAGMENT SUBMITTER-ID A valid submitter ID ADDRESS-FRAGMENT Part of, or all of the e-mail address to be matched Here is an example of an `addresses' file: # Addresses for Yoyodine Inc yoyodine:yoyodine.com yoyodine:yoyodine.co.uk # Addresses for Foobar Inc. foobar1:sales.foobar.com foobar2:admin.foobar.com foobar3:clark@research.foobar.com GNATS checks each line in the `addresses' file, comparing ADDRESS-FRAGMENT to the end of the "From:" header, until it finds a match. If no match is found, GNATS uses the default submitter ID. You can only have one address fragment per line, but you can have more than one line for a given submitter ID. An address fragment can be a domain (i.e. yoyodine.com), a machine location (admin.foobar.com), or a full e-mail address (clark@research.foobar.com). GNATS can match addresses in three e-mail formats: `From: name@address.com' The address by itself without a full name, not enclosed in brackets `From: Real Person ' A full name (optional, with or without quotation marks), followed by the address enclosed in angle brackets `From: name@address.com (Real Person)' An address, followed by a name or comment in parentheses If GNATS sees other e-mail address formats, it uses the default submitter ID.  File: gnats.info, Node: classes file, Prev: addresses file, Up: Other config files 4.4.6 The `classes' file ------------------------ This file lists the possible classes of Problem Reports. Each line consists of a class name, followed by a colon and an optional class type name (the class type name is not used for anything in the current implementation of GNATS, so it may be left blank. The `class' and `class-type-name' fields may only contain alphanumerics, `-', `_', and `.', but no other characters. Then comes another colon, followed by an optional one-line description of the class. GNATS itself does not use the class description, but external tools such as Gnatsweb and TkGnats may use it. Therefore, a line in this file should at least contain the following: class::class description Lines beginning with `#' will be ignored, and the first listed class is the default class for an incoming Problem Report.  File: gnats.info, Node: send-pr.conf file, Next: Admin files, Prev: Other config files, Up: Management 4.5 The `send-pr.conf' file =========================== This file contains some default values that need to be known in order for `send-pr' to work properly. This file needs to be copied to all hosts where `send-pr' will be used. If GNATS was built with default options, the `send-pr.conf' file should be placed in the `/usr/local/etc/gnats' directory. However, if the option `--sysconfdir' was used during building of GNATS, the `send-pr.conf' file resides at the location given to this option. Entries in this file are on the format variable=VALUE The valid variables are: `SUBMITTER' The default value to be used for the Submitter-Id field when `send-pr' is invoked. `DEFAULT_RELEASE' The default value to be used for the Release field (only applicable if the Release field is defined in the `dbconfig' file. `DEFAULT_ORGANIZATION' The default value to be used for the Organization field. (only applicable if the Organization field is defined in the `dbconfig' file. `MAILPROG' If the GNATS server can't be reached directly over the network, i.e. it is behind a firewall or suchlike, `send-pr' can be set up to submit Problem Reports by e-mail. This is done by setting the `MAILPROG' variable to point to a mailer such as Sendmail. If `MAILPROG' needs to have the address that the mail is being sent to specified on the command line, it should be specified here as well (for example, `MAILPROG=''mail bugs@foo.bar.com''' should work). If Sendmail is used, use `MAILPROG=''/usr/lib/sendmail -oi -t'''. See also `MAILADDR' and `TEMPLATE' below. `MAILADDR' If using e-mail to submit PRs, this is the address that PRs should be sent to. `TEMPLATE' When invoked, `send-pr' communicates directly over the network with the GNATS server to determine what fields to include in a correctly formatted Problem Report so that it can present the user with a template. If the GNATS server can't be reached directly over the network, a template must be provided. Set the `TEMPLATE' variable to point to a template file created on the GNATS server by using the command `send-pr -p'. *Note Installing the user tools: Installing tools.  File: gnats.info, Node: Admin files, Next: Admin utils, Prev: send-pr.conf file, Up: Management 4.6 Administrative data files ============================= The following files are database-specific and are located in the `gnats-adm' subdirectory of the database directory. These files are maintained by GNATS; you should never need to touch them. * Menu: * index file:: The `index' file * current file:: The `current' file  File: gnats.info, Node: index file, Next: current file, Up: Admin files 4.6.1 The `index' file ---------------------- The index is used to accelerate searches on the database by `query-pr' and `edit-pr'. This file is not created until the first PR comes in. It is then kept up to date by GNATS; you should never touch this file. Searches on subjects contained in the index are much faster than searches which depend on data not in the index. Inexes come in two different formats: "binary" and "plain-text". Binary indexes are safer, in that they avoid certain problems that may crop up if the field separators used by plain-text indexes appear in field data. A plain-text index contains single-line entries for all PR fields except for the multitext fields such as Description, How-To-Repeat, etc. Fields are separated by bars (`|') except for `Category' and `Number', which are separated by a slash (`/'). Binary indexes are not meant to be human-readable, but they are safer than the plain-text variety, in that they avoid certain problems that may crop up if the field separators used by plain-text indexes appear in field data. The format of the index for a database is set in the `dbconfig' file. *Note Index file description: Index file description. Should the `index' file become corrupted, the `gen-index' utility can be used to regenerate it. *Note Regenerating the index: gen-index.  File: gnats.info, Node: current file, Prev: index file, Up: Admin files 4.6.2 The `current' file ------------------------ This file contains the last serial number assigned to an incoming PR. It is used internally by GNATS; you need never touch this file.  File: gnats.info, Node: Admin utils, Next: Internal utils, Prev: Admin files, Up: Management 4.7 Administrative utilities ============================ These tools are used by the GNATS administrator as part of the periodic maintenance and configuration of GNATS. *Note GNATS Administration: Management. * Menu: * mkdb:: Adding another database * mkcat:: Adding a problem category * rmcat:: Removing a problem category * gen-index:: Regenerating the index * check-db:: Checking database health * gnats-pwconv:: Managing user passwords  File: gnats.info, Node: mkdb, Next: mkcat, Up: Admin utils 4.7.1 Adding another database ----------------------------- To initialize a new GNATS database: 1. Add a line for the new database in the `databases' file (*note Where GNATS lives: Locations. 2. Run `mkdb', using mkdb DATABASE where DATABASE is the database you specified in the `databases' file. `mkdb' creates the database directory and populates it with the directories `pending', `gnats-queue' and `gnats-adm'. A full set of sample configuration files is copied to the `gnats-adm' directory.  File: gnats.info, Node: mkcat, Next: rmcat, Prev: mkdb, Up: Admin utils 4.7.2 Adding a problem category ------------------------------- To add new categories to the database: 1. Add a line to for each new category to the `categories' file in the gnats-adm directory of the database. *Note The `categories' file: categories file. 2. Run `mkcat' If applicable. If `create-category-dirs' is set to `false' in the database `dbconfig' file, you need to create category directories with `mkcat'. `mkcat' creates a subdirectory under the database directory for any new categories which appear in the `categories' file.  File: gnats.info, Node: rmcat, Next: gen-index, Prev: mkcat, Up: Admin utils 4.7.3 Removing a problem category --------------------------------- To remove a category from the database: 1. Remove the Problem Reports from the subdirectories corresponding to the categories you wish to remove, or assign the PRs to new categories. All PRs for a given category reside in a subdirectory of the database directory, with the same name as the category. 2. Run `rmcat' using rmcat CATEGORY [ CATEGORY... ] where CATEGORY is the category you wish to remove. You can specify as many categories as you wish as long as each category has no PRs associated with it. `rmcat' removes the directory where the Problem Reports for that category had been stored.  File: gnats.info, Node: gen-index, Next: check-db, Prev: rmcat, Up: Admin utils 4.7.4 Regenerating the index ---------------------------- If your `index' file becomes corrupted, or if you need a copy of the current index for some reason, use gen-index [ -n | --numeric ] [ -d DATABASENAME | --database=DATABASENAME ] [ -o FILENAME | --outfile=FILENAME ] [ -i | --import ] [ -e | --export ] [ -h | --help] [ -V | --version ] With no options, `gen-index' generates an index that is sorted by the order that the categories appear in the `categories' file. The index is generated in plaintext or binary format according to the value of `binary-index' in the `dbconfig' file (*note Index file description: Index file description.). The results are printed to standard output. The options are: `-n' `--numeric' Sorts index entries numerically. `-d DATABASENAME' `--database=DATABASENAME' Specifies the database to index. If this option is left out, `gen-index' attempts to index the database with name taken from the the GNATSDB environment variable, and if that is undefined, the default database, as set when GNATS was built (usually `default'). `-o FILENAME' `--outfile=FILENAME' Places output in FILENAME rather than sending it to standard output. `-i' `--import' Import the existing index file instead of re-indexing the database. `-e' `--export' Force plaintext output. `-h' `--help' Prints the usage for `gen-index'. `-V' `--version' Prints the version number for `gen-index'.  File: gnats.info, Node: check-db, Next: gnats-pwconv, Prev: gen-index, Up: Admin utils 4.7.5 Checking database health ------------------------------ The `check-db' script is useful for performing periodic checks on database health. It accepts the following options: `-d DATABASENAME' `--database=DATABASENAME' Determines the database which to operate on. `--all-databases' Check all GNATS databases on the system. This option takes precedence over the `--database' option. If no option is given, the default database is checked. During its operation, `check-db' first attempts to lock DATABASE. If this is not possible, it repeats the locking attempts for five minutes; if it fails, it sends a mail message notifying the administrator of the failure and exits. Once the database is locked, the script searches the database for lock files that are more than 24 hours old. Any old lock files are reported to the administrator in a mail message. After checking for old lock files, it calls `gen-index' (*note Regenerating the index: gen-index.) and compares the results with the current `index' file of the database; any inconsistencies are reported to the administrators in a mail message. After checking the index file for inconsistencies, the script unlocks the database and exits.  File: gnats.info, Node: gnats-pwconv, Prev: check-db, Up: Admin utils 4.7.6 Managing user passwords ----------------------------- Older versions of GNATS, up to and including version 3.x, stored user passwords in plaintext in the `gnatsd.user_access' files. Version 4 has the options of storing the password as MD5 or standard DES `crypt()' hashes (as most UNIX versions do in the system password files) as well as in plaintext. Since the password strings require a prefix to indicate how they are encrypted, one is forced to convert the old password files to a new format when upgrading to GNATS version 4. *Note Upgrading from older versions: Upgrading. The `gnats-pwconv' tool takes care of converting the old password files to the new format: gnats-pwconv [ -c | --crypt ] [ -m | --md5 ] [ -p | --plaintext ] [ -h | --help] [ -V | --version ] INFILE [OUTFILE] Unless the `--version' or `--help' options are given, exactly one encryption method must be specified, as well as an input file. The output file parameter is optional. If one is not specified, results will be printed on standard output.  File: gnats.info, Node: Internal utils, Prev: Admin utils, Up: Management 4.8 Internal utilities ====================== These tools are used internally by GNATS. You should never need to run these by hand; however, a complete understanding may help you locate problems with the GNATS tools or with your local implementation. * Menu: * queue-pr:: Handling incoming traffic * file-pr:: Processing incoming traffic * at-pr:: Timely reminders * pr-edit:: The edit-pr driver * diff-prs:: The `diff-prs' tool * pr-age:: The `pr-age' tool  File: gnats.info, Node: queue-pr, Next: file-pr, Up: Internal utils 4.8.1 Handling incoming traffic ------------------------------- The program `queue-pr' handles traffic coming into GNATS. `queue-pr' queues incoming Problem Reports in the `gnats-queue' directory of the database, and then periodically (via `cron') passes them on to `file-pr' to be filed in the GNATS database. *Note Installing GNATS: Installation. The usage for `queue-pr' is as follows: queue-pr [ -q | --queue ] [ -r | --run ] [ -f FILENAME | --file=FILENAME ] [ -m KBYTES | --max-size=KBYTES ] [ -d DATABASENAME | --database=DATABASENAME ] [ -h | --help] [ -V | --version ] One of `-q' or `-r' (or their longer-named counterparts) must be present upon each call to `queue-pr'. These options provide different functions, as described below. `-q' `--queue' Accepts standard input as an incoming mail message, placing this message in an incrementally numbered file in the `gnats-queue' directory under the database directory (*note Where GNATS lives: Locations.). `-r' `--run' Redirects files in the `gnats-queue' directory into the program `file-pr' one by one. `-f FILENAME' `--file=FILENAME' Used with `-q' (or `--queue'), accepts the file denoted by FILENAME as input rather than reading from standard input. `-m KBYTES' `--max-size=KBYTES' Do not process messages larger then KBYTES kilobytes. Files larger than the limit are left for human intervention. `-d DATABASENAME' `--directory=DATABASENAME' Specifies database to operate on. If this option is left out, the value of the GNATSDB environment variable is used, and if that is undefined, the default database name set when GNATS was built is used (usually `default'). `-h' `--help' Prints the usage for `gen-index'. `-V' `--version' Prints the version number for `gen-index'.  File: gnats.info, Node: file-pr, Next: at-pr, Prev: queue-pr, Up: Internal utils 4.8.2 Processing incoming traffic --------------------------------- `queue-pr' hands off queued Problem Reports to `file-pr' one at a time. `file-pr' checks each Problem Report for correct information in its fields (particularly a correct `Category'), assigns it an identification number, and files it in the database under the appropriate category. If the `Category' field does not contain a valid category value (i.e., matching a line in the `categories' file; *note The `categories' file: categories file.), the PR is assigned to the default category, as set in the `dbconfig' file. If there is no default category defined, the PR is given a `Category' value of `pending' and is placed in the `pending' directory. The GNATS administrator is notified of the unplaceable PR. `file-pr' assigns the Problem Report an identification number, files it in the GNATS database (under the default, if the `Category' field contains an invalid category), and sends acknowledgments to appropriate parties. For the default GNATS configuration, the person responsible for that category of problem (*note The `categories' file: categories file.) and the person responsible for the submitter site where the PR originated (*note The `submitters' file: submitters file.) receive a copy of the PR in its entirety. Optionally, the originator of the PR receives an acknowledgment that the PR arrived and was filed (*note Changing your GNATS configuration: GNATS configuration.). The usage for `file-pr' is as follows: file-pr [ -f FILENAME | --file=FILENAME ] [ -d DATABASENAME | --database=DATABASENAME ] [ -h | --help ] [ -V | --version ] network options: [ -H HOST | --host=HOST ] [ -P PORT | --port=PORT ] [ -v USERNAME | --user=USERNAME ] [ -w PASSWORD | --passwd=PASSWORD ] `file-pr' requires no options in order to operate, and takes input from standard input (normally, the output of `queue-pr -r') unless otherwise specified. The options include: `-f FILENAME' `--filename=FILENAME' Uses FILENAME as input rather than standard input. `-d DATABASENAME' `--database=DATABASENAME' Performs refiling operations on DATABASE. If this option is left out, the value of the GNATSDB environment variable is used, and if that is undefined, the default database name set when GNATS was built is used (usually `default'). `-h' `--help' Prints the usage for `file-pr'. `-V' `--version' Prints the version number for `file-pr'. `file-pr' can file PRs across a network, talking to a remote gnatsd. The following options relate to network access: `-H HOST' `--host=HOST' Hostname of the GNATS server. `-P PORT' `--port=PORT' The port that the GNATS server runs on. `-v USERNAME' `--username=USERNAME' Username used to log into the GNATS server. `-w PASSWORD' `--passwd=PASSWORD' Password used to log into the GNATS server.  File: gnats.info, Node: at-pr, Next: pr-edit, Prev: file-pr, Up: Internal utils 4.8.3 Timely reminders ---------------------- `at-pr' creates a queued job using `at' which, after an allotted "response time" is past, checks the PR to see if its state has changed from `open'. When the PR is originally filed, `file-pr' checks the `notify-about-expired-prs' parameter in the `dbconfig' file. If this parameter is set to `true', `file-pr' calls `at-pr', which sets up the expiry check. The `submitters' file contains the response time for each `>Submitter-Id:' (*note The `submitters' file: submitters file.). The time is determined in "business hours", which are defined in the database's `dbconfig' file (*note Overall database configuration: Overall database configuration.). If the PR is urgent and is still open after the requisite time period has passed, `at-pr' sends a reminder to the GNATS administrator, to the maintainer responsible for that submitter, and to the maintainer responsible for the PR with the following message: To: SUBMITTER-CONTACT RESPONSIBLE GNATS-ADMIN Subject: PR GNATS-ID not analyzed in #HOURS hours PR GNATS-ID was not analyzed within the acknowledgment period of #HOURS business hours. The pertinent information is: Submitter-Id: SUBMITTER Originator: FULL NAME OF THE SUBMITTER Synopsis: SYNOPSIS Person responsible for the PR: RESPONSIBLE -- The GNU Problem Report Management System (GNATS) The PR is "urgent" if its priority is `critical' or if its priority is `serious' and the severity is `high'.  File: gnats.info, Node: pr-edit, Next: diff-prs, Prev: at-pr, Up: Internal utils 4.8.4 The `edit-pr' driver -------------------------- `pr-edit' does the background work for `edit-pr', including error-checking and refiling newly edited Problem Reports, handling file and database locks and deletion of PRs. It can be called interactively, though it has no usable editing interface. The usage for `pr-edit' is: pr-edit [ -l USERNAME | --lock=USERNAME ] [ -u | --unlockdb ] [ -L | --lockdb ] [ -U | --unlockdb ] [ -c | --check ] [ -C | --check-initial ] [ -s | --submit [ --show-prnum ] ] [ -a FIELD | --append field=FIELD ] [ -r FIELD | --replace=FIELD ] [ --delete-pr ] [ -R REASON | --reason=REASON ] [ -p PROCESS-ID | --process=PROCESS-ID ] [ -d DATABASENAME | --database=DATABASENAME ] [ -f FILENAME | --filename=FILENAME ] [ -V | --version ] [ -h | --help ] [ -v USERNAME | --user=USERNAME ] [ -w PASSWD | --passwd=PASSWD ] [ -H HOST | --host=HOST ] [ -P PORT | --port=PORT ] [ -D | --debug ] [ PR NUMBER ] A "lock" is placed on a Problem Report while the PR is being edited. The lock is simply a file in the `locks' subdirectory of the `gnats-adm' directory of the database, with the name `GNATS-ID.lock', which contains the name of the user who created the lock. USER then "owns" the lock, and must remove it before the PR can be locked again, even by the same USER(1). If a PR is already locked when you attempt to edit it, `pr-edit' prints an error message giving the name of the user who is currently editing the PR. If you do not specify PR NUMBER, `pr-edit' reads from standard input. You must specify PR NUMBER for the functions which affect PR locks, `--lock=USERNAME' and `--unlock'. `-L' `--lockdb' Locks the database specified with the `--database' or `-d' option. No PRs may be edited, created or deleted while the database is locked. This option is generally used when editing the index file. `-U' `--unlockdb' Unlocks the specified database. No check is made that the invoking user actually had locked the database in the first place; hence, it is possible for anyone to steal a database lock. `-c' `--check' `-C' `--check-initial' The `--check' options are used to verify that a proposed PR's field contents are valid. The PR is read in (either from stdin or a file specified with `--filename'), and its fields are compared against the rules specified by the database configuration of the selected database. Warnings are given for enumerated fields whose contents do not contain one of the required values or fields that do not match required regexps. `--check-initial' is used to verify initial PRs, rather than proposed edits of existing PRs. `-s' `--submit' Used to submit a new PR to the database. The PR is read in and verified for content; if the PR is valid as an initial PR, it is then added to the database. If the submission is successful a zero exit code is returned. Otherwise, the reason(s) for the PR being rejected are printed, and a non-zero exit code is returned. `--show-prnum' This option is used with the `--submit' option to display the PR number associated with the submitted PR. The following options require a PR number to be given. `--delete-pr' Deletes the specified PR from the database. The PR must be in a closed state, and not locked. Only the user _gnats_ (or the user name specified instead of _gnats_ during the building of GNATS) is permitted to delete PRs. `-l USERNAME' `--lock=USERNAME' Locks the PR. USERNAME is associated with the lock, so the system administrator can determine who actually placed the lock on the PR. However, anyone is permitted to remove locks on a PR. If the optional `--process' or `-p' option is also given, that process-id is associated with the lock. `-u' `--unlock' Unlocks the specified PR. `-a FIELD' `--append=FIELD' `-r FIELD' `--replace=FIELD' `--append' and `--replace' are used to append or replace content of a specific field within a PR. The new field content is read in from stdin (or from the file specified with the `--filename' option), and either appended or replaced to the specified field. The field contents are verified for correctness before the PR is rewritten. If the edit is successful, a zero exit status is returned. If the edit failed, a non-zero exit status is returned, and the reasons for the failure are printed to stdout. `-R REASON' `--reason=REASON' Certain PR fields are configured in the database configuration to require a short text describing the reason of every change that happens to them, *Note dbconfig file::. If you edit a problem and change any of such fields, you must issue a short text, the REASON of the change, through this option. If the option is used and no change-reason requiring field is actually changed, the option has no effect. `PR number' If only a `PR number' is specified with no other options, a replacement PR is read in (either from stdin or the file specified with `--filename'). If the PR contents are valid and correct, the existing PR is replaced with the new PR contents. If the edit is successful, a zero exit status is re turned. If the edit failed, a non-zero exit status is returned, and the reasons for the failure are printed to stdout. `-d DATABASE' `--database=DATABASE' Specifies the database which is to be manipulated. If no database is specified, the default database name set when GNATS was built is used (usually `default'). This option overrides the database specified in the GNATSDB environment variable. `-f FILENAME' `--filename=FILENAME' For actions that require reading in a PR or field content, this specifies the name of a file to read. If `--filename' is not specified, the PR or field content is read in from stdin. `-h' `--help' Prints the usage for `pr-edit'. `-V' `--version' Prints the version number for `pr-edit'. `pr-edit' can edit PRs across a network, talking to a remote gnatsd. The following options relate to network access: `-H HOST' `--host=HOST' Hostname of the GNATS server. `-P PORT' `--port=PORT' The port that the GNATS server runs on. `-v USERNAME' `--username=USERNAME' Username used to log into the GNATS server. `-w PASSWORD' `--passwd=PASSWORD' Password used to log into the GNATS server. `-D' `--debug' Used to debug network connections. ---------- Footnotes ---------- (1) This approach may seem heavy-handed, but it ensures that changes are not overwritten.  File: gnats.info, Node: diff-prs, Next: pr-age, Prev: pr-edit, Up: Internal utils 4.8.5 The `diff-prs' tool ------------------------- The `diff-prs' tool is invoked as follows: diff-prs PRFILE1 PRFILE2 `diff-prs' simply reads the PRs contained in PRFILE1 and PRFILE2 and returns a list of the fields that are different between the two. No output is produced if the PRs are identical.  File: gnats.info, Node: pr-age, Prev: diff-prs, Up: Internal utils 4.8.6 The `pr-age' tool ----------------------- The `pr-age' tool reports the time, in days and hours, since the PR arrived. Usage is pr-age [ -d DATABASENAME | --database=DATABASENAME ] [ -H HOST | --host=HOST ] [ -P PORT | --port=PORT ] [ -v USERNAME | --user=USERNAME ] [ -w PASSWORD | --passwd=PASSWORD ] [ -h | --help ] [ -V | --version ] For an explanation of the arguments listed above, please refer to the usage description for `file-pr' (*Note `file-pr': file-pr.).  File: gnats.info, Node: Locations, Next: gnatsd, Prev: Management, Up: Top Appendix A Where GNATS lives **************************** We use a few conventions when referring to the installation structure GNATS uses. These values are adjustable when you build and install GNATS (*note Installing GNATS: Installation.). * Menu: * prefix:: * exec-prefix:: * gnats-adm:: * defaults:: Default installation locations  File: gnats.info, Node: prefix, Next: exec-prefix, Up: Locations A.1 PREFIX ========== PREFIX corresponds to the variable `prefix' for `configure', which passes it on to the `Makefile' it creates. PREFIX sets the root installation directory for "host-independent" files as follows: the directory path of the default database `PREFIX/com' site-wide configuration files `PREFIX/etc/gnats' `man' pages `PREFIX/man' `info' documents `PREFIX/info' `include' files `PREFIX/include' _etc..._ The default value for PREFIX is `/usr/local', which can be changed on the command line to `configure' using configure --prefix=PREFIX ... *Note Configuring and compiling the software: Configure and make.  File: gnats.info, Node: exec-prefix, Next: gnats-adm, Prev: prefix, Up: Locations A.2 EXEC-PREFIX =============== EXEC-PREFIX corresponds to the variable `exec-prefix' for `configure', which passes it on to the `Makefile' it creates. EXEC-PREFIX sets the root installation for "host-dependent" files as follows: GNATS user tools `EXEC-PREFIX/bin' administrative and support utilities `EXEC-PREFIX/libexec/gnats' compiled libraries `EXEC-PREFIX/lib' _etc..._ `configure' supports several more options which allow you to specify in great detail where different files are installed. The locations given in this appendix do not take into account highly customized installations, but fairly ordinary GNATS installations should be covered by the material here. For a complete list of options accepted by `configure', run `./configure --help' in the `gnats' subdirectory of the distribution. Since most installations are not intended to be distributed around a network, the default value for EXEC-PREFIX is the value of `prefix', i.e., `/usr/local'. However, using EXEC-PREFIX saves space when you are installing a package on several different platforms for which many files are identical; rather than duplicate them for each host, these files can be shared in a common repository, and you can use symbolic links on each host to find the host-dependent files. Use EXEC-PREFIX in conjunction with PREFIX to share host-independent files, like libraries and `info' documents. For example: _for each host:_ configure --prefix=/usr/gnu --exec-prefix=/usr/gnu/H-HOST make all install ... Using this paradigm, all host-dependent binary files are installed into `/usr/gnu/H-HOST/bin', while files which do not depend on the host type for which they were configured are installed into `/usr/gnu'. You can then use a different symbolic link for `/usr/gnu' on each host (`/usr' is usually specific to a particular machine; it is always specific to a particular architecture). _on host-1:_ ln -s /usr/gnu/H-HOST-1 /usr/gnu _on host-2:_ ln -s /usr/gnu/H-HOST-2 /usr/gnu To the end user, then, placing `/usr/gnu/bin' in her or his `PATH' simply works transparently for each HOST type. You can change EXEC-PREFIX on the command line to `configure' using configure --exec-prefix=EXEC-PREFIX ... We recommend that you consult *Note Using `configure': (configure)Using configure, before attempting this.  File: gnats.info, Node: gnats-adm, Next: defaults, Prev: exec-prefix, Up: Locations A.3 The `gnats-adm' directory ============================= Each GNATS database located on a server has its own directory, as listed in the `databases' (*note The `databases' file: databases file. and given when the `mkdb' utility is invoked to initialize the database (*note Initializing a new database: mkdb.). This directory has several subdirectories, one of which is named `gnats-adm'. This directory contains all configuration files related to this specific database, including the `categories', `submitters', `responsible', `states', `classes', `dbconfig', `addresses', `states' and `gnatsd.user_access', as well as two files generated and maintained by GNATS, `index' and `current'.  File: gnats.info, Node: defaults, Prev: gnats-adm, Up: Locations A.4 Default installation locations ================================== PREFIX defaults to `/usr/local'; change using `configure' (*note Configuring and compiling the software: Configure and make.). EXEC-PREFIX defaults to PREFIX; change using `configure' (*note Configuring and compiling the software: Configure and make.). GNATS installs tools, utilities, and files into the following locations. `EXEC-PREFIX/bin' `send-pr' *Note Submitting Problem Reports: send-pr. `edit-pr' *Note Editing existing Problem Reports: edit-pr. `query-pr' *Note Querying the database: query-pr. `EXEC-PREFIX/libexec/gnats' `at-pr' *Note Timely reminders: at-pr. `check-db' *Note Checking database health: check-db. `delete-pr' Tool for deleting PRs. Deprecated. Use the -delete-pr option of `pr-edit' instead (*note The edit-pr driver: pr-edit.). `diff-prs' *Note The `diff-prs' tool: diff-prs. `file-pr' *Note Interface to pr-edit for filing new PRs: file-pr. `gen-index' *Note Regenerating the index: gen-index. `gnatsd' The GNATS daemon. `gnats-pwconv' *Note Converting old password files: gnats-pwconv. `mail-query' *Note Setting up mail aliases: Aliases. `mkcat' *Note Adding a problem category: mkcat. `mkdb' *Note Script for creating new databases: mkdb. `pr-age' *Note The `pr-age' tool: pr-age. `pr-edit' *Note The main PR processor: pr-edit. `queue-pr' *Note Handling incoming traffic: queue-pr. `rmcat' *Note Removing categories: rmcat. `EXEC-PREFIX/lib/libiberty.a' The GNU `libiberty' library. `PREFIX/etc/gnats' `databases' *Note The `databases' file: databases file. `defaults' *Note Overview of GNATS configuration: GNATS configuration. `gnatsd.host_access' *Note The `gnatsd.host_access' file: gnatsd.host_access. `gnatsd.user_access' *Note The `gnatsd.user_access' file: gnatsd.user_access. `PREFIX/share/emacs/site-lisp' `gnats.el' `gnats.elc' The Emacs versions of the programs `send-pr', `query-pr', `edit-pr', and `view-pr'. *Note The GNATS user tools: GNATS user tools. To change this directory you must change the `lispdir' variable in `Makefile.in'; see *Note Configuring and compiling the software: Configure and make. `PREFIX/info' `gnats.info' `send-pr.info' The GNATS manuals, in a form readable by `info' (the GNU hypertext browser). *Note Reading GNU Online Documentation: (infoman)Info. `PREFIX/man/man1' `PREFIX/man/man8' `man' pages for all the GNATS tools and utilities. *Note The GNATS user tools: GNATS user tools. `Per-database directory' `gnats-adm' Administration and configuration data files that define behaviour of the particular database. The files `categories' `submitters' `responsible' `states' `classes' `dbconfig' `addresses' `states' `gnatsd.user_access' `index' (_This file is created by GNATS._) `current' (_This file is created by GNATS._) exist here. *Note Other database-specific config files: Other config files, *Note Administrative data files: Admin files. and *Note Controlling access to databases: Access Control. `gnats-queue' Incoming Problem Reports are queued here until the next iteration of `queue-pr -r' (*note Handling incoming traffic: queue-pr.). `pending' If no default category is set, problem reports without a category are reassigned to the category `pending' and placed here pending intervention by GNATS administrators. *Note GNATS administration: Management. `CATEGORY' Each valid category has a corresponding subdirectory in the database. All Problem Reports associated with that category are kept in that subdirectory.  File: gnats.info, Node: gnatsd, Next: Access Control, Prev: Locations, Up: Top Appendix B The GNATS network server - `gnatsd' ********************************************** This section describes in details how the GNATS network daemon works. This information is mainly assumed to be useful for developers of GNATS client software. * Menu: * Description of gnatsd:: * gnatsd options:: * gnatsd command protocol:: * gnatsd commands:: * gnatsd environment variables::  File: gnats.info, Node: Description of gnatsd, Next: gnatsd options, Up: gnatsd B.1 Description of `gnatsd' =========================== The `gnatsd' network daemon is used to service remote GNATS requests such as querying PRs, PR creation, deletion, and editing, and miscellaneous database queries. It uses a simple ASCII-based command protocol (similar to SMTP or POP3) for communicating with remote clients. It also provides a security model based either on IP-based authentication (generally considered very weak) or username/passwords, where passwords may be in cleartext, UNIX crypt or MD5 hash format. Access through `gnatsd' is granted according to certain predefined "access levels". Access levels are further discussed in *Note Controlling access to databases: Access Control. It should be emphasized that security has not been a focus of development until now, but future versions are expected to address this more thoroughly. All of the GNATS clients are capable of communicating via the GNATS remote protocol to perform their functions. `gnatsd' is usually started from the inetd facility and should run as the `gnats' user (the actual username of this user is configurable during installation, *note Configuring and compiling the software: Configure and make. for details.)  File: gnats.info, Node: gnatsd options, Next: gnatsd command protocol, Prev: Description of gnatsd, Up: gnatsd B.2 `gnatsd' options ==================== The daemon supports the following command-line options: gnatsd [--database database | -d database] [--not-inetd | -n] [--max-access-level LEVEL | -m LEVEL] [--version | -V] [--help | -h] `-V, --version' Prints the program version to stdout and exits. `-h, --help' Prints a short help text to stdout and exits. `-d, --database' Specifies the default database which is to be serviced by this invocation of `gnatsd'. (The selected database may be changed via the `CHDB' command; the name set with this option is simply the default if no `CHDB' command is issued.) If no database is specified, the database named default is assumed. This option overrides the database specified in the `GNATSDB' environment variable. `-n, --not-inetd' As its name suggests, indicates that `gnatsd' is not being invoked from inetd. This can be used when testing `gnatsd', or if it is being run via ssh or some other mechanism. This has the effect of using the local hostname where `gnatsd' is being invoked for authentication purposes, rather than the remote address of the connecting client. `--max-access-level, -m' Specifies the maximum access level that the connecting client can authenticate to. Authentication is as normal but if the user or host authenticates at a higher level, access level is still forced to this level. See *Note Controlling access to databases: Access Control. for details on access levels.  File: gnats.info, Node: gnatsd command protocol, Next: gnatsd commands, Prev: gnatsd options, Up: gnatsd B.3 `gnatsd' command protocol ============================= Commands are issued to `gnatsd' as one or more words followed by a carriage-return/linefeed pair. For example, the `CHDB' (change database) command is sent as `CHDB database' (the `CRLF' will not be explicitly written for future examples.) Replies from `gnatsd' are returned as one or more response lines containing a 3-digit numeric code followed by a human-readable string; the line is terminated with a `' pair. For example, one possible response to the `CHDB' command above would be: 210 Now accessing GNATS database 'database'. The three-digit code is normally followed by a single ASCII space (character 0x20). However, if additional response lines are to be returned from the server, there will be a single dash `-' instead of the space character after the three-digit code. Response code values are divided into ranges. The first digit reflects the general type of response (such as "successful" or "error"), and the subsequent digits identify the specific type of response. CODES 200-299 Positive response indicating that the command was successful. No subsequent data will be transmitted with the response. In particular, code 210 (`CODE_OK') is used as the positive result code for most simple commands. Commands that expect additional data from the client (such as `SUBM' or `VFLD') use a two-step mechanism for sending the data. The server will respond to the initial command with either a 211 (`CODE_SEND_PR') or 212 (`CODE_SEND_TEXT') response line, or an error code if an error occurred with the initial command. The client is then expected to send the remaining data using the same quoting mechanism as described for server responses in the 300-349 range. The server will then send a final response line to the command. CODES 300-399 Positive response indicating that the query request was successful, and that a PR or other data will follow. Codes 300-349 are used when transmitting PRs, and 350-399 are used for other responses. Codes in the 300-349 range are followed by a series of `CRLF'-terminated lines containing the command response, usually a PR. The final line of the result is a single period `.'. Result lines that begin with a period have an extra period prepended to them. Codes in the 350-399 range use a different scheme for sending their responses. The three-digit numeric code will be followed by either a dash `-' or a single space. If the code is followed by a dash, that indicates that another response line will follow. The final line of the response has a single space after the three-digit code. In previous versions of the protocol the first line of a `CODE_INFORMATION' (310) response was to be ignored. This is no longer the case. Instead, any lines marked with code `CODE_INFORMATION_FILLER' (351) are to be ignored. This allows the server to transmit additional headers or other human-readable text that can be safely ignored by the clients. CODES 400-599 An error occurred, usually because of invalid command parameters or invalid input from the client, missing arguments to the command, or a command was issued out of sequence. The human-readable message associated with the response line describes the general problem encountered with the command. Multiple error messages may be returned from a command; in this case the `-' continuation character is used on all but the last response line. CODES 600-799 An internal error occurred on the server, a timeout occurred reading data from the client, or a network failure occurred. These errors are of the "this should not occur" nature, and retrying the operation may resolve the problem. Fortunately, most GNATS transactions are idempotent; unfortunately, locking the database or a PR are not repeatable actions (we cannot determine if an existing lock is the one we originally requested, or someone else's).  File: gnats.info, Node: gnatsd commands, Next: gnatsd environment variables, Prev: gnatsd command protocol, Up: gnatsd B.4 `gnatsd' commands ===================== Note that the set of GNATS commands and their responses is somewhat inconsistent and is very much in flux. At present the GNATS clients are rather simple-minded and not very strict about processing responses. For example, if the server were to issue a code 300 (`CODE_PR_READY') response to a `CHDB' command, the client would happily expect to see a PR appear (and would print it out if one was sent). It is thus suggested that any clients that use the GNATS protocol be equally flexible about the way received responses are handled; in particular, only the first digit of the response code should be assumed to be meaningful, although subsequent digits are needed in some cases (codes 300-399). No attempt should be made to parse the message strings on error response lines; they are only intended to be read by humans, and will be changed on a regular basis. Almost every command may result in the response 440 (`CODE_CMD_ERROR'). This indicates that there was a problem with the command arguments, usually because of insufficient or too many arguments being specified. Access to most `gnatsd' commands requires a certain "access level". For details of this, see *Note Privileged `gnatsd' commands: Privileged gnatsd commands. `USER [USERID PASSWORD]' Specifies the userid and password for database access. Either both a username and password must be specified, or they both may be omitted; in the latter case, the current access level is returned. The possible server responses are: `350 (CODE_INFORMATION)' The current access level is specified. `422 (CODE_NO_ACCESS)' A matching username and password could not be found. `200 (CODE_OK)' A matching username and password was found, and the login was successful. `QUIT' Requests that the connection be closed. Possible responses: `201 (CODE_CLOSING)' Normal exit. The `QUIT' command has the dubious distinction of being the only command that cannot fail. `LIST LIST TYPE' Describes various aspects of the database. The lists are returned as a list of records, one per line. Each line may contain a number of colon-separated fields. Possible values for LIST TYPE include `Categories' Describes the legal categories for the database. `Submitters' Describes the set of submitters for the database. `Responsible' Lists the names in the responsible administrative file, including their full names and email addresses. `States' Lists the states listed in the state administrative file, including the state type (usually blank for most states; the closed state has a special type). `FieldNames' Lists the entire set of PR fields. `InitialInputFields' Lists the fields that _should_ be present when a PR is initially entered. `InitialRequiredFields' Lists fields that _have_ to be present and nonempty when a PR is initially entered (fields containing only blank characters such as spaces or newlines are considered empty.) `Databases' Lists the set of databases. The possible responses are: `301 (CODE_TEXT_READY)' Normal response, followed by the records making up the list as described above. `416 (CODE_INVALID_LIST)' The requested list does not exist. `FTYP FIELD [FIELD ...]' Describes the type of data held in the field(s) specified with the command. The currently defined data types are: `Text' A plain text field, containing exactly one line. `MultiText' A text field possibly containing multiple lines of text. `Enum' An enumerated data field; the value is restricted to one entry out of a list of values associated with the field. `MultiEnum' The field contains one or more enumerated values. Values are separated with spaces or colons `:'. `Integer' The field contains an integer value, possibly signed. `Date' The field contains a date. `TextWithRegex' The value in the field must match one or more regular expressions associated with the field. The possible responses are: `350 (CODE_INFORMATION)' The normal response; the supplied text is the data type. `410 (CODE_INVALID_FIELD_NAME)' The specified field does not exist. If multiple field names were given, multiple response lines will be sent, one for each field, using the standard continuation protocol; each response except the last will have a dash `-' immedately after the response code. `FTYPINFO FIELD PROPERTY' Provides field-type-related information. Currently, only the property `separators' for MultiEnum fields is supported. When `separators' is specified, the possible return codes are: `350 (CODE_INFORMATION)' A proper MultiEnum FIELD was specified and the returned text is the string of separators specified for the field in the dbconfig file (*note Field datatypes::) quoted in `'''s. `435 (CODE_INVALID_FTYPE_PROPERTY)' The `separators' property is not defined for this field, i.e. the specified FIELD is not of type MultiEnum. Currently, specifying a different property than `separators' results in return code 435 as above. `FDSC FIELD [FIELD ... ]' Returns a human-readable description of the listed field(s). The possible responses are: `350 (CODE_INFORMATION)' The normal response; the supplied text is the field description. `410 (CODE_INVALID_FIELD_NAME)' The specified field does not exist. Like the `FVLD' command, the standard continuation protocol will be used if multiple fields were specified with the command. `FIELDFLAGS FIELD [FIELD ... ]' Returns a set of flags describing the specified field(s). The possible responses are either `410 (CODE_INVALID_FIELD_NAME)' meaning that the specified field is invalid or nonexistent, or `350 (CODE_INFORMATION)' which contains the set of flags for the field. The flags may be blank, which indicate that no special flags have been set for this field. Like the `FDSC' and `FTYP' commands, multiple field names may be listed with the command, and a response line will be returned for each one in the order that the fields appear on the command line. The flags include: `textsearch' The field will be searched when a text field search is requested. `allowAnyValue' For fields that contain enumerated values, any legal value may be used in the field, not just ones that appear in the enumerated list. `requireChangeReason' If the field is edited, a reason for the change must be supplied in the new PR text describing the reason for the change. The reason must be supplied as a multitext PR field in the new PR whose name is `field-Changed-Why' (where `field' is the name of the field being edited). `readonly' The field is read-only, and cannot be edited. `FVLD FIELD' Returns one or more regular expressions or strings that describe the valid types of data that can be placed in field. Exactly what is returned is dependent on the type of data that can be stored in the field. For most fields a regular expression is returned; for enumerated fields, the returned values are the list of legal strings that can be held in the field. The possible responses are: `301 (CODE_TEXT_READY)' The normal response, which is followed by the list of regexps or strings. `410 (CODE_INVALID_FIELD_NAME)' The specified field does not exist. `VFLD FIELD' `VFLD' can be used to validate a given value for a field in the database. The client issues the `VFLD' command with the name of the field to validate as an argument. The server will either respond with `212 (CODE_SEND_TEXT)', or `410 (CODE_INVALID_FIELD_NAME)' if the specified field does not exist. Once the `212' response is received from the server, the client should then send the line(s) of text to be validated, using the normal quoting mechanism described for PRs. The final line of text is followed by a line containing a single period, again as when sending PR text. The server will then either respond with `210 (CODE_OK)', indicating that the text is acceptable, or one or more error codes describing the problems with the field contents. `INPUTDEFAULT FIELD [FIELD ... ]' Returns the suggested default value for a field when a PR is initially created. The possible responses are either `410 (CODE_INVALID_FIELD_NAME)', meaning that the specified field is invalid or nonexistent, or `350 (CODE_INFORMATION)' which contains the default value for the field. Like the `FDSC' and `FTYP' commands, multiple field names may be listed with the command, and a response line will be returned for each one in the order that the fields appear on the command line. `RSET' Used to reset the internal server state. The current query expression is cleared, and the index of PRs may be reread if it has been updated since the start of the session. The possible responses are: `200 (CODE_OK)' The state has been reset. `440 (CODE_CMD_ERROR)' One or more arguments were supplied to the command. `6xx (internal error)' There were problems resetting the state (usually because the index could not be reread). The session will be immediately terminated. `LKDB' Locks the main GNATS database. No subsequent database locks will succeed until the lock is removed. Sessions that attempt to write to the database will fail. The possible responses are: `200 (CODE_OK)' The lock has been established. `440 (CODE_CMD_ERROR)' One or more arguments were supplied to the command. `431 (CODE_GNATS_LOCKED)' The database is already locked, and the lock could not be obtained after 10 seconds. `6xx (internal error)' An internal error occurred, usually because of permission or other filesystem-related problems. The lock may or may not have been established. `UNDB' Unlocks the database. Any session may steal a database lock; no checking of any sort is done. The possible responses are: `200 (CODE_OK)' The lock has been removed. `432 (CODE_GNATS_NOT_LOCKED)' The database was not locked. `440 (CODE_CMD_ERROR)' One or more arguments were supplied to the command. `6xx (internal error)' The database lock could not be removed, usually because of permissions or other filesystem-related issues. `LOCK PR USER [PID]' Locks the specified PR, marking the lock with the USER name and the optional PID. (No checking is done that the USER or PID arguments are valid or meaningful; they are simply treated as strings.) The `EDIT' command requires that the PR be locked before it may be successfully executed. However, it does not require that the lock is owned by the editing session, so the usefulness of the lock is simply as an advisory measure. The `APPN' and `REPL' commands lock the PR as part of the editing process, and they do not require that the PR be locked before they are invoked. The possible responses are: `440 (CODE_CMD_ERROR)' Insufficient or too many arguments were specified to the command. `300 (CODE_PR_READY)' The lock was successfully obtained; the text of the PR (using the standard quoting mechanism for PRs) follows. `400 (CODE_NONEXISTENT_PR)' The PR specified does not exist. `430 (CODE_LOCKED_PR)' The PR is already locked by another session. `6xx (internal error)' The PR lock could not be created, usually because of permissions or other filesystem-related issues. `UNLK PR' Unlocks PR. Any user may unlock a PR, as no checking is done to determine if the requesting session owns the lock. The possible responses are: `440 (CODE_CMD_ERROR)' Insufficient or too many arguments were specified to the command. `200 (CODE_OK)' The PR was successfully unlocked. `433 (CODE_PR_NOT_LOCKED)' The PR was not locked. `6xx (internal error)' The PR could not be unlocked, usually because of permission or other filesystem-related problems. `DELETE PR' Deletes the specified PR. The user making the request must have admin privileges (*note Controlling access to databases: Access Control.). If successful, the PR is removed from the filesystem and the index file; a gap will be left in the numbering sequence for PRs. No checks are made that the PR is closed. The possible responses are: `200 (CODE_OK)' The PR was successfully deleted. `422 (CODE_NO_ACCESS)' The user requesting the delete does not have admin privileges. `430 (CODE_LOCKED_PR)' The PR is locked by another session. `431 (CODE_GNATS_LOCKED)' The database has been locked, and no PRs may be updated until the lock is cleared. `6xx (internal error)' The PR could not be successfully deleted, usually because of permission or other filesystem-related problems. `CHEK [initial]' Used to check the text of an entire PR for errors. Unlike the `VFLD' command, it accepts an entire PR at once instead of the contents of an individual field. The `initial' argument indicates that the PR text to be checked is for a PR that will be newly created, rather than an edit or replacement of an existing PR. After the `CHEK' command is issued, the server will respond with either a `440 (CODE_CMD_ERROR)' response indicating that the command arguments were incorrect, or a `211 (CODE_SEND_PR)' response code will be sent. Once the `211' response is received from the server, the client should send the PR using the normal PR quoting mechanism; the final line of the PR is then followed by a line containing a single period, as usual. The server will then respond with either a `200 (CODE_OK)' response, indicating there were no problems with the supplied text, or one or more error codes listing the problems with the PR. `EDIT PR' Verifies the replacement text for PR. If the command is successful, the contents of PR are completely replaced with the supplied text. The PR must previously have been locked with the `LOCK' command. The possible responses are: `431 (CODE_GNATS_LOCKED)' The database has been locked, and no PRs may be updated until the lock is cleared. `433 (CODE_PR_NOT_LOCKED)' The PR was not previously locked with the `LOCK' command. `400 (CODE_NONEXISTENT_PR)' The specified PR does not currently exist. The `SUBM' command should be used to create new PRs. `211 (CODE_SEND_PR)' The client should now transmit the replacement PR text using the normal PR quoting mechanism. After the PR has been sent, the server will respond with either `200 (CODE_OK)' indicating that the edit was successful, or one or more error codes listing problems either with the replacement PR text or errors encountered while updating the PR file or index. `EDITADDR ADDRESS' Sets the e-mail address of the person communicating with `gnatsd'. The command requires at least the `edit' access level. The possible responses are: `200 (CODE_OK)' The address was successfully set. `440 (CODE_CMD_ERROR)' Invalid number of arguments were supplied. `APPN PR FIELD' `REPL PR FIELD' Appends to or replaces the contents of FIELD in PR with the supplied text. The command returns a `201 (CODE_SEND_TEXT)' response; the client should then transmit the new field contents using the standard PR quoting mechanism. After the server has read the new contents, it then attempts to make the requested change to the PR. The possible responses are: `200 (CODE_OK)' The PR field was successfully changed. `400 (CODE_NONEXISTENT_PR)' The PR specified does not exist. `410 (CODE_INVALID_FIELD_NAME)' The specified field does not exist. `402 (CODE_UNREADABLE_PR)' The PR could not be read. `431 (CODE_GNATS_LOCKED)' The database has been locked, and no PRs may be updated until the lock is cleared. `430 (CODE_LOCKED_PR)' The PR is locked, and may not be altered until the lock is cleared. `413 (CODE_INVALID_FIELD_CONTENTS)' The supplied (or resulting) field contents are not valid for the field. `6xx (internal error)' An internal error occurred, usually because of permission or other filesystem-related problems. The PR may or may not have been altered. `SUBM' Submits a new PR into the database. The supplied text is verified for correctness, and if no problems are found a new PR is created. The possible responses are: `431 (CODE_GNATS_LOCKED)' The database has been locked, and no PRs may be submitted until the lock is cleared. `211 (CODE_SEND_PR)' The client should now transmit the new PR text using the normal quoting mechanism. After the PR has been sent, the server will respond with either `351 (CODE_INFORMATION_FILLER)' and `350 (CODE_INFORMATION)' responses indicating that the new PR has been created and supplying the number assigned to it, or one or more error codes listing problems with the new PR text. `CHDB DATABASE' Switches the current database to the name specified in the command. The possible responses are: `422 (CODE_NO_ACCESS)' The user does not have permission to access the requested database. `417 (CODE_INVALID_DATABASE)' The database specified does not exist, or one or more configuration errors in the database were encountered. `220 (CODE_OK)' The current database is now DATABASE. Any operations performed will now be applied to DATABASE. `DBLS' Lists the known set of databases. The possible responses are: `6xx (internal error)' An internal error was encountered while trying to obtain the list of available databases, usually due to lack of permissions or other filesystem-related problems, or the list of databases is empty. `301 (CODE_TEXT_READY)' The list of databases follows, one per line, using the standard quoting mechanism. Only the database names are sent. The `gnatsd' access level `listdb' denies access until the user has authenticated with the USER command. The only other command available at this access level is `DBLS'. This access level provides a way for a site to secure its GNATS databases while still providing a way for client tools to obtain a list of the databases for use on login screens etc. *Note Controlling access to databases: Access Control. `DBDESC DATABASE' Returns a human-readable description of the specified DATABASE. Responses include: `6xx (internal error)' An internal error was encountered while trying to read the list of available databases, usually due to lack of permissions or other filesystem-related problems, or the list of databases is empty. `350 (CODE_INFORMATION)' The normal response; the supplied text is the database description. `417 (CODE_INVALID_DATABASE)' The specified database name does not have an entry. `EXPR QUERY EXPRESSION' Specifies a QUERY EXPRESSION used to limit which PRs are returned from the `QUER' command. The expression uses the normal query expression syntax, (*note Query expressions::). Multiple `EXPR' commands may be issued; the expressions are boolean ANDed together. Expressions are cleared by the `RSET' command. Possible responses include: `415 (CODE_INVALID_EXPR)' The specified expression is invalid, and could not be parsed. `200 (CODE_OK)' The expression has been accepted and will be used to limit the results returned from `QUER'. `QFMT QUERY FORMAT' Use the specified QUERY FORMAT to format the output of the `QUER' command. The query format may be either the name of a query format known to the server (*note Named query definitions::), or an actual query format (*note Formatting query-pr output::). The possible responses are: `200 (CODE_OK)' The normal response, which indicates that the query format is acceptable. `440 (CODE_CMD_ERROR)' No query format was supplied. `418 (CODE_INVALID_QUERY_FORMAT)' The specified query format does not exist, or could not be parsed. `QUER [PR] [PR] [...]' Searches the contents of the database for PRs that match the (optional) specified expressions with the `EXPR' command. If no expressions were specified with `EXPR', the entire set of PRs is returned. If one or more PRs are specified on the command line, only those PRs will be searched and/or output. The format of the output from the command is determined by the query format selected with the `QFMT' command. The possible responses are: `418 (CODE_INVALID_QUERY_FORMAT)' A valid format was not specified with the `QFMT' command prior to invoking `QUER'. `300 (CODE_PR_READY)' One or more PRs will be output using the requested query format. The PR text is quoted using the normal quoting mechanisms for PRs. `220 (CODE_NO_PRS_MATCHED)' No PRs met the specified criteria. `ADMV FIELD KEY [SUBFIELD]' Returns an entry from an administrative data file associated with FIELD. KEY is used to look up the entry in the data file. If SUBFIELD is specified, only the value of that subfield is returned; otherwise, all of the fields in the adm data file are returned, separated by colons `:'. The responses are: `410 (CODE_INVALID_FIELD_NAME)' The specified field does not exist. `221 (CODE_NO_ADM_ENTRY)' An adm entry matching the key was not found, or the field does not have an adm file associated with it. `350 (CODE_INFORMATION)' The normal response; the supplied text is the requested field(s).  File: gnats.info, Node: gnatsd environment variables, Prev: gnatsd commands, Up: gnatsd B.5 `gnatsd' environment variables ================================== `gnatsd' supports the `GNATSDB' environment varable, *Note Environment::, in almost the same way as the GNATS tools do. This variable is used to determine which database to use. For a local database, it contains the name of the database to access. `gnatsd' cannot service remote databases (though it might be interesting if it could) so the database is always assumed to be local. If `GNATSDB' is not set and the `--database' option is not supplied, it is assumed that the database is local and that its name is `default'.  File: gnats.info, Node: Access Control, Next: Regexps, Prev: gnatsd, Up: Top Appendix C Controlling access to databases ****************************************** * Menu: * Overview:: * Overall gnatsd access level:: * gnatsd.host_access:: Per-host access settings * gnatsd.user_access:: Access levels per user * Privileged gnatsd commands::  File: gnats.info, Node: Overview, Next: Overall gnatsd access level, Up: Access Control C.1 Overview ============ GNATS supports granting various levels of access to the GNATS databases served by the network daemon, `gnatsd'. GNATS access can be controlled at these levels: `deny' gnatsd closes the connection `none' no further access until userid and password given `listdb' only listing of available databases is allowed `view' query and view PRs with Confidential=no only `viewconf' query and view PRs with Confidential=yes `edit' full edit access `admin' full admin access These access levels are used in the following settings: * overall gnatsd access level * overall access level set by host name or IP address * overall access level set by userid and password * per-database access level set by userid and password  File: gnats.info, Node: Overall gnatsd access level, Next: gnatsd.host_access, Prev: Overview, Up: Access Control C.2 Overall `gnatsd' access level ================================= The overall `gnatsd' access level is set by starting `gnatsd' with the option `-m' LEVEL or `--maximum-access-level'=LEVEL, where LEVEL is one of the six access levels listed above. This restricts any access to the GNATS daemon to levels up to and including LEVEL, regardless of the settings in the access control files discussed below. If this option is left out, any access levels set in the access control files will be allowed. The discussion below assumes that the pre-build configure of GNATS was done without altering the default values for the `--with-gnatsd-user-access-file' and `--with-gnatsd-host-access-file' options. If non-default values were given, substitute as appropriate below.  File: gnats.info, Node: gnatsd.host_access, Next: gnatsd.user_access, Prev: Overall gnatsd access level, Up: Access Control C.3 Overall access levels per host ================================== The host access file (by default `/usr/local/etc/gnats/gnatsd.host_access') controls overall access levels on a per-host basis, meaning that settings in this file apply across all databases on the server. Entries in this file are in the following format: HOST:ACCESS-LEVEL:WHATEVER HOST is the hostname or IP address of the host contacting gnatsd. Wildcard characters are supported: `*' matches anything; `?' matches any single character. By using wildcards, you can specify access levels for entire network subnets and domains. Note that when GNATS authenticates hosts, it reads the entries in this file in sequence until a match is found. This means that wildcard entries must be placed near the end of the file, otherwise, they will override non-wildcard entries appearing after the wildcard ones. The second field is the access level of HOST. The default is `deny'. If the user's hostname isn't in the file or its access level is set to `deny', the connection is closed immediately. GNATS currently doesn't make use of the third field. Remember to still include the second `:' on the line if you choose to leave the third field empty. Whenever a `CHDB' command is processed (or defaulted), the user's access level is set to the level for their host, as determined by the values in the `gnatsd.host_access' file. However, even if a host is given the `none' access level, an individual can still give the `USER' command to possibly gain a higher (but never lower) access than is set for their host. The gnatsd `USER' command takes two arguments: `USER '.  File: gnats.info, Node: gnatsd.user_access, Next: Privileged gnatsd commands, Prev: gnatsd.host_access, Up: Access Control C.4 Access levels per user ========================== Access levels per user can be set both across all databases on the server or on a per-database basis. The `gnatsd.user_access' file in a database's `gnats-adm' directory specifies the user access rules for that database. If it doesn't exist, or doesn't contain the user name given to `gnatsd', then the overall user access file (by default `/usr/local/etc/gnats/gnatsd.user_access') specifying the per-user access levels across all the databases on the server is checked. The user access files can only _increase_ the access level defined in the host access files for the given host, they can never lower it. If the access level is `none' after processing the userid and password, the connection is closed. The `gnatsd.user_access' files can contain plain text passwords, in such a case they should be owned by the GNATS user with file permission 600. Wildcard characters are supported for the userid and password with plain text passwords. A null string or `*' matches anything; `?' matches any one character. Note that when GNATS authenticates users, it reads the entries in this file in sequence until a match is found. This means that wildcard entries must be placed near the end of the file, otherwise, they will override non-wildcard entries appearing after the wildcard ones. Entries in the database-specific `gnatsd.user_access' user access file in the `gnats-adm' directory of the database have the following general format: USERID:PASSWORD:ACCESS-LEVEL The overall `gnatsd.user_access' user access file adds a fourth DATABASES field: USERID:PASSWORD:ACCESS-LEVEL:DATABASES PASSWORD should either be in plain text, DES `crypt()'(1) or MD5 hash format(2). If the password is in plain text format, it must be prefixed by `$0$' and if it is in MD5 format, it needs to be prefixed by the string `$1$'.(3) Passwords encrypted by `crypt()' should have no prefix. If no password is given then users can login with an empty password string. A `gnats-passwd' tool to manage `gnatsd.user_access' files is planned. In the meantime, `crypt()' passwords can be generated by using standard UNIX passwords tools, while MD5 passwords can be generated with the following little Perl snippet: perl -e 'use Crypt::PasswdMD5 ; print Crypt::PasswdMD5::unix_md5_crypt "PASSWORD" , time() % 100000000' If your Perl installation doesn't have the Crypt module installed, you need to install it. On most systems, the following command achieves this: perl -MCPAN -e 'install Crypt::PasswdMD5' A tool for conversion of pre-version 4 `gnatsd.user_access' files is distributed with GNATS 4. *Note Converting old password files: gnats-pwconv. The ACCESS-LEVEL field should contain one of the values listed at the beginning of this appendix. This overrides (increases but never lowers) the access level given as the default for the user's host in the global gnatsd.host_access file. The following shows an example `gnatsd.user_access' file with plain text passwords: rickm:$0$ruckm:edit pablo:$0$pueblo:view *::none And this is the same file with MD5-encrypted passwords: rickm:$1$92388613$D7ZIYikzTUqd./dODTFrI.:edit pablo:$1$92388652$QRfAhIBG5elT.FQjQKhj80:view *::none In these examples, anybody other than rickm and pablo get denied access, assuming that the host access level is also `none'. You could set the catch-all rule at the end to be `*::view' to allow view access to anyone who does not supply a password. Note the important detail that such a rule would allow view access only to persons who do not supply a password at all, i.e. if rickm or pablo tries to log in but mistypes his password, this rule would not apply and they would be denied access entirely. This is by design, since people might be surprised if they suddenly found themselves logged in, but with a lower access level than they usually have. The DATABASES field contains a comma-separated list of database names, as defined in the `databases' file (*note The `databases' file: databases file. Wildcard characters are supported. The databases listed in this field are the ones to which the other settings on the same line will be applied. ---------- Footnotes ---------- (1) DES crypt is the standard password encryption format used by most UNIX systems (2) MD5 is only supported on platforms that have a `crypt()' function that supports MD5. Among others, this currently includes GNU Linux and OpenBSD. (3) Some systems support even more encryption methods. In FreeBSD, for instance, a prefix of `$2$' implies Blowfish encoding. GNATS will happily accept any encryption that the OS supports.  File: gnats.info, Node: Privileged gnatsd commands, Prev: gnatsd.user_access, Up: Access Control C.5 Privileged `gnatsd' commands ================================ Every `gnatsd' command has a minimum access level attached to it. If your access level is too low for a command, you get this response: LOCK 12 422 You are not authorized to perform this operation (LOCK). The commands `CHDB', `USER' and `QUIT' are unrestricted. The `DBLS' command requires at least `listdb' access. A user must have at least `edit' access for these commands: `LKDB' lock the main GNATS database. `UNDB' unlock the main GNATS database. `LOCK PR USER PID' lock PR for USER and optional PID and return PR text. `UNLK PR' unlock PR. `EDIT PR' check in edited PR. `APPN PR FIELD, REPL PR FIELD' Appends to or replaces the contents of FIELD in PR. The `DELETE' PR command is special in that it requires `admin' access. All other commands require `view' access. `edit-pr' and `query-pr' accept the command line arguments `-v|--user' and `-w|--passwd'. *Note The GNATS User Tools: GNATS user tools.  File: gnats.info, Node: Regexps, Next: dbconfig recipes, Prev: Access Control, Up: Top Appendix D Querying using regular expressions ********************************************* See also *Note Query expressions::. Unfortunately, we do not have room in this manual for a complete exposition on regular expressions. The following is a basic summary of some regular expressions you might wish to use. _NOTE: When you use query expressions containing regular expressions as part of an ordinary query-pr shell command line, you need to quote them with `''', otherwise the shell will try to interpret the special characters used, yielding highly unpredictable results._ *Note Regular Expression Syntax: (regex)Regular Expression Syntax, for details on regular expression syntax. Also see *Note Syntax of Regular Expressions: (emacs)Regexps, but beware that the syntax for regular expressions in Emacs is slightly different. All search criteria options to `query-pr' rely on regular expression syntax to construct their search patterns. For example, query-pr --expr 'State="open"' --format full matches all PRs whose `State' values match with the regular expression `open'. We can substitute the expression `o' for `open', according to GNU regular expression syntax. This matches all values of `State' which begin with the letter `o'. We see that query-pr --expr 'State="o"' --format full is equivalent to query-pr --expr 'State="open"' --format full in this case, since the only value for `State' which matches the expression `o' in a standard installation is `open'. `State="o"' also matches `o', `oswald', and even `oooooo', but none of those values are valid states for a Problem Report in default GNATS installations. We can also use the expression operator `|' to signify a logical `OR', such that query-pr --expr 'State="o|a"' --format full matches all `open' or `analyzed' Problem Reports. Regular expression syntax considers a regexp token surrounded with parentheses, as in `(REGEXP)', to be a "group". This means that `(ab)*' matches any number (including zero) of contiguous instances of `ab'. Matches include `', `ab', and `ababab'. Regular expression syntax considers a regexp token surrounded with square brackets, as in `[REGEXP]', to be a "list". This means that `Char[(ley)(lene)(broiled)' matches any of the words `Charley', `Charlene', or `Charbroiled' (case is significant; `charbroiled' is not matched). Using groups and lists, we see that query-pr --expr 'Category="gcc|gdb|gas"' --format full is equivalent to query-pr --expr 'Category="g(cc|db|as)"' --format full and is also very similar to query-pr --expr 'Category="g[cda]"' --format full with the exception that this last search matches any values which begin with `gc', `gd', or `ga'. The `.' character is known as a "wildcard". `.' matches on any single character. `*' matches the previous character (except newlines), list, or group any number of times, including zero. Therefore, we can understand `.*' to mean "match zero or more instances of any character." query-pr --expr 'State=".*a"' --format full matches all values for `State' which contain an `a'. (These include `analyzed' and `feedback'.) Another way to understand what wildcards do is to follow them on their search for matching text. By our syntax, `.*' matches any character any number of times, including zero. Therefore, `.*a' searches for any group of characters which end with `a', ignoring the rest of the field. `.*a' matches `analyzed' (stopping at the first `a') as well as `feedback'. _Note:_ When using `fieldtype:Text' or `fieldtype:Multitext' (*note Query expressions::), you do not have to specify the token `.*' at the beginning of your expression to match the entire field. For the technically minded, this is because these queries use `re_search' rather than `re_match'. `re_match' "anchors" the search at the beginning of the field, while `re_search' does not anchor the search. For example, to search in the `>Description:' field for the text The defrobulator component returns a nil value. we can use query-pr --expr 'fieldtype:Multitext="defrobulator.*nil"' --format full To also match newlines, we have to include the expression `(.|^M)' instead of just a dot (`.'). `(.|^M)' matches "any single character except a newline (`.') _or_ (`|') any newline (`^M')." This means that to search for the text The defrobulator component enters the bifrabulator routine and returns a nil value. we must use query-pr --expr 'fieldtype:Multitext="defrobulator(.|^M)*nil"' --format full To generate the newline character `^M', type the following depending on your shell: `csh' `_control_-V _control_-M' `tcsh' `_control_-V _control_-J' `sh (_or_ bash)' Use the key, as in (.| ) Again, see *Note Regular Expression Syntax: (regex)Regular Expression Syntax, for a much more complete discussion on regular expression syntax.  File: gnats.info, Node: dbconfig recipes, Next: Support, Prev: Regexps, Up: Top Appendix E `dbconfig' recipes ***************************** The `dbconfig' file (*Note The `dbconfig' file: dbconfig file.) is the heart of any GNATS installation. It contains some very powerful machinery, something which this appendix tries to illustrate. We provide a range of examples that are both intended to be useful in their own right and to serve as starting points or building blocks for your own modifications. Provide Gnatsweb URL in initial response ........................................ Sites that have Gnatsweb installed may wish to modify the response e-mail which is sent to the submitter of a PR so that it includes a URL where the status of the PR can be monitored. In order to allow this, you should first create an entry in `gnatsd.user_access' which allows viewing of PRs in your database (*Note The `gnatsd.user_access' file: gnatsd.user_access.) Next, locate the entry `mail-format "initial-response-to-submitter"' in the `dbconfig' file of your database and add the following _before_ the line reading "The individual assigned..." in the `body' section: \nYou can follow the status of this report on\n\ http://hostname/cgi-bin/scriptname?\n\ cmd=view&database=dbname&user=username&\n\ password=passwd&pr=%s\n\n\ Substitute `hostname', `cgi-bin' and `scriptname' as appropriate for the setup of your web server. The part before the `?' would typically look something like `http://www.example.com/cgi-bin/gnatsweb.pl'. Substitute the name of your database for `dbname', and the username and password of the user with `view' rights for `username' and `passwd'. Next, add a `Number' to the `fields' list statement inside the `body' so it reads as follows: fields { "Category" "Number" "Number" "Responsible" "Category" "Responsible" "Synopsis" "Arrival-Date" } State full name of responsible in initial response .................................................. The initial e-mail response to the submitter of a PR identifies the responsible person assigned to the PR as follows: "The individual assigned to look at your report is: GNATS USERNAME". Some sites may wish to modify this so that the full name of the responsible person is used instead of the GNATS user name. The full name is contained in the `fullname' subfield of the user's entry in the `responsible' file and can be accessed as `Responsible[fullname]' (*note Enumerated field administrative files: administrative files.) The change is achieved by editing the `dbconfig' item `mail-format "initial-response-to-submitter"' and changing the `fields' part of the `Body' from fields { "Category" "Number" "Responsible" "Category" "Responsible" "Synopsis" "Arrival-Date" } to fields { "Category" "Number" "Responsible[fullname]" "Category" "Responsible" "Synopsis" "Arrival-Date" } Append-only Audit-Trail ....................... The Audit-Trail of a PR is by default editable. For some applications, one might want to make the Audit-Trail append-only, so it provides a full and unchangeable case history. Also by default, only certain changes, such as change of state and change of responsible gets recorded in the Audit-Trail. In some cases, it might also be convenient to have a way of inserting comments directly into the Audit-Trail. The following procedure creates such an append-only Audit-Trail and adds a PR field which makes it possible to register comments in the Audit-Trail. First, add the keyword `read-only' to the Audit-Trail field definition in `dbconfig'. Then, add the following field definition to `dbconfig': field "Add-To-Audit-Trail" { description "Add a log entry to the Audit Trail" multitext { default "\n" } on-change { add-audit-trail audit-trail-format { format "**** Comment added by %s on %s ****\n %s\n\n" fields { "$EditUserEmailAddr" "$CurrentDate" "$NewValue" } } } on-change { set-field "Add-To-Audit-Trail" { "\n" } } } Supporting GNATS "release-based" fields ....................................... When installing GNATS version 3.x, it was possible to choose whether to enable three optional fields: `Quarter', `Keywords' and `Date-Required'. Default installations had these fields switched off, and installations which had them were called "release-based". The default `dbconfig' shipped with GNATS version 4 or newer does not have these fields, so if you are upgrading from an old release-based system, you need to add the following field definitions to your `dbconfig' file: field "Quarter" { description "What quarter does the PR fall into?" text query-default inexact-regexp textsearch } field "Keywords" { description "Keywords used to index this PR" text query-default inexact-regexp textsearch } field "Date-Required" { description "Date that the PR must be fixed by" date } A side note: Pre-release versions of GNATS 4 also had a field named `Cases'. For those who may need it, here is the field definition of `Cases': field "Cases" { text query-default inexact-regexp textsearch }  File: gnats.info, Node: Support, Next: Index, Prev: dbconfig recipes, Up: Top Appendix F GNATS support ************************ The GNATS home page is located at `http://www.gnu.org/software/gnats'. It contains all the important references to the available information about GNATS and the related software. There is also a special page dedicated to the GNATS development at `http://savannah.gnu.org/projects/gnats'. There are several GNATS mailing lists. The most important ones are: Announcements and other important information about GNATS and the related software. This is a very low volume moderated list. The bug reporting mailing list on the GNATS itself. Please note that the preferred way to report GNATS bugs is to submit them via the web interface at `http://bugs.gnu.org/cgi-bin/gnatsweb.pl?database=gnats'. New bug reports submitted via the web interface are copied to the mailing list automatically. General discussion about GNATS. Anything related to GNATS (user questions, development, suggestions, etc.) can be discussed there. The complete list of GNATS related mailing lists is available from the web page at `http://savannah.gnu.org/project/gnats'. When you report problems concerning GNATS itself, please do not forget to provide especially the following information: * The GNATS version you are using. * The _exact_ way how to reproduce the bug. * Your configuration. * If you encounter a compilation or build problem, it is especially important to mention the operating system, compiler and possibly other build utilities you use. Providing this information in the initial report avoids further unnecessary communication, saves our limited development resources and helps to track down and fix the problem soon.  File: gnats.info, Node: Index, Prev: Support, Up: Top Index ***** [index] * Menu: * -with-gnats-dblist-file: Configure and make. (line 112) * -with-gnats-default-db: Configure and make. (line 117) * -with-gnats-service: Configure and make. (line 91) * -with-gnats-user: Configure and make. (line 95) * -with-gnatsd-host-access-file: Configure and make. (line 106) * -with-gnatsd-user-access-file: Configure and make. (line 99) * -with-kerberos: Configure and make. (line 123) * -with-krb4: Configure and make. (line 126) * >Submitter-Id: PR template. (line 108) * _analyzed_ state: States. (line 19) * _change-request_ class: Problem Report fields. (line 108) * _closed_ state: States. (line 30) * _critical_ severity problems: Problem Report fields. (line 63) * _doc-bug_ class: Problem Report fields. (line 105) * _duplicate_ class: Problem Report fields. (line 114) * _feedback_ state: States. (line 25) * _high_ priority problems: Problem Report fields. (line 83) * _low_ priority problems: Problem Report fields. (line 89) * _medium_ priority problems: Problem Report fields. (line 86) * _mistaken_ class: Problem Report fields. (line 118) * _non-critical_ severity problems: Problem Report fields. (line 74) * _open_ state: States. (line 15) * _serious_ severity problems: Problem Report fields. (line 68) * _support_ class: Problem Report fields. (line 111) * _suspended_ state: States. (line 35) * _sw-bug_ class: Problem Report fields. (line 102) * adding a problem category <1>: mkcat. (line 6) * adding a problem category: Management. (line 40) * adding and removing maintainers: Management. (line 60) * adding another database: Management. (line 34) * addresses file <1>: addresses file. (line 6) * addresses file: GNATS configuration. (line 71) * admin files: Admin files. (line 6) * administering GNATS: Management. (line 6) * administrative utilities: Admin utils. (line 6) * age of PR: pr-age. (line 6) * alias for incoming Problem Reports: Aliases. (line 21) * aliases: Aliases. (line 6) * appended-email-response: Outgoing email formats. (line 57) * arrival-date: Individual field configuration. (line 38) * Arrival-Date field: Problem Report fields. (line 203) * at: Setting up the default database. (line 53) * at-pr: at-pr. (line 6) * audit-mail: Outgoing email formats. (line 61) * audit-trail: Individual field configuration. (line 41) * Audit-Trail field: Problem Report fields. (line 212) * Audit-trail format: Audit-trail formats. (line 6) * autoload commands: Installing utils. (line 28) * automatic notification <1>: at-pr. (line 6) * automatic notification: States. (line 8) * BACK UP YOUR DATA: Management. (line 77) * bad Problem Reports: PR template. (line 113) * bug alias: Aliases. (line 21) * bug reporting: Support. (line 34) * building a new index: Management. (line 65) * building GNATS: Installation. (line 6) * building in a different directory: Configure and make. (line 136) * builtin-name: Individual field configuration. (line 29) * bury-buffer: Emacs querying. (line 45) * business-day-hours: Overall database configuration. (line 46) * business-week-days: Overall database configuration. (line 53) * categories file <1>: rmcat. (line 6) * categories file <2>: mkcat. (line 6) * categories file <3>: categories file. (line 6) * categories file: GNATS configuration. (line 48) * category: Individual field configuration. (line 44) * Category field: Problem Report fields. (line 92) * category-dir-perms: Overall database configuration. (line 67) * check-db: check-db. (line 6) * Class field: Problem Report fields. (line 98) * classes file <1>: classes file. (line 6) * classes file: GNATS configuration. (line 82) * closed-date: Individual field configuration. (line 47) * command line options: send-pr from the shell. (line 6) * comment section in the PR template: PR template. (line 25) * compiling the software: Configure and make. (line 6) * confidential: Individual field configuration. (line 50) * Confidential field: Problem Report fields. (line 42) * confidentiality in PRs: Problem Report fields. (line 42) * configure: Configure and make. (line 6) * configuring GNATS: Installation. (line 6) * configuring and compiling the software: Configure and make. (line 6) * configuring GNATS for remote users: Installing tools. (line 59) * configuring GNATS on a local network: Installing tools. (line 30) * configuring GNATS on a network: Installing tools. (line 6) * create-category-dirs: Overall database configuration. (line 61) * creating an account for the GNATS user: Configure and make. (line 31) * cron: Setting up the default database. (line 53) * crontab: Setting up periodic jobs. (line 14) * current file: current file. (line 6) * daemon: Installing the daemon. (line 6) * database paradigm: Paradigm. (line 6) * database rationale: Introduction. (line 6) * database similarities: Fields. (line 6) * databases: GNATS configuration. (line 20) * databases file: databases file. (line 6) * datatype: Field datatypes. (line 10) * date: Field datatypes. (line 134) * Date-Required: Problem Report fields. (line 207) * Date-Required field: Problem Report fields. (line 207) * dbconfig: dbconfig recipes. (line 6) * dbconfig file <1>: dbconfig file. (line 6) * dbconfig file: GNATS configuration. (line 44) * dbconfig mode: dbconfig mode. (line 6) * dbconfig recipes: dbconfig recipes. (line 6) * debug-mode: Overall database configuration. (line 17) * default installation locations <1>: defaults. (line 6) * default installation locations: Locations. (line 6) * defaults: GNATS configuration. (line 26) * deleted-pr-mail: Outgoing email formats. (line 65) * description: Individual field configuration. (line 53) * Description field: Problem Report fields. (line 134) * diff-prs: diff-prs. (line 6) * Direct e-mail: Submitting via e-mail. (line 6) * disabling SUBMITTER-ID: submitters file. (line 68) * driver for edit-pr: pr-edit. (line 6) * duties for gnats-admin: Management. (line 6) * edit controls: Edit controls. (line 6) * edit-pr <1>: Emacs editing. (line 6) * edit-pr: edit-pr. (line 6) * edit-pr driver: pr-edit. (line 6) * edit-pr from the shell: edit-pr from the shell. (line 6) * effective problem reporting: Helpful hints. (line 6) * Emacs: Emacs. (line 6) * Emacs functions: Installing utils. (line 28) * Emacs lisp file installation: Configure and make. (line 20) * emptying the pending directory: Management. (line 12) * enum: Field datatypes. (line 31) * enumerated-in-file: Field datatypes. (line 73) * Environment field: Problem Report fields. (line 129) * environment variables and GNATS tools: Environment. (line 6) * errors: PR template. (line 113) * example Problem Report: Fields. (line 34) * example queries: Example queries. (line 6) * EXEC-PREFIX <1>: exec-prefix. (line 6) * EXEC-PREFIX: Configure and make. (line 86) * Field datatypes: Field datatypes. (line 6) * field format: Problem Report fields. (line 6) * fields: Fields. (line 6) * fields - list: Problem Report fields. (line 18) * file-pr: file-pr. (line 6) * files used for GNATS administration: Admin files. (line 6) * final state ("closed"): States. (line 30) * Fix field: Problem Report fields. (line 149) * flowchart of GNATS activities: Flowchart. (line 6) * follow-up via email <1>: follow-up via email. (line 6) * follow-up via email: Problem Report fields. (line 234) * foreword: Top. (line 6) * format: Fields. (line 6) * format parameters: Audit-trail formats. (line 31) * format-name: Outgoing email formats. (line 42) * From header: Mail header fields. (line 23) * gen-index <1>: gen-index. (line 6) * gen-index: Management. (line 65) * GNATS administrator: Paradigm. (line 48) * GNATS configuration: GNATS configuration. (line 6) * GNATS database fields: Problem Report fields. (line 6) * GNATS fields - list: Problem Report fields. (line 18) * GNATS management: Management. (line 6) * GNATS support: Support. (line 6) * GNATS-ADM: gnats-adm. (line 6) * gnats-admin alias: Aliases. (line 15) * gnats-apply-or-submit: Emacs editing buffer. (line 47) * gnats-change-database <1>: Emacs and databases. (line 6) * gnats-change-database: Emacs querying. (line 41) * gnats-dbconfig-mode: dbconfig mode. (line 6) * gnats-dbconfig-mode-hook: dbconfig mode. (line 11) * GNATS-DEFAULT-ORGANIZATION: Emacs submitting. (line 19) * GNATS-DEFAULT-SUBMITTER: Emacs submitting. (line 23) * gnats-edit-mode-hook: Emacs editing buffer. (line 53) * gnats-next-field: Emacs editing buffer. (line 23) * gnats-previous-field: Emacs editing buffer. (line 23) * gnats-pwconv: gnats-pwconv. (line 6) * gnats-query-edit-pr: Emacs querying. (line 26) * gnats-query-mode-hook: Emacs querying. (line 57) * gnats-query-reread: Emacs querying. (line 30) * GNATS-QUERY-REVERSE-LISTING: Emacs querying. (line 50) * gnats-query-view-pr: Emacs querying. (line 20) * gnats-show-connection: Other Emacs commands. (line 16) * gnats-view-edit-pr: Emacs viewing. (line 9) * gnats-view-mode-hook: Emacs viewing. (line 13) * gnatsd: gnatsd. (line 6) * gnatsd command protocol: gnatsd command protocol. (line 6) * gnatsd commands: gnatsd commands. (line 6) * gnatsd description: Description of gnatsd. (line 6) * gnatsd environment variables: gnatsd environment variables. (line 6) * gnatsd options: gnatsd options. (line 6) * gnatsd startup options: gnatsd options. (line 12) * gnatsd, Emacs: Emacs and databases. (line 11) * gnatsd.host_access <1>: gnatsd.host_access. (line 6) * gnatsd.host_access: GNATS configuration. (line 31) * gnatsd.user_access <1>: gnatsd.user_access. (line 6) * gnatsd.user_access: GNATS configuration. (line 36) * gnatsd.user_access file: GNATS configuration. (line 88) * GNATSDB <1>: gnatsd environment variables. (line 6) * GNATSDB: Environment. (line 6) * handling incoming traffic: queue-pr. (line 6) * helpful hints: Helpful hints. (line 6) * How-To-Repeat field: Problem Report fields. (line 137) * incoming alias for Problem Reports: Aliases. (line 21) * incoming PRs that GNATS cannot parse: Paradigm. (line 62) * index file <1>: gen-index. (line 6) * index file: index file. (line 6) * Index file description: Index file description. (line 6) * Individual field configuration: Individual field configuration. (line 6) * information to submit: Helpful hints. (line 6) * Initial PR input fields: Initial PR input fields. (line 6) * initial state ("open"): States. (line 15) * initial-pr-notification: Outgoing email formats. (line 49) * initial-pr-notification-pending: Outgoing email formats. (line 53) * initial-response-to-submitter: Outgoing email formats. (line 43) * initializing a database: mkdb. (line 6) * installing GNATS: Installation. (line 6) * installing the utilities: Installing utils. (line 6) * integer: Field datatypes. (line 141) * interactive interface: send-pr in Emacs. (line 6) * internal utilities: Internal utils. (line 6) * Internet standard RFC-822: Mail header fields. (line 6) * introduction to GNATS: Introduction. (line 6) * invalid Problem Reports: PR template. (line 113) * invoking edit-pr: edit-pr. (line 6) * invoking query-pr: query-pr. (line 6) * invoking send-pr: send-pr. (line 6) * invoking send-pr from Emacs: send-pr in Emacs. (line 6) * invoking send-pr from the shell: send-pr from the shell. (line 6) * invoking the GNATS user tools: GNATS user tools. (line 6) * keep-all-received-headers: Overall database configuration. (line 23) * kinds of helpful information: Helpful hints. (line 6) * last-modified: Individual field configuration. (line 56) * libexecdir: Overall database configuration. (line 40) * life-cycle of a Problem Report: States. (line 8) * lisp file installation: Configure and make. (line 20) * loading .el files: Installing utils. (line 28) * locations: Locations. (line 6) * locks: pr-edit. (line 29) * mail aliases: Aliases. (line 6) * mail header fields: Mail header fields. (line 6) * mail header section: PR template. (line 48) * mailing lists: Support. (line 13) * maintenance: Paradigm. (line 6) * make: Configure and make. (line 6) * managing GNATS: Management. (line 6) * mkcat <1>: mkcat. (line 6) * mkcat: Management. (line 40) * mkdb <1>: mkdb. (line 6) * mkdb: Management. (line 34) * multi-enumerated-in-file: Field datatypes. (line 116) * multienum: Field datatypes. (line 52) * multitext: Field datatypes. (line 24) * Named query definitions: Named query definitions. (line 6) * networks: Installing tools. (line 6) * new database: mkdb. (line 6) * new problem categories: mkcat. (line 6) * notification of overdue PRs: at-pr. (line 6) * notify-about-expired-prs: Overall database configuration. (line 28) * Notify-List field: Problem Report fields. (line 29) * number: Individual field configuration. (line 59) * Number field: Problem Report fields. (line 157) * OBJDIR: Configure and make. (line 136) * Organization field: Problem Report fields. (line 39) * originator: Individual field configuration. (line 62) * Originator field: Problem Report fields. (line 35) * Outgoing email formats: Outgoing email formats. (line 6) * Overall database configuration: Overall database configuration. (line 6) * Overview of GNATS configuration: GNATS configuration. (line 6) * overview to GNATS: Top. (line 6) * paradigm: Paradigm. (line 6) * password, Emacs: Emacs and databases. (line 16) * pending directory: Paradigm. (line 62) * pending file: categories file. (line 77) * PR confidentiality: Problem Report fields. (line 42) * PR locks: pr-edit. (line 29) * pr-age: pr-age. (line 6) * pr-edit: pr-edit. (line 6) * PREFIX <1>: prefix. (line 6) * PREFIX: Configure and make. (line 80) * prepare send-pr.conf: Installing utils. (line 49) * priority: Individual field configuration. (line 65) * Priority field: Problem Report fields. (line 79) * Problem Report format: Fields. (line 6) * Problem Report states: States. (line 8) * Problem Report template: Fields. (line 34) * processing incoming traffic: file-pr. (line 6) * pruning log files: Management. (line 70) * query expressions: Query expressions. (line 6) * query-pr <1>: Emacs querying. (line 6) * query-pr: query-pr. (line 6) * query-pr by mail: Invoking query-pr. (line 10) * query-pr output format: Formatting query-pr output. (line 6) * querying individual problem reports: query-pr. (line 6) * querying using regexps: Regexps. (line 6) * queue-pr: queue-pr. (line 6) * queue-pr -q: Aliases. (line 21) * rationale: Introduction. (line 6) * Received-By headers: Mail header fields. (line 32) * regular expressions: Regexps. (line 6) * related mail <1>: follow-up via email. (line 6) * related mail: Problem Report fields. (line 234) * Release field: Problem Report fields. (line 125) * reminder message: at-pr. (line 24) * removing a problem category <1>: rmcat. (line 6) * removing a problem category: Management. (line 48) * Reply-To header: Mail header fields. (line 28) * Report all the facts!: Helpful hints. (line 6) * reporting problems with send-pr: send-pr. (line 6) * responsible: Individual field configuration. (line 68) * Responsible field: Problem Report fields. (line 198) * responsible file <1>: responsible file. (line 6) * responsible file: GNATS configuration. (line 57) * Responsible-Changed-- in Audit-Trail: Problem Report fields. (line 219) * Responsible-Changed-By in Audit-Trail: Problem Report fields. (line 222) * Responsible-Changed-When in Audit-Trail: Problem Report fields. (line 226) * Responsible-Changed-Why in Audit-Trail: Problem Report fields. (line 230) * rmcat <1>: rmcat. (line 6) * rmcat: Management. (line 48) * sample Problem Report: Fields. (line 34) * send-pr <1>: Emacs submitting. (line 6) * send-pr <2>: Emacs querying. (line 38) * send-pr: send-pr. (line 6) * send-pr fields <1>: PR template. (line 86) * send-pr fields: send-pr from the shell. (line 50) * send-pr within Emacs: send-pr in Emacs. (line 6) * send-pr.conf file: send-pr.conf file. (line 6) * send-submitter-ack: Overall database configuration. (line 33) * setting up GNATS: Installation. (line 6) * severity: Individual field configuration. (line 71) * Severity field: Problem Report fields. (line 59) * shell invocation: send-pr from the shell. (line 6) * Site wide configuration files: GNATS configuration. (line 19) * so what does it do: Paradigm. (line 6) * state: Individual field configuration. (line 74) * State field: Problem Report fields. (line 172) * state--"analyzed": States. (line 19) * state--"closed": States. (line 30) * state--"feedback": States. (line 25) * state--"open": States. (line 15) * state--"suspended": States. (line 35) * State-Changed-- in Audit-Trail: Problem Report fields. (line 216) * State-Changed-By in Audit-Trail: Problem Report fields. (line 222) * State-Changed-When in Audit-Trail: Problem Report fields. (line 226) * State-Changed-Why in Audit-Trail: Problem Report fields. (line 230) * states file <1>: states file. (line 6) * states file: GNATS configuration. (line 78) * states of Problem Reports: States. (line 8) * Subject header: Mail header fields. (line 19) * submitter-id: Individual field configuration. (line 77) * Submitter-Id field <1>: PR template. (line 108) * Submitter-Id field: Problem Report fields. (line 18) * submitters file <1>: submitters file. (line 6) * submitters file: GNATS configuration. (line 66) * Submitting a PR via e-mail: Submitting via e-mail. (line 6) * subsequent mail <1>: follow-up via email. (line 6) * subsequent mail: Problem Report fields. (line 234) * support site: Paradigm. (line 6) * synopsis: Individual field configuration. (line 80) * Synopsis field: Problem Report fields. (line 55) * syntax of regexps: Regexps. (line 6) * template: PR template. (line 11) * template comment section: PR template. (line 25) * text: Field datatypes. (line 14) * the section on query-by-mail needs to be relocated: Invoking query-pr. (line 17) * timely reminders: at-pr. (line 6) * To header: Mail header fields. (line 14) * unformatted: Individual field configuration. (line 83) * Unformatted field: Problem Report fields. (line 240) * unlock-database: Other Emacs commands. (line 12) * unlock-pr: Other Emacs commands. (line 6) * unpacking the distribution: Configure and make. (line 6) * unparseable incoming PRs: Paradigm. (line 62) * upgrade, procedure: Upgrading. (line 53) * upgrading from older versions: Upgrading. (line 6) * upgrading, overview: Upgrading. (line 15) * usage for the GNATS user tools: GNATS user tools. (line 6) * Using and Porting GNU CC: Helpful hints. (line 6) * using edit-pr: edit-pr. (line 6) * using GNATS over a local network: Installing tools. (line 30) * using GNATS over a network <1>: Installing tools. (line 6) * using GNATS over a network: Installing the daemon. (line 6) * using GNATS remotely: Installing tools. (line 59) * using query-pr: query-pr. (line 6) * using send-pr: send-pr. (line 6) * using send-pr from within Emacs: send-pr in Emacs. (line 6) * view-pr: Emacs viewing. (line 6) * visual map of data flow: Flowchart. (line 6) * what is a PR: Paradigm. (line 25) * where GNATS lives: Locations. (line 6) * why GNATS: Paradigm. (line 6)  Tag Table: Node: Top824 Node: Introduction2803 Node: Paradigm3904 Node: Flowchart8894 Node: States11061 Node: Fields12633 Node: Field datatypes reference15305 Node: Mail header fields16300 Node: Problem Report fields17795 Node: GNATS user tools27193 Node: Environment28316 Node: send-pr29167 Node: send-pr from the shell29912 Node: send-pr in Emacs32172 Ref: send-pr in Emacs-Footnote-132850 Node: PR template32966 Node: Submitting via e-mail38301 Node: Helpful hints39386 Node: edit-pr42488 Node: edit-pr from the shell44853 Node: follow-up via email46894 Node: query-pr48842 Node: Invoking query-pr50321 Node: Formatting query-pr output59526 Node: Query expressions62056 Node: Example queries66361 Node: Emacs67416 Node: Emacs viewing68874 Node: Emacs querying69415 Node: Emacs submitting71356 Node: Emacs editing72398 Node: Emacs editing buffer73035 Node: Emacs and databases75614 Node: dbconfig mode76625 Node: Other Emacs commands77107 Node: Emacs customization78034 Node: Installation78295 Node: Configure and make81248 Node: Installing utils87733 Node: Setting up the default database89729 Ref: Setting up the default database-Footnote-192063 Node: Setting up periodic jobs92199 Node: Aliases93345 Node: Installing the daemon95754 Node: Installing tools98798 Node: Upgrading104350 Node: Management112628 Node: GNATS configuration116672 Node: databases file120943 Node: dbconfig file123039 Node: Overall database configuration125274 Node: Individual field configuration128545 Node: Field datatypes132785 Ref: administrative files135772 Node: Edit controls138854 Node: Named query definitions141331 Node: Audit-trail formats142437 Node: Outgoing email formats144143 Node: Index file description150683 Node: Initial PR input fields152046 Node: Other config files152786 Node: categories file153104 Node: responsible file156394 Node: submitters file157781 Node: states file160786 Node: addresses file163710 Node: classes file165615 Node: send-pr.conf file166557 Node: Admin files168953 Node: index file169396 Node: current file170820 Node: Admin utils171084 Node: mkdb171665 Node: mkcat172278 Node: rmcat172937 Node: gen-index173744 Node: check-db175362 Node: gnats-pwconv176693 Node: Internal utils177830 Node: queue-pr178398 Node: file-pr180373 Node: at-pr183438 Node: pr-edit185053 Ref: pr-edit-Footnote-1191954 Node: diff-prs192048 Node: pr-age192452 Node: Locations193079 Node: prefix193520 Node: exec-prefix194258 Node: gnats-adm196745 Node: defaults197531 Node: gnatsd201912 Node: Description of gnatsd202389 Node: gnatsd options203699 Node: gnatsd command protocol205397 Node: gnatsd commands209683 Node: gnatsd environment variables232509 Node: Access Control233204 Node: Overview233575 Node: Overall gnatsd access level234468 Node: gnatsd.host_access235371 Node: gnatsd.user_access237173 Ref: gnatsd.user_access-Footnote-1241609 Ref: gnatsd.user_access-Footnote-2241696 Ref: gnatsd.user_access-Footnote-3241850 Node: Privileged gnatsd commands242045 Node: Regexps243189 Node: dbconfig recipes248306 Ref: release-based support252418 Node: Support253561 Node: Index255470  End Tag Table gnats-4.1.0/doc/gnats-faq.info0000600000175000017500000012412410212665130016655 0ustar chewiechewie00000000000000This is gnats-faq.info, produced by makeinfo version 4.7 from gnats-faq.texi. START-INFO-DIR-ENTRY * GNATS FAQ: (gnats-faq). FAQ for the GNU Problem Report Management System END-INFO-DIR-ENTRY Copyright (C) 2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the sections entitled "Copying" and "GNU General Public License" are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation.  File: gnats-faq.info, Node: Top, Next: General, Up: (dir) GNATS Frequently Asked Questions ******************************** This document answers some frequently asked questions concerning GNATS, the GNU problem report management system, and related software. The most recent version of this FAQ can be found at `http://www.gnu.org/software/gnats/doc/faq/gnats-faq.html'. The questions and answers have been compiled by Hans-Albert Schneider , mainly using the help-gnats mailing list and the GNATS documentation as input. Please report any errors and suggestions to him. * Menu: * General:: General questions * Installation:: Problems during installation * Configuration:: Problems with GNATS configuration * Clients:: Ways to access a GNATS system * Glossary:: Abbreviations and definitions * Index:: Important things and where they are referenced  File: gnats-faq.info, Node: General, Next: Installation, Prev: Top, Up: Top 1 General Questions ******************* * Menu: * What is GNATS:: A very short overview * How to pronounce it:: Pronunciation: with or without the "G"? * Get it:: Where to get GNATS * Versions:: Which versions are available? * Mailing Lists:: E-mail discussion lists * Bug Reporting:: How to report a bug * Upgrading:: Considerations for the 3.x to 4.0 transition  File: gnats-faq.info, Node: What is GNATS, Next: How to pronounce it, Up: General 1.1 What is GNATS? ================== GNATS is the GNU problem report management system. Problem report management systems are also known as "bug-tracking systems", though the entries need not be bugs (e.g., think of change requests). The acronym stands for "GNats: A Tracking System". GNATS stores all information about the problem reports at a central site, and enables users to access this site by various means, including e-mail, WWW, and a network daemon. New problem reports can be created, and existing reports can be queried and updated, by most of these means. GNATS is widely customizable: Of course you can define report categories (is the report about tool A or service B?), responsibles (who takes care of this report?), and submitters (is it from customer1 or from the sales department?). You can also define possible states of a report (open, analyzed, closed, etc.) and classes (software bug, documentation bug, change request, ...). Starting with GNATS 4.0, you can define your own custom fields, and customize many of the built-in fields; you can have fields automatically set to a certain value when another field changes its contents (e.g., set a "Closed-Date" field to the current date when the report goes to state "closed", and unset it when it goes back from "closed" to something else), or when the report is changed at all (e.g., to maintain a "Last-Modified" field). * Menu: * User view:: Short overview for users * Administrator View:: Short overview for system administrators  File: gnats-faq.info, Node: User view, Next: Administrator View, Up: What is GNATS 1.1.1 How it Works--User's View ------------------------------- Users enter their problem reports (PRs) via some front-end. This front-end either directly contacts the GNATS server, or sends the report via e-mail. (The server is available since about version 3.90 of GNATS). For an incomplete list of front-ends see *Note Clients::. Some front-ends (like TkGnats, see *Note TkGnats::) are capable of contacting several GNATS servers, or several problem report databases managed by the same GNATS server.  File: gnats-faq.info, Node: Administrator View, Prev: User view, Up: What is GNATS 1.1.2 How it Works--Administrator's View ---------------------------------------- The server is started by a super-server like inetd or xinetd. It has a built-in access control mechanism based on IP addresses and username/password. For users sending their PRs via e-mail, some mail addresses must be configured.  File: gnats-faq.info, Node: How to pronounce it, Next: Get it, Prev: What is GNATS, Up: General 1.2 How is "GNATS" pronounced? ============================== Q: So, How can I pronounce "GNATS?" Should I pronounce "G"? It has been reported that the original developers pronounced the "G". (This is unlike the little insect called "gnat" where the "G" is not pronounced.)  File: gnats-faq.info, Node: Get it, Next: Versions, Prev: How to pronounce it, Up: General 1.3 Where do I get it? ====================== See the GNATS home page at `http://www.gnu.org/software/gnats/'. The current development version is available via CVS only, see the GNU savannah GNATS project page (http://savannah.gnu.org/projects/gnats) for the instructions how to get it.  File: gnats-faq.info, Node: Versions, Next: Mailing Lists, Prev: Get it, Up: General 1.4 What is the latest version? =============================== The version numbers of GNATS 3.x is somewhat confusing, because 3.1xx is newer than 3.2. Version 3.2 was released in 1993 (I never tried it, but it is said to be "really broken"). A lot of new features have been added since 3.2, including multiple database support and customized fields. Among the contributed software are comprehensive WWW and Tk based front-ends. The latest 3.x release is 3.113.1. It is deprecated due to security concerns and lack of maintenance. GNATS 4.0 was released in August 2003, and 4.1 was released in March 2005. All released versions are available for download at `http://ftp.gnu.org/pub/gnu/gnats/'.  File: gnats-faq.info, Node: Mailing Lists, Next: Bug Reporting, Prev: Versions, Up: General 1.5 Is there a Mailing List? ============================ Currently, the following GNATS mailing lists exist: * info-gnats@gnu.org (http://lists.gnu.org/mailman/listinfo/info-gnats) This is a low volume moderated mailing lists for GNATS related announcements, like new releases or important information. * help-gnats@gnu.org (http://lists.gnu.org/mailman/listinfo/help-gnats) A low-to-middle volume mailing list where anything related to GNATS can be discussed (development, help, questions, suggestions, etc.). * bug-gnats@gnu.org (http://lists.gnu.org/mailman/listinfo/bug-gnats) Bug reports can be sent there. Please note that it's preferred to submit bug reports via the bug tracking system (*note Bug Reporting::), which automatically mirrors them to this list. Lists that are of interest mainly for the GNATS developers: * gnats-prs@gnu.org (http://lists.gnu.org/mailman/listinfo/gnats-prs) Copies of the bug tracking system messages are sent there. Contrast to bug-gnats@gnu.org which only gets new bug reports, this list also gets the follow-ups (Whatever goes into GNATS' `>Audit-Trail:' field). * gnats-commit@gnu.org (http://lists.gnu.org/mailman/listinfo/gnats-commit) CVS commit messages are sent there. * gnats-diffs@gnu.org (http://lists.gnu.org/mailman/listinfo/gnats-diffs) Diffs of committed files are sent automatically to this address.  File: gnats-faq.info, Node: Bug Reporting, Next: Upgrading, Prev: Mailing Lists, Up: General 1.6 How do I Report a Bug? ========================== Before reporting a bug, make sure it really is a bug, not a simple misunderstanding or a misconfiguration. Please check the manual and this FAQ. You may also ask for help on the help-gnats@gnu.org (http://lists.gnu.org/mailman/listinfo/help-gnats) mailing list (you may want to search the list archive first; it is available from `http://lists.gnu.org/mailman/listinfo/help-gnats'). If it is a bug, please report it via the bug tracking system. It resides at `http://bugs.gnu.org/cgi-bin/gnatsweb.pl?database=gnats'. This is a common bug database for GNATS, Gnatsweb and TkGnats. (And, yes, of course: It uses GNATS and Gnatsweb.) When you report problems concerning GNATS itself, please do not forget to provide especially the following information: * The GNATS version you are using. If your problem involves Gnatsweb or TkGnats, please also report their versions. * The _exact_ way how to reproduce the bug. * Your configuration. * If you encounter a compilation or build problem, it is especially important to mention the operating system, compiler and possibly other build utilities you use. Providing this information in the initial report avoids further unnecessary communication, saves the limited resources of the developers (keep in mind that they are working on GNATS and friends in their spare time) and helps to track down and fix the problem soon.  File: gnats-faq.info, Node: Upgrading, Prev: Bug Reporting, Up: General 1.7 Upgrading Considerations ============================ See *Note Upgrading from older versions: (gnats)Upgrading. for the upgrade process from 3.x to 4.x. If you are running a 3.x version, _please consider upgrading to 4.0._ There are some security concerns about the 3.1xx code that have gone with 4.0. Furthermore, the GNATS 3 branch is not maintained anymore due to lack of capacity. The default format of the reports has not changed during the transition from 3.113.1 to 4.0, though you may add more fields to 4.0 reports (and leave out others). The format of the index file is now binary. However, you have to change the e-mail aliases because the meaning of the `-d' option to the client programs has changed: It took the _directory_ of the GNATS database in 3.1xx, and now takes its _name_ (plus, it is now installed into the `libexec' directory instead of the `lib' directory). I.e., you must change the aliases: # GNATS 3 aliases: ourdb-query: "|/usr/local/lib/gnats/mail-query -d /usr/local/gnats/db2" ourdb-bugs: "|/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -q" to # GNATS 4 aliases: ourdb-query: "|/usr/local/libexec/gnats/mail-query -d ourdb" ourdb-bugs: "|/usr/local/libexec/gnats/queue-pr -d ourdb -q" Also note that the client/server protocol has changed from 3.1xx to 4.0; you cannot run clients from one version with the server from the other version.  File: gnats-faq.info, Node: Installation, Next: Configuration, Prev: General, Up: Top 2 Problems during Installation ****************************** As installation and configuration problems often overlap, please check also *Note Configuration::. * Menu: * Gnatsweb and GNATS:: Cooperation problems between GNATS and Gnatsweb  File: gnats-faq.info, Node: Gnatsweb and GNATS, Prev: Installation, Up: Installation 2.1 Gnatsweb and GNATS do not like each other. ============================================== Q: I have installed GNATS 3.999.x and Gnatsweb 2.9.x, and I cannot get them work together. Symptoms are that "make test" fails; if Gnatsweb is installed nevertheless, it hangs when trying to login into the GNATS server. A: The versions are incompatible. Gnatsweb 2.9.x is for use with GNATS 3.113.1. With GNATS 3.999.x, you must use Gnatsweb 3.99.x; it is in the contrib subdirectory of the GNATS distribution. (GNATS 3.999.x/Gnatsweb 3.99.x were pre-releases of the 4.0 releases. As 4.0 is out now, you may consider to upgrade to the non-pre versions.) For GNATS 4.x, use Gnatsweb 4.0 or greater.  File: gnats-faq.info, Node: Configuration, Next: Clients, Prev: Installation, Up: Top 3 Configuration Issues ********************** * Menu: * General configuration:: General questions about GNATS configuration * Gnatsd:: Configuration of the GNATS daemon * E-Mail:: Problems with the e-mail interface * Miscellaneous:: Other configuration problems  File: gnats-faq.info, Node: General configuration, Next: Gnatsd, Up: Configuration 3.1 General Configuration Questions =================================== * Menu: * Add a database:: How to create a new database * Renaming a Category:: How to rename categories * Changing Fields:: Add, remove, or rename a PR field  File: gnats-faq.info, Node: Add a database, Next: Renaming a Category, Up: General configuration 3.1.1 How do I add a new database? ---------------------------------- A: (GNATS 3.1xx) (Please consider upgrading to GNATS 4.0 or greater.) 1. Create the base directory for the new database, say `/usr/local/gnats/db2', and make sure it is owned by the GNATS user. 2. In there, create subdirectories `gnats-adm', `gnats-adm/locks', and `gnats-queue', and make sure they is owned by the GNATS user. 3. Now you need to populate the new `gnats-adm' directory. The easiest way is to copy all files from `gnats-db/gnats-adm' to `/usr/local/gnats/db2/gnats-adm', and edit them to reflect the needs of your new database. Again, make sure they are owned by the gnats user. Note that there _must_ be a category named `pending'. It is used when no category is given in a report, and when a report names an invalid category. Also note that each database needs its own mail address for submissions (see also step 8 below), and that you must enter it in the file `config'. 4. As the GNATS user, run `mkcat --directory=/usr/local/gnats/db2' to create the directories for the categories. Remove the files `current' and `index', if they exist. 5. If the new database is split off of another one, move or copy the existing reports to their new location. This is easiest if the categories have the same names as in the original database. (See *Note Renaming a Category:: if some of them changed names.) Run the program `gen-index' to create the index file (*note Regenerating the index: (gnats)gen-index.). Find the greatest report number and put it (or any larger number) into `/usr/local/gnats/db2/gnats-adm/current'. *Caution:* E-mail updates to the PRs you moved to the new database may still arrive at the old database. You may want to contact everybody who knows about these PRs, asking them to use the mail address of the new database when sending a follow-up. 6. Now add a line for the new database to `gnats-db.conf', like this: `/usr/local/gnats/db2:GreatNewDB' Gnatsd reads it on startup (and as it is started by inetd, this means it becomes effective with the next connection to gnatsd). Gnatsweb (see *Note Gnatsweb::) learns the database list from gnatsd, so it will offer you the new database "GreatNewDB" when it is invoked next time. If you do not know where `gnats-db.conf' lives, run: `strings /where/ever/gnatsd | grep gnats-db.conf' 7. Don't forget to setup a cron job to run through the additional `gnats-queue'. Note that you need to specify the database directory to `queue-pr', i.e., `/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -r' or, if you prefer the long options, `/usr/local/lib/gnats/queue-pr --directory=/usr/local/gnats/db2 --run' 8. Don't forget to create mail aliases for your new database (*note Setting up mail aliases: (gnats)Aliases.). Take care that the aliases have the right database, e.g., GreatNewDB-bugs: "|/usr/local/lib/gnats/queue-pr -d /usr/local/gnats/db2 -q" GreatNewDB-query: "|/usr/local/lib/gnats/mail-query -d /usr/local/gnats/db2" If you do not want to allow querying the database by mail, omit the `GreatNewDB-query' alias. You usually need the cooperation of a system administrator for this step (if you are not a system administrator yourself, of course). Make sure that `/usr/local/gnats/db2/gnats-adm/config' gives the correct mail addresses for GNATS_ADDR (this _must_ be different for each database) and for GNATS_ADMIN (this is probably the same for all databases). GNATS_ADDR="GreatNewDB-bugs@bugs.example.com" GNATS_ADMIN="gnats-admin@bugs.example.com" If your GNATS sits behind a firewall and needs to exchange mails with the outside world, see also *Note Outgoing mail bounces::. A: (GNATS 4.x) With version 4, this has become much easier (*note Adding another database: (gnats)mkdb.): 1. Add a line for the new database to `databases', like this: `GreatNewDB:Our great tools:/usr/local/gnats/db2' Then, as the GNATS user, run `mkdb GreatNewDB' to create the database. Make sure that the directory (in our example, `/usr/local/gnats/db2') can be created by the GNATS user. (Note that there _must_ be a database named `default'. It is used as a fallback by some tools if no database is specified. You need not use it actively, but you should have run `mkdb default'.) Gnatsd reads the file `databases' on startup (and as it is started by inetd, this means it becomes effective with the next connection to gnatsd). Gnatsweb (see *Note Gnatsweb::) learns the database list from gnatsd, so it will offer you the new database "GreatNewDB" when it is invoked next time. If you do not know where `databases' lives, run: `strings /where/ever/gnatsd | grep databases' 2. Now, as the GNATS user, edit the files in directory `/usr/local/gnats/db2/gnats-adm' to reflect the needs of your new database. 3. Depending on the settings in the `dbconfig' file of the new database, you need not run `mkcat' anymore in order to create new category directories in your database--GNATS 4 creates them automatically when they are missing. *Note The `dbconfig' file: (gnats)dbconfig file, for details. 4. Don't forget to setup a cron job to run through the additional `gnats-queue'. Note that you need to specify the database to `queue-pr', i.e., `/usr/local/libexec/gnats/queue-pr -d GreatNewDB -r' or, if you prefer the long options, `/usr/local/libexec/gnats/queue-pr --database=GreatNewDB --run' 5. Don't forget to create mail aliases for your new database (*note Setting up mail aliases: (gnats)Aliases.). Take care that the aliases have the right database, e.g., GreatNewDB-bugs: "|/usr/local/libexec/gnats/queue-pr -d GreatNewDB -q" GreatNewDB-query: "|/usr/local/libexec/gnats/mail-query -d GreatNewDB" If you are updating from GNATS 3.1xx, note that the `-d' option has changed its meaning: it does not give the directory of the database, but its name. (In case you prefer the long form of the option, it is now `--database' instead of `--directory'.) If your GNATS sits behind a firewall and needs to exchange mails with the outside world, see also *Note Outgoing mail bounces::.  File: gnats-faq.info, Node: Renaming a Category, Next: Changing Fields, Prev: Add a database, Up: General configuration 3.1.2 How do I rename a category? --------------------------------- Renaming a category requires to touch every PR in that category, because each report contains the name of its category. To rename category `A' to `B', proceed as follows: 1. Create a new category `B'. 2. Edit every report in category `A', changing its category to `B'. This can be done with any GNATS client; check the archives of the HELP-GNATS mailing list for hints about automating this step. 3. Run `gen-index' (*note Regenerating the index: (gnats)gen-index.) to refresh the `index' file. 4. If you are using GNATS 4 (or planning to upgrade soon), you should not remove the category `A'. When a follow-up to an existing PR arrives via e-mail, GNATS 4.x checks that both the category and the PR number indicated in the mail exist (this is a sanity check). To reduce the risk of new reports being filed to category `A', change its description in the `categories' file to something like `obsolete, use category `B' instead'.  File: gnats-faq.info, Node: Changing Fields, Prev: Renaming a Category, Up: General configuration 3.1.3 How do I add, remove, or rename a PR field? ------------------------------------------------- A: (GNATS 3.1xx) The fields and their names are fixed in GNATS 3.1xx, so this is not possible. A: (GNATS 4.x) Edit the file `dbconfig' to reflect your changes. Note that the PR fields with the builtin-names `severity', `priority' and `state' are required if you want automatic reminders (`notify-about-expired-prs = true'). In this case, the file `submitters' must also contain a response time. The `severity' field is checked for values `critical' and `serious', and `priority' for value `high'. This is currently not configurable.  File: gnats-faq.info, Node: Gnatsd, Next: E-Mail, Prev: General configuration, Up: Configuration 3.2 Gnatsd, the GNATS Daemon ============================ * Menu: * Port Number:: How to connect to gnatsd * Starting gnatsd:: How to make gnatsd accept connections * Gnatsd messages:: Some error messages and what they mean  File: gnats-faq.info, Node: Port Number, Next: Starting gnatsd, Up: Gnatsd 3.2.1 Gnatsd Port Number ------------------------ In 3.xxx versions, gnatsd uses port 1529 by default; as this port is officially assigned to another application (see the list of port numbers (http://www.iana.org/assignments/port-numbers) maintained by the Internet Assigned Numbers Authority (http://www.iana.org/)) it will probably change in 4.x. If you want/need to run gnatsd on another port, you can change the default port at compile time (call `configure --help' to learn about compile time configuration options). Most clients also accept an option or configuration variable to change the port. Don't forget to tell inetd (or xinetd, or whatever super-server you use) to start gnatsd on the other port.  File: gnats-faq.info, Node: Starting gnatsd, Next: Gnatsd messages, Prev: Port Number, Up: Gnatsd 3.2.2 How to Start Gnatsd ------------------------- Gnatsd is intended to be started by some "super server", like `inetd' or `xinetd'. ("Super servers" are sometimes also called "super daemons".) This is also described in the GNATS manual; see *Note Installing the daemon: (gnats)Installing the daemon. * Menu: * inetd configuration:: The traditional super server * xinetd configuration:: Another widespread super server  File: gnats-faq.info, Node: inetd configuration, Next: xinetd configuration, Up: Starting gnatsd How to configure inetd to start gnatsd ...................................... If your gnatsd will be started by inetd (the "internet daemon"), add the following entry to your `/etc/inetd.conf': # port userid program support stream tcp nowait gnats /usr/local/libexec/gnats/gnatsd gnatsd and to `/etc/services': support 1529/tcp # GNATS (You may need to use tabulator characters to separate the fields of `/etc/services'.) Then send inetd a hangup signal (`kill -HUP _pid-of-inetd_'). You may want to use another port instead of 1529 (*note Port Number::).  File: gnats-faq.info, Node: xinetd configuration, Prev: inetd configuration, Up: Starting gnatsd How to configure xinetd to start gnatsd ....................................... If your gnatsd will be started by xinetd (the "extended internet daemon"), create a file `/etc/xinetd.d/support' with the following lines (*note Installing the daemon: (gnats)Installing the daemon.): service support { disable = no socket_type = stream protocol = tcp wait = no user = gnats server = /usr/local/libexec/gnats/gnatsd server_args = gnatsd } or add theses lines to your `xinetd.conf' file, whatever is appropriate. The equal signs seem to need spaces around them with some versions of xinetd. You need to add support 1529/tcp # GNATS to `/etc/services' (it may be necessary to use tabulator characters to separate the fields), and to tell xinetd to reread its configuration (`kill -HUP _pid-of-xinetd_').  File: gnats-faq.info, Node: Gnatsd messages, Prev: Starting gnatsd, Up: Gnatsd 3.2.3 Gnatsd Messages --------------------- * Menu: * No host access for stdin:: Error when starting gnatsd manually * No host access for remote:: Cannot connect from another machine  File: gnats-faq.info, Node: No host access for stdin, Next: No host access for remote, Up: Gnatsd messages You are not on the host access list: stdin (stdin) .................................................. Q: When starting gnatsd manually (on the command line), I get `520 You are not on the host access list: stdin (stdin)'. A: (GNATS 3.1xx) Gnatsd is not intended to be started manually, but via inetd, xinetd, or a similar "super server". When gnatsd is started this way, its stdin and stdout (standard input and standard output streams) are connected to a so called "TCP socket" (one end of the network connection), and from this socket gnatsd learns the IP address of the remote end (and from this it derives the remote host name). When you start gnatsd from the command line, its stdin and stdout are connected to the terminal, and thus gnatsd gets a nonsense value. You usually need `root' privileges in order to change the configuration of your "super server". If you don't have them, contact your system administrator. See *Note Starting gnatsd:: for inetd and xinetd configuration. A: (GNATS 4.0) This error message should not occur with gnatsd 4.0 anymore, because gnatsd can be started from the command line. However, this probably only makes sense for debugging and diagnosing problems. Furthermore, you need to play the part of the client program yourself (i.e., you must "speak" the gnatsd client protocol).  File: gnats-faq.info, Node: No host access for remote, Prev: No host access for stdin, Up: Gnatsd messages You are not on the host access list ................................... Q: Gnatsd rejects connections from a remote host with the error message `520 You are not on the host access list'. A: Check the file `gnatsd.host_access'; if you are using the default locations, this is `/usr/local/etc/gnats/gnatsd.host_access'. (If you are still using GNATS 3.xxx, the file is named `gnatsd.conf'; its default place is `/usr/local/etc/gnatsd.conf'.) Each line of the file names a host and its access level, separated by colons. Gnatsd tries the lines in turn to match the remote host, and the first line that matches wins. The first field specifies the host(s); it may be a host name (like `goedel.example.com'), a partial domain (like `*.example.com'), an IP address (like `192.168.1.5'), or a partial IP address (like `192.168.*'). If it is only `*', it matches all hosts. Depending on how IP addresses are mapped to hostnames on your gnatsd machine, you may be able to omit the domain (like in `goedel'). You may even _need_ to omit the domain for some hosts. The second field is the access level granted to the remote host. This is usually increased by the access level granted to the user as soon as (s)he logs in. The third field is currently not used; just leave it empty (but supply the colon between the second and the third field). Example: # # This is a comment # # Grant view access to all hosts with IP addresses # ranging from 192.168.0.0 to 192.168.255.255: 192.168.*:view: # Users on host goedel.example.com get (at least) edit access: goedel.example.com:edit: # Users from escher.example.com may view all reports, even # confidential ones: escher.example.com:viewconf: # Users from bach.example.com may only view all non-confidential # reports: bach.example.com:view: # Users from other example.com hosts # only get the access specified for them in gnatsd.user_access: *.example.com:none: # Same for domain our-users.example: *.our-users.example:none: # All other hosts are rejected # without even asking for username and password: *:deny: The format is described in detail in the comments at the beginning of the file.  File: gnats-faq.info, Node: E-Mail, Next: Miscellaneous, Prev: Gnatsd, Up: Configuration 3.3 E-Mail Issues ================= * Menu: * queue-pr not available:: Sendmail refuses to run queue-pr * Outgoing mail bounces:: Mail system complains on outgoing mail  File: gnats-faq.info, Node: queue-pr not available, Next: Outgoing mail bounces, Prev: E-Mail, Up: E-Mail queue-pr not available for sendmail programs ............................................ Your sendmail installation uses `smrsh' to check programs that are invoked from a mail alias. `smrsh' only allows the execution of programs of which it is told that they are save. To tell it that `queue-pr' is save, create a symbolic link in the directory `/etc/smrsh' to `queue-pr', like this: mkdir /etc/smrsh # if it does not yet exist cd /etc/smrsh ln -s /usr/local/libexec/gnats/queue-pr queue-pr Replace `/usr/local/libexec/gnats/queue-pr' by the real path to `queue-pr'.  File: gnats-faq.info, Node: Outgoing mail bounces, Prev: queue-pr not available, Up: E-Mail Mail from GNATS bounces ....................... You are getting bounce mails like this: ----- Transcript of session follows ----- ... while talking to mail.example.com.: >>> MAIL From: SIZE=334 <<< 501 5.1.8 ... Domain of sender address gnats@mymachine.subdomain.example.com does not exist Probably your GNATS sits behind a firewall, but it needs to exchange mails with the world outside the firewall. Make sure that GNATS_ADDR is valid outside. This is what probably happens behind the scenes: On its way to the outside world, the sender address of the mail gets rewritten to something "official" (like `Hans-Albert.Schneider@example.com', as opposed to `me@mymachine.subdomain.example.com'). This is especially necessary if the internal hosts are not visible outside. If your outgoing mail gateway still sees the internal address, it complains with a message like the above (it has probably checked `mymachine.subdomain.example.com' with your organization's external DNS server, which does not know `mymachine'). To solve this problem, get an "official" address for your GNATS system, e.g., tool-bugs@example.com, and use that one for GNATS_ADDR.  File: gnats-faq.info, Node: Miscellaneous, Prev: E-Mail, Up: Configuration 3.4 Miscellaneous Configuration Issues ====================================== * Menu: * No New Reports:: New reports do not show up in the database * Initially Assign Field Values:: If you want to set additional fields when entering a report  File: gnats-faq.info, Node: No New Reports, Next: Initially Assign Field Values, Prev: Miscellaneous, Up: Miscellaneous New reports do not show up in the database .......................................... 1. Make sure you have set up the mail aliases for your database(s). (See *Note Add a database:: and *Note Adding another database: (gnats)mkdb.) 2. Try to send a PR using `send-pr'. If you get error replies, investigate the causes. See *Note E-Mail::. 3. Does a new file show up in the `gnats-queue' directory of your database, with the report as its contents? If it does, make sure you have created the cron job for this database. 4. If the report does not show up in the `gnats-queue' of the desired database, does it show up in the `gnats-queue' directory of another database? In this case, make sure your mail aliases are set up correctly; especially, make sure that you have specified the correct `--directory' option (`--database' for GNATS 4.x) for each `queue-pr'.  File: gnats-faq.info, Node: Initially Assign Field Values, Prev: No New Reports, Up: Miscellaneous Assigning responsible etc. when entering a report ................................................. Q: When entering a new PR, I want to assign a value to some field (e.g., `Responsible') which is normally assigned by GNATS. A: (GNATS 3.1xx) This is not possible in GNATS 3.1xx. A: (GNATS 4.x) This is done by adding the field name (in this example, `Responsible') to the `initial-entry' item at the very end of the `dbconfig' file. Gnatsweb will pick this up and add a `Responsible' field to the Create PR form.  File: gnats-faq.info, Node: Clients, Next: Glossary, Prev: Configuration, Up: Top 4 Client Software ***************** Several client applications can be found in the GNATS distribution. The most important are Gnatsweb (a WWW interface to GNATS), TkGnats (a Tcl/Tk based interface), a GNATS mode for Emacs and XEmacs, and send-pr (the traditional command line interface that sends a PR by e-mail). * Menu: * Gnatsweb:: a WWW interface to GNATS * TkGnats:: a Tcl/Tk based client * Emacs mode:: for (X)Emacs enthusiasts * send-pr:: traditional command line interface  File: gnats-faq.info, Node: Gnatsweb, Next: TkGnats, Up: Clients 4.1 Gnatsweb ============ See also *Note Gnatsweb and GNATS:: in the chapter on *Note Installation::. * Menu: * Gnatsweb Login Questions:: Problems logging in to Gnatsweb  File: gnats-faq.info, Node: Gnatsweb Login Questions, Up: Gnatsweb 4.1.1 Login Questions --------------------- * Menu: * What to enter:: What to enter at login * Login Not Remembered:: Reasons why Gnatsweb forgets your login * Cookies:: What Gnatsweb stores in its cookies  File: gnats-faq.info, Node: What to enter, Next: Login Not Remembered, Up: Gnatsweb Login Questions What should be entered as login information? ............................................ A: If you get an HTML form asking you to enter username, password, and database, use what your gnats administrator has told you. In this case, your authentication data is checked with gnatsd's own user database. If your browser gives you a window asking for username and password (or for "credentials"), the authentication is done by the WWW server. You should have got the necessary data either from your gnats administrator, or from the webmaster of the site offering Gnatsweb access.  File: gnats-faq.info, Node: Login Not Remembered, Next: Cookies, Prev: What to enter, Up: Gnatsweb Login Questions Login data are not remembered ............................. Q: After logging in via Gnatsweb, the main screen is displayed, but whatever action is selected (whatever button is clicked), the login screen gets displayed again. A: This is usually a problem of cookies getting ignored. Gnatsweb uses cookies to store the login information (see "Gnatsweb and Cookies" below). Configure your web browser to allow the cookies Gnatsweb tries to set. Q: There is not even the main screen, the user immediately gets the login screen when trying to log in. The login data entered is correct. It works fine on another machine and for other users. A: This has actually been reported only once; but as the effect is similar to the previous one, it is included in the FAQ. It apparently was related to very strict security settings, but has not been investigated in detail.  File: gnats-faq.info, Node: Cookies, Prev: Login Not Remembered, Up: Gnatsweb Login Questions Gnatsweb and Cookies .................... Q: Wait a moment! Cookies? Can I eat them? A: No, not these. The cookies about which we are talking here are little data packages that a web-server sends to your browser (in our case, on behalf of Gnatsweb) and your browser sends them back to the server next time. Modern browsers give you the option to generally accept or reject cookies, or to be asked whenever a cookie arrives (some even can make this decision based on the web-server). To learn more about cookies, visit, e.g., the Cookie Central (http://www.cookiecentral.com/). Q: So, which cookies does Gnatsweb send, and why? A: Gnatsweb uses a cookie `gnatsweb-db-'_database_name_ to store your login information (username, password), and a cookie `gnatsweb-global' to store the GNATS database you are working on, your e-mail address (to fill it in for you when you create a new report or reply to an existing report), a default list of fields to display in search results, and defaults for `Submitter-Id' and `Originator' fields. Gnatsweb also sets a cookie for each "saved query" (named `gnatsweb-query-'_queryname_). It is therefore essential that you allow Gnatsweb to set its cookies. For a typical effect of rejecting them, see *Note Login Not Remembered::.  File: gnats-faq.info, Node: TkGnats, Next: Emacs mode, Prev: Gnatsweb, Up: Clients 4.2 TkGnats =========== To be completed.  File: gnats-faq.info, Node: Emacs mode, Next: send-pr, Prev: TkGnats, Up: Clients 4.3 GNATS Mode for Emacs ======================== The Emacs mode is in the file gnats.el * Menu: * XEmacs:: Does it also work for XEmacs?  File: gnats-faq.info, Node: XEmacs, Prev: Emacs mode, Up: Emacs mode Does it also work for XEmacs? ............................. A: (GNATS 3.1xx) Yes. A: (GNATS 4.x) Still to be tested.  File: gnats-faq.info, Node: send-pr, Prev: Emacs mode, Up: Clients 4.4 send-pr =========== A simple command line tool that sends a report via electronic mail. This is not contributed software, but part of GNATS itself. The 3.xxx versions do not support multiple databases. To be completed.  File: gnats-faq.info, Node: Glossary, Next: Index, Prev: Clients, Up: Top Appendix A Glossary ******************* "cookie" A chunk of data that a WWW server stores in your browser. It is sent back to the server when you contact it again. Gnatsweb (see *Note Gnatsweb::) uses cookies to store your login information, preferences, and named queries. "gnats.el" GNATS mode for (X)Emacs. "gnatsd" The GNATS daemon (server program). "Gnatsweb" A WWW interface to GNATS. "port" A communication endpoint of various IP based protocols, notably TCP and UDP. A server program waits for connections ("listens") on a port, and a client program connects to this port. IANA (http://www.iana.org/) (the Internet Assigned Numbers Authority) maintains a list of port numbers (http://www.iana.org/assignments/port-numbers) registered for certain purposes. "PR" Short for "Problem Report". An entry in a GNATS database. "send-pr" A command line tool that sends a new report by e-mail. "super server" A super server (sometimes also called "super daemon") is a daemon (= UNIX server process) that waits for connections on the ports of various server programs and starts the corresponding server when a connection is made. This way, there is only one server process for a set of services (instead of one for each service), but each service in the set is available to its clients. The most common super servers are `inetd' (the "InterNET Daemon" that comes with many UNIX installations) and xinetd (http://www.xinetd.org) (the "eXtended InterNET Daemon"). "TkGnats" A Tcl/Tk based interface to GNATS.  File: gnats-faq.info, Node: Index, Prev: Glossary, Up: Top Index ***** [index] * Menu: * bug reporting: Bug Reporting. (line 6) * cookies: Cookies. (line 6) * GNATS server, see gnatsd: Gnatsd. (line 6) * gnatsd: Gnatsd. (line 6) * gnatsd, starting: Administrator View. (line 6) * inetd: inetd configuration. (line 6) * port: Port Number. (line 6) * server port: Port Number. (line 6) * server, see gnatsd: Gnatsd. (line 6) * starting gnatsd: Administrator View. (line 6) * xinetd: xinetd configuration. (line 6)  Tag Table: Node: Top1052 Node: General2055 Node: What is GNATS2613 Node: User view4253 Node: Administrator View4855 Node: How to pronounce it5263 Node: Get it5647 Node: Versions6038 Node: Mailing Lists6844 Node: Bug Reporting8415 Node: Upgrading9981 Node: Installation11500 Node: Gnatsweb and GNATS11846 Node: Configuration12647 Node: General configuration13067 Node: Add a database13423 Node: Renaming a Category20136 Node: Changing Fields21325 Node: Gnatsd22072 Node: Port Number22443 Node: Starting gnatsd23243 Node: inetd configuration23793 Node: xinetd configuration24498 Node: Gnatsd messages25547 Node: No host access for stdin25823 Node: No host access for remote27276 Node: E-Mail29665 Node: queue-pr not available29944 Node: Outgoing mail bounces30646 Node: Miscellaneous32023 Node: No New Reports32398 Node: Initially Assign Field Values33452 Node: Clients34081 Node: Gnatsweb34732 Node: Gnatsweb Login Questions34981 Node: What to enter35303 Node: Login Not Remembered35993 Node: Cookies36992 Node: TkGnats38385 Node: Emacs mode38518 Node: XEmacs38770 Node: send-pr38968 Node: Glossary39274 Node: Index41006  End Tag Table gnats-4.1.0/gnats/0000755000175000017500000000000010212665130014472 5ustar chewiechewie00000000000000gnats-4.1.0/gnats/ChangeLog0000644000175000017500000034071610207435534016266 0ustar chewiechewie000000000000002005-02-19 Mel Hatzis * adm.c (copy_adm_entry): Handle blank metadata fields by correctly assigning the relevant field in the adm struct to NULL - and thereby avoid an attempt to xstrdup a NULL value. * file-pr.c (createNewPRFile): Avoid a NULL pointer dereference when there's a blank response time field in the submitters file. * gnatsd.c (findUserAccessLevel): Avoid a strlen of NULL when the gnatsd.user_access file contains a blank 'database-alias' field. * gnats.h (rewrite_pr): Made it a static function in edit.c - it wasn't being used outside this scope anyway. * mail.c (get_responsible_address): Avoid a NULL pointer dereference if the responsible file doesn't have an email address for the gnats-admin user. * index.c, index.h (getPrevPR, setPrevPR, setNextPR): New functions. The index chain is now doubly linked allowing edited PRs to be replaced without incurring the overhead of a search through the chain. As well as offering significantly better performance, this supports a change to the PR edit functionality whereby we now start with a copy of the old PR as well as the updated PR instead of retrieving the old PR (from the index) in the guts of rewrite_pr. The motivation behind this change is to isolate the index functionality and move toward a generic backend datastore which doesn't require the index. (replaceCurrentPRInIndex): Modified signature. Pass in the PR to be replaced (as well as the new PR) since we can now use the doubly linked index chain to replace the PR without searching for it. * pr.h (lookup_pr_path): Removed. Replaced by a call to the new get_pr_from_index () function followed by a call to (a modified) get_pr_path (). This change allows a single index search to be done once (early on in a given call stack) to retrieve a PR and thereafter access the PR file without requiring more index searches. (pr_delete): New function. Contains the flat-file specific logic related to PR deletions which will be moved out into a flat-file backend when the datastore backend is generalized. * pr.c (get_pr_from_index): New function. Retrieve a PR from the index. (pr_file_readable): New function. Check if a file can be opened for reading. (pr_delete): New function. Flat-file specific logic for delete. (prExists): Now utilize get_pr_from_index () and get_pr_path () instead of the deprecated lookup_pr_path (). (readPRWithNum): Ditto. Also set the PR's next/prev index pointers. (get_pr_path): New signature. Take in a PR * instead of searching the index. (lookup_pr_path): Deprecated. * edit.c (applyChangeActions, processFieldChange, sendAuditMail): Repositioned within the file so as not to require prototypes. (processPRChanges): Handle NULL values appropriately when undoing changes to modified read-only fields. (rewrite_pr, replace_pr, edit_field): rewrite_pr now takes in a copy of the old pr instead of retrieving it from the index. This is in preparation for allowing it to be used with more than just the flat file backend datastore. Also moved some error checking out of rewrite_pr and simplified it...no need to validate the whole PR when editing a single field. (deletePR): Moved the file-related logic into a new pr_delete function inside pr.c thereby preparing for a general backend datastore. 2005-02-24 Chad Walstrom * man/*.man, man/Makefile.in: Removing historical remnants. Manpages were moved to ../doc/man. 2005-02-22 Mike M. Volokhov * misc.c (xmalloc, xrealloc, xstrdup, basename, asprintf, vasprintf): New fault-tolerant functions (x*), rewritten from scratch as replacements for libiberty stuff. A basename() and [v]asprintf() functions was stolen from libiberty tree to be more consistent on various platforms. The xstrndup() function was strengthen when passed length is less than 1; this fixes potential problems with other functions which relies on xstrndup(), i.e.: strlen(xstrndup(string, 0)). * gnugetopt.c, gnugetopt1.c, gnugetopt.h: Stolen from libiberty sources to avoid possible portability problems and was bit enreached with GNATS build directives. Contains GNU getopt(), getopt_long(), and getopt_long_only() functions (however GNATS use getopt_long only, which is now enforced in configure.in). Files was renamed to gnu* for more clean selection of getopt sources. * configure, configure.in: The following functions now handled by AC_CHECK_FUNC macro - basename, asprintf, vasprintf, getopt, getopt_long. See also autoconf.h.in file. * autoconf.h.in: The libiberty stuff was replaced with GNATS own HAVE_GETOPT* and HAVE_BASENAME triggers. * ansidecl.h: Stolen from libiberty sources. This generic definitions used accross GNATS sources. * gnats.h: Add prototypes for new functions from misc.c. Include "ansidecl.h", stored locally. Include getopt_long select logic. * Makefile.in: Remove libiberty stuff, include gnugetopt* sources. 2004-11-30 Chad Walstrom * gnatsd.c, gnats-pwconv.c (HAVE_CRYPT_H): Changed HAVE_CRYPT to HAVE_CRYPT_H, which is the real define found in autoconf.h.in. * gnats-pwconv.c: Removed extraneous header file #includes. * misc.c (xstrndup): Added sanity check for len parameter, and documented the function. * Makefile.in (install-tools-bin): Removed $(srcdir) from install command for diff-prs, since it is a generated file from diff-prs.sh. This allows builds in directories != srcdir. 2004-11-18 Pankaj Garg * mail.c (getOneAddress): Check addr pointer against addrStart before trying to copy a zero-length string. 2004-11-18 Chad Walstrom * configure.in: Added conditional define's for HAVE_DECL_GETOPT and HAVE_DECL_BASENAME to get around include/getopt.h and include/libiberty.h "three-state macro" function declarations of getopt() and basename(). Updated Copyright. * configure: regnerated * autoconf.h.in: regenerated 2004-11-13 Chad Walstrom * configure.in (--with-lispdir): Added new option to specify lispdir rather than have it automatically determined. Updated version to 4.1.0. * configure: regenerated * Makefile.in (install-gnats-arch-indep): Added $(DESTDIR) variable to test for GNATSD_HOST_ACCESS_FILE 2004-11-03 Chad Walstrom * Makefile.in (VERSION): replaced version string with @PACKAGE_VERSION@ substitution variable from configure.in. * configure.in (AC_INIT): Updated to use autoconf v2.50 to specify PACKAGE_NAME, PACKAGE_VERSION, and PACKAGE_BUG. Set version to 4.1. (AC_CONFIG_FILES, AC_OUTPUT): Updated use of these macros to v2.50 * configure: regenerated 2004-09-06 Hans-Albert Schneider * misc.c (gnats_strftime): If we have to interpret %z ourselves, avoid a buffer overflow with 10 or more %z in format string. (log_msg): Fix format string bug (in calling syslog()) described in http://lists.gnu.org/archive/html/bug-gnats/2004-06/msg00028.html and in http://www.zone-h.org/advisories/read/id=4889 * gnats-pwconv.c: commented out definition of MAXLINE which is not used. gcc -Werror complains about this. 2004-06-11 Jon Meredith * misc.c (gnats_strftime): added check for +/- at the start of the string to support SCO OpenServer. The undocumented %z does not have a '+' on for positive offsets, so the return from get_curr_date() cannot be parsed by get_date(). (Closes: patch #1461) 2004-06-09 Chad Walstrom * Makefile.in, man/Makefile.in: Prepended the $(DESTDIR) variable to all destination targets. This will help with building distribution packages. Moved mkinstalldir calls to install targets. 2003-10-26 Mel Hatzis * file-pr.c (createNewPRFile): Get builtin originator field rather than field named "Originator". * client.c (read_server): Free memory for line to avoid leak. 2003-09-21 Yngve Svendsen * configure.in: Add standard check for awk program * configure: Regenerated * Makefile.in: Substitute AWK in diff-prs.sh. Add rm of diff-prs to domostlyclean target. * diff-prs: Renamed to diff-prs.sh. Add substitution marker for awk program 2003-08-30 Carl Lindberg * mail.c (getOneAddress): Fix test for start address when ignoring ending white space. 2003-08-30 Mel Hatzis , Andrew J. Gray * client.c (get_reply): Check for outfp being NULL. (netSendPRCmd): Add flag to show information received. All callers changed. * cmds.c (GNATS_subm): Send PR number for new submission. * file-pr.c (submit_pr): Return PR number for new submission. * pr-edit.c (long_options, handleNetworkEdit, main): Add show_prnum option. 2003-07-27 Andrew J. Gray * Makefile.in (VERSION): Increased to 4.0. 2003-06-23 Yngve Svendsen - Sun Norway * gnatsd.user_access: Fix a couple of typos. Thanks to Ben Elliston. 2003-05-01 Yngve Svendsen * gnatsd.user_access, gnatsd.host_access: Add explanation of why wildcard entries must be placed near the end of these files. 2003-04-27 Andrew J. Gray * check-db.sh, Makefile.in (check-db): Use BINDIR to find query_pr; fixes PR gnats/446. 2003-03-08 Milan Zamazal * regex.h: #undef `__restrict_arr' before #defining it. 2003-03-09 Andrew J. Gray * file-pr.c (checkIfReply): Change regex so that "PR" must be all capitals and "PR#" matches; patch by Lars Henriksen . 2003-01-13 Milan Zamazal * fconfig.y: Missing semicolons added. * fconfig.c: Regenerated. 2002-11-25 Yngve Svendsen * client.c, database.c, edit.c, gen-closed-date.c, mail.c, misc.c, pr.c, query.c: Add cast of argument of isspace to unsigned char. Fixes PR 434. 2002-11-24 Andrew J. Gray * Makefile.in (VERSION): Increased to 4.0-beta2. 2002-11-09 Yngve Svendsen * delete-pr.sh: Fix usage message. 2002-11-08 Yngve Svendsen * client.c (netEditField): Iterate over replies from server until CODE_OK. Otherwise, a required change reason would never get submitted properly. Fixes PR 331. Fix due to Adrian Ashley. 2002-11-01 Yngve Svendsen * file-pr.c (run_atpr): Decrease number of arguments to at-pr by one. * edit-pr.c (main): Provide reason to edit_field(). Fixes PR 331. * at-pr.sh, file-pr.c: Remove unused "path to the PR file" at-pr parameter. * gnats.h, internal.c: Add database_name parameter to gnatsdbHasNetconn. This allows tools to determine properly whether to use network mode or not to access a database. Patch by Mel Hatzis. * (getclose.c, pr-age.c, pr-edit.c, query-pr.c, client.c): Use database_name parameter when calling gnatsdbHasNetconn. 2002-10-31 Yngve Svendsen * dbconfig.in: Warn people that they may need to set category dir permissions to 755 if they have users running query-pr etc. locally, i.e. not through gnatsd. 2002-10-28 Yngve Svendsen * edit.c (applyChangeAction): Use value_is_empty to check not only for empty fields but also for fields that contain only blanks. * file-pr.c (missing_required_fields): Ditto * lists.c, query.h: Add ListInitialRequiredFields, implementing an argument InitialRequiredFields to LIST. 2002-10-27 Hans-Albert Schneider * gnatsd.access: Renamed to gnatsd.user_access. Fixed reference to gnatsd.conf (now gnatsd.host_access). * Makefile.in, gnatsd.host_access, mkdb.sh: Reflect this renaming. 2002-10-27 Andrew J. Gray * adm.c (get_adm_record): Check for fields with no associated adm file to avoid deferencing NULL in get_adm_dir. Fixes PR gnats/330. 2002-10-24 Yngve Svendsen * dbconfig.in: Use Notify-List in the initial-pr-notification and initial-pr-notification-pending mail formats. * dbconfig.in: Add new field Notify-List. Use it in the audit-mail mail format definition. 2002-10-24 Andrew J. Gray * database.c (databaseInfo, newDatabaseInfo) (freeDatabaseInfo): Add "require" parameter to "initial-entry" fields; patch by Mel Hatzis . (setRequiredInputFields, getRequiredInputFields): New funtions. * file-pr.c (createNewPRFile): Likewise. (missing_required_fields): New function. * fconfig.y: Likewise. * edit.c (applyChangeAction): Check for empty string in required fields; patch by Mel Hatzis . 2002-10-24 Yngve Svendsen * dbconfig.in: Removed Cases, Quarter, Keywords and Date-Required field definitions. They are documented in the "dbconfig recipes" appendix of the manual for those that need it. 2002-10-15 Yngve Svendsen * misc.c (gnats_strftime): Fix a bug seriously affecting systems without support for the format code %z. The dates in PRs would be incorrect when the timezone was different from GMT. The brokentime pointer passed to gnats_strftime() would point to static data that might be overwritten by calls to (among others) gmtime(). Fix due to Lars Henriksen, Lars.Henriksen@netman.dk. Fixes PR 414. * states: Clarify and correct some details. 2002-10-14 Yngve Svendsen * dbconfig.in: Make the `states' field behave as described in the states file, i.e. when changing from one closed state to another, do not touch the Closed-Date field, and reset the Closed-Date field only when changing from a closed state to an non-closed. Patch submitted by Alwin Dieperink. 2002-10-14 Pankaj K. Garg * gnatsd.access: Say a bit more about password encryption methods. Mention empty passwords. Say that default access level is `listdb', not `edit'. Change example entry to set blank password for view access. * gnats.texi (gnatsd.user_access): Say a bit more about password encryption methods. Amend examples to illustrate the use of blank passwords. Demonstrate the new fall-through mechanism for password matching. * gnatsd.c (password_match): Clean up password matching. Handle blank passwords. (findUserAccessLevel): If the password given during the login is not blank and doesn't match the correct password, deny access. * cmds.c (GNATS_user): Handle case where a blank password has been given by user. Change usage message to allow for blank passwords. (gnatsdChdb): Handle blank passwords. (GNATS_chdb): Allow for one, two or three arguments to CHDB. (GNATS_help): Amend help text for CHDB and USER. 2002-10-13 Yngve Svendsen * mail-agent.sh: Redirect mail-agent output to /dev/null. Fixes PR355. Fix due to Andrew Gray. * file-pr.c (run_atpr): Call at with &> /dev/null. 2002-09-24 Yngve Svendsen * mkdb.sh: Change to use gnatsd.user_access as user access file name. - mkdb.sh (domkdir): Provide -p parameter to mkdir, so that non-existing parent directories are automatically created. Fixes PR 316. Both fixes by Pankaj K. Garg. * dbconfig.in: Fix capitalization of the descriptions of the How-To-Repeat and Release fields. * mail.c (getOneAddress): Cast the argument of isspace to int. Fixes a problem where GNATS wouldn't compile on Solaris with GCC. 2002-09-01 Milan Zamazal * mail.c (getOneAddress, get_responsible_addr): Handle spaces around mail addresses; patch by Mel Hatzis . 2002-08-12 Milan Zamazal * cmds.c (GNATS_lock): Invalid order of arguments in the help message fixed; thanks to Mel Hatzis. 2002-08-04 Milan Zamazal * gnats.el (gnats-change-database): Offer default values when prompting for the arguments. (gnats-dbconfig-mode): Imenu support added. * Makefile.in (mkdb): Substitute GLOBAL_DB_LIST_FILE. * mkdb.sh (DATADIR): Get the value from GLOBAL_DB_LIST_FILE; patch by Lars Henriksen . * gnatsd.c (get_name): Reference to `host' fixed in `gethostbyaddr'; fixes PR gnats/363. * at-pr.sh (QUERY_PR): A mistaken space removed; fixes PR gnats/394. * edit.c (validateFieldValue): Don't process an Integer string if `text' is NULL; patch by Mel Hatzis . 2002-07-28 Milan Zamazal * pr-stat.c (long_options): The `--help' option uncommented. * queue-pr.c (main): `-m' added to the short options; thanks to Dirk Schenkewitz. * gnats-pwconv.c (USAGE): More customization of the messages depending on HAVE_LIBCRYPT. (main): Make OPTSTRING dependent on HAVE_LIBCRYPT. Thanks to Dirk Schenkewitz. * cmds.c (gnatsdChdb): Missing `const' qualifier added. * gen-closed-date.c (main): The unused and undocumented option `-c' removed. (USAGE): Misaligned text aligned. Thanks to Dirk Schenkewitz. * gen-index.c (main): Don't use automatic option variable setting. 2002-07-19 Milan Zamazal * cmds.c (gnatsdChdb): On verification error, be safe against nameOfDb being NULL; based on a patch by Lars Henriksen, fixes PR gnats/380. 2002-07-14 Milan Zamazal * configure.in: pdm's copyright moved to FSF. `gnatsd.access' changed to `gnatsd.user_access'; fixes PR gnats/348. * gnats.h: Likewise. * at-pr.sh (RESP_ADDR): Use query-pr instead of pr-addr. * gnats-pwconv.c: Copyright changed to FSF. (encrypt_): Don't include the salt in the resulting string; fixes PR gnats/395. * client.c (scanEnv): If `database' is NULL and GNATSDB is a local database name, use it instead of "default". Based on a patch by Mel Hatzis. 2002-05-26 Milan Zamazal * mkdb.sh: Ignore remote databases; fixes PR gnats/384; patch by Lars Henriksen . * edit-pr.sh: Don't do duplicate actions in traps; remove $new only on success. 2002-05-21 Milan Zamazal * Makefile.in (dodistclean): Remove `#*'. 2002-05-20 Milan Zamazal * edit-pr.sh: Don't delete new files on error signals. * gen-index.c (main): Code formatting fix. * gnats.el (gnats-get-addr-info): Call `query-pr --print-server-addr' only if server is given. 2002-05-17 Milan Zamazal * file-pr.c (checkIfReply): Regex fixed, use `re_search' instead of `re_match'; patch by Andrew Gray . 2002-05-15 Milan Zamazal * gnatsd.host_access: Let the default access level is `listdb'. * gen-index.c (add_pr): Use numeric_sorting's value implicitly, don't compare it with TRUE. 2002-04-23 Milan Zamazal * gnats.el (gnats-dbconfig-font-lock-keywords): `business-week-days' typo fixed. 2002-03-31 Yngve Svendsen * query-pr.c (USAGE): field-flags, adm-field, adm-subfield and adm-key added. * pr-age.c (main): PR number is argv[optind], not argv[1]. Fixes PR 362. 2002-03-19 Yngve Svendsen * gen-index.c (main): Add forgotten short options n, e, i to case structure. Fixes PR 351. 2002-03-02 Milan Zamazal * gnatsd.c (password_match): DES password handling fixed; patch by Mario Joussen . * Makefile.in (install-tools-arch-indep): Don't depend on `dbconfig'. (all-tools): Depend on `dbconfig'. 2002-02-19 Milan Zamazal * gnats.el (gnats-replace-curr-text, gnats-advertised-undo): Deuglified wrt variable value overriding. 2002-02-10 Milan Zamazal * query.h: `regcmp' -> `gnats_regcmp'. * getclose.c (do_prlist): `regcmp' -> `gnats_regcmp'. * edit.c (validateFieldValue): `regcmp' -> `gnats_regcmp'. * query.c (regcmp): Renamed to `gnats_regcmp'. (iterate_prs): Consider the previous change. * file-pr.c (createNewPRFile): Don't always set the default value to the field; based on a patch by Forrest J. Cavalier III ; fixes PR gnats/333. 2002-01-22 Milan Zamazal * gnats.el (unlock-pr): Let `pr' is a string, not a number. 2002-01-13 Milan Zamazal * query-pr.c (USAGE): --print-server-addr added. * Makefile.in (LDFLAGS): Use @LDFLAGS@ instead of $(CFLAGS). * gnats.el (gnats-show-connection): New command. (unlock-database): New command. (gnats-edit-mode): New argument `quietp'. (gnats-apply-edits): Call gnats-edit-mode with `quietp' set to t. 2002-01-10 Milan Zamazal * gnats.el (gnats-query-mode): RET added to the overrided view mode keys; fixes PR gnats/326. 2002-01-07 Milan Zamazal * gnats.el (query-pr): `edit-buffer' renamed to `query-buffer'. (query-pr): Report the number of the matching PRs. (gnats-query-mode-map): `G' (query-pr) added. 2002-01-06 Milan Zamazal * gnats.h: Include libgen.h if available; fixes PR gnats/319; patch by Noritoshi Demizu . * configure.in: libgen.h added to AC_CHECK_HEADERS; patch by Noritoshi Demizu . * configure: Regenerated. * autoconf.h.in: Regenerated. * misc.c (temporary_directory): `tmpdir' is `char *' now; fixes PR gnats/317; patch by Forrest Cavalier . (init_logging): With no syslog, put into log_method NOLOG and not NONE; fixes PR gnats/318; patch by Forrest Cavalier . * Makefile.in (mandir): Removed. 2001-12-27 Milan Zamazal * Makefile.in (VERSION): Increased to 4.0-beta1. (dodistclean): Remove TAGS. (dorealclean): File list updated. (doclean): Don't remove the files generated by lex and yacc. (dorealclean): Remove the files generated by lex and yacc. 2001-12-23 Milan Zamazal * file-pr.c (checkIfReply): Matching changed. * cmds.c (GNATS_help): The EDITADDR command added. * gnatsd.c (password_match): Removed the remark about missing manual description. * configure.in: Declaration check for `unsetenv' added. * configure: Regenerated. * autoconf.h.in: Regenerated. * gnats.h: `basename' declaration removed, it's already in libiberty.h. Protect `unsetenv' by HAVE_DECL_UNSETENV rather than only HAVE_UNSETENV. 2001-12-15 Milan Zamazal * gnats.el (gnats-change-database): Reset `gnats-password'. 2001-12-11 Milan Zamazal * gnats.el (send-pr): When run with a universal argument, run `gnats-change-database' in advance. (gnats-get-field-info): Replace `\n' by newline; strip off a starting newline from multiline fields. 2001-12-10 Milan Zamazal * regex.c: Updated from current gnulib. * regex.h: Updated from current gnulib. * gnatsd.c (match): Cast `tolower' arguments to `int'. * gnats-pwconv.c (encrypt_): Make all the parts concerning encryption conditional. (encrypt_): Check for `asprintf' error. 2001-12-08 Milan Zamazal * mail-query.sh: Add the --database argument only if GNATSDB is non-empty. 2001-12-08 Lars Henriksen * Makefile.in (install-tools-bin): Typo in the warning message fixed. 2001-12-08 Milan Zamazal * Makefile.in (install-tools-bin): Don't install `gnats-pwconv'. * adm.c (initAdmField): Set field's `default_value' only if it's not set already. * cmds.c (GNATS_lock): Fix the order of arguments in the help string. * fconfig.y (fieldDec, optChangeExpr, multiEnumItem) (multiEnumFileItem, enumFieldMember, auxFlagsList): Added closing semicolon. (startFieldDec): Set field's `default_value' to NULL. 2001-12-07 Milan Zamazal * Makefile.in (install-gnats-bin, uninstall, doclean): Add `gnats-pwconv'. 2001-12-07 Yngve Svendsen * Makefile.in (install-tools-bin): Install gnats-pwconv in $(libexecdir)/gnats. 2001-12-06 Milan Zamazal * Makefile.in (all-gnats): `gnats-pwconv' added to targets. (gnats-pwconv): New target. * gnats-pwconv.c: New utility. * misc.c (usage): If `exit_code' is zero, print usage to stdout. 2001-12-04 Milan Zamazal * lists.c (listTypeList, getGnatsFile): `listClasses' removed again. * query.h (queryOp): Likewise. * query-pr.c (USAGE): The no longer pertinent `--list-classes' option removed. 2001-12-03 Milan Zamazal * dbconfig.in: Exclude "Originator" from the "audit-mail" recipient list, use FROM fields instead. 2001-12-02 Milan Zamazal * pr-edit.c (USAGE): New option `reason'. 2001-12-02 Dan Martinez * pr-edit.c (long_options): New option `reason'. (handleNetworkEdit): New argument `reason'. (main): Process the `reason' option. * gnats.h (get_reply): Returns an int value. (netEditField): New argument `reason'. * client.c (get_reply): Return an int value. (netEditField): Provide the change reason to the server if required. 2001-12-02 Milan Zamazal * mkdb.sh: The argument changed from DATADIR to DATABASE. * mkdb.sh: Run gen-index. * Makefile.in (mkdb): Replace xSYSCONFDIRx too. 2001-12-01 Milan Zamazal * query.c (iterate_prs): Don't report an index error just because there are no PRs, report it only when reading the index finished with an error. * gen-index.c (long_options): Moved to `main', cosmetic improvements. (main): Don't handle the flag options "manually", let them be handled by `long_options' flags. (sort_numerical): Renamed to `numeric_sorting'. (add_pr, main): Consider the previous change. (main): Don't open the output file until it's needed (especially all options are processed). 2001-11-14 Yngve Svendsen * responsible: Add note on how to change the address of the GNATS admin. * categories: Add a couple of words explaining that the first entry is used as default for PRs that arrive without a set category. * UPGRADING: Details on migrating `config' file settings to GNATS 4 added. 2001-11-12 Milan Zamazal * cmds.c (GNATS_appnOrRepl): Missing arguments to the `daemon*lock*' calls added. * internal.c (lock_gnats): Missing `res' declaration added. (lock_gnats): MAXWAIT and GRANULARITY turned into constant variables. * edit.c (lock_pr): Missing `count' and `fdes' declarations added. 2001-11-09 Lars Henriksen * Makefile.in (install-gnats-arch-indep): Don't fail if the installed files can't be chowned, only print a warning. (install-gnats-bin): Use $(GNATS_USER) instead of `gnats' in the printed message. 2001-11-08 Milan Zamazal * pr-edit.c (main): Don't test a "boolean" int value by comparing it with 1. 2001-11-08 Dirk Bergstrom * index.c (getFirstPR): Always checkPRChain; this decreases the chances of writing out stale index data. (writeIndex): Check to make sure that index hasn't changed since last read, fail with CODE_INVALID_INDEX if it has. Also generate email to admin about the problem. Update indexDesc->mtime after writing out new index. * cmds.c (GNATS_appnOrRepl): Lock database before editing. * pr-edit.c (main): Lock database before --append or --replace in non-network mode. * edit.c (lock_pr): Quash a race bug in PR locking. Use basically the same code as in lock_gnats. Report lock time if PR is locked. * internal.c (lock_gnats): Changed from using creat(path, 0) to atomic open() to eliminate a race in database lock creation. * internal.c (punt): Complain to stderr if database is null. queue-pr sometimes calls punt() before defining database, and this way cron will report the error. * edit-pr.sh (lock): Report pid when locking PR. (submit): If there are errors during submission, prompt the user to abort or retry. * queue-pr.c (main, run_gnats): Added new command-line option "max-size"; in --run mode, messages larger than max-size will not be processed, but instead will generate an email to the database admin. (fork_gnats): Fork off pr-edit, instead of file-pr (which is just a shell script wrapper around pr-edit). (USAGE): Add max-size option. (run_gnats): If pr-edit exits with status 2, check to see if file still exists; if not, another queue-pr is probably running. Report file as missing. 2001-11-06 Yngve Svendsen * UPGRADING: Details GNATS 3 -> 4 upgrades. Procedure is untested, but is believed to work. 2001-11-05 Yngve Svendsen * UPGRADING: Rename to UPGRADING.old. We still need it around for people upgrading from very old GNATS 3 versions to GNATS 4. * INSTALL: Rewritten for GNATS 4. * PROBLEMS, README: Updated/rewritten for GNATS 4. 2001-11-01 Milan Zamazal * gnats.h (DEFAULT_MULTIENUM_SEPARATOR): New constant. * cmds.c (GNATS_ftypinfo): Use it. * fconfig.y: Likewise. 2001-11-01 Yngve Svendsen * gnatsd.c (cmds): New command FTYPINFO. * cmds.c (GNATS_help): Document it. * cmds.c (GNATS_ftypinfo): New command function. * gnatsd.h: Declare it. * pcodes.h (CODE_INVALID_FTYPE_PROPERTY): New error code. 2001-10-29 Milan Zamazal * fconfigl.l: The `noyywrap' option added. 2001-10-29 Carl E. Lindberg * database.c (initDatabaseList): Null the databaseEnt pointers in databaseInfoList; fixes PR gnats/181. 2001-10-28 Milan Zamazal * pr.c (addLineToPR): Don't terminate enum fields on a space. 2001-10-22 Yngve Svendsen * query-pr.c (USAGE): Split in a few more parts to get rid of GCC 2.96 and 3.0 ISO C89 string length warning. 2001-10-17 Milan Zamazal * mail.c (composeMailMessage): If From: address is not given, assign admin's address to `fromAddr'; patch by Yngve Svendsen. 2001-10-16 Milan Zamazal * Makefile.in (sysconfdir): Defined. * gnatsd.host_access: access-level description updated; patch by Yngve Svendsen. * gnatsd.access: access-level and password description updated; based on a patch by Yngve Svendsen. * query-pr.c (USAGE): Updated to match the manual; based on a patch by Yngve Svendsen. * gnats.el (gnats-query-mode-map): Binding of `send-pr' changed from "a" to "s". 2001-10-15 Milan Zamazal * misc.c (read_line): The type of `default_len' changed to `size_t'; fixes PR gnats/270. 2001-10-14 Milan Zamazal * gnatsd.h (Access_Level): New type; `ACCESS_LISTDB' added. (FLAG_MASK, FLAG_ONE_ARG): Removed. * gnatsd.c (Access_String): New auxiliary structure. (ACCESS_STRINGS): New constant. (access_level, access_level_str): Rewritten. (cmds): The structure of the array elements changed; DBLS's access level lowered to ACCESS_LISTDB. * gnatsd.c: All access level variable types changed from `int' to `Access_Level'. * gnats.h: Likewise. * cmds.c: Likewise. 2001-09-28 Milan Zamazal * gnatsd.access: The description of the `admin' access level fixed; patch by Yngve Svendsen. * gnatsd.host_access: Likewise. 2001-09-23 Milan Zamazal * gnats.el: Unnecessary progns removed. (gnats-fetch-pr): Reset all fields, not only input fields. 2001-09-20 Milan Zamazal * cmds.c (GNATS_help): Missing commands added to the help; patch by Yngve Svendsen from PR gnats/264. 2001-09-19 Milan Zamazal * cmds.c (gnatsdChdb): Reset `queryFormat' if the database is changed; fixes PR gnats/257. 2001-09-07 Milan Zamazal * dbconfig.in (audit-mail): "Category[notify]" and "Originator" added; fixes PR gnats/188. * gnats.el (gnats-dbconfig-mode): Made interactive. 2001-09-06 Milan Zamazal * cmds.c (daemon_lock_gnats): New argument `verbose'; if it is FALSE, don't print success message. (daemon_unlock_gnats): Likewise. (GNATS_subm, GNATS_lkdb, GNATS_undb, GNATS_edit): The new argument to `daemon*' calls added. * configure.in: AC_CONST removed, it's useless in a subdirectory. New special check for Solaris' const handling added. * configure: Regenerated. * misc.c (read_line): Formatting changes. 2001-09-04 Milan Zamazal * file-pr.c (submit_pr): The Originator check moved to `createNewPRFile' where it belongs to. * configure.in: Standard autoconf check for `const' added. * configure: Regenerated. 2001-09-03 Milan Zamazal * edit.c (validateFieldValue): Missing argument to `setError' in the Integer section added. 2001-09-01 Milan Zamazal * configure.in: Help formatting improved. * configure: Regenerated. 2001-08-13 Milan Zamazal * gnats.el (gnats-extend-properties): New function. (gnats-edit-mode): Add it to after-change-functions. (gnats-change-database): Set default values as well. (gnats-change-database): `gnats-server', not `gnats-host'. (gnats-run-modify-command): Turned into a macro and implemented in the right way. (gnats-mark-field-edited): Consider the previous change. (gnats-delete-field, gnats-delete-char): Likewise. (gnats-delete-backward-char, gnats-insert-char): Likewise. (gnats-end-line, gnats-open-line, gnats-kill-line): Likewise. (gnats-submit-pr): Connection buffer killing disabled for debugging purposes, the buffer is killed anyway when the edit buffer is killed. (gnats-fetch-pr): Reset all input fields before parsing the PR. 2001-08-12 Milan Zamazal * cmds.c (get_text_memory): Initialize `buf' to NULL and set it to NULL after freeing it. (get_text_memory): When reading the input, put '\0' at its end only after the buffer is reallocated to a sufficient size. 2001-08-11 Milan Zamazal * gnats.el (gnats-clear-edit-buffer): The previous change undone. (query-pr): Call `gnats-delete-process'. (gnats-dbconfig-mode): New major mode. (gnats-dbconfig-mode-map): New variable. (gnats-dbconfig-mode-syntax-table): New variable. (gnats-dbconfig-mode-hook): New variable. (gnats-dbconfig-mode-abbrev-table): New variable. (gnats-edit-mode): Set paragraph-start and paragraph-separate. (gnats-request-enum): New argument NO-DEFAULT. (gnats-end-line): Use it. (gnats-cycle-enum-value): New function. (gnats-insert-char): Use it and bind it to the space key. (gnats-query-font-lock-keywords): Highlight any line containing `high'. This is of course wrong but it can't be handled well until new query table formatting is written. (gnats-insert-char): Character notation of \r and \n fixed. (gnats-change-database): New command. (gnats-query-mode-map): Bind it to a key. (gnats-port): Clarify the type of the variable in the docstring. 2001-08-10 Milan Zamazal * pr.c (read_header): Stop processing if you encounter the GNATS field delimiter `>'. * file-pr.c (submit_pr): Don't crash when there's no `Originator' field in the database. * gnats.el (gnats-get-mail-alias): Send the e-mail address to the daemon; fixes PR gnats/131. (gnats-debug-string): Don't complain if process-buffer is nil. (gnats-delete-process): Kill server buffer. (gnats-default-organization): Transformed into a customizable option. (gnats-default-submitter): Likewise. (gnats-query-mode-map): Key binding `a' for `send-pr' added. (gnats-clear-edit-buffer): Call `gnats-delete-process'. 2001-08-09 Milan Zamazal * gnats.el (gnats-apply-or-submit): Enclosed by save-excursion. (gnats-default-organization): Set the default value to an empty string. (gnats-default-submitter): Likewise. (gnats-submit-pr): The kill-buffer argument fixed. (gnats-edit-server): Don't set default value of gnats-server-conn. (gnats-server-conn): `permanent-local' set to t. (gnats-delete-process): New function. Add it to kill-buffer-hook. 2001-08-04 Milan Zamazal * configure.in: `AM_PATH_LIBDIR' added. * aclocal.m4: Regenerated. * configure: Regenerated. * Makefile.in (EMACS): Removed. (lispdir): Assign it to `@lispdir@' instead of `@LISPDIR@'. * misc.c (value_is_empty): Cast the argument of `isspace' to `int'. 2001-08-03 Milan Zamazal * configure.in: Don't continue with configuration if `sendmail' is not available; fixes PR gnats/54. * configure: Regenerated. 2001-08-02 Milan Zamazal * adm.c (getAdmSubfieldValue): Return NULL if `i' is NULL, don't crash. 2001-07-30 Milan Zamazal * mkcat.sh: Protect category names by quotes; fixes PR gnats/41. * rmcat.sh: Likewise. * rmcat.sh: Use `rmcat', not $0, as the program name. * mkcat.sh: Final messsage improved. * rmcat.sh: Messages improved. * gnats.el (gnats-get-addr-info): Read password from prompt if not available. (gnats-query-reread): New command. (gnats-query-mode-map): Add a key for it. (gnats-query-mode): Override the key in view-mode-map. 2001-07-28 Milan Zamazal * file-pr.c (append_report): Performance problems fixed; based on a patch by Dirk Bergstrom. * check-db.sh: New `--all-databases' option implemented. Indentation level changed to 2. * gnats.el (gnats-query-current-pr): Match the string without text properties. (gnats-query-view-pr): Convert the PR number string to a number. (gnats-query-edit-pr): Likewise. (gnats-fetch-pr): Apply `prin1-to-string' on `pr'. 2001-07-23 Milan Zamazal * fconfig.y: `multiEnumFileContents' added for the new `multi-enumerated-in-file' section. 2001-07-23 Johannes Poehlmann * fconfigl.l: `multi-enumerated-in-file' added. * fconfig.y: New token `MULTI_ENUM_IN_FILE'. 2001-07-15 Milan Zamazal * misc.c (value_is_empty): New function. * gnats.h: Declare it. * file-pr.c (submit_pr): If `Originator' is not set, try to set it to the value of the `Reply-To:' or `From:' e-mail headers. * pr.c (header_name): Use ANSI function argument declaration. (lookup_header): Use `InvalidHeaderName' instead of the numeric code. (find_header_index): Use `lookup_header' instead of duplicating the implementation. * mkcat.sh (USAGE): Usage string slightly improved. (prog): Set it uncoditionally. * mkdb.sh (prog): Set it uncoditionally. 2001-07-04 Milan Zamazal * database.c (getDatabaseFieldInfo): Remove the `const' qualifier; fixes: PR gnats/208. * database.h: Likewise. * misc.c (init_gnats): Likewise. * gnats.h: Likewise. 2001-06-24 Milan Zamazal * Makefile.in: Documentation support removed. 2001-06-21 Milan Zamazal * Makefile.in: All man related targets and dependencies removed. * configure.in: Don't generate man/Makefile. * configure: Regenerated. * All Texinfo and man files moved to ../doc/. 2001-06-17 Milan Zamazal * gnats.el (gnats-edit-server): Fix the buffer killing. 2001-06-13 Yngve Svendsen * misc.c (gnats_strftime): Cast the argument of `isdigit' to `int'. * gnats.texi: Document support for MD5 encrypted passwords in gnatsd.access files. Change location of global gnatsd.access and gnatsd.host_access. p-inst.texi: Change location of global gnatsd.access and gnatsd.host_access. Fix some typos. 2001-06-12 Yngve Svendsen * p-admin.texi, p-inst.texi: Largely rewritten for GNATS 4. gnats.texi: Revise appendixes for GNATS 4. 2001-06-11 Milan Zamazal * configure.in: Default gnatsd access configuration files to $sysconfdir instead of $datadir. * configure: Regenerated. 2001-06-11 Peter Novodvorsky * check-db.sh: Multiple database support added; fixes: PR gnats/198. 2001-06-10 Milan Zamazal * configure.in: Check for crypt.h added. * autoconf.h.in: Regenerated. * aclocal.m4: Regenerated. * configure: Regenerated. * gnatsd.c: Include crypt.h only if present; fixes PR gnats/200. * edit-pr.sh (DATE): Removed. * configure.in: Remove the test for strftime (replaced by a run-time check). * misc.c (gnats_strftime): Add run-time check for `%z'. 2001-06-10 Peter Novodvorsky * lists.c (listTypeList): Classes added; fixes PR gnats/62. (getGnatsFile): Handle ListClasses. * query.h (e_lists): ListClasses added. 2001-06-10 Carl E. Lindberg * misc.c (gnats_strftime): Handle unsupported `%z' manually. (minutes_gmt_offset): New function. 2001-05-27 Milan Zamazal * misc.c (gnats_strftime): Didn't work without `%z' support, fixed. * at-pr.sh (USAGE): Long options added. (prog): Use the explicit name, not $0. * gnats.el (query-pr-history): New variable. (query-pr): Use it. (view-pr): Convert the argument to a string. 2001-05-26 Milan Zamazal * edit-pr.sh (QUERY_PR): Use full path of the `query-pr' command; fixes PR gnats/113. * at-pr.sh (QUERY-PR): New variable, sets full path to the `query-pr' command; fixes PR gnats/115. * cmds.c (GNATS_help): Document the USER command in the version without arguments. * configure.in: Check for `%z' in `strftime' added. (AC_DIFF_OPT): Commented out (no longer supported by autoconf). (AC_LISPDIR): Likewise. (AC_FIND_PROGRAM): Replaced by AC_PATH_PROG. * acconfig.h: Introduce HAVE_STRFTIME_WITH_Z. Copyright header added. * autoconf.h.in: Regenerated. * aclocal.m4: Regenerated. * configure: Regenerated. * misc.c (gnats_strftime): New function. * gnats.h: Declare it. * query.c (format_pr_field): Use it. * pr.c (write_pr_field): Likewise. * internal.c (get_curr_date): Likewise. * file-pr.c (createNewPRFile): Likewise. 2000-05-26 Steffen Opel * cmds.c (GNATS_user): Reenable documented USER access level return value if issued without arguments; fixes PR gnats/108. * gnatsd.h (GNATS_nocl): Deleted left over prototype; fixes PR gnats/112. * Makefile.in (edit-pr): Substitute BINDIR. (at-pr): Likewise. (mail-query): Substitute LIBEXECDIR; fixes PR gnats/114. * file-pr.c (run_atpr): Supply --database option; fixes PR gnats/116. * cmds.c (gnatsChdb): Default editing users email address; fixes PR gnats/118. 2001-05-20 Peter Novodvorsky * gen-index.c (main): Write the number of fields in binary index before data writing starts; PR gnats/189. * cmds.c (set_confidential_access): Typo in the query expression fixed; PR gnats/187. 2001-05-06 Milan Zamazal * file-pr.c (createNewPRFile): Use %z instead of %Z in strftime. * internal.c (get_curr_date): Likewise. * pr.c (write_pr_field): Likewise. * query.c (format_pr_field): Likewise. * getdate.y: Updated (taken from tar-1.13.19 sources). * getdate.c: Regenerated. 2001-04-15 Milan Zamazal * gnats.h: Reviewed and made less confused. Merged in things from globals.h and config.h. * globals.h: Removed. * config.h: Move things not belonging here to gnats.h. * misc.c (version): Use EXIT_OK instead of number. (initGnats): Renamed to `init_gnats'. (newStringListEnt): Renamed to `new_string_list_ent'. (quoteString): Renamed to `quote_string'. (readLine): Renamed to `read_line'. (init_gnats): Description added. (log_msg): Likewise. Miscellaneous other coding style changes. * Makefile.in (mkdb): Replace xSYSCONFDIRx instead of xDATADIRx. (install-tools-arch-indep): Install defaults to sysconfdir. * mkdb.sh: Use xSYSCONFDIRx in DATADIR. * check-db.sh: Escape the single quote in here documents (Debian bug fix). Be verbose about missing index file (Debian customization). * categories: Sample categories commented out. 2001-04-14 Milan Zamazal * misc.c (usage): New function. (version): New function. * gnats.h: Declare the new functions. * pr-edit.c (main): Use the new functions. (usage): Removed. (USAGE): New constant; help text rewritten. (PROGRAM_NAME): New macro. * queue-pr.c: Likewise. * gen-index.c: Likewise. * gen-closed-date.c: Likewise. * pr-age.c: Likewise. (long_options): hostname -> host. * getclose.c: Likewise. * gnatsd.c: Likewise. (long_options): maximum-access-level takes an argument. (main): Exit with the code 1 if an invalid option is given. * query-pr.c: Likewise. (main): Do not perform actions before all options are parsed. 2001-04-08 Milan Zamazal * pr-edit.c (main): Return `2', not `!0' on other failures. * queue-pr.c (drop_msg): Do the copying of the temporary file to the queue directory correctly. * Makefile.in (SOURCES): Missing files added. * misc.c (temporary_directory): New function. * gnats.h: Declare it. * cmds.c (get_text): Use it. * queue-pr.c (drop_msg): Use it. * file-pr.sh: New option `--debug' (does nothing yet, it's for queue-pr). * queue-pr.c (USAGE): The help text improved. (USAGE): Split into several smaller strings. (main): Consider the new form of USAGE. Various stylistic and coding standard related changes. 2001-03-17 Milan Zamazal * query-pr.c (usage): Large string split into smaller pieces. * configure.in: Copyright header added. AC_FUNC_CHECK replaced by AC_CHECK_FUNC. AC_HAVE_FUNCS replaced by AC_CHECK_FUNCS. AC_HAVE_HEADERS replaced by AC_CHECK_HEADERS. * configure.in: Test for `unsetenv' availability added. * configure: Regenerated. * autoconf.h.in: Regenerated. * gnats.h: Declare `unsetenv' only if unavailable in libc. 2001-02-25 Milan Zamazal * flowchart.fig: The administrator and maintainers can use user tools too. * Makefile.in (fconfigl.c): Don't depend on flex command line options. 2001-02-20 Milan Zamazal * getdate.y: Additional time zone names added; thanks to Yngve Svendsen. 2001-02-17 Milan Zamazal * flowchart.fig: New file. * gnats.el (gnats-query-reverse-listing): New user option. (query-pr): Use it. (gnats-view-edit-pr): Let the buffer be no longer read-only. 2001-02-05 Milan Zamazal * gnats.el (gnats-edit-mode-map): Override the keys in the right order so that all the definitions take their effect. 2001-02-04 Milan Zamazal * configure.in (--with-gnats-server): Removed, it's no longer used. 2001-01-31 Mark D. Baushke * cmds.c (gnatsdChdb): Return the user access level for Gnatsweb use. 2001-01-29 Milan Zamazal * gnatsd.c (verifyHostAndUser): Ensure resulting access is not lower than host access. * configure.in: Check for crypt. * gnatsd.c (password_match): New function, based on a patch by Tommi Virtanen . (findUserAccessLevel): Use it. 2001-01-27 Milan Zamazal * gnats.el (gnats-edit-mode): Don't make the buffer read only. (gnats-next-field): New command. (gnats-previous-field): New command. (gnats-find-field-adjust): New function. (gnats-find-previous-field): New function. (gnats-edit-mode-map): New keys for the new commands defined. (gnats-edit-mode-menu): New menu. (gnats-format-field): Support mouse editting on enumerated fields. (gnats-replace-curr-text): Likewise. (gnats-edit-button-map): New keymap. (gnats-mouse-request-enum): New command. (gnats-request-enum): If invoked by a mouse event, use X menu. (gnats-request-enum): Choose as the default value the one starting with the last command letter, if possible. (gnats-find-next-field): Return a right position for multiline fields. (gnats-query-view-pr): Call mouse-set-point if needed. 2001-01-24 Milan Zamazal * edit.c (deletePR): Don't let `composeMailMessage' crash by giving it just NULL as the first argument. 2001-01-21 Milan Zamazal * man/Makefile.in (mostlyclean): Remove *.5 files too. * Makefile.in (doclean): Remove *.elc, *.html, and TAGS files. * gnats.el: Copyright notice updated. (gnats-format-field): INPUT documented. (gnats-format-pr): New argument INPUT added. (gnats-get-pr): NO-LOCK-P renamed to INPUT. (gnats-fetch-pr): Likewise. (gnats-view-mode): Enable view mode. (gnats-query-mode): Likewise. (gnats-view-edit-pr): Reformat the problem. (view-pr): New function. (gnats-query-view-pr): Use it. (unlock-pr): New function. (gnats-fetch-pr): Use it. (gnats-view-mode-map): "q" removed. 2001-01-15 Yngve Svendsen * gnats.texi: Spelling fixed. * p-admin.texi: Likewise. * p-inst.texi: Likewise. * p-usage.texi: Likewise. 2001-01-09 Milan Zamazal * check-db.sh: Handle binary indexes. 2001-01-08 Milan Zamazal * gen-index.c (main): Don't use the non-existent option `-c'. (usage): Likewise. (do_prs): New function. (main): New options `-i' and `-e'. (long_options): Likewise. (usage): Likewise. (add_pr): New function. (do_category): Use it. 2001-01-02 Milan Zamazal * index.c (writeIndex): Set the mode of the temporary file. * cmds.c (get_text): Set the mode of the temporary file. * misc.c (fopen_temporary_file): New argument for setting the file access rights mode. 2001-01-01 Milan Zamazal * gnats.el (gnats-query-font-lock-keywords): New variable. (gnats-query-mode): Use it. (gnats-edit-font-lock-keywords): New variable. (gnats-edit-mode): Use it. (gnats-query-view-pr): Use it. (gnats-do-query): Don't set EXPR if QUERY is empty. (gnats-update-font-lock-keywords): New function. (gnats-edit-mode): Use it. (gnats-query-view-pr): Use it. (gnats-server,gnats-port,gnats-database,gnats-user,gnats-password): New user options. (gnats-get-addr-info): Use them. (gnats-view-mode): New function. (gnats-query-view-pr): Use it. (gnats-view-edit-pr): New function. (gnats-view-mode-hook,gnats-query-mode-hook,gnats-edit-mode-hook): New hooks. (gnats-get-addr-info): Don't escape when doing prin1-to-string. (gnats-edit-mode): Print hint about submitting the edits. * query.c (iterate_prs): Set some error message when no PR is found. (The first GNATS bug fix of the 3rd millenium. Good.) 2000-12-31 Milan Zamazal * gnats.el (gnats-query-current-pr): New function. (gnats-query-view-pr): New function. (edit-pr): Put stars around the buffer name. (send-pr): Put stars around the buffer name. (gnats-get-addr-info): Put stars around the buffer name. (gnats-edit-server): Put stars about the buffer name. (gnats-fetch-pr): Allow fetching problem reports without locking. (gnats-get-pr): Allow fetching problem reports without locking. * database.c (newDatabaseInfo): Missing initializations added. * gnats.el (query-pr): New function. (gnats-do-query): New function. (gnats-query-mode): New function. (gnats-query-edit-pr): New function. (gnats-query-buffer-name): New variable. (gnats-query-mode-map): New variable. * Makefile.in (SOURCES): gnatsd source files added. 2000-12-30 Milan Zamazal * Makefile.in (LIBSRC): Updated. * gnats.el: Minor docstring fixes. Fixes required by checkdoc. (gnats-apply-edit): Invalid construct fixed. (send-pr): Autoload. (edit-pr): Autoload. (edit-pr): Convert `pr' to string before using it as a string. (gnats-get-addr-info): Convert `pr' to string before using it as a string. (gnats-apply-or-submit): The `count' argument removed. (gnats-submit-pr): The `count' argument removed. (gnats-apply-edits): The `count' argument removed. (gnats-send-command): Make `cstr' a local variable. (gnats-edit-server): Assign a value to `gnats-server-conn'. (gnats-get-addr-info): Signal an error if the server info couldn't be retrieved. (gnats-get-addr-info): Be careful about the buffer locality of `gnats-server-conn'. * query-pr.c (main): Wrong `database' identifier reference fixed. * internal.c (punt): Try to mail only if `database' is not NULL. * configure.in: Two typos fixed. GLOBAL_DB_LIST_FILE defaults to a location below sysconfdir, not datadir. * gnatsd.c (match): Use bool. (main): Call init_logging. * gnats.h (EXIT_OK): New constant. (EXIT_PROGRAM_ERROR): New constant. * misc.c (init_logging): New function. (enable_debugging): New function. (initGnats): Call init_logging. (log_msg): Consider log_method. (log_method): Change to NOLOG. (program_error): New function. * gnats.h (Logging_Methods): LOGFILE and NOLOG added. 2000-12-29 Milan Zamazal * configure.in: Test on mkstemp added. * autoconf.h.in: HAVE_MKSTEMP added. * queue-pr.c (drop_msg): Use open_temporary_file. * index.c (writeIndex): Use fopen_temporary_file. * cmds.c (get_text): Use fopen_temporary_file. * misc.c (open_temporary_file): New function. (fopen_temporary_file): New function. Wed Aug 23 12:49:59 2000 Bob Manson * pr.c (verifyMultiEnum): Accept NULL values if the field doesn't have a default value. (checkEnumTypes): If the field doesn't have a default value, don't try to copy it in. Mon Aug 14 17:10:47 2000 Bob Manson * cmds.c (gnatsdChdb): Don't free the current database if it's the same as the new one. Wed Aug 2 14:44:14 2000 Bob Manson * gnatsd.c (cmds): Allow multiple arguments to CHDB. * Makefile.in (getdate.c): Move the -o option in front, so it works with FreeBSD 4's slightly bizarre byacc. * configure.in: Add -Wno-format to make FreeBSD 4's broken headers happy; they erroneously claim that syslog() uses printf formatting. * configure: Regenerated. Tue May 30 14:41:09 2000 Bob Manson * database.c (freeDatabaseInfo): Unlink the entry from the list of databases before freeing it. Fri May 26 19:09:15 2000 Bob Manson * pr.c (fillInPR): Renamed from simple_get_pr (); add an ErrorDesc parameter. (get_pr): Make it static. (readPRWithNum): New function. * index.c (clearPRChain): Make sure the desc is non-NULL before referencing it. * cmds.c, edit.c, file_pr.c, getclose.c, pr-age.c, pr-edit.c: Finish cleanup of lock_pr() and unlock_pr(); they now take the PR ID instead of the pathname of the PR. Use readPRWithNum () and prExists () instead of getting the PR path etc. * queue-pr.c(main): Initialize the database to NULL. Fri May 19 20:45:01 2000 Bob Manson The current database is no longer a set of implicit global variables, but instead is passed in to the various functions that need it. initGnats () returns the requested database as a DatabaseInfo handle. * cmds.c (gnatsdChdb): New function. * gnatsd.c: Clean up authentication code a bit; all user authentication is now verified when a CHDB is done. Changing to the initial database is now done via gnatsdChdb (). The authentication is probably now broken, however. Tue Mar 28 15:29:51 2000 Bob Manson * edit-pr.sh: Fixed calls to query-pr to be consistent. Thu Mar 23 15:19:26 2000 Bob Manson * query.c (format_pr_field): Add support for %{strftime-format}D, to make formatting dates more flexible; you can even say "%{strftime-format}-8D" etc. Allow integer fields to be printed with %d. (process_printf_format): Detect the %{ and skip over to the matching }. * man/Makefile.in (SRCS8): Added pr-edit.man. * edit-pr.sh: Need to process the pre-changed PR template with $fixfil before comparing the two to see what fields changed. Thu Mar 23 14:26:50 2000 Bob Manson * query-pr.c: Fixed typo in builtin queries. Added "deprecated" warning. Tue Mar 21 21:24:48 2000 Bob Manson * edit.c (processPRChanges): If the old PR really doesn't have a value stored in its field (just an index entry), and the new PR doesn't either, then that field didn't change. * pr.c (prFieldHasValue): New function. Tue Mar 21 13:34:21 2000 Bob Manson * gnats.el (gnats-request-enum): Only go to the next field if the field didn't need a changed-why reason. * lists.c: Remove the "Classes" option. * query.h: Remove the ListClasses value. * query-pr.c (long_options): Remove --list-classes. * pr-init.c (getBuiltinField): Look up the field as a non-builtin field, if it's not a builtin. * dbconfig.in: Remove the builtin-name for fields that are no longer builtins. * builtin-fields.h: Remove several builtin fields that are no longer needed as builtins. * query-pr.c(query_opts): Use the builtin field names as strings instead of using the builtin structs. Mon Mar 20 23:12:05 2000 Bob Manson * gnats.el: Add submission ability. * client.c (scanEnv): Check the validity of the port in all cases. Sun Mar 19 01:19:35 2000 Bob Manson * gnats.el: Use query-pr --gnats-server-addr to get the hostname, port, etc. of the database to connect to. * query-pr.c: Add --print-server-addr option. * Change callers of client_init_gnats () to check its return status, and to handle exiting etc. * client.c (clientConnect): Add an ErrorDesc argument to return an error status. Don't exit on error anymore. (scanEnv): Make public, and don't use const char ** arguments since we're putting allocated strings into the pointers. The values returned contain defaults; this function now completely determines the user/password/host/port/database to use. (client_init_gnats): Make copies of the passed-in arguments to facilitate cleanup. Free up values obtained from scanEnv(). Add an ErrorDesc argument, and return a non-zero value on error. Fri Mar 17 12:27:55 2000 Bob Manson * misc.c (open_mail_file): If the mail agent is NULL, just leave without doing anything. * mail.c (get_responsible_address): If the database hasn't been properly configured, just return the mail address as-is. * internal.c (unlock_gnats): Fail gracefully if gnats_adm_dir () returns NULL. (punt): Try "mail user" if the mail agent can't be found or opened. Add the hostname where the error occurred to the subject line. * database.c: Add lots of checks for database validity, to prevent coredumps. * Makefile.in (install-tools-arch-indep): Fix path of gnats.el. Fri Mar 17 01:11:28 2000 Bob Manson * Makefile.in: References to gnats-el.in removed, no more byte compiling, no more references to send-pr.el etc. * gnats-el.in: Deleted. * gnats.el: Added. Thu Mar 16 20:32:12 2000 Michael Brader * gnatsd.c: Add support for --maximum-access-level option; remove --require-db option. Thu Mar 16 20:24:00 2000 Bob Manson * pr.c (setFieldChangeReason): New function. (unsetField): Free the change reason text as well. * pcodes.h (CODE_SEND_CHANGE_REASON): Added. * edit.c (edit_field): Add changeReason parameter, and change the field name string to a FieldIndex. * cmds.c (GNATS_appnOrRepl): Add additional prompt for the change reason text, if one is required. Thu Mar 9 20:48:34 2000 Bob Manson * Renamed field-config to dbconfig. A few minor changes to the .texi docs. Wed Mar 8 15:08:22 2000 Bob Manson * cmds.c (print_server_errors): Print out the list of bad fields if the error is CODE_INVALID_ENUM (the error message is not set in one case, because there may be multiple fields in error). Fri Mar 3 00:27:04 2000 Bob Manson * database.c (initHostList): Check for a per-database host access list. (Temporary fix, along with the change to GNATS_user ().) (databaseSpecServer): Init the list of databases as needed. * cmds.c (GNATS_user): The check here for access levels is a bit screwy; temporary hack to make it work in the obvious case. * client.c (client_init_gnats): If no user was specified, then use getlogin() or getpwuid () to determine a username to authenticate with to the server. Wed Mar 1 13:34:21 2000 Bob Manson * adm.c (build_chain_for_field): Ignore records with an incorrect number of fields. Mon Feb 28 19:04:48 2000 Bob Manson * pr.c (simple_get_pr, get_pr): Moved here from query.c. Sun Feb 27 12:15:16 2000 Bob Manson * query.c (freeQueryItem): Check for a NULL item being freed. * index.c (finishIndexDesc): Always mark the builtin number and category fields as indexed. * pr.c (struct PR_private): Add a flag to indicate if data is stored in the PR; speeds up freeing the PR. (allocPR): Use memset instead of setting individual pointers to NULL. (find_field_num): Subtract 12 bytes instead of 13 from the name when we find a -Changed-Why: field. * index.c (extractBinaryField): Avoid a couple of unnecessary pointer derefs. (freeIndexDesc): Free the indexed field flags. * database.c (initDatabaseList): Free the existing list before storing a new one. * flowchart.txt: A few minor tweaks (oh, well, it amuses me anyway ;-) Sat Feb 26 12:42:00 2000 Bob Manson * pr.c (addLineToPR): Take ownership of the passed-in buffer to avoid making a new copy of the contents. (read_pr): Let addLineToPR () take ownership of the line buffer. * index.c: Move the indexed field flags into the index descriptor. * client.c (readPRFromServer): Give ownership of the line buffer to addLineToPR (). * configure.in (GNATS_INSTALL): Remove --with-full-gnats. (Leave the partial targets in the Makefile, however). Fri Feb 25 10:19:19 2000 Bob Manson * field.h (struct field_def): Add isIndexedField member, to avoid linear searches in isIndexedField (). * index.c (isIndexedFieldIndex): Use isIndexedField member of the FieldDef for the field. * Fix a few missing (void) parameters from function definitions. * edit.c (validateFieldValue): Add missing parameter to regcmp (). * globals.h(APPEND_STRING): Deleted, no longer used. * query.c (newQueryItem): Keep the last-freed entry, and return it instead of allocating a new one. Make sure we free the regexp buffer we allocated. * pr.c (getFieldHeader): Don't bother making a copy of the header name, just return a pointer into the line and the length of the header. (find_field_num): Add LEN parameter. * field.c: Create a sorted list of field names. (find_field_index_with_len): New function (basically renamed from find_field_index). Do a binary search for the field name on the sorted field name list. * query.c (freeQueryItem): Oops, one too many free()s. * pr.c: Use fputs () instead of fprintf() in several places. (find_field_num): Use find_field_index (). * field.c (allocComplexFieldIndex): New function, to optimize their allocation. * pr.c (getFieldHeader): Use xstrndup. (write_pr_field): Don't call xmalloc (); instead, be a bit smarter about formatting output. * field.c (isConstantFieldValue): New function. * query.c: Add QueryItem object to hold individual query items; this lets us keep around precompiled regexps for constant query regexps, instead of recompiling every time. (regcmp, regfind): Add pattern buffer argument; only compile the regexp into the supplied buffer once. * misc.c (readLine): Optimize (remove a unnecessary memcpy()). * cmds.c (GNATS_help): Add some missing commands. * query.c (parseQueryFormat): Add "or query format" to error message. Thu Feb 24 19:23:16 2000 Bob Manson * edit.c (processPRChanges): For now, ignore changes to read-only fields instead of generating an error. * query.c (intFieldCompare): Make global. * edit-pr.sh: Just set the user's email addr to $me. * query-pr.c (main): Allow the --adm-field field to be a complex field name. * cmds.c (GNATS_admv): Allow complex field names here. * query-pr.c (main): Allow the --field-flags and --field-types arguments to be lists of fields; this is already handled in the server, but we need to do something similar in the non-server case. * edit-pr.sh: Add blanks for fields that aren't already in the PR; for now they're stuffed at the end of the PR. Wed Feb 23 15:54:49 2000 Bob Manson * mail.c (getOneAddress): New function, to cheezily rfc822-parse one address out. (get_one_responsible_addr): If the address already cheezily appears to be a full email address, then just return a copy of it as is (with no express or implied warranties as to fitness or purpose). * gnatsd.c: Misc cleanups. * edit.c (deletePR): Move UID check... * pr-edit.c (main): to here. * client.c (netDeletePR): It's DELETE. * cmds.c (GNATS_delete): New function. Tue Feb 22 15:02:09 2000 Bob Manson * cmds.c (GNATS_inputdefault): mmmm, typo. * edit.c (edit_field): Don't coredump if the field didn't exist before and we're appending. * gnatsd.c (serverMainLoop): Make sure it exits on input error. * edit.c (rewrite_pr): Check if the PR has changed categories and if the new category directory exists; if it doesn't and we're in autocreate mode, create it. * cmds.c (GNATS_inputdefault): Escape newlines in the default value. * gnatsd.c (serverMainLoop): Don't segfault on blank lines (patch suggested by Michael Brader ) * Add random casts and #defines for Solamis (including my favorite redefinition of SIG_DFL). Yeah, it's just random flotsam, and it won't work in some other Solamis release. Use an OS that supports user-built software and doesn't have massively broken headers, or fix it yourself. * gnats.h: Add missing prototypes from libiberty, plus one piece of Solamis trash. * Makefile.in: Sordid rules to make Solamis' ancient make work. (fconfig.c): Checks for various yacc-brand (tm) lossage. It still won't work with an ancient yacc tho--old yaxxen don't handle -p correctly for yylval. Mon Feb 21 18:54:57 2000 Bob Manson * client.c (scanEnv): Fixes for checking the presence of a default database with a host/port in the adm file. Mon Feb 21 15:00:12 2000 Bob Manson * cmds.c (get_text): If we free buf, set it to NULL. Don't try to free buf if it's NULL. * internal.c (gnatsdbHasNetconn): Check for a database adm entry that has a server and port. * database.c (readAdmFile): Add option to allow more fields than required. (databaseSpecIsNetConn, databaseSpecServer, databaseSpecPort): New functions. * client.c (scanEnv): Check for a database name that has optional host and port associated, and use them. * adm.h: Add optional DatabaseHost and DatabasePort fields to the database adm entry. * fconfig.y, mail.c, mail.h: Allow Reply-To: to be a list of addresses, not just one. * file-pr.sh: Use --database, not --directory. * misc.c (init_gnats): Set the regexp syntax to Posix Extended (which is a brand of wine most favored by champions). * query.c (parseQueryExpression): Skip text in double quotes, just like parseSimpleQueryExpression (). Fri Feb 18 17:40:32 2000 Bob Manson * field-config.in: Add entry for category-dir-perms. * fconfig.y: Add support for category-dir-perms keyword. * database.c (setCategoryDirPerms, categoryDirPerms): New functions. * mail.c (insertAddress): Don't insert duplicate addresses. Thu Feb 17 17:11:41 2000 Bob Manson * edit.c (applyChangeActions): Need to keep the original action list around. * pr.c (unsetField): New function. Wed Feb 16 20:32:47 2000 Bob Manson * edit.c (processPRChanges): Ignore empty fields in the new PR that weren't present in the old one. Tue Feb 15 17:57:24 2000 Bob Manson * pr.c (checkEnumTypes): Don't generate an error if this PR is an initial PR and the field is nonexistent. * index.c (build_index_entry): Assume nonexistent fields are empty. (format_field): Ditto. Mon Feb 14 15:54:48 2000 Bob Manson * pr.c (field_value): Always return NULL if the field doesn't exist and it doesn't have a default value; don't arbitrarily put an empty value in the PR field. If the field is a date field and its index entry contains a 0, return NULL instead. (Date values are still busted, but this is less busted now.) * edit.c (validateFieldValue): Handle a non-existent field value when verifying regexps. (processFieldChange): Add the old and new field values to the read-only error message. * cmds.c (print_server_errors): Don't handle any errors specially, since the error message is always filled in now. * query.c (parseQueryFormat): Make sure the list of fields ends up in the correct order. (writeFullPR): Don't use variables before they're set. * edit.c (addAuditEntryP): New function. (processPRChanges): Ignore the case where a field isn't present in the new PR but did in the old, and field is readonly; we set the new PR's field to have the same value as the old one. (edit_field): Use append_string () instead of the macro. (applyChangeAction): Don't handle adding audit-trail entries here... (applyChangeActions): Do it here instead; we can also check for a global "add audit trail entries" action. Fri Feb 11 16:55:09 2000 Bob Manson * mail.c (get_responsible_addr): Assume multiple addresses, and split them by commas before mapping. (get_one_responsible_addr): New function (renamed from get_responsible_addr). Fri Feb 11 14:09:57 2000 Bob Manson * file-pr.c (createNewPRFile): Fix bug preventing new directories from being created. * Add lots of checks for nonexistent fields. * fconfig.y: Add support for edit-only flag, and virtual-format field descriptor. * field.c (get_field_value): Add support for virtual fields; add mustBeFreed parameter. * edit.c (rewrite_pr): Require a category value. (addAuditTrailEnt): Check for a missing audit-trail field; set it to "" if it's not there. Thu Feb 3 21:40:43 2000 Bob Manson * field.h (FieldType): Add PRListType. (struct field_def): Add maxPrsPerLine entry. * fconfig.y: Add support for pr-list type. * edit.c (validateFieldValue): Add checking for PRListType. Wed Feb 2 10:59:41 2000 Bob Manson * gen-closed-date.c (get_closed): Fix some potential buffer overrun bugs. * client.c (scanEnv): Free items we allocated but didn't use. * query.c (iterate_prs): Add err parameter. * misc.c(init_space): Deleted, no longer used. * gnatsd.h: Move system includes to the front of the file. * gnats.h: Include . (SKIP_WHITE_SPACE): Deleted, no longer used. * index.c (get_pr_chain, open_index, getIndex, getCategoryFromIndex): Add err parameter. * queue-pr.c (fork_gnats): Use "--database databaseName ()" instead of "-d databaseDir ()" for the option to file-pr. * file-pr.c (createNewPRFile): Fix typo. Tue Feb 1 17:47:45 2000 Bob Manson * pr.c (addLineToPR): Add spaces to the beginning of Unformatted: field entries if they don't have one already. Ignore text that looks like a field name if it isn't a valid name. * query.c (process_format): Don't try to reference NULL PRs. * pr-edit.c (main): Check for a PR number before allowing edit actions. Don't close already-closed file descriptors. * index.c (createIndexEntryBinary): Fix typo. * file-pr.sh: Fix another typo. * field.c (get_field_value): If the supplied PR is NULL, return an empty string for field values. * field-config.in: Reorganize to match the traditional PR full format. * cmds.c (GNATS_inputdefault): New command. * adm.c (free_adm_entry): If the entry is NULL, don't try to free it. * queue-pr.c (main): Don't call punt() if the command usage isn't right. Sat Jan 29 01:14:01 2000 Bob Manson * internal.c (setError): CODE_READONLY_FIELD has a BadFields list. * index.c (writeCurrIndex): Fix writing out of binary indexes; we need to write the number of fields in the index as the first byte. (createIndexEntry): Call createIndexEntryBinary () if the index is binary. Fri Jan 28 10:11:48 2000 Bob Manson * query-pr.c (queryPrExit): New function; do cleanup before exiting. Remove unused support for --network-mode. * internal.c (newBadFieldEntry): Don't try to xstrdup () NULL values. * database.c (defaultSubmitter): Use the cached contents of the adm file. (defaultCategory, defaultState): Ditto. * Add support for binary index files. * fconfig.y: Add support for new binary-index keyword. * fconfigl.l: Ditto. * client.c (client_exit): Clear the current database. * index.c(readBinaryRecord, extractBinaryField, nextIndexEntryBinary, appendBinaryFieldContents, createIndexEntryBinary, findPrCategoryBinary, indexIsBinary, indexFieldCount): New functions. Thu Jan 27 11:08:17 2000 Bob Manson * query-pr.c (main): Finish the network support for all options. * pr.c (write_multitext): Don't arbitrarily add an EOL if the input string doesn't have one. (printValidValues): Write out an EOL after each value. * gnatsd.c (main): Don't twiddle with the regexp syntax arbitrarily. * client.c (get_reply): Handle a few more error types. (clientConnect): Add support for invoking gnatsd locally via socketpair (). (sendRemoteQuery): Need to increment the current PR index. (netValidValues, netFieldDescription, netFieldType): New functions. * query.c (do_print): Print %d formated values as an integer value. Wed Jan 26 14:07:35 2000 Bob Manson * query.c (findQueryFormat): Add err parameter. (print_named_format_pr): Ditto. (parseQueryFormat): Check the field name to see if it's valid; fail if it isn't. Add err parameter. Set the name field of the result to NULL. * field.c (parseComplexFieldIndex): Return an error if the field name is invalid. * gnatsd.c (match): Minor cleanups. (gnatsd_argify): Fix typo. * Remove all line length limits. Change the error handling to be much cleaner; remove all calls to punt() from library code. Use asprintf() extensively. * internal.c (fileExists): New function. * gnatsd.c (serverMainLoop): New function; move most of the code out of main(). Don't call exit() here. * fconfig.y: Remove index-field-is-optional. * gnatsd.c (gnatsd_argify): Restructure. Don't needlessly allocate 4x the length of the line. (Read: rewrite really crappy code.) * index.c (format_field): Don't fail if the date is invalid; put a 0 in the index instead. * config.h: Delete STR_MAX et al. * pathmax.h: Deleted, no longer used. Sat Jan 22 21:29:00 2000 Bob Manson * files.[ch]: Deleted, no longer used. * Added global PR change options. Changed "char *" to "const char *" in many appropriate places, and -Wwritable-strings to GCC_CFLAGS. Fixed several potential bugs regarding const strings. Added read-only fields. Tue Jan 18 08:49:04 2000 Bob Manson * Fix error handling on parse errors, so that partially-allocated data is freed. Make sure error status on parse errors is propagated to the right places. Clients now exit when an invalid configuration is read in, and gnatsd reports the database as invalid. * field-config.in: Add a few additional comments. * fconfigl.l: Change quote strings so they're either explicitly taken over by the parser, or freed when the parser exits. * getclose.c (do_netprlist): Don't return confidential PRs. Mon Jan 17 21:59:10 2000 Bob Manson * Add ChangeActions struct, to consolidate various per-field change information. Add conditional edits; this breaks existing field-config files. Fix several memory leaks. * field-config.in: Fix syntax for State: and Responsible: fields. Add entry to State: field to update Closed-Date: field. * query.c (pr_matches_expr): Add PARAMS argument. * field.c (get_field_value): Fix bug with not returning oldPR values. * edit.c (fix_closed_date): Deleted, no longer used. (applyFieldEdit): Actually do something. Free data that we allocated. (addAuditTrailEnt): Add FMT parameter. Free up value gotten from get_curr_date (). Sun Jan 16 20:23:57 2000 Bob Manson * man/query-pr.man: Update a bit. * file-pr.c (create_new_pr_file): Check for NULL field values, instead of assuming non-existent fields return an empty string. Fri Jan 14 23:20:09 2000 Bob Manson * Replace most uses of FieldList with a new type, ComplexFieldIndex. FieldList is now what it claims to be. Enhance queries and formatting even more; now query arguments are completely symmetrical (way overkill, but it actually simplifies code). * field.c: New file. * cmds.c: Deleted fval command. * builtin-fields.h (struct pr_builtin_field): Removed fieldDef member, no longer used. Thu Jan 13 19:54:22 2000 Bob Manson * pr.c (getFieldFlags): New function. (read_header): Fix problem with overwriting array boundaries, and make sure the header value has a terminating NUL. * gnatsd.c (freeArgs): New function. (main): Restructure a bit; make sure we're freeing up the arguments we parse. * field.h (struct field_def): Add requireChangeReason flag. (The flags should probably be collapsed into a single bitfield.) * misc.c (init_gnats): Call clearCurrDatabase (). * database.c: Encapsulate the database state into a struct (tho there are still static variables scattered throughout the code). (clearCurrDatabase): New function. * configure.in: Did some remaining cleanup; deleted several unused options. * cmds.c (GNATS_fieldflags): New function. * client.c (netFieldFlags): New function. * query-pr.c (long_options): Add --field-flags option. * edit-pr.sh: Use diff-prs; ask about fields that require a reason for change, if they've changed. * diff-prs: New script to list the fields that have changed between two PRs. Wed Jan 12 15:40:17 2000 Bob Manson * delete-pr.sh: Don't send mail about deleted PRs--the server does it now. * Makefile.in, configure.in: Deleted GNATS_ADMIN; it's now wired to gnats-admin. (To change gnats-admin's mail address, change it in the responsible file.) * config.h: Delete INDEX define, no longer used. * index.c: Use the "path" entry in the index descriptor. (build_index_entry): Fix index allocation code. (free_pr_index): Free the individual field entries if we didn't allocate them with a buffer. * query.c: Change the funny '[' and '%' designators to real words (builtinfield: and fieldtype: respectively). Use FieldList instead of FieldIndex for referring to which fields to search; this makes it possible to do even more interesting queries. Remove the FieldType search ('#' operator), it's no longer needed. * files.c: Delete a bunch of unused functions. * query.c (append_string, append_char, do_print): New function. (format_pr_field, process_printf_format, process_format): Add the ability to produce output into a char* instead of a FILE pointer. (allocateNamedParameter, getNamedParameterValue, freeFormatParameterList): New functions, for supporting parameters to format statements. * pr.c (get_field_value): Add PARAMS argument, for format parameters. * edit.c: Add parameters for the email address of the user performing the various edit actions. (addAuditTrailEnt, sendAuditMail): New functions. * edit-pr.sh: Simplify--the server now takes care of Audit-Trail: entries and sending email for edits. * cmds.c: Add editEmailAddr static variable (this belongs somewhere else...) (GNATS_user): Use get_responsible_addr () to set a default edit email address for the user. (GNATS_editaddr): New function. * client.c (netSetEditEmailAddr): New function. (netEditField): Set the email address of the editing user before doing the edit. (netModifyPR): Ditto. * database.c (setAuditTrailFormat, getAuditTrailFormat): New functions. Tue Jan 11 17:06:40 2000 Bob Manson * query.c (format_pr_field): Take a FieldList** instead of a FieldIndex; take care of moving the pointer to the next field if we actually consumed one. Add appendedAudit parameter. Use get_any_date (). Add 'P' and 'A' formats. * pr.h: Delete bizarre comment. Add predefines for various structs and typedefs before including the headers needed by this file. * pr.c: One of my favorite fixes--headers no longer have that &$#(*@$ newline at the end. (Simplifies a lot of code.) (verify_enum): Call verifyMultiEnum () if the field is a MultiEnum field. (verifyMultiEnum): New function. (set_field): Use validateFieldValue () to verify that the field value is OK. (find_header_index): New function. (get_field_value): Smarter, faster, more powerful. (We have two field indexes now...not good. Tho they really do different things.) * pr-init.c (fconfig_parse): Call init_header () here (bleah! badness! eeeugh!) * gnatsd.c (cmds): Make most commands ACCESS_VIEW at least. PR submission is ACCESS_SUBMIT. (Access levels should be bits, probably defined by field-config. Not yet.) (main): Not sending a required CHDB gives an error message now. * gnats.h: Move StringList here (???). * file-pr.c (create_new_pr_file): Note that the received Category: field is invalid. Call composeMailMessage () to send out our mail. (notify_responsible, reply_to_submitter, append_notify): Deleted, no longer used. (append_report): Use edit_field () and composeMailMessage (). * field-config.in: Add mail-format entries for submitted PRs and PR notes received by mail. * fconfig.y: Add support for parsing the new mail-format entry, and support for multiple enum fields (enum fields with more than one value). * adm.c (getAdmSubfieldValue): New function. * mail.c: New file. Move several mail-related routines into here. (composeMailMessage): New function. Fri Jan 7 23:19:16 2000 Bob Manson * edit.c (validateFieldValue): Add a check for Integer fields. Allow Date fields to be an empty string. * pr.c (set_field): Validate the new field value with validateFieldValue (). Add an err parameter to return errors if the value is invalid. Wed Jan 5 21:59:43 2000 Bob Manson * Makefile.in: Remove all traces of GNATS_ADDR. Wed Jan 5 12:53:02 2000 Bob Manson * gnats-databases.in: Added. Tue Jan 4 14:12:27 2000 Bob Manson * query-pr.c (main): Don't try to parse empty expressions. * mkdb.sh: Copy gnatsd.access instead of gnatsd.host_access. * Makefile.in (install-tools-arch-dep): Add dependency on field-config. (doclean): Delete fconfig.c and friends. * query-pr.c (main): Check for lists before trying to parse the query expression. * query.c (getSearchOperatorForType): Make global. (parseSimpleQueryExpression): Add support for initial '[' marker indicating that the field name referred to is the builtin name. (appendSearchItem): Ditto. * query-pr.c: Construct queries initially as strings; we then either send them directly to the server as is in network mode, or parse it for doing a direct query later. (oldQueryField): New function. * pr-init.c (getBuiltinField): New function, for looking up builtin field information. * pr-edit.c: We no longer parse PRs when in network mode. Let the server win. (readPR): Deleted, no longer used. * misc.c (quoteString): Move here; it's now a global. * edit.c (replace_pr): Fill in err->msg. (check_pr_file): Ditto. * edit-pr.sh: pr-edit now requires the number of the edited PR. * client.c (sendRemoteListQuery): Add outfile parameter. (sendRemoteQuery): Add queryString parameter, for sending unparsed expressions. (netSendPRCmd, netEditField, netCheckPR, netSubmitNewPR, netModifyPR): Change PR* parameter to FILE*; we send the files directly now, so the server does all the work. * lists.c (getGnatsFile): Removed ListFieldConfig, no longer used. Removed infile. * client.c: Removed unused variable reply. (clientConnect): Renamed from client_init. (get_reply): Handle CODE_TEXT_READY. (client_get_field_config, client_get_field_config_line): Deleted, no longer used. (client_init_gnats): Don't call client_get_field_config (). * Makefile.in: Removed GNATS_ADDR (oops). * configure.in: Ditto. * configure: Regenerated. Sun Jan 2 13:24:43 2000 Bob Manson * pr.c (init_header): Make init_header () a global, we need to call it from client_init_gnats () for now. * client.c (client_get_field_config): It's CODE_TEXT_READY now. (client_init_gnats): Call init_header (). * fconfig.y: Add a bit of useless error recovery. * fconfigl.l: Fix quoted string lexing. Match bad tokens and return the arbitrary token BADTOK for them. Sat Jan 1 22:44:17 2000 Bob Manson * man/gnatsd.man, man/pr-edit.man: New files, again woefully incomplete. * man/query-pr.man: Add a bit more verbiage. * man/gnats.man: Mark obsolete commands. Mention pr-edit. * Use InvalidFieldIndex or the other Invalid* enum entries instead of -1. Don't compare returned values from Unix system calls against -1; it's either 0 or non-zero. Delete global is_network_client variables, they haven't been used for some time. Change QueryExpr into an anonymous pointer-to-struct; it's now encapsulated within query.c as it should be. * query.c: Changed DateLessThan and DateGreaterThan to LessThan and GreaterThan. Added ability to search all fields of a particular data type (replacement for hardcoded multitext and text searches). Simplified QueryExpr construction. (SearchItem, QueryExpr): Moved here from query.h. Added operator string for DefaultSearchType. (intFieldCompare): New function, for returning an integer value describing the relation between two arbitrary field values. (< and > now work on any field type.) * query-pr.c (long_options): Removed bogus --print-field option. * pr.c (PR_FIELD_TAG_END, PR_FIELD_TAG_START): Moved here; this is the only place they should be used. (stringToFieldType): New function; use an array instead of hardcoding values into a function. * lists.c (stringToListType): Case-insensitive comparisons are better. * gen-closed-date.c: Removed unused catfile option. * file-pr.c (create_new_pr_file): Completely fill in the error field values. * cmds.c: Clean up the response codes so they make more sense and are reasonably consistent. (The gnatsd.man page describes the classes of errors and responses.) Removed a few more unneeded commands. (set_confidential_access): Moved here from gnatsd.c. (GNATS_help): Add description for SUBM. * client.c: Get rid of a few more globals. (server_reply): Strip off the line terminator. (get_reply): Handle continuation replies more gracefully. Don't try to parse error strings, they're not intended for us. Make the response codes we handle match those now sent by the server. Fri Dec 31 13:28:44 1999 Bob Manson * query.c (pr_match_field): Fix multitext searches. Thu Dec 30 17:14:43 1999 Bob Manson * man/query-pr.man: Mostly revised, still woefully incomplete. * man/*: Very preliminary (and incomplete) updates. Added a couple of pages, deleted references to mkdist. * edit-pr.sh: Fixed --database option. * delete-pr.sh: Added --database option; fixed exit statuses for invalid options. * gen-index.c: Minor cleanups; also fixed output so newlines appear when -n option is used. Removed bogus --catfile option. * delete-pr.sh: Use query-pr to get the address of gnats-admin. * npr-edit.c: Deleted, no longer used; functionality merged into pr-edit.c. * gnats-*.sh: Deleted, no longer used; functionality merged into their respective scripts (gnats-file-pr.sh->file-pr.sh, gnats-edit-pr.sh->edit-pr.sh). * client.c (netSendPRCmd, netCheckPR, netEditField, netSubmitNewPR, netModifyPR, netLockDB, netUnlockDB, netLockPR, netUnlockPR, netDeletePR): New functions. Wed Dec 29 15:33:18 1999 Bob Manson * query.c (insert_closed): New function. * gnats-edit-pr.sh: Automatically set the mode to "network" if a : appears in the GNATSDB variable. Clean up option processing of --host etc. Don't set default values for HOST, PORT, etc. here, let nedit-pr take care of it. * getclose.c: Added network support. * client.c (clientReadPR, readPRListFromServer, clientGetPRList): New functions. * pr-age.c: Added network support. * query.c: Added support for parsing FieldType operator (assigned to '#'); needed for checking for closed PRs. * query-pr.c: Added new options --adm-field, --adm-subfield and --adm-key. (main): Default username and password are now NULL. * pr-stat.c: Minor fixes; it's still pretty badly broken. Not sure if it's worth fixing. * npr-edit.c (main): Default username and password are NULL now. * lists.c (getGnatsFile): Fixed erroneous fallthrough to abort (). * internal.c (gnatsdbHasNetconn): New function. * edit.c (validateFieldValue): New function. (check_pr): Massively simplified; uses validateFieldValue (). (edit_field): Use validateFieldValue (). * database.c (getHostList): Add a call to initHostList (). * cmds.c(GNATS_mlct, GNATS_mlsu, GNATS_mlrs, GNATS_type, GNATS_resp, GNATS_catg, GNATS_vdat, GNATS_nocl): Deleted. (GNATS_admv, GNATS_vfld, GNATS_expr): New functions. * client.c (client_get_field_config): Use sendRemoteListQuery (). (sendRemoteQuery): Send a string expression with the EXPR command instead of sending individual nodes. (send_query_field, send_query_node): Deleted. (clientGetAdmField): New function. * adm.c (printAdmSubfield): New function. * file-pr.c (create_new_pr_file): Replaced sole use of PENDING with defaultCategory (). Tue Dec 28 14:03:52 1999 Bob Manson * sub-type.c, pr-addr.c, pr-mail.c, npr-addr.c: Deleted; functionality added to query-pr. * Replaced --directory options with --database, and edited usage strings to match. * configure.in: Changed with-gnatsd-access-file to with-gnatsd-user-access-file. Added with-gnatsd-host-access-file. Moved the gnatsd.host_access file into ${datadir}/gnats; there should probably be a per-database version as well, but I'm too lazy to add it. Mon Dec 27 20:38:18 1999 Bob Manson * file-pr.c (notify_responsible): Fix typo causing bad fields to be misreported. * man/Makefile.in: Removed mkdist.8 references. * pr-init.c (getFconfigLine): Renamed from get_line (). * pr-edit.c (main): Fixed submit_pr () call. * internal.c (readLine): New function, unused as of yet. * index.c (find_pr_category): Replace 512 with STR_MAXLONG. * file-pr.c (submit_pr): Removed flag_autocreate argument; this is obtained from the database spec now. * fconfig.y: Added rule to parse create-category-dirs database item. * database.c (setCreateCategoryDirs, createCategoryDirs): New functions. * configure.in: Changed various config options at pst's suggestion. Put the shared gnats_databases file in gnats subdirectory. * cmds.c (GNATS_subm): Fix submit_pr () call. * Makefile.in: Added rules for mkdb and installation of default (template) files; removed rules for creation of default database. Added reminder to run mkdb, and removed mention of mkcat (category directories are now created on the fly by default). Removed references to mkdist. Tue Dec 21 22:38:29 1999 Bob Manson * client.c (scanEnv): New function, to get various items out of GNATSDB if they weren't supplied by the caller. (client_init_gnats): Call scanEnv (). * query-pr.c (main): Add a temporary hack to check for a : in GNATSDB; if it's there, we're a network client. Remove cheezoid manipulation of regexp matching for EOF, we better not need it anymore. * client.c (client_chdb): Send "default" if we're handed a NULL database name (handle it like init_gnats does). * configure.in: Add test for socklen_t. * Replaced calls to strdup with xstrdup. * pr.c (allocPR): NULL != 0; I'm surprised gcc-2.7.1 didn't catch these. (verify_enum): If the enum value is NULL, don't try to check it. * pathmax.h: Another linux fix, this one's probably a decent change--we should include sys/param.h before deciding there's no PATH_MAX and we need to define our own. * internal.c (get_curr_date): Changed %y to %Y, which makes egcs shut up. Admittedly it may fix a "why, tookay?" bug, but I'm much more worried about the y3000 bugs. * gnatsd.c (cmds): Fixed last entry. (start_connection): Made len a socklen_t if socklen_t is present, which makes linux happy. * config.h: Add crappy bad fix for linux glibc madness. "But it's correct according to the standard!" Bleah. * Makefile.in: Added GNATSD_ACCESS_FILE, left it out from previous changes. Also added rules for fconfigl.o and getdate.o to work around non-easily-fixable warnings. * configure: Regenerated with autoconf-2.13. * client.c (client_exit): Don't do anything if we're not a network client. Mon Dec 20 15:47:25 1999 Bob Manson * Removed config file and associated trappings, and now most of the config that was previously there is now in field-config (which will probably be renamed shortly). GNATS_ROOT is no longer. The GNATSDB environment variable is now used to determine which database to use (or the -d option to the clients). Databases must now be specified by name. The list of database names is now in ${datadir}/gnats_databases by default. It is formatted similarly to the other adm files, and uses the same routines. Since there is one other GNATS file in ${datadir}, namely gnatsd.access, it may make sense to make a gnats/ subdirectory there but I'm reluctant to do it for two files. Currently GNATSDB only contains a database name; eventually it will also be of the form host:port:name which is used for remote access. Someday some sort of ssh tunneling functionality will be added, especially now that the emphasis is on remote access. The default database is now located in ${sharedstatedir}/gnatsdb. I may change things to allow the datafiles to be located indepndently from the database. The only major change would be to the scripts, and the vast majority shouldn't need to be changed now. query-pr now supports specifying a format string on the command line with the --format option: query-pr --format '"%s %s" Number State' prints out the Number: and State: field values with a space between the two. Also, query-pr --format State prints out the State field. A new server command, QFMT, has been added. The query format is now specified with QFMT (and must be specified before QUER is invoked). I have not tested remote access lately, it may very well be broken (tho gnatsd seems to be working from the command line). A few new options have been added to query-pr, to print out the directory where a database is located, and to dump a sh-compatible set of variables describing things like the name of the database, its location, etc. The NOTIFY, ACKNOWLEDGE and DEFAULT_SUBMITTER configure options have been deleted. DEFAULT_SUBMITTER is gotten from the submitters list instead--it's the first entry. (It always was, it's just not being kept in two places now). There's also no longer a default port number--if you need to set a default port, add it to /etc/services as a service instead. MAIL_AGENT is also gone; the mail-agent script is used instead (the script is installed in ${libexecdir}/gnats/mail-agent). lists.c has been reoverhauled; it's much better now. It no longer dumps out files directly, except for the field-config file. db_conf* have been removed (functionality replaced in database.c). Many of the scripts are currently broken (they refer to GNATS_ROOT, and they need to call query-pr to get the directory name for the database instead). Many, many, many prototype fixes. 10 hours worth, in fact. Enabled several anal pedantic warnings in gcc. Eventually these will only be enabled when --enable-maintainer-mode is turned on (some systems have broken headers and things simply won't compile otherwise). Removed xmalloc.[ch]; xmalloc is used from libiberty, and free is called directly. There will probably be problems because of this, because some libcs are unhappy about freeing NULL pointers; the code in GNATS should be fixed instead of using a wrapper. gnatsd.conf is now renamed to gnatsd.host_access; a slightly more descriptive name. It also uses the adm.c routines for reading. Most of delete-pr is in pr-edit now; delete-pr still handles deleting all closed PRs. Most of the scripts have been fixed. Some of them are almost certainly still busted. Scripts that still directly refer to files are (mostly) \hbadness 10000 and need to be fixed. None of the scripts should be manipulating PRs or the index file directly. I know that check-db is massively not working right now. edit-pr is kind of suckage right now, but it should still work. It still knows about which fields need to have audit-trail entries added; I had planned on fixing this for 4.0, but it won't happen. Most of the functionality is actually in the server, except for sending mail when changes occur. The "site" functionality has been removed. It never was implemented very well or thoroughly. Something similar may be reimplemented, but not in 4.0. This is likely the last major set of changes before 4.0 beta is released. The only planned changes are to filenames, and of course the major associated documentation cleanups. I also need to track down memory leaks, tho given the nature of the programs involved this actually isn't all that crucial. 1999-12-16 Kenneth H. Cox * Makefile.in (install-gnats-arch-indep): Location of gnats was $(top_builddir) which was not defined. Changed to $(srcdir). Fri Dec 10 17:04:38 1999 Bob Manson * query.c (parseQueryExpression): Make sure both sides of the QueryExpr are NULL. * pr.c (newFieldDef, freeFieldDef, freeStringList, freeFieldList, freeFieldEdit, clearFieldList, freeInputTemplate): New functions. * pr-edit.c (main): Removed -F option. * index.c (indexEntry): Added nextPR member. The index chain is now kept as part of the PR's index. (check_pr_chain, free_pr_chain, init_index, get_pr_chain, free_curr_pr_chain, replaceCurrentPRInIndex, get_next_pr): New functions, or moved from pr.c. * field.h: Moved PR_FieldType and SearchType here. * edit.c (replace_pr): Removed force argument. (rewrite_pr): Ditto. (processPRChanges): New function. * client.c (sendRemoteListQuery): New function. (sendRemoteQuery): Renamed from send_remote_query(). Moved list functionality into sendRemoteListQuery(). * adm.c (freeAdmFieldDesc, freeAdmEntryChain): New functions. Thu Dec 9 20:57:02 1999 Bob Manson * pr.c (field_value): Fundamental change--PR contents always override index contents. * getclose.c (do_prlist): Use gen_pr_path(). * gen-index.c (do_category): Check to see if the PR read in is remotely sane. (We should return an error status from read_pr() since it no longer insanely exits). * query.c(make_path): Removed, no longer used. * internal.c: Removed gnats_locked (identical to is_gnats_locked). * lists.c (stringToListType, listTypeToString): New functions. (getGnatsFile): Renamed from get_gnats_file; simplified. * cmds.c (GNATS_list): New function, calls getGnatsFile. Remove old GNATS_l* list functions. * client.c (send_remote_query): Change list parameter. Use listTypeToString (). * query.h: Remove unused format #defines. Remove LIST_* bitmasks; add ListTypes enum. Wed Dec 8 16:30:09 1999 Bob Manson * query-pr.c (main): Use printValidValues instead of coding it here. * pr.c (printValidValues): New function. * gnatsd.c (cmds): Add new commands. * cmds.c (GNATS_fdsc, GNATS_flds, GNATS_linp, GNATS_ftyp, GNATS_fvld): New functions. (GNATS_help): Add descriptions for new server commands. * edit.c (check_pr): Don't bother setting the bad value for Category:, Submitter:, or Responsible: fields. strdup invalid fields when we *do* pass them in. * client.c (client_print_errors): Print out the supplied error message for an invalid category, submitter, responsible or date field. * pr.c (check_enum_types): Require values for all enum fields that don't allow any value. (Possibly should require a value even if it allows any value.) * query-pr.c: Add list-fields, list-input-fields, field-type, field-description and valid-values options. * pr.c (fieldTypeAsString, setInputTemplate, getInputTemplate): New functions. * npr-edit.c: Add check-initial option. * pr-edit.c: Ditto. * lists.c (get_gnats_file): Add LIST_FIELD_NAMES and LIST_INPUT_FIELD_NAMES list options. * field.h (InputTemplate): New structure. (field_def): Add description member. * field-config: Add a few more comments, description entries for most of the fields, and an initial-entry section. * fconfigl.l: Add description and initial-entry keywords. * fconfig.y: Add "input" section for describing which fields should be required for an initial PR, and a "description" field to describe each field. * edit.c (check_pr_file): Add option for verifying initial PRs. (check_pr): Ditto. * cmds.c (GNATS_chek): Add command option for verifying initial PRs. Thu Dec 2 17:54:33 1999 Bob Manson * query.c (parseFieldName): Make public. * pr.c (field_change_reason): New routine. (struct PR_private): Added multiFieldIsReason member. (setPRChain): Don't free the current PR chain, for now. (replace_existing_pr): Use field_value () instead of violating interfaces. (replace_existing_pr): Step to the next field. (get_field_value): New function. * pcodes.h (CODE_INVALID_FIELD_NAME): New code. * field.h (field_list): Add name and isReason fields. (field_edit): New structure. * fconfig.y: Add support for on-change, require, append-to-field and set-field tokens. Remove code for audit-related keywords. * edit.c (rewrite_pr): Get the PR index chain before we do anything else. Don't redeclare old_pr. Invoke applyChangeActions () on fields that have changed in the PR. (editGetFieldValue, applyFieldEdit, applyChangeActions): New functions. Wed Dec 1 13:29:02 1999 Bob Manson * pr.c (find_field_num): Check for a "reason changed" field. (verify_enum): Check for allow_any_value. * pr-edit.c (main): Fix --unlockdb. * field-config: Remove default value for Audit-Trail. * fconfig.y: Add support for add-audit keyword. * adm.c (initAdmField): Only set the default value if allow_any_value isn't set for the field. Tue Nov 30 14:28:27 1999 Bob Manson * pr.c (free_pr_header): New function. (free_pr_contents): Don't free the header contents here, as otherwise the header will never be available after a PR is read in. (free_pr): Free the PR's header too. * query.c (iterate_prs): Ditto. * index.c (indexValue): If there's no index available for this PR, return NULL instead of coredumping. * pr.c (allocPR): Initialize the private struct. * Move more PR-related code into pr.c; move index-related code into index.c. Make Index weak and wimpy (with the thought of removing it entirely). * index.c: Move the Index struct into here, as it is no longer needed publicly. Mon Nov 29 18:52:47 1999 Bob Manson * pr.c: Change the value member into a struct. 1999-11-14 Jason Molenda (jsm@bugshack.cygnus.com) * BETA: This file renamed to "NEWS". Seems more appropriate. 1999-11-14 Jason Molenda (jsm@bugshack.cygnus.com) * mkdist.sh: Recognize --database command line option. Get the categories file from the gnats database directory instead of the dist directory. Update copyright text to correct FSF address. Fixes one part of PR gnats/15 TODO: man/mkdist.man is in need of an update. Tue Nov 9 17:45:36 1999 Bob Manson * pr.h: Remove temptation. * pr.c: Move tempted members into private struct. (free_pr_contents): Free up the PR's buffer. * file-pr.c (append_report): Don't check the contents of the X-Gnats-Nonotify: field; if it's there, then don't send mail. Remove gratuitous goto. * edit.c (rewrite_pr): We only need to check the state types; if they're different, the state has changed. * npr-edit.c (net_send_pr_command): New function; read in a PR and send it along with the appropriate command. (net_check_pr): Use it. (net_submit_pr): Ditto. * file-pr.c: Clean up a few function prototypes. Delete bad_fields static variable; pass it in as needed. (append_report): Simplify; use rewrite_pr (). * edit.c (fix_closed_date): New function. (rewrite_pr): Use it. (edit_field): Free the PR after we're done with it. Don't free it if we actually passed it into rewrite_pr (), tho. * cmds.c (GNATS_mlpr): Free the PR we allocated if we exit early. 1999-11-07 Jason Molenda (jsm@makita.cygnus.com) * BETA: Add notes about 3.113 release. 1999-11-1 Bob Manson * Massive changes to implement PRs as first-class objects; there is no longer the concept of "current pr". Initial cut at removing K&R compatibility cruft. * autoconf.h.in, configure.in, query-pr.c: Removed GNATS_RELEASE_BASED--it was mostly gone anyway. * npr-edit.c: Removed XXXnet_check_pr (); it was badness 10k. 1999-10-27 Bob Manson * fconfig.y: Fix typo in regexpList rule. 1999-10-27 Jason Molenda (jsm@bugshack.cygnus.com) * at-pr.sh: Send error/warning messages to stderr. Fix handling of --directory option, thanks to patch from Fixes PR gnats/6 1999-10-27 Jason Molenda (jsm@bugshack.cygnus.com) * getdate.y: Add local modification to recognize EEST, CES, and CEST timezones. * getdate.c: Regenerated. 1999-10-27 Jason Molenda (jsm@bugshack.cygnus.com) * ChangeLog.old: Moved to ChangeLog.v3. 1999-10-26 Andreas Luik * Makefile.in (distclean): Also remove config.log. (maintainer-clean): Accept this as the same as realclean. 1999-10-26 Andreas Luik * mkcat.sh: Portability fix for zeroing out GNATS_SITE and categories files. Mon Oct 25 16:23:27 1999 Bob Manson * pr.c: Moved contents of headers.c here. Header contents now exist as part of the PR object; names are kept in a separate array. * headers.c, headers.h: Deleted, no longer used. 1999-10-26 Jason Molenda (jsm@bugshack.cygnus.com) * getdate.y, getdate.c, getdate.h: Import current FSF version of getdate.y and its generated siblings. Pulled in from tar-1.13.9, master versions are apparently under RCS on the FSF machines. * MANIFEST: List getdate.h. 1999-10-26 Andreas Luik * mkdist.sh: Change set call for better portability. 1999-10-26 Jason Molenda (jsm@bugshack.cygnus.com) * BETA: Include beta notes for 3.111 and 3.112. 1999-10-26 Jason Molenda (jsm@bugshack.cygnus.com) * configure, config.h.in: Regenerate with autoconf 2.13. 1999-10-25 Andreas Luik * man/edit-pr.man, man/file-pr.man, man/gen-index.man, man/gnats.man, man/mkcat.man, man/mkdist.man, man/nquery-pr.man, man/query-pr.man, man/queue-pr.man, man/rmcat.man: Correct references ("SEE ALSO") to "gnats(7)" instead of "gnats(l)". One line description in .SH NAME; required for Solaris windex generation. 1999-10-25 Jason Molenda (jsm@bugshack.cygnus.com) * gnats-el.in (start-background): Convert random number to a string before concatenating. Patch from Palle Girgensohn Fixes PR gnats/13 Fri Oct 22 15:43:59 1999 Bob Manson * file-pr.sh, nfile-pr.sh, gnats-file-pr.sh: New files. file-pr is now replaced with edit-pr --submit. * main.c: Deleted, no longer used. * cmds.c (print_server_errors): Handle CODE_INVALID_FIELD_CONTENTS specially. (GNATS_appnOrRepl, GNATS_appn, GNATS_repl, get_text_memory): New functions. * field.h (FieldDef): regex is now a Stringlist. * fconfig.y: Make the regex qualifier a StringList. * edit.c (check_curr_pr): If a date field is null, don't coredump. The regex field is now a StringList; check all of the regexps. (edit_field): Read in the PR we're editing. * client.c (client_print_errors): Print out the field.value contents when there is an invalid field. Thu Oct 21 19:10:26 1999 Bob Manson Add commands to allow the server to add new PRs. * pr-edit.c: Add submit, append and replace options. * npr-edit.c: Ditto. * main.c (main): Call submit_pr () instead of gnats (). * file-pr.c (create_pr_file, submit_pr): New functions. (gnats): Call create_pr_file. * edit.c (check_curr_pr, rewrite_curr_pr, edit_field): New functions. (check_pr): Read in the PR and call check_curr_pr. * cmds.c (GNATS_subm): New function. Wed Oct 20 20:09:51 1999 Bob Manson * pr.c (struct PR_private): Used by the PR reading code to keep track of state while reading. * pr.h(struct PR_struct): New type to represent contents of PRs. Tue Oct 19 15:33:36 1999 Bob Manson * pr.c (read_pr): Split up into three new functions, so that PRs can be added line-by-line. * Makefile.in (install-gnats-arch-indep): Fix from Jeff Bailey when srcdir != objdir. * fconfig.y: Added allow-any-value entry for enums, to allow any value to appear (this seems contradictory, but it's needed for the Responsible: field). * fconfigl.l: Added allow-any-value keyword. * pr.c (check_enum_types): Check for allow_any_value flag in the field. Thu Sep 30 12:36:59 1999 Bob Manson * pr.c (check_enum_types): strdup() the field's default value, if we have to assign one. Wed Sep 29 13:34:31 1999 Bob Manson * query.c (pr_match_field): Read in the PR if the field we're checking doesn't appear in the index. (parseQueryExpression): New function. Parses a query expression into a QueryExpr. (queryExprToString): New function. Converts a QueryExpr into a string query expression. * query-pr.c (long_options): Added new option "expr", which accepts a boolean query expression; uses parseQueryExpression() to parse the expression. * gnats.h: Moved gnats_* variables here; they will eventually be deleted. * field.h (struct field_def): Rearrangement of members to make a bit more sense. Mon Sep 27 21:08:18 1999 Bob Manson * pr.h (SearchType): Added DefaultSearchType value. * query.c (add_query_builtin_field): New function. Changed previous callers of add_query_field to use it as appropriate. (searchTypes): Added entry for DefaultSearchType. (pr_match_field): Handle DefaultSearchType. Thu Sep 23 19:54:19 1999 Bob Manson * pr.c (check_enum_types): Don't set the value to the default unless the original value was bad. Tue Sep 21 16:53:52 1999 Bob Manson Changes to allow adding new fields, and to divorce the concept of "field name" versus "builtin name". * Use BUILTINNAME->index to get a builtin field's index number. (FieldIndex): New type, partially replacing PR_Name. * query.c (iterate_prs): Call clean_pr () after we're done with the PR. * client.c (client_print_errors): Fix printout of invalid enum errors. * builtin-fields.h: New file. It currently contains all of the pre-4.0 fields; this will eventually only contain those fields strictly needed by GNATS. * fconfig.y, fconfigl.l: Add new builtin-name keyword. * field.h (struct field_def): Remove netquery field. Wed Aug 25 12:04:22 1999 Bob Manson * pr-init.c (fconfig_parse, argument func): New argument. (get_line): New function. * cmds.c (GNATS_lfds): New function; command for dumping the field-config file to the client. * client.c (client_get_field_config_line, client_get_field_config): New functions. (client_init_gnats): Call client_get_field_config (). * adm.c (initAdmField): Don't explode if the contents of the chain for the field are NULL. * query.c (getSearchTypeForName, getSearchNameForType): New functions. * pr.h (FIRST_BUILTIN_FIELD, NUM_BUILTIN_FIELDS): New. * pr-init.c (builtin): Change "Target" to be "Quarter". * gnatsd.c (cmds): Add FVAL. * files.c: Remove init_classes() and init_states(). * field-config: Remove the network-query-command definitions. * fconfigl.l: Add "%option nounput" to make flex behave. Remove network-query-command. * fconfig.y: Add extern declarations for fconferror() and fconflex (). Remove the network-query-command parse. * cmds.c (netcommands): New array to hold the old-style network query commands; these are now hardcoded, and will probably be removed. (init_server_cmds): Initialize netcommands. (GNATS_fval): New function, to add the FVAL command. * client.c (send_query_field): Use the FVAL query command. * Makefile.in: Use @CFLAGS@ instead of hardcoding -g. * configure.in: Turn on -Wall -ansi -pedantic -Werror for GCC. 1999-08-24 Bob Manson * Initial checkin for 4.0. Local Variables: left-margin: 8 fill-column: 74 version-control: never End: gnats-4.1.0/gnats/ChangeLog.v30000644000175000017500000076727407005521737016634 0ustar chewiechewie00000000000000GNATS ChangeLog record for gnats version 3 (roughly 1993-1999). 1999-07-12 Jason Molenda (jsm@bugshack.cygnus.com) * mkdist.sh (SAVEOPTS): Set appropriately if only one command line option is being passed to the script. 1999-04-15 Kenneth H. Cox * Makefile.in: Fixed bug in 'gnats-edit-pr' target; xGNATS_SERVERx was not being substituted. 1999-04-11 Paul Traina * Makefile.in, version.texi: Bumped version number to 3.110 * Makefile.in, bring back INSTALL_SCRIPT since top-level Makefile is a mess. * BETA: Described what's new in 3.110 * NEWS: removed, obsolete 1999-03-17 Rick Macdonald * index.c: free_index(): removed the free of index_filename, (actually moved it to GNATS_chdb()) because modify_pr() calls free_index with an index other than index_chain. This broke a few things. * cmds.c: GNATS_chdb(): added free of index_filename (actually moved from free_index()). * edit.c: modify_pr(): set the global index_chain to the newly built index to reflect any changes (especially a changed category). 1999-03-15 Kenneth Cox * gnats-edit-pr.sh: nedit-pr incorrectly tried to connect to gnatsd on the local host. Default GNATS_HOST to GNATS_SERVER if present. 1999-03-03 Paul Traina * file-pr.c, pr.c, edit.c: portability -- convert strftime %e and %T arguments to %d and %H:%M:%S for POSIX (and OpenStep). (suggested by Carl Lindberg ) * cmds.c, internal.c: When the UNDB command is issued, we sent back two response codes if the database was already unlocked. Handle all the responses directly in unlock_db (which isn't really where this should be, but that's easier than changing the semantics. IMHO, unlock_db() should *not* be responsible for sending output to the daemon. :-( ). (reported by lindberg) 1999-02-26 Paul Traina * file-pr.c: Accept subject lines of the form "pr: " too since people seem to make that mistake a lot * gen-index.c: malformed line -> malformed category line * check-db.sh: Bring it in from the contrib area, clean it up. * delete-pr.sh: Change index delimiter from ':' to '|' to match new format, fix several bugs, and include it in the regular distribution, removing it from the contrib area. * Makefile.in: fix missing regex entry, remove obsolete DISTFILES macro, remove INSTALL_SCRIPT favor of INSTALL_PROGRAM, install file-pr setuid gnats, add support for check-db and delete-pr Thu Nov 18 22:46:12 1998 Rick Macdonald * version.c, version.texi, Makefile.in: set to version 3.108. * Makefile.in: added new program npr-addr. * PROBLEMS: removed bugs that are now fixed. Added another note about gnats.el needing more work. Added more words about how hosed doret/ret is. * client.c: get_reply(): changed CODE_INVALID_STATE to CODE_INVALID_ENUM and changed for general enum errors. read_server() now un-escapes dots. New function client_init_gnats(). client_chdb() now uses global gnats_root instead of passed arg. * cmds.c: deleted daemon_lock_pr() and daemon_pr() and put code directly into the one calling function, GNATS_lock(). Moved lookup_pr_path() to index.c for more general use. Changed GNATS_edit() to never unlock the PR. Improved various return messages. General cleanup of LOCK, UNLK and EDIT functions. New gnatsd command CHEK that calls new function GNATS_chek() to allow the daemon to check PR fields instead of duplicating the functionality in the client (npr-edit). Moved printing of PR text from GNATS_lock() to lock_pr() so pr-edit would have same behaviour as npr-edit and gnatsd (lock retrieves PR text). get_text() now un-escapes dots. Removed call to configure from GNATS_chdb since it's now in init_gnats(). * contrib/check-db.sh: updated for new locks directory. * db_conf.c: local_chdb(): now uses global gnats_root instead of passed arg, and returns if gnats_root is null. * db_conf.c: modified prototype for local_chdb. * edit.c: changed get_path() to get_lock_path(), changed it to use new lock location, and moved it to internal.c. lock_pr() now prints PR text so pr-edit has same behaviour as npr-edit and gnatsd (lock retrieves PR text). lock_pr() now properly sends "\r\n.\r\n" to terminate the PR text sent (like query FULL does). General cleanup of lock_pr(), unlock_pr() and get_lock_path(). modify_pr() changed to use new lock location. Fixed check_pr() to handle all fields properly for the case of is_daemon (gnatsd). * edit-pr.sh: replaced with a simple stub to call the new script gnats-edit-pr.sh. * files.c: new function get_responsible_addr() for pr-addr and gnatsd. * gen-closed-date.c: Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * gen-index.c: change return type of entry_cmp to int. Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * getclose.c: Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * globals.h: new prototype for get_responsible_addr(). * gnatsd.c: Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * gnats.h: added prototype for lookup_pr_path(), GNATS_chek(). Changed prototype for init_gnats(). * gnats.el-in: gnats::finish-filing: npr-edit (gnatsd) no longer unlocks PRs when updating, so the gnats:::pr-locked variable is no longer unset for the network case. gnats::handle-pr-edit: temporary hack to erase the gnats-error buffer after locking because pr-edit now returns the full PR text like npr-edit does. For now the code still operates the old way of reading the PR file directly. Added new network program npr-addr to gnats::real-pr-addr. * gnats-edit-pr.sh: new script to do the task of both edit-pr and nedit-pr (both local and network editing). Removed direct access to any GNATS files. Ignores any category supplied with the PR number. All /tmp files are cleaned up. Properly saves aborted edits to "$new.changed". Added unlock command now that gnatsd no longer unlocks the PR. Removed gnats-bin from PATH. Separate dual usage of GNATS_ROOT to GNATS_DB for --directory arg. Error fixing loop (to re-enter the editor) now works for both local and network editing. Calls pr-addr or npr-addr as required. * index.c: moved get_category() from query.c and lookup_pr_path() from cmds.c here for more general use. lookup_pr_path() modified to ignore any given category and use only the PR number. * internal.c: moved get_lock_path from edit.c so file-pr could use it. New functions get_prid_from_path() and get_cat_prid_from_path(). * lists.c: fixed \n vs \r\n when printing lists. * main.c: call get_lock_path() to get PR lock pathname. Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * misc.c (init_gnats): added calls to configure() and local_chdb() and reordered calls. * nedit-pr.sh: replaced with a simple stub to call the new script gnats-edit-pr.sh. * npr-edit.c: CHECK now calls daemon CHEK for check_pr function. Replaced client_init()/client_chdb()/client_user() calls with new client_init_gnats(). net_check_pr() now calls init_pr()/init_header()/init_network() instead of init_gnats(). Added missing --prt option to Usage print. * nquery-pr.c: Replaced client_init()/client_chdb()/client_user() calls with new client_init_gnats(). * pcodes.h: changed CODE_INVALID_STATE to CODE_INVALID_ENUM. * pr.c: check_enum_types(): don't put newlines in msgs if is_daemon. New function write_multitext() to escape single dots in multitext fields when writing to the network. Also, each line is sent terminated with "\r\n" when appropriate (a local "ret" variable is used). * pr-addr: added -d|--directory arg; now supports multiple databases. Moved internal code to files.c to share with gnatsd for network version npr-addr. * pr-age: modified to call lookup_pr_path instead of get_category. Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * pr-edit.c: LOCK and UNLOCK edit options now call lookup_pr_path first. pr-edit no longer locks the entire database when locking a single PR for edit (LOCK) since gnatsd doesn't. Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * pr-stat: modified to call lookup_pr_path instead of get_category. Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * pr-mail: added args for multi-database and user access control: -d|--directory, --v|user, -w|--passwd, plus missing network args -H|--host, -P|--port. * query-pr.c: Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * queue.c: Replaced configure()/init_gnats()/local_chdb() calls with new init_gnats(). * sub-type-pr.c: Replaced client_init()/client_chdb()/client_user() calls with new client_init_gnats(). Wed Nov 4 20:37:33 1998 Rick Macdonald * cmds.c: GNATS_chdb: fixed to set user access to the host default for the new db, not the previous one. * gnatsd.c: Changed the access level from "view" to unrestricted for the HELP and DBLA commands. The DBLS command was changed from "view" to "admin". Mon Nov 2 16:57:50 1998 Rick Macdonald * Makefile.in: nedit-pr.sh target needed to set GNATS_SERVER_PORT. * nedit-pr.sh: removed the unused variables bindir and query_pr. Changed GNATS_USER and GNATS_PASSWD variables to EDIT_USER and EDIT_PASSWD (they were set one way but used the other way, causing the command line args to be ignored). Changed "oldstate-newstate" to "oldstate->newstate" as discussed on mailing list. This was previously done for edit-pr but nedit-pr got missed. * gnatsd.c: (match): added 3rd argument to flag case sensitive match. Now matches to end of both stings, such that "abcd" no longer matches "abcde". Use "abcd*" or "abcd?". A null string in the gnatsd config (gnatsd.conf, gnatsd.access) is still assumed to be "*"). * gnatsd.c: improved syslog messages for host and user access denied messages. * cmds.c: improved syslog messages for host and user access denied messages. Mon Oct 19 16:33:46 1998 Rick Macdonald * INSTALL: added mention of some newish files: states, classes, addresses and gnatsd.access. * MANIFEST: added files gnatsd.access, gnatsd.conf, gnats-db.conf and UPGRADING. * Makefile.in (VERSION): up to 3.107. Install empty gnatsd.access file to gnats-adm and chown.chmod to gnats/600. * PROBLEMS: added mention of 6 things not done for gnats.el. * README: changed the gnats mailing list to bug-gnats@gnu.org. * TODO: added mention of three programs that could be rewitten to use dates from the expanded index instead of parsing the Audit-Trail and other fields. * TAGS: replaced with an updated tags file that includes gnats.el functions. * UPGRADING: new file with quickstart instructions for upgrading to gnats-3.107. * client.c: added new function client_user() to send userid and password to gnatsd. * cmds.c: Cleaned up the qualify and pr_matches functions to use expanded index. Added SQL2 query format, like SQLF but without padded blanks. Added GNATS_user function. Modified GNATS_chdb to only accept database aliases. Fixed GNATS_chdb "doret" setting when changing databases. Fixed problems with GNATS_rset. * config.h: added define for STR_MAXLONG as 512, needed for reading and handing expanded index entries. Added DB_ACCESS_FILE and GLOBAL_ACCESS_FILE. * db_conf.c: local_chdb: changed to abort (exit) if errors occur looking up database entries. Otherwise, a program such as mkcat would operate on the wrong database. * edit-pr.sh: removed the -v argument. Surely -V and --version is good enough. Changed index separator character from : to |. Redirected stderr to stdout so that the error handling and re-edit option would work as intended. * edit.c: Fixed various problems with date handling. * file-pr.c: Update the Last-Modified date in the index when email is appended to the Audit-Trail. * gen-closed-date: Added call to local_chdb for multiple database support. * gen-index.c: Increased length of line variable to handle expanded index. * getdate.y: Y2K fixes. GNATS should now be Y2K compliant. Added cest and ces timezones for Central Europe Summer. * gnats-db.conf: added sample file (doesn't get installed). * gnats.el: Added support for multiple databases: variables gnats:::types, gnats:alias. Added support for user/passwd authentication: variables gnats:userid, gnats:password. There is still more work to be done: see the PROBLEMS file. * gnats.h: added prototypes. * gnats.texi: added new node: Controlling User Access, describing access levels. * gnatsd.access: New sample access file; gets installed to gnats-db/gnats-adm. * gnatsd.c: added user/passwd authentication and host/user access levels. New arg: -r|require-db insists first cmd sent to gnatsd is CHDB. Reworked getopt_long entries to support access levels. Added FLAG_ONE_ARG flag to SYNP to allow spaces in Synopsis queries. New function set_confidential_access to handle the difference between view and viewconf access. New functions access_level, access_level_str and get_user_access for access level support. Upgraded the "allowed" function to support IP addresses and a host default access level in the gnatsd.conf file. Reordered code to delay reading the gnats index until determining if the first command is CHDB to avoid reading in the default index unnecessarily). * gnatsd.conf: added instructions for new access level feature. * gnatsd.h: new prototypes. Bit masks for access level control of gnatsd commands. * index.c: support for expanded index. All fields excpet multitext are now in the index. Changed the index separator from : to |. *** compatibility issue *** * internal.c: support for expanded index. * mail-query.sh: reordered args passed to query-pr: moved GNATS_ROOT and newly added /etc/aliases args ($*) to come after the email senders args so they can't override GNATS_ROOT or --directory. --directory="$GNATS_ROOT" is somewhat redundant now because the database alias should be given in the mail alias file for total control. * nedit-pr.sh: Redirected stderr to stdout so that the error handling and re-edit option would work as intended. Added -v|--user, -w|--passwd args. * npr-edit.c: Added -v|--user, -w|--passwd args. Added missing call to client_chdb for multiple database support. * nquery-pr.c: Added -v|--user, -w|--passwd args. Changed for expanded index support. Added new -I|--sql2 query format. * p-admin.texi: changed description of the index file to match the new expanded index. * p-inst.texi: added mention of some newish files: states, classes, addresses and gnatsd.access. More work is required to update this file. * p-usage.texi: removed warnings about slow query performance to reflect the improved performance of the new expanded index. Added the -I|--sql2 query output format. More work is required to update this file. * pr.c: added expanded index support. Changed LAST_MODIFIED datatype from Text to Date. * pr.h: added expanded index support. * query-pr.c: added expanded index support. Added SQL2 query format. * query.c: added expanded index support. Added SQL2 query format. Added seconds to sql time format output. Reworked do_query, pr_matches, query, do_pr functions to simplify. All matching is now done in pr_matches. PR files are only opened when necessary: multitext search or full format query output. The end dot (".") sent after full PR output is now properly preceeded by "\r\n" from gnatsd. This only affects front-ends written with direct socket communication to gnatsd. *** compatibility issues *** * query.h: various globals and prototypes for sql2 format and user access control. * queue-pr: added missing support for multiple databases. * sub-type.c: added -v|--user, -w|--passwd args. Fixed Usage print. * version.c: changed to 3.107. * version.texi: changed to 3.107. Mon Oct 12 20:42:52 1998 Rick Macdonald * client.c: Fixed client_chdb() to just return if it's passed a null string for new_root. * cmds.c: GNATS_chdb() - removed fatal exit when the index file can't be read. Front-ends need to get information from GNATS in order to submit the very first PR even though there is no index file yet. * at-pr.sh: Removed the tag "function" from the get_default_state declaration. This is optional in bash and invalid in sh. This fix came from Paul Triana . Wed Jul 29 16:04:03 1998 Rick Macdonald * Makefile.in: when you follow the install instructions and run "make install" as root, "mkcat" later fails because root owns the files and directories that mkcat needs to write. I added a chown to GNATS_USER of the DATADIR/gnats directory. * Makefile.in: added GNATS_USER to GNATS_VARS for the send-pr Makefile, where it is needed to chmod the gnats/dist directory for mkcat to write to. * Makefile.in: the Makefile was checking only for the existance of an installed categories file before assuming that it was OK to install the categories, responsible, submitters and gnatsd.conf files. There is now a separate check for _each_ of these files. * send-pr/Makefile.in: when you follow the install instructions and run "make install" as root, "mkcat" later fails because root owns the files and directories that mkcat needs to write. I added a chown to GNATS_USER of the gnats/dist directory. * query-pr.c: removed fatal exit when the index file can't be read. Front-ends need to get information from GNATS in order to submit the very first PR even though there is no index file yet. * gnatsd.c: same as query-pr.c. * index.c: same as query-pr.c. Fri Jul 24 13:01:34 1998 Rick Macdonald * Makefile.in: added target for new gen-closed-date program. * gnatsd.c: added missing commands MBFR and MAFT for modified before/after. * gnatsd.c: added new commands CBFR, CAFT and LCFG for closed before/after, and list config. * gnatsd.h: added prototypes for GNATS_mbfr, GNATS_maft, GNATS_cbfr, GNATS_caft, GNATS_lcfg. * query.h: - referenced globals for closed_before and closed_after. * query.c: added closed before/after support to do_pr_internal(). Fixed do_pr_internal bugs when a date field was missing from PR (Segmentation fault). Added LAST_MODIFIED and CLOSED_DATE to SQL output format. added CLOSED_DATE to the default output format. * qvariable.c: added globals for closed_before and closed_after. * query-pr.c: added queries for closed before/after: [-z | --closed-before] [-Z | --closed-after]. Added query for list config: [-G | --list-config]. Fixed bug in error checking of arrived before/after and modified before/after. * nquery-pr.c: added queries for closed before/after: [-z | --closed-before] [-Z | --closed-after]. Added query for list config: [-G | --list-config]. Added missing args: -a/-b/-B/-M. * pr.h: added CLOSED_DATE to pr fields. Remove state.final_value member. * pr.c: added CLOSED_DATE to pr fields. Remove state.final_value member. Change customizable states to use new functions init_states(), get_state_enum_field(). Change customizable classes to use new functions init_classes(), get_class_enum_field(). * edit.c: added support to set Closed-Date. * lists.c: added support for list-config. list-classes lists class_chain instead of re-reading external file. list-states lists state_chain instead of re-reading external file. * config.h: added config file name for list-config. * p-usage.texi: reversed -M and -B to match actual code and descriptions. Added -z|--closed-before, -Z|--closed-after, -G|--list-config, -A|--release, -o|--outfile -x|--skip-closed -J|--list-classes, to query-pr usage. Added new fields Closed-Date and Release-Note to various parts. Added Last-Modified and Closed-Date to the query output descriptions. * cmds.c: Fixed RSET command for arrived/modified/closed before/after. Added commands GNATS_mbfr, GNATS_maft, GNATS_cbfr, GNATS_caft and GNATS_lcfg. Added several missing commands to HELP (lock, unlk, edit, etc). Changed VDATE to VDAT in HELP. * MANIFEST: added gen-closed-date.c * classes: added class type fields and descriptions. * states: added state type fields and descriptions. * files.h: added Classes structure for classes file. Added States structure for states file. * files.c: added init_classes() and free_class(), global Classes *class_chain. Added check_class_type(), get_class_type(). Added init_states() and free_state(), global States *state_chain. Added check_state_type(), get_state_type(). Fixed memory overrun when too many fields are in the data given to next_record(). EG, when a class or state description field contains a colon. * globals.h: added init_classes() and free_class(), global Classes *class_chain. Added check_class_type(), get_class_type(). Added init_states() and free_state(), global States *state_chain. Added check_state_type(), get_state_type(). * query.c, query-pr.c, getclose.c, pr-stat.c, edit.c: replace state.final_value with check_state_type(). Mon Jul 20 22:35:27 1998 Rick Macdonald * query-pr.c: Added missing args to usage() for the non-release-based case: -b, -a, -B, -M, --modified-before and --modified-after were all missing. Also, a bracket was missing from --list-classes. Fri Jul 17 12:37:34 1998 Mike Sutton * file-pr.c, npr-edit.c, pr.c: Compilation error fixes for running on SunOS 4.1 using Sun's K&R C compiler. Wed Jul 15 12:20:00 1998 Paul Traina * edit-pr.sh: Change "oldstate-newstate" to "oldstate->newstate" as discussed on mailing list. * man/Makefile.in, man/gnats.man: Put the gnats general manual page in manual section 7, not "local". Mon Jun 29 13:53:14 1998 Paul Traina * pr.c: Change the ordering of states to match the original SQL numeric values in GNATS 3.104. Sun Jun 28 12:05:54 1998 Paul Traina * edit-pr.sh: Always run the date(1) command with language support set to the C default because the getdate() code is not multi-language aware. (From FreeBSD) * gen-index.c (xxx): Fix gen-index's error reporting when it encounters empty files. (Gen-index was reporting errors like gen-index: error reading pr /usr/local/share/gnats/gnats-db/pending/ (From ??? someone on the mailing list (Karl?)) * pr.c, pr.h: Add "Release-Note:" field for human readable comments about problems or fixes (suitable for incorporation into release notes for a given software release). * query.c (do_pr_internal): Remove useless backslashes. * query.c, Makefile.in, cmds.c, config.h, gnatsd.c, gnatsd.h, lists.c, nquery-pr.c, pr.c, query-pr.c, classes: Add support for user-defined classes, lifted from Karl's user-defined states code. * query.c: (enum_numeric) Clean up some of the grotty enumerated field-to-sql value code and make everything use the new routine. This should mean that future changes to enumerated fields don't need hacking here. Functionality first, performance second. enum_numeric needs to be re-coded to be more efficient, it's a pig now. * query.c: Make SQL date output Y2K compliant by changing output to provide 4 digits of years (FLAG DAY!!!) Wed Feb 11 07:43:30 EST 1998 Mike Sutton * at-pr.sh: added support for -d option * client.c, gnats.h: added client_chdb routine. * db_conf.c, db_conf.h: added to support database changing, listing and alias listing. * mail-query.sh: Updated so that a previously set GNATS_ROOT environment variable is not ignored. Also added support for --directory=gnats_root. * misc.c (init_gnats): added initialization of database configuration. * Makefile.in: added support for db_conf.c compilation * cmds.c (GNATS_help): added GNATS_chdb, GNATS_dbls and GNATS_dbla command descriptions. * cmds.c: added GNATS_chdb, GNATS_dbls and GNATS_dbla commands changing and listing databases via gnatsd. * edit-pr.sh, mkdist.sh: Updated so that a previously set GNATS_ROOT environment variable is not ignored. * gen-index.c, getclose.c, npr-edit.c, nquery-pr.c, pr-age.c, pr-edit.c, pr-stat.c, query-pr.c: added support for --directory=gnats_root. * gnatsd.c (allowed): Made the gnats_root (aka database) an argument to support access checking for DBLS and DBLA commands. * gnatsd.c (main): added a host access check (security fix) to prevent access to databases when in --not-inetd mode. * gnatsd.c (main): added initialization and clean up for database database aliases. * gnatsd.c, gnatsd.h: Added the CHDB (change database) command. * gnatsd.c: Added --help (-h) command line option. * main.c: Added support --directory=gnats_root. * nedit-pr.sh, npr-edit.c, nquery-pr.c: modified to support multiple databases. * nedit-pr.sh: Updated so that a previously set GNATS_ROOT environment variable is not ignored. added --directory, --host and --port options. * sub-type.c: added support for --directory=gnats_root and --host. * gnats.texi: added node discussing multiple databases on one host. Thu Dec 18 15:54:28 1997 Karl Fogel Changes to implement customizable PR states: * Makefile.in (DISTFILES): added `states' file. (install-gnats-arch-indep): install the `states' file to gnats-adm with everything else, if not already installed. (install-tools-arch-indep): fixed typo, so gnats.elc installs. * states: new admin file, old hardcoded states put in as defaults. * pr.c (get_pr_states): new func, reads states from an init file if possible, else returns what used to be hardcoded. (get_default_state, get_final_state): new funcs, retrieve first/last state from "this | kind | of | string". (init_pr): use above new funcs to init `enum_value', `default_value', and `final_value', in pr[STATE]. * pr.h (PR_entry): new member char * `final_value'. For states, holds the string which signifies a "closed" PR (this may or may not be the literal string "closed", depending on the last entry in the new gnats-adm/states file). No other PR fields use `final_value' yet. * config.h (STATES): new #define, for `states' file in gnats_root/gnats_adm/. * getclose.c (do_prlist): use pr[STATE].final_value, instead of hardcoding "closed". * pr-stat.c (do_category): same as above. * query.c (pr_matches): same as above. (state_numeric): new func. (sql_type): use above new func for numeric value of a state. * pr-addr.c (is_daemon): Add definition to 0 (necessary for above changes to compile, don't even THINK of asking why). * at-pr.sh (STATES_FILE): new var, init according to $GNATS_ROOT. (OPEN_STATE): new var, use instead of hardcoded "open". (get_default_state): new function, use to above new var OPEN_STATE. Defaults to "open". * p-admin.texi (Local configuration): add `states file' to menu. Update references everywhere for changes below: (states file): new node. (config file): replaces `config' node. (categories file): replaces `categories' node. (responsible file): replaces `responsible' node. (submitters file): replaces `submitters' node. (addresses file): replaces `addresses' node. * p-usage.texi (Reporting): note mapping of numbers to states may not hold if administrator made custom states; explain meaning of "0". (Invoking query-pr): document "--list-*" options, including new "--list-states", and document their short versions as well. * gnats.texi (GNATS_ROOT): mention the new `states' file. (defaults): same. * query-pr.c (long_options): associate 'T' option with list-states. (main): handle 'T' option. (usage): include "--list-states" option. (query_pr): use pr[STATE].final_value, instead of hardcoding "closed". (print_pr): format state as a string not a number. (sql_types): don't handle states anymore -- the administrator now has too much flexibility with states for us to assume they're ordered. * nquery-pr.c (long_options): added "list-states" option ('T' is short option). (main): handle new 'T' option to get states, in getopt() and in switch-case. (usage): include "--list-states" option. (ask_about): add case for LIST_STATES. * query.h (LIST_STATES): new #define. * lists.c (get_gnats_file): add case for STATES. * cmds.c (GNATS_lsta): new func, gets states file. (GNATS_help): add help msg for "LSTA". (get_reply): handle CODE_INVALID_STATE, although currently no one sends it. * pcodes.h (CODE_INVALID_STATE): new code, unused but available for those who like that sort of thing. * gnatsd.h: declare new func GNATS_lsta(). * gnatsd.c (cmds): added "LSTA" * gnats-el.in (gnats::states): new var. (gnats::default-states): new constant var, contains old hardcoded states as a fallback. (gnats::states-sans-descriptions): new func. (gnats::state-following): new func replaces var of same name. (gnats::fields): use above new funcs instead of hardcoding state names. Moved to end of file so everything it needs is defined before it gets set. (gnats::set-states): new func, passes new noerror arg to below. (gnats::get-list-from-file): take optional noerror arg. (gnats::get-alist): fix regexp to handle comments, blank lines. Sun Dec 7 20:33:20 1997 Karl Fogel * file-pr.c (check_if_reply): don't file if category in Subject header is not a valid category (this helps prevent spurious matches, for example "Re: OS/2 release"). Fri Dec 5 14:18:16 1997 Karl Fogel * file-pr.c (append_report): init `cc' and `subject' to have newlines, otherwise GNATS sends out mail with misformatted headers. (pr_number_from_path): new func. (append_report): use above new func instead of unreliable field_value(NUMBER) to determine pr number. Fri Dec 5 13:43:20 1997 Karl Fogel * files.c (free_responsible): if `alias' lives in borrowed space then don't try to free() it. Sun Nov 30 21:05:29 1997 Karl Fogel * Makefile.in (getdate.c): handle bisons that output FILENAME.tab.[ch] as well as those that output y.tab.[ch]. Tue Nov 24 16:00:00 1997 Abe Feldman * file-pr.c: (gnats) If submitter ID is null or default, call defive_submitter. (derive_submitter) New function, looks for end fragment of "From:" header in "addresses" file; returns submitter ID if found, othewise returns the default submitter * addresses: New file. Meant to contain mappings between submitter IDs and incoming e-mail addresses. Template contains format instructions for entries. Used by derive_submitter * Makefile.in: Install addresses file in gnats-adm * p-admin.texi: Documentation for new feature Wed Oct 29 12:02:41 EST 1997 Mike Sutton * file-pr.c:(reply_to_submitter) Changed the From and Reply-To lines to be gnats_admin from gnats_addr. This is best compromise for multiple databases. * file-pr.c:(notify_responsible) Changed gnats_user to gnats_admin in Resent-From field. Changed gnats_addr to gnats_admin in Resent-Reply-To field. A good compromise for multiple databases. Mon Oct 27 09:42:10 EST 1997 Mike Sutton * query.c: Removed a trailing backslash that the compiler complained about. Fri Oct 24 16:10:00 1997 Abe Feldman * query-pr.c: (main) Look for new qualifiers -B, -M, --modified-before, --modified-after. Enable -a, -b. (usage) include usage notes on -a, -b, -B, -M, --modified-before, --modified-after. * query.c: (do-pr-internal) Check for modified_before, modified_after. if either of these is non-zero, do date-compare between PR in question and given date. * query.h: New extern variables modified_before, modified_after. * qvariables.c: Initialize modified_before, modified_after * p-usage.texi: Notes on query-pr qualifiers --arrived-before, --arrived-after, --modified-before, modified-after. Fri Oct 24 08:33:31 EDT 1997 Mike Sutton * cmds.c: Corrected the print of db locked message when lock fails. * edit.c: Corrected the date checking of the date required field. Mon Oct 6 17:00:00 1997 Abe Feldman * pr.c: (read_pr) Unformatted text new has a space at the beginning of each line, indicating that is is "quoted text". If there is no "description" field, unformatted text is stored in pr[DESCRIPTION]. Fri Sep 26 16:00:00 1997 Abe Feldman * file-pr.c: Changed log messages and "punt" function call to mention default category * gnats.texi: added references to default category * p-admin.text: added description of how to set a default category Sun Sep 21 21:20:00 1997 Abe Feldman * config.c.in: Added call to CN_OPT to create default_category variable, to be read in from config file * gnats.h: added extern char *default_category * file-pr.c: (gnats) Changed from hard-coded "pending" default category to default_category variable * pr.c: Changed default value of category entry in PR data structure from PENDING constant to default_category variable string 1998-04-08 Brendan Kehoe * pr-addr.c (main): Only accept r->alias as a possibility if it's a character we can use. Specifically, not a space. Mon Mar 23 18:14:02 1998 Eric Mumpower * client.c (client_init): Cache the return value from our effort to authenticate via kerberos, for possible use in error-reporting later. (remember_krb_auth_ret): global variable for simple cacheing (get_reply): Give more useful errors if access is denied and kerberos-authentication failed previously * gnats-el.in (gnats::handle-results): Recognize krb4-auth errors and 'error them with a succinct error message. (gnats:summ-pr, gnats:net-view-pr): Likewise. (gnats:network-server): Default to networked gnats protocol via GNATS_SERVER rather than defaulting to local gnats. * Makefile.in (gnats.el): Substitute the configure-defined GNATS_SERVER into the configured copy of gnats.el 1997-11-26 Brendan Kehoe * pr-age.c (report_age): Give an error if the PR doesn't exist. 1997-10-09 Brendan Kehoe * Makefile.in (getdate.c): Use an explicit `-o getdate.c' rather than play games with bison and byacc's different options. 1997-09-18 Brendan Kehoe * cmds.c (GNATS_edit): New local variable UNLOCKP. Only unlock the PR if writing it succeeded. (qualify): Only go thru for a particular pattern until we make a match; once we do, move on to the next argument. 1997-09-15 Brendan Kehoe * gnats-el.in (gnats:net-view-pr): Pass a NIL first arg to view-mode-enter, since emacs 20.1 changed it to expect a list. This will work with both 19.* and 20.*. Mon Aug 18 14:00:58 1997 Brendan Kehoe * Makefile.in (VERSION): Up to 3.104. I forgot to modify this for 3.103. * contrib/tkgnats: Update to tkgnats-2.0b5. * configure.in: Add checks for -lkrb5 and -lcom_err. * configure: Regenerated. * Makefile.in (install-tools-bin, install-gnats-bin): Fix paths to use libexecdir instead of libdir. * contrib/check-db.sh: Put binaries in LIBEXECDIR, not LIBDIR. Thu Aug 7 12:16:33 1997 Brendan Kehoe * Made 3.103 beta release. Wed Jul 30 12:16:33 1997 Brendan Kehoe * PROBLEMS: Mention that we need to pick a new port other than 1529, which is already taken. Tue Jul 29 20:09:02 1997 Ken Raeburn * configure.in: Don't override supplied krb4 pathname on BSD. Build mk_auth only if it's not available in libraries, and do it by defining EXTRA_OBJS rather than adding to LIBS. Now CNS can be used on BSD. * Makefile.in (EXTRA_OBJS): New variable. (LIBOBJS): Include it. (LIBSRC): Add mk_auth.c. * Makefile.in (install-gnats-arch-indep): Print correct mkcat pathname. Wed Jul 23 14:33:18 1997 Brendan Kehoe Fix from Brian White . * mkdist.sh: Handle a file in the dist directory being gzipped. Fix from Brian White . * contrib/delete-pr/delete-pr.sh (GNATS_ROOT, LIBDIR, VERSION): Adjust to use `xFOOx' instead of `@FOO@'. * contrib/delete-pr/README: Adjust. Thu Jul 17 10:43:38 1997 Brendan Kehoe * configure: Regenerated. Thu Jul 17 10:31:41 1997 David J. MacKenzie * Makefile.in, at-pr.sh, edit-pr.sh, gnats-el.in, gnats.texi, nedit-pr.sh, man/Makefile.in, man/gnats.man, man/mkcat.man, man/rmcat.man: Use the modern standard file system layout (libexec, share, etc. instead of putting non-libraries in lib). * client.c, cmds.c, configure.in: Make it compile with the BSD Kerberos. * mk_auth.c: New file from CNS containing functions not present in BSD Kerberos. * configure.in: Don't assume "m4" is GNU m4. * file-pr.c: Fix a compiler warning. * gnats.texi, p-admin.texi, p-inst.texi, p-usage.texi, fields.texi: Clean up a few formatting errors, duplicated text, typos, etc. Add a few missing examples. Document the new file system layout. Tue Jul 15 11:28:18 1997 Brendan Kehoe * Makefile.in (install-tools-arch-indep): Use $(srcdir)/../mkinstalldirs instead of `$(INSTALL) -d'. (install-gnats-arch-indep): Likewise. (install-gnats-bin): Likewise. Fix from "Jonathan I. Kamens" . Make it possible to separately install the architecture-dependent pieces for the main server on one machine, and the independent pieces for the clients. * Makefile.in (install-arch-dep, install-tools-arch-dep): New dependencies. (install-tools): Add install-tools-arch-indep. (install-tools-arch-indep): New rule. (install-tools-bin): Move the elisp installation up into indep. (install-gnats, install-gnats-arch-dep): New dependencies. (install-gnats-arch-indep): New rule, installing the elisp and data files. (install-gnats-bin): New rule, installing the binaries. Fix from "Jonathan I. Kamens" . * files.h (struct responsible_entry): Add AUTHENTIC member. * files.c (find_responsible): Set it. Initialize the FULLNAME field to an empty string instead of a null string. (get_responsible_address): Set/clear it as appropriate. * gnats-el.in (gnats::real-pr-addr): Give `-s' to pr-addr. * pr-addr.c (long_options): Add -s/--strict. (main): Set local STRICT if it's there, and only show the addr if !STRICT or the AUTHENTIC field is set. (usage): Add -s/--strict. Fix from "Jonathan I. Kamens" . * configure.in: Add checks for libdes425 and libcrypto, for krb5 vs krb4 compatability. * configure: Regenerated with autoconf 2.12. * nquery-pr.c (usage): Add -P/--port, and mention -H, both with and without GNATS_RELEASE_BASED. Fix from "Jonathan I. Kamens" . * mkcat.sh (CATEGORIES): Use `cp /dev/null' instead of touch to create and zero out each of the dist/categories file and the GNATS_SITE file. Fix from "Jonathan I. Kamens" . * contrib/check-db.sh (PATH): Don't use $GNATS_ROOT/gnats-bin anymore. Sun Jun 8 17:34:50 1997 Ken Raeburn * sub-type.c (long_options): Must end with null option. Add new --help/-h option. (usage): New argument, exit status to use. (main): Remove short options from getopt string that aren't really handled. Add 'h' support. Be consistent about passing argument to usage function. * pr-mail.c: Likewise. (usage): Fix typo. * query.h: Rename "host_name" from "name", and add var "port". All definitions and uses changed. * npr-edit.c (long_options): New option --port/-P. (main): Handle it (currently numeric only). * nquery-pr.c (long_options): New option --port, no short form. (main): Handle it (currently numeric only). * client.c (client_init): Use port if positive, otherwise call getservbyname or fall back to hardcoded value. * npr-edit.c: Reduce network delays in check_pr: (n_to_validate): New variable. (do_field): Increment it, don't call get_reply. (finish_field_validations): Call get_reply n_to_validate times. (net_check_pr): Call finish_field_validations. Call do_field for date-required instead of open-coding it here. * cmds.c (GNATS_auth) [HAVE_KERBEROS]: Don't do fflush on stdout just before another printf; it's likely to make for more packets. * client.c (client_exit): Use fclose, not close, to flush buffered output. Thu Jun 5 17:32:00 1997 Brendan Kehoe * getclose.c (failed_dates): New variable. (procdate): Also check for t == -1 for bad date fmts. Set FAILED_DATES. (long_options): Add -v/--verbose. (do_stat): Print the name of what we're reading if VERBOSE. (main): Handle it and FAILED_DATES. (version): Add usage. Tue May 20 12:46:03 1997 Brendan Kehoe * npr-edit.c (do_field): Make parms unsigned char*. * internal.c (lock_gnats): Take out daemon msg about it being locked. (unlock_gnats): Make int return type, giving -1 if it's not locked, 0 otherwise. Take out daemon msg. * gnats.h (unlock_gnats): Change prototype. * cmds.c (GNATS_{lkdb,undb}): Give the message here. Fri May 16 18:24:01 1997 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.102. * query-pr.c (usage): Mention -R/--restricted. * nquery-pr.c (usage): Likewise. * contrib/cern-wwwgnats: Import CERN wwwgnats 2.0 from the URL http://wwwcn1.cern.ch/~lovell/gnats.html. Thu May 15 10:58:18 1997 Brendan Kehoe * man/nquery-pr.man: New file. * nquery-pr.c (version): Fix name. * gnats-el.in (gnats-mode-map): Add `C-c C-y' for changing severity, and `C-c C-p' for changing priority. (gnats:severity-change-from-to): New fn. (gnats::update-priority): New fn. (gnats::fields): Add Severity and Priority, to both put entries in the audit trail. * p-usage.texi: Document them. * TODO: these audit trail entries should be implemented in edit-pr.sh. * contrib/tkgnats: Update to tkgnats-2.0b4. Tue May 6 12:18:18 1997 Brendan Kehoe * query-pr.c (usage): Mention --arrived-before and --arrived-after. * nquery-pr.c (usage): Likewise. Get rid of --quarter and --keywords for non-release-based case. * qvariable.c (required_{before,after}) [GNATS_RELEASE_BASED]: Renamed from just BEFORE and AFTER, to match the option and make it clearer. * query.h (required_{before,after}) [GNATS_RELEASE_BASED]: Rename decls. * query.c (pr_matches) [GNATS_RELEASE_BASED]: Change uses. * cmds.c (GNATS_{bfor,aftr,rset}) [GNATS_RELEASE_BASED]: Change uses. * nquery-pr.c (required_{before,after}_string) [GNATS_RELEASE_BASED]: Renamed from BEFORE_STRING and AFTER_STRING. (ask_about) [GNATS_RELEASE_BASED]: Change use. (main) [GNATS_RELEASE_BASED]: Likewise. * query-pr.c (main) [GNATS_RELEASE_BASED]: Likewise. Mon May 5 13:36:17 1997 Brendan Kehoe * pr.c (read_pr): Double the BUFFER_SIZE and UNFORMATTED_SIZE each time, rather than just increase it by BUFSIZ. * headers.c (read_header): Don't leap out if we see a `>'. Sat May 3 18:31:51 1997 Brendan Kehoe * Makefile.in (config): Fix bug in direct of GNATS_USER. Tue Apr 22 14:26:10 1997 Brendan Kehoe Pointed out by Brian Abernathy . * getclose.c (long_options): Add -V/--version. (main): Accept it. (usage): Mention it. (version): New function. * pr-age.c (long_options): Add -V/--version. (main): Accept it. (usage): Mention it. (version): New function. * pr-stat.c (long_options): Add -V/--version. (main): Accept it. (usage): Mention it. (version): New function. * gnatsd.c (long_options): Add -V/--version. (main): Accept it. (usage): Mention it. (version): New function. Mon Apr 14 16:28:04 1997 Ian Lance Taylor * Makefile.in (INSTALL): Change install.sh to install-sh. Mon Apr 7 14:28:52 1997 Brendan Kehoe * files.c (find_responsible): Zero out ARRAY, so if it's missing the alias field in the submitters file, we don't end up with garbage. Use NUM_RESPONSIBLE_FIELDS, not NUM_SUBMITTER_FIELDS. Thu Jan 23 06:14:54 1997 Brendan Kehoe Make install inside the gnats directory work. * Makefile.in (INSTALL): Put back to `$(srcdir)/../install.sh -c'. (SUB_INSTALL{,_DATA}): Define. (FLAGS_TO_PASS): Pass those instead of INSTALL and INSTALL_DATA. * cmds.c (usage): Do a lot of cleanup, and put in the missing commands. Add testing for arrival dates. This needs to be done w/ the value indexed to have it go at any decent speed. * query-pr.c (cmds): Add -b/--arrived-before and -a/--arrived-after. (main): Use them. * nquery-pr.c (cmds, main): Likewise. (arrived_{before,after}_string): New vars. (ask_about): Send the commands. * gnatsd.h (GNATS_{abfr,araf}): Add decls. * cmds.c (GNATS_{abfr,araf}): New fns. * gnatsd.c (cmds): Add them to the list. * query.c (date_compare): Add fourth argument CONVERT_P. Do get_date on SDATE if this is true. (pr_matches): Add arg to date_compare. (do_pr_internal): Check and compare arrived_{before,after}. Add arg to date_compare. * man/query-pr.man: Document the new options. Get rid of this ridiculous need for an empty start_data fn everywhere. * query.h (start_data): Delete decl. * file-pr.c, getclose.c, pr-age.c, pr-stat.c, query-pr.c (start_data): Delete fns. * cmds.c (start_data): Delete fn. (started): Deleted var. (do_query): Call reset_started now, instead of clearing STARTED. (GNATS_lock): Delete call to start_data. * query.c: Remove the global variables. Include pcodes.h for CODE_PR_READY. (print_pr): Put equivalent of start_data code inside here. (started): Move static variable here. (reset_started): New fn that does nothing but zero it out. * gnatsd.h (CODE_*): Move macros into pcodes.h, and include it. * pcodes.h: New file. * Makefile.in (gnatsd.h): Add dependency on pcodes.h. (LIBSRC): Add qvariable.c. (LIBOBJ): Add qvariable.o. * qvariable.c: New file w/ global vars from query.c. * nquery-pr.c: Turn on -o/--outfile. (full_report, sql_format): Delete unused vars. * query.h (outfile): Declare here now. * query-pr.c: Not here. * lists.c (get_gnats_file): Rename OUTFILE to OUTF. * Makefile.in (LIBGNATS): Delete useless variable. Change all references to just use libgnats.a. (all-tools): Do our work on a tmp copy. * query-pr.c (cmds): Add the -D/--debug option, to match nquery-pr. (main): Use it (really just a no-op right now for compatibility). * nquery-pr.c (cmds): Get rid of bogus -E/--entire option. (main): Take out the case for it. (entirety): Delete global var. * query.h (before, after): Move to within #ifdef GNATS_RELEASE_BASED. (arrived_before, arrived_after): Add decls. * query.c (arrived_before, arrived_after): Define variables. (do_pr_internal): Compare them. (before, after): Move to within #ifdef GNATS_RELEASE_BASED. * gnatsd.c (cmds): Move BFOR and AFTR cmds to within #ifdef GNATS_RELEASE_BASED. * gnatsd.h (GNATS_{bfor,aftr}): Wrap decls to within #ifdef GNATS_RELEASE_BASED. * cmds.c (GNATS_{bfor,aftr}): Move definitions to within #ifdef GNATS_RELEASE_BASED. (GNATS_rset): Move setting of BEFORE and AFTER inside #ifdef GNATS_RELEASE_BASED. * nquery-pr.c ({before,after}_string): Likewise. (ask_about): Move use of them to within #ifdef GNATS_RELEASE_BASED. (main): Move use of -u and -U to within #ifdef GNATS_RELEASE_BASED. * query-pr.c (main): Likewise. Thu Dec 26 12:10:08 1996 Brendan Kehoe * query-pr.c (long_options): #if 0 arrived-{before,after} for now. Tue Dec 10 17:11:46 1996 Brendan Kehoe * gnats-el.in (gnats::pr-addr): Wrap the user's name with quotes if it's got a period in it. Mon Dec 9 13:07:45 1996 Brendan Kehoe * query-pr.c (long_options): Add -A/--release to the list. (main): Deal with it. (usage): Add -A and --release. * nquery-pr.c (long_options): Add -A/--release to the list. (release): New global variable. (ask_about): Send `RLSE %s'. * query.c (do_pr_internal): Compare against RELEASE. (release): New global variable. * gnatsd.c (cmds): Add RLSE command. * cmds.c (GNATS_rlse): New function. (GNATS_help): Add RLSE to the help response. * gnatsd.h: Add decl. * query.h (release): Add extern decl. * p-usage.texi: Document -A/--release. * query-pr.c (long_options): Add -y/--synopsis to the list. (main): Deal with it. (usage): Add -y and --synopsis. * nquery-pr.c (long_options): Add -y/--synopsis to the list. (synopsis): New global variable. (ask_about): Send `SYNP %s'. * query.c (do_pr_internal): Compare against SYNOPSIS. (synopsis): New global variable. * gnatsd.c (cmds): Add SYNP command. * cmds.c (GNATS_synp): New function. (GNATS_help): Add SYNP to the help response. * gnatsd.h: Add decl. * query.h (synopsis): Add extern decl. * p-usage.texi: Document -y/--synopsis. * query-pr.c (usage) [GNATS_RELEASE_BASED]: Add `Q:' and `K:' to the list. * nquery-pr.c: Remove --arrived-before/--arrived-after bits for now, since they aren't doing anything yet. Fri Dec 6 10:53:43 1996 Brendan Kehoe * file-pr.c (append_report): Cast the string-constant first argument of APPEND_STRING to `(char*)', to deal with compilers that think of it as an array type. * headers.c (read_header): Redeclare local var LINE to be created with xmalloc, rather than using an array. Mon Dec 2 12:11:13 1996 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.101. * contrib/scripts: New set of stuff from Brian Abernathy . * contrib/elisp: New dir. * contrib/elisp/gnats-admin.el: New file from roger.hayes@sun.com. * edit.c (modify_pr): Use GNATS_TIME_LENGTH instead of 30 for the date buffer. * file-pr.c (run_atpr): Likewise instead of STR_MAX. (notify_responsible): Likewise. (append_report): Likewise. (GNATS_TIME_LENGTH): Move definition from here... * gnats.h (GNATS_TIME_LENGTH): ...to here. * gnatsd.c (match): Call tolower on each character, to force the comparison of the hostnames to be case-insensitive. * queue-pr.c (main): Use strlen ("/gnats-queue") instead of 11. * internal.c (write_index): Likewise for "/gnats-adm/indXXXXXX" instead of 20. (write_index): Likewise for "/gnats-adm/" instead of 10. Thu Nov 14 10:48:04 1996 Brendan Kehoe * queue-pr.c (fork_gnats): Redecl local SAFE_ENV as static. Thu Nov 7 06:38:25 1996 Brendan Kehoe * gnatsd.c (Argify): Make sure *cp is non-nil before we try to check it for flags. Otherwise, we attempt to dereference what is now a null pointer with bogus commands. Let npr-edit do locking and unlocking of GNATS. * gnatsd.c (cmds): Add LKDB and UNDB commands. * cmds.c (GNATS_lkdb, GNATS_undb): New functions. (GNATS_help): Add LKDB and UNDB to the help message. * gnatsd.h (GNATS_lkdb, GNATS_undb): Add decls. * npr-edit.c (main, case LOCKDB): Send LKDB. (main, case UNLOCKDB): Send UNDB. * internal.c (unlock_gnats): If IS_DAEMON, say when it's already unlocked or when unlocking it is finished. Also say if it's not locked at all. Use PROGRAM_NAME in the errors. (lock_gnats): Likewise. * gnats-el.in (gnats::find-pr-buffer): New function. (gnats:edit-pr): If we already have a buffer for a given PR, switch to it instead of trying to lock it. (gnats::handle-results): Only give the message, not the error. (gnats::pr-being-edited): Delete error condition. * npr-edit.c (do_field): New function, dealing with the value of a particular PR field---which could be null. (net_check_pr): Use it. Handle the responsible field being null. * cmds.c (GNATS_resp): Say "responsible entry" instead of "name" for the error message. Thu Oct 31 15:24:15 1996 Brendan Kehoe Add `getclose', which will show which PRs closed between certain dates. * getclose.c: New file. * Makefile.in (all-tools): Add getclose. (DISTFILES): Add getclose.c. (install-tools-bin): Add getclose. (uninstall): Delete it. (doclean): Add getclose. (getclose): Add rule. (getclose.o): Add dependencies. Mon Oct 28 12:49:45 1996 Brendan Kehoe * gnatsd.c (match): Should force default of failure if the line doesn't match the string in P. * gnats-el.in (gnats::unlock-all-buffers): Force GNATS:RUN-IN-BACKGROUND to be nil before we do the forced unlocking of remaining buffers. Mon Oct 28 12:45:29 1996 Jonathan I. Kamens * edit.c (modify_pr) (GNATS_RELEASE_BASED): Don't dereference a null pointer if the PR doesn't have a "Date-Required" field in it. Mon Oct 28 12:11:29 1996 Brendan Kehoe * Makefile.in (VERSION): Forgot to boost to 3.100. (Was made available on October 2, 1996.) Fri Sep 27 15:02:42 1996 Brendan Kehoe * internal.c (write_index): Adjust to allocate 20 for the filename. Thu Sep 19 19:14:30 1996 Eric Mumpower * configure.in: I changed the configure algorithm here to assume that if a libkrb.a is found in the specified $KRB4 directory, that it is preferred to any libkrb.a that may be present in the system library directories. * configure: Regenerated. Mon Sep 16 16:25:19 1996 Brendan Kehoe Problem pointed out by Tom Schutter . * configure.in (HOESTNAME): Don't set anymore. (_h): Init with "`(hostname || uname -n) 2>/dev/null | sed 1q`". * configure: Regenerated. Thu Sep 5 14:18:01 1996 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.99. * PROBLEMS: New file. * file-pr.c (GNATS_TIME_LENGTH): Define to 50. (gnats): Use it for arrival_time instead of 30. * contrib/wwwgnats/wwwgnats.shar: New version by Karl Berry. Retrieved from http://www.tug.org/gnats/. * contrib/wwwgnats/{README.html, libgnats.pl, wwwgnats.pl}: Remove old version. Tue Aug 27 14:19:33 1996 Brendan Kehoe * pr.c (write_pr): Define macro MAYBE_NL, and use it for MultiText fields. Mon Aug 26 11:55:50 1996 Brendan Kehoe * mkdist.sh (all): Take out send-pr.elc for default rule. * index.c (create_index_entry) [GNATS_RELEASE_BASED]: Also check that TIM is non-nil value. * internal.c (write_index) [GNATS_RELEASE_BASED]: Avoid garbage values of date_required field. * query.c (date_compare): Return 1 if VAL is a zero value, meaning that the date field is unset. * pr.c (read_pr): Free the old value of the multitext field before we go ahead and replace it with what's in the BUFFER. Likewise for freeing before dup'ing value of L. * gnats-el.in (gnats::start-background): Make sure we have a trailing newline in the stuff sent to PROC before we send EOF. * gnatsd.c (FLAG_ONE_ARG): Define. (cmds): Set it for ORIG, CLSS, SUBM, TEXT, MTXT, BFOR, AFTR, and VDAT. (cmds) [GNATS_RELEASE_BASED]: Likewise for QRTR and KYWD. (Argify): Add third arg Command CP. Add a little sanity to use FLAG_ONE_ARG properly. (main): Pass &CP down into Argify. Instead of doing strncasecmp on each of CP, just see that CP is non-null. * cmds.c (GNATS_orig, GNATS_clss, GNATS_auth): Check the nargs, then just copy the args into its var. (GNATS_bfor, GNATS_aftr): Don't bother using full_date, instead let FLAG_ONE_ARG do the trick. (GNATS_qrtr, GNATS_kywd) [GNATS_RELEASE_BASED]: Likewise. (full_date): Remove unneeded function. * gnatsd.h (GNATS_qrtr, GNATS_kywd) [GNATS_RELEASE_BASED]: Add decls. * cmds.c (started): Make it static. (do_query): Init STARTED to zero before looking at the args, instead of clearing after hit was set. * query.c (started): Remove unused extern decl. Wed Aug 21 08:34:15 1996 Brendan Kehoe * configure.in: If $prefix is NONE, use $ac_default_prefix for setting of GNATS_ROOT. * configure: Regenerate. * gnats-el.in (gnats:unlock-buffer): Undo change of June 26, 1995, to make the most recent edited PR go into the `*edited-pr*' buffer when GNATS:KEEP-EDITED-BUFFERS is nil. * gnats-el.in (gnats::handle-results): Add EXIT-STATUS argument, flagging when we see an unknown error. (gnats::handle-pr-edit): Pass RESULT down as that arg. (gnats::handle-check-pr): Likewise. (gnats::handle-file-pr): Likewise. (gnats::handle-unlock-pr): Likewise. * Makefile.in (install-info): Use basename on $I. * file-pr.c (notify_responsible): Make sure REPLY_TO is really a null string, to see if we want to put the From: header in there. Get rid of a variety memory leaks and minor buglets. * gnats.h (free_index, free_index_entry): Add decls. * pr.h (struct index_entry): Add BUF field. * index.c (free_index, free_index_entry): New functions. (next_index_entry): Set p->buf to BUF. (get_index): Rename INDEX_CHAIN to CURRENT_CHAIN. * edit.c (modify_pr): Init INDEX_CHAIN, PATH, OLD_PATH, and LOCK_PATH to NULL. Make S a char*, using it instead of just using s->number. Init new_index->buf to NULL. Call free_index and free_index_entry in a variety of places where we otherwise return or exit because of an error. Rename INDEX_CHAIN to CURRENT_INDEX. (check_pr): Call free_category once we've checked it. Likewise call free_submitter and free_responsible. (lock_pr): Rename stat BUF to SBUF. * files.c (find_submitter): Free array[3]. (find_category): Zero out CPTR before we use it. (find_responsible): Free ARRAY before we return. (get_responsible_address): Free responsible->alias, then set it to a copy of the key for both cases. * file-pr.c (gnats): Call free_responsible, and free the RESPONSIBLE ptr at the end. (gnats): Rename stat BUF to SBUF. (run_atpr): Rename PIPE to P. (append_report): Rename local CC to NEW_CC. * internal.c (write_index): Adjust allocation of PATH and TMPFILE to only happen when we need it to, and only allocate TMPFILE to be L_tmpnam if HAVE_MKTEMP isn't set. Stop using PATH_MAX for this. Free TMPFILE if opening it failed. Free PATH before punting about renaming the temp index. Free both PATH and TMPFILE before we leave. Rename TMPFILE to WORKFILE. * nquery-pr.c (usage): Rename param STAT to S. * gen-index.c (usage): Rename param STAT to S. * gnatsd.c (allowed): Rename local ACCESS to ACC. * cmds.c (check_locked): Rename param PR to P. (GNATS_auth): Delete local unused array USER. * query-pr.c (usage): Rename param STAT to S. * client.c (client_init): Delete unused local var LREALM. * file-pr.c (free_category, free_submitter): Move from here... * files.c (free_category, free_submitter): ...to here. * globals.h (free_category, free_submitter): Put decls here. * Makefile.in (QUEUE_DIR): Remove defunct definition. (GNATS_DEFS): Remove QUEUE_DIR from the defs passed down. * edit.c (check_pr) [case GNATS_RELEASE_BASED]: Only try to parse the date in D if it's non-null. * gnats-el.in (gnats::start-background): Put the value of PR into a buffer-local GNATS:::CURRENT-PR before creating the ARGS for unlocks. * cmds.c (GNATS_mlpr): Only use responsible->alias if responsible is non-null. Free RESPONSIBLE before we unify_addrs, instead of after we say end of list. (GNATS_resp): Free RESPONSIBLE when we're done. * gen-index.c (do_category): Free PATH before we return. * client.c (get_reply) [case CODE_GREETING]: Free R before we read in the next reply. (client_init): Free R after getting CODE_OK, et al. Tue Aug 20 10:46:57 1996 Brendan Kehoe * gnats-el.in: Only require 'env if it's emacs19. (gnats::start-background): Only try to set PROCESS-ENVIRONMENT if we're using emacs19. Fix from "Jonathan I. Kamens" to work w/ emacs18. * gnats-el.in (gnats:kill-buffer): No longer make BUF optional, instead prompt them for it. Adjust use of get-buffer instead of current-buffer, to avoid killing the wrong one. * Makefile.in (INSTALL): Make sure we get the full path for this. Mon Aug 19 12:44:07 1996 Brendan Kehoe * file-pr.c (check_if_reply): Adjust PAT to catch `Re[2]: ...'. Adjust offset into start and end to use the value of this pattern. Thu Aug 15 10:55:21 1996 Brendan Kehoe * query-pr.c (usage) [!GNATS_RELEASE_BASED]: Don't mention --required-before or --required-after. * nquery-pr.c (usage) [!GNATS_RELEASE_BASED]: Likewise. Fix from Brian Abernathy . * query.c (pr_matches): Use strcasecmp for closed case. Fri Aug 9 10:22:47 1996 Brendan Kehoe * edit.c (modify_pr) [GNATS_RELEASE_BASED]: Remember to set the date_required field. Thu Aug 8 17:02:14 1996 Brendan Kehoe * Makefile.in (VERSION): Up version to 3.98. * gnats-el.in (gnats:gnats-mode): Don't make it interactive. Thu Jul 18 10:43:48 1996 Brendan Kehoe Allow users to use GNATS in the foreground as before, if they want. * gnats-el.in (gnats:run-in-background): New variable. (gnats::handle-unlock-pr): Renamed from gnats::unlock-pr-sentinel. (gnats:unlock-pr, gnats:unlock-pr-force): Pass 'gnats::handle-unlock-pr. (gnats::handle-pr-edit): Renamed from gnats::edit-pr-sentinel. Use switch-to-buffer instead of display-buffer if we don't want gnats:run-in-background. (gnats::pr-edit-background): Pass 'gnats::handle-pr-edit. (gnats::handle-check-pr): Renamed from gnats::check-pr-sentinel. (gnats::check-pr-background): Pass 'gnats::handle-check-pr. (gnats::mail-PR-changed): Return the mail buffer being used. (gnats::finish-filing): New local RETBUF, set to the value returned by gnats::mail-PR-changed. Give that back to its caller. (gnats::handle-file-pr): Renamed from gnats::file-pr-sentinel. Return RETBUF. (gnats::file-pr-background): Pass 'gnats::handle-file-pr. Switch to RETBUF returned by gnats::start-background. (gnats:submit-pr): Only call bury-buffer if gnats:run-in-background. * queue-pr.c (main): Move checking of gnats_root and setting of queue_dir to be after the call to configure(). Mon Jul 15 15:00:23 1996 Brendan Kehoe Fix switching between GNATS types. * gnats-el.in (gnats:::{query-pr, nquery-pr, query-regexp}): Define vars. (gnats:net-view-pr): Use gnats:::nquery-pr and gnats:::query-regexp. (gnats:change-type): Set the new vars. (gnats:query-pr): Use gnats:::nquery-pr and gnats:::query-pr. (gnats:summ-pr): Likewise, and use gnats:::query-regexp. Wed Jun 26 12:10:43 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) * Makefile.in (VPATH, INSTALL_PROGRAM, INSTALL_DATA, bindir, libdir, statedir, datadir, mandir, infodir, includedir): Use autoconf-set values. (docdir): Removed. * configure.in (AC_PREREQ): autoconf 2.5 or higher. (AC_PROG_INSTALL): Uncomment. * configure: Regenerated. * man/Makefile.in (VPATH, bindir, libdir, datadir, mandir, infodir, INSTALL, INSTALL_PROGRAM, INSTALL_DATA): Use autoconf-set values. (oldincludedir, docdir): Removed. Wed Jun 19 11:35:02 1996 Brendan Kehoe * queue-pr.c (queue_dir): Add definition. (main): Set queue_dir based on current value of gnats_root. (fork_gnats): Pass `-d gnats_root' to file-pr. * config.h (queue_dir): Remove decl. * config.c.in (queue_dir): Remove CN_OPT. * config.c: Regenerate. * configure.in (QUEUE_DIR): Remove subst/setting/echo of it. * configure: Regenerate. Fri Jun 14 08:36:22 1996 Brendan Kehoe * files.c (get_responsible_address): Always accept the responsible name, even if it doesn't have a passwd entry. * file-pr.c (append_report): Report not getting a responsible address. Thu Jun 13 08:31:16 1996 Brendan Kehoe * client.c (free_reply): Cast R to char* for xfree. * pr-age.c (report_age): Cast T to char* for xfree. * index.c (find_pr_category): Return NULL at the end. * cmds.c (get_text): Delete decl of fopen. * gnats.h (safe_exit): Add decl. * nquery-pr.c (safe_exit): Delete decl. * sub-type.c (safe_exit): Likewise. * gnatsd.h (client_init, client_exit): Move decls from here... * gnats.h: ... to here. * configure.in: Check for netdb.h. * configure: Regenerate with autoconf 2.8. * autoconf.h.in: Regenerate. * gnatsd.h [HAVE_NETDB_H]: Include for gethostbyname decl. * Makefile.in (regex.o): Don't depend on $(srcdir)/gnats.h. * gnats.h (get_date): Add prototype. * query.c (sql_time): Delete decl of get_date. * pr-age.c (report_age): Delete decl of get_date. * gnatsd.h (get_reply): Move prototype from here... * gnats.h (get_reply): ... to here. * nquery-pr.c (get_reply): Remove prototype. * globals.h (find_category): Fix prototype, was `find_categories'. * gnats.h (check_index): Add prototype. * gnatsd.h (server_reply, read_server): Remove decls, only used in client.c. * cmds.c (name_verify): #if 0 fn definition. * internal.c (lock_gnats): Use `%d', not `%s', for error number. * client.c (client_init): Delete unused var H. * cmds.c (GNATS_mlpr): Delete unused var LIST. * npr-edit.c (main): Delete unused vars I and PWP. * pr.c (check_enum_types): Delete unused vars P and P2. * query.c (date_compare): Abort if neither case is met. * gen-index.c (main): Make return type `int'. * main.c (main): Likewise. * npr-edit.c (main): Likewise. * nquery-pr.c (main): Likewise. * pr-age.c (main): Likewise. * pr-edit.c (main): Likewise. * pr-mail.c (main): Likewise. * pr-stat.c (main): Likewise. * gnatsd.c (main): Likewise. * query-pr.c (main): Likewise. * queue-pr.c (main): Likewise. * sub-type.c (main): Likewise. Patch from Uwe Block . * query-pr.c (main): Add `L:' to getopt_long string. * nquery-pr.c: Likewise. Thu Apr 4 11:59:28 1996 Brendan Kehoe * gnats-el.in (gnats::mail-PR-changed-mhe-setup): Instead of MH-SEND, use MH-SEND-OTHER-WINDOW, (gnats::finish-filing): Fix to unlock the PR Buffer, not the mail buffer. Wed Apr 3 16:07:12 1996 Brendan Kehoe Make edit-pr throw the stuff into the background, popping back up when it's done. * gnats-el.in (gnats::pr-being-edited): Set up the error condition. (gnats:submit-pr): Rewrite to only start up gnats::check-pr-background. (gnats::pr-edit, gnats::check-pr, gnats::file-pr): Deleted functions. (gnats:current-pr, gnats:newfile, gnats:::pr-buffer, gnats:::do-file-pr, gnats:::force): New variables. (gnats::handle-results, gnats::start-background): New functions. (gnats::pr-edit-background, gnats::pr-edit-sentinel): New functions. (gnats::check-pr-background, gnats::check-pr-sentinel): New functions. (gnats::file-pr-background, gnats::file-pr-sentinel, gnats::finish-filing): New functions. (gnats:unlock-pr-force, gnats:unlock-pr): Rewrite to use the start-background fn. (gnats::unlock-pr-sentinel): New function. (gnats:net-view-pr): Add (require 'view). Need to REWRITE this and the summary fns! (gnats:edit-pr): Rewrite to just use gnats::lock, everything else is now done by gnats::handle-results. Tue Apr 2 17:00:40 1996 Brendan Kehoe * gnats-el.in (gnats::pr-edit): Replace MIN and MAX with SEND-BUFFER. If that's true, use (point-min) and (point-max). (gnats::check-pr): Change call. (gnats::file-pr): Likewise. (gnats:unlock-pr-force): Fix call. Fri Mar 29 13:30:23 1996 Brendan Kehoe * npr-edit.c (net_check_pr) [GNATS_RELEASE_BASED]: Make sure there's a DATE_REQUIRED value before we check its contents being non-zero. Tue Mar 12 15:02:48 1996 Brendan Kehoe * gnats-el.in (gnats::tr): Clean up to use string-to-char, rather than match-beginning. From Mark Eichin . Wed Mar 6 12:18:09 1996 Brendan Kehoe * npr-edit.c (net_check_pr): Make sure we have a date required before we validate it. * cmds.c (GNATS_vdat): Check that we got a date before trying to validate it. * index.c (create_index_entry) [GNATS_RELEASE_BASED]: Fix typo, time_t. * edit.c (check_pr) [GNATS_RELEASE_BASED]: Add decl for locals T and D. * file-pr.c (reply_to_submitter): Say "at your report", not "at your bug". Tue Feb 20 17:48:20 1996 Brendan Kehoe * files.c (init_responsibles): Clean up to deal with responsible files that have missing entries. * gnats-el.in (gnats::tr): Clean up to not die on "[" and "]". * config.h (ACCESS_FILE): Take off leading slash. Fri Feb 16 16:28:21 1996 Brendan Kehoe * query.c (print_pr): Free the time after we've printed it. Wed Feb 14 12:38:43 1996 Brendan Kehoe * nedit-pr.sh: New file. * Makefile.in (all-tools): Add nedit-pr. (nedit-pr): New rule. (install-tools-bin): Install nedit-pr. (uninstall): Remove nedit-pr. (doclean): Likewise. Tue Feb 13 15:57:34 1996 Brendan Kehoe * Makefile.in (config, at-pr, mkcat, rmcat, mkdist, edit-pr, mail-query, gnats.el): Make these quiet. * man/Makefile.in (SRCS1, SRCS8, SRCSL): Likewise. Add functionality for GNATS to be release-based, by configuring it with the configure flag `--with-release-based'. * configure.in, configure: Take the new flag. * acconfig.h (GNATS_RELEASE_BASED): Add undef. * autoconf.h.in: Regenerate. * pr.h (PR_Name) [GNATS_RELEASE_BASED]: Add QUARTER, KEYWORDS, and DATE_REQUIRED. (PR_Type): Add Date. (Index) [GNATS_RELEASE_BASED]: Add date_required. ({QUARTER,KEYWORDS,DATE_REQUIRED}_STRING) [GNATS_RELEASE_BASED]: Define. * pr.c (init_pr): Make ARRIVAL_DATE be Date type. (init_pr) [GNATS_RELEASE_BASED]: Set QUARTER, KEYWORDS, and DATE_REQUIRED. * query.c (before, after): Define. (quarter, keyword) [GNATS_RELEASE_BASED]: Define. (date_compare): New function. (pr_matches): Check before and after against the arrival date. (pr_matches) [GNATS_RELEASE_BASED]: Check before and after against the date required instead. (do_pr_internal) [GNATS_RELEASE_BASED]: Also check for quarter and keyword searches. (print_pr) [GNATS_RELEASE_BASED]: Write QUARTER and KEYWORDS. * nquery-pr.c (quarter, keywords) [GNATS_RELEASE_BASED]: Define. (before_string, after_string): Define. (long_options) [GNATS_RELEASE_BASED]: Add quarter and keywords flags. Add required-before and required-after flags. (long_options): Otherwise, add arrived-before and arrived-after flags. (ask_about) [GNATS_RELEASE_BASED]: Add QRTR and KYWD cmds. (ask_about): Add BEFOR and AFTR cmds. (main) [GNATS_RELEASE_BASED]: Add Q and K options. (usage) [GNATS_RELEASE_BASED]: Add the --quarter and --keywords flags. * cmds.c (GNATS_qrtr, GNATS_kywd) [GNATS_RELEASE_BASED]: New functions. (full_date, GNATS_bfor, GNATS_aftr, GNATS_vdat): New functions. (GNATS_rset): Also reset before and after. (GNATS_rset) [GNATS_RELEASE_BASED]: Also reset quarter and keywords. (GNATS_help) [GNATS_RELEASE_BASED]: Add QRTR and KYWD. * edit.c (modify_pr) [GNATS_RELEASE_BASED]: Do DATE_REQUIRED. (check_pr) [GNATS_RELEASE_BASED]: Check DATE_REQUIRED. * index.c (create_index_entry) [GNATS_RELEASE_BASED]: Also include the date required in the index. (next_index_entry) [GNATS_RELEASE_BASED]: See the date required field. * internal.c (write_index) [GNATS_RELEASE_BASED]: Add the date required field. * npr-edit.c (net_check_pr) [GNATS_RELEASE_BASED]: Send a VDAT w/ the DATE_REQUIRED field. * gnatsd.h (GNATS_bfor, GNATS_aftr, GNATS_vdat): Add decls. (GNATS_qrtr, GNATS_kywd) [GNATS_RELEASE_BASED]: Add decls. * gnatsd.c (cmds) [GNATS_RELEASE_BASED]: Add QRTR and KYWD. * config.c.in: Put missing fclose here too. * file-pr.c (append_notify): Clean up code to not skip the last notification entry in the categories file. * mkdist.sh (FILES): Add categ.texi, fields.texi, s-usage.texi, states.texi, and version.texi. (send-pr.elc): Add rule to the Makefile we create. (lispdir): Install everything in $(prefix)/lib/emacs/site-lisp. * Makefile.in (domostlyclean): Also delete *.cps. (dodistclean): Also delete config.cache and gnats.info*. (dorealclean): Delete TAGS and version.texi, not *info. (install-tools-bin): Don't install with write permission. (install-gnats-bin): Likewise. * file-pr.c (check_if_reply): Don't quote the period in the PAT character class. * cmds.c (GNATS_bfor, GNATS_aftr): Make sure we got a date. Fri Jan 19 11:57:50 1996 Brendan Kehoe * gnats-el.in (gnats::try-responsible-completion): Set completion-ignore-case to t before we complete on the name. Tue Jan 9 17:56:16 1996 Brendan Kehoe * gen-index.c (main): Remember to close the outfile. * query-pr.c (main): Say we couldn't read the index if the chain is null. * pr-age.c (main): Likewise. * pr-stat.c (main): Likewise. Tue Jan 9 14:19:33 1996 Brendan Kehoe * files.c (find_responsible): Remember to free PATH. * client.c (dupfd): Add decl. (client_init): Use it. (client_exit): Close it. * nquery-pr.c (ask_about): Remember to free BUF before we leave. * pr.c (read_pr): Remember to free BUFFER also for non-full queries. * config.c (configure): Remember to close the config file. * client.c (free_reply): New function. (get_reply): Make sure to free the reply when we're done. (get_reply, case CODE_INFORMATION): Free the reply before we get the info, and free each additional bit of info for REPLY_CONTs. Mon Jan 8 19:39:51 1996 Brendan Kehoe * pr-age.c (report_age): Free the timediff after we've printed it. Always free the path when we're done. * pr.c (verify_enum): New function, based on code from check_enum_types. (check_enum_types): Call it. * gnats.h (verify_enum): Add decl. * cmds.c (check_locked): New function, based on code from GNATS_edit. (GNATS_edit): Use it. * cmds.c (GNATS_unlk): Return right after chk_nargs, and bring that block out into the function instead. (GNATS_mlpr, GNATS_mlct, GNATS_catg, GNATS_conf, GNATS_svty, GNATS_stat, GNATS_prio, GNATS_subm, GNATS_text, GNATS_mtxt): Likewise. * gnatsd.c (GNATS_*): Delete decls. * gnatsd.h (GNATS_*): Add them here as extern w/ PARAMS. * cmds.c (current_pr): Define. (daemon_pr): Set current_pr to the path if it was set. (do_query): Pass 1 as print arg to daemon_pr. (GNATS_lock): Likewise. * gnatsd.c (GNATS_bfor, GNATS_aftr): New functions. (cmds): Add BFOR and AFTR. * gnatsd.h (GNATS_bfor, GNATS_aftr): Declare. * cmds.c (GNATS_rset): Clear before and after. * pr.h (PR_Type): Add Date type. * pr.c (field_value): If the field is Date, return NULL. (init_pr): Make >Arrival-Date: Date type, not Text. * query.h (before, after): Declare. * query.c (before, after): Define. * gnatsd.c (cmds): Add VDAT. (GNATS_vdat): Add decl. * cmds.c (GNATS_vdat): Handle VDAT. (full_date): New function. * client.c (get_reply): Deal with CODE_INVALID_DATE. * gnats-el.in (gnats::pr-edit): Add invalid date message. (gnats::invalid-date): Add invalid date error. * gnatsd.h (CODE_INVALID_DATE): Define. Wed Nov 15 11:09:43 1995 Brendan Kehoe * gnats-el.in (gnats:change-type): Rewrite to allow the type to be passed as a parameter, not just interactively set. Fix it to not be case sensitive. Wed Nov 8 18:04:03 1995 Brendan Kehoe * gnats-el.in (gnats:net-view-pr): Use view-mode-enter if it's defined. Wed Oct 25 14:50:12 1995 Per Bothner * Makefile.in (diststuff): Also make 'info'. Tue Oct 17 16:52:17 1995 Brendan Kehoe * gnats-el.in (gnats::get-header-using-mail-fetch-field): Use re-search-forward instead of search-forward-regexp. Mon Oct 16 14:15:47 1995 Brendan Kehoe * gnats-el.in (gnats-summary-mode-map): Check if we're emacs 19 before calling suppress-keymap. (gnats:summary-redisplay): Call buffer-flush-undo for emacs 18. (gnats:summ-pr): Likewise. Say that summary mode only works with 19. (string-to-number): Defun to call string-to-int if we're emacs 18. (gnats:::format-max-width): Only use abs if we're emacs 19. Fri Oct 13 17:47:13 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.97. Wed Oct 4 13:58:11 1995 Brendan Kehoe * cmds.c (GNATS_rset): Clear ORIGINATOR and CLASS after we've freed them. Fri Sep 22 15:00:41 1995 Brendan Kehoe * index.c (check_index): Don't exit if stat failed. Thu Sep 21 18:22:12 1995 Brendan Kehoe Make the daemon reload the index if necessary when given a RSET. * index.c: Include gnatsd.h. (index_mtime): New variable with the mod time of the index. (index_filename): New variable with the name of the index. (stat_index): New function to check the modification time of the index. (open_index): Use it. (check_index): New function. * gnats.h (index_mtime): Add var decl. (stat_index): Add function decl. * cmds.c (GNATS_rset): Also run clean_pr, clean_header, and check_index. Reword the response message. Thu Sep 14 13:56:12 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.96. * gnats-el.in (gnats:summ-pr): Only run nquery-pr if gnats:network-server. Ignore the results of --print-path. Add Ken Raeburn's support for doing an emacs-based PR summary. We require emacs 19 now. * gnats-el.in (GNATS:::PRs, GNATS::options, gnats:::limited-fields, gnats::summary-sort-function, gnats::summary-format-alist, gnats::format-string, gnats-summary-mode-map): New variables. (gnats:::fieldval): New subst. (summ-pr): New fset. (gnats:::prompt-for-pr-number, gnats:summary-edit, gnats:summary-view, gnats:summary-quit, gnats:summary-revert, gnats:::parse-summary-format, gnats:::format-max-width, gnats:summary-redisplay, gnats-summary-mode, gnats:summ-pr): New functions. Wed Sep 13 12:37:30 1995 Brendan Kehoe * configure.in (CF): We need to do `. ${CF}', to make the variables take effect. Tue Sep 5 13:23:56 1995 Brendan Kehoe * gnats-el.in (gnats::mail-PR-changed): Change order to we actually get to use what we put in CC and TO. Tue Aug 22 23:26:29 1995 Ken Raeburn * gnatsd.h (GNATS_KRB4_PRINCIPAL_NAME): Use gnats_user, not GNATS_USER. * Makefile.in (client.o): Add dependencies. * gnats.h: Include libiberty.h. (xmalloc, xrealloc, basename): Don't declare. Fri Aug 11 09:32:35 1995 Brendan Kehoe Add the ability to change the username of the GNATS user. * configure.in: Accept new option `--with-gnats-user=name'. Subst GNATS_USER. * configure: Regenerate. * config.c.in (gnats_user): Declare. * config.c: Regenerate. * gnats.h (gnats_user): Add extern decl. * Makefile.in (GNATS_USER): Add decl. (GNATS_DEFS): Add -DGNATS_USER. (install-tools-bin): Refer to GNATS_USER. (install-gnats-bin): Likewise. (config): Also emit GNATS_USER. (at-pr): Substitute it. * at-pr.sh: Declare and use GNATS_USER. * file-pr.c (notify_responsible) [!DONT_USE_RESENT]: Use gnats_user. * internal.c (punt): Likewise. * misc.c (open_mail_file): Likewise. * gnatsd.h (GNATS_KRB4_PRINCIPAL_NAME): Use GNATS_USER. * queue-pr.c (safe_env): Take out of global scope. (fork_gnats): Instead, move in here and set USER=foo by hand based on gnats_user. * cmds.c (GNATS_resp): Re-enable verifying the RESP argument. Thu Aug 10 13:49:32 1995 Brendan Kehoe * mkdist.sh: Don't shift after IFS is reset. Wed Aug 9 10:49:44 1995 Brendan Kehoe * mkdist.sh (install): Create infodir. * configure.in: Put back in handling of --with-gnats-root. * configure: Regenerate. Fri Aug 4 12:16:44 1995 Brendan Kehoe * cmds.c (GNATS_help): Add RSET. Thu Aug 3 12:16:39 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.95. * cmds.c (qualify): Move the check of SEARCHING. * gnats-el.in (gnats:::types): Add definition. (gnats:change-type): New function. (gnats-change-type, change-gnats): Add fsets. * client.c (client_exit): Don't do get_reply after QUIT, we may have already been closed out. * index.c (open_index): Only emit the error message if !IS_DAEMON. * pr-age.c (is_daemon): Add definition to 0. * query-pr.c (is_daemon): Likewise. * gen-index.c (is_daemon): Likewise. * Makefile.in (config.c): Don't depend on Makefile. * client.c (get_reply): Handle CODE_FILE_ERROR. * gnats-el.in (gnats:change-root): New function. (change-gnats, gnats-change-root): New fets. * configure.in: Add --with-gnats-port and --with-gnats-service. * configure: Regenerate. * config.c.in (gnats_server_port): Set to GNATS_SERVER_PORT. (gnats_service): Set to GNATS_SERVICE. * config.c: Regenerate. * Makefile.in (GNATS_SERVER_PORT, GNATS_SERVICE): Add decls. (GNATS_DEFS): Pass them. (install-tools-bin, install-gnats-bin): Do chown/chmod if root or gnats. * gnatsd.h (GNATS_SERVER_PORT, GNATS_SERVICE): Take out definitions. * query.h (gnats_service, gnats_server_port): Add extern decls. * client.c (client_init): Use gnats_server_port and gnats_service instead of the macros. Wed Jul 26 18:29:32 1995 Brendan Kehoe * mkdist.sh: Take off trailing asterisk matching --release. Add a shift after setting IFS. Wed Jul 26 10:51:37 1995 Fred Fish * configure.in: Test for -lgen, needed for syslog on Unixware 2.0. * configure: Regenerated with autoconf 2.4. * Makefile.in (Makefile): Make dependant on config.status, so a "make" will cause config.status and Makefile to be regenerated if configure is updated. Mon Jul 24 09:08:29 1995 Brendan Kehoe Add RSET command, to clear out searching criteria. * gnatsd.c (cmds): Add RSET/GNATS_rset. (GNATS_rset): Add decl. * cmds.c (GNATS_rset): New function. * cmds.c (qualify): If the PR matches, drop its path in place here. (verify): Deleted function. (do_query): Don't call verify. Say that no PRs matched if none qualified. * query.c (get_category): Delete alternate sprintf, we leave if CATEGORY was null. * config.c.in: Don't include stdio.h or string.h. * config.c: Regenerate. * regex.c (re_match_2): Don't do arithmetic if STRING1 is null. * client.c (read_server): Only go 2 back on RECVLINE and check for a linefeed if we've got a second character. Sun Jul 23 15:48:46 1995 Brendan Kehoe * getdate.[ch]: Regenerate. Sun Jul 23 15:43:47 1995 Jeff Law (law@snake.cs.utah.edu) * getdate.y: Include to get various ansi/traditional C compatability macros. Sat Jul 22 01:21:29 1995 Jeff Law (law@snake.cs.utah.edu) * Makefile.in (lists.o): Add missing dependency on pathmax.h. Fri Jul 21 15:01:12 1995 Brendan Kehoe * file-pr.c (append_report): Allocate LINE dynamically, not auto. Free it after we've closed the input file. Tue Jul 18 12:06:24 1995 Brendan Kehoe In the lock for a PR, say what locked it. * edit.c (lock_pr): New arg PROCESSID. Print it into the lock if it's set. Use fgets when reading who locked it, not fscanf. * gnats.h (lock_pr): Update prototype. * cmds.c (daemon_lock_pr): New arg PROCESSID, passed into lock_pr. (GNATS_lock): Pass third arg into daemon_lock_pr, allowing the old version of just the number and username. * client.c (get_reply, case CODE_ERROR): Move up to the same as CODE_LOCKED_PR, so we say what the error was. * edit-pr.sh: Run pr-edit with --process set. * gnats-el.in (gnats::lock): Pass in our PID, if 'emacs-pid is set; only say "emacs18" if it isn't. (gnats:unlock-pr-force): Don't use --host=, just --host. (gnats:unlock-pr): Likewise. (gnats:query-pr): Likewise. (gnats::check-pr): Likewise. * npr-edit.c (long_options): Add -p/--process. (main): New variable PROCESSID, setting w/ the argument. (main, case LOCK): Pass it if it's set. (usage): Update usage. * pr-edit.c (long_options, main, usage): Likewise. (main): Pass PROCESSID into lock_pr. Mon Jul 17 07:35:07 1995 Brendan Kehoe * configure.in: Only run ${CF} if it's there; use /bin/sh or CONFIG_SHELL, not `.'. (HOESTNAME): Put it back. * configure: Regenerate. * Makefile.in (VERSION): Up to 3.93. * file-pr.c (gnats): Set all three fields, don't leave alias blank. Make sure the responsible field was non-null. (append_report): Set the LAST_MODIFIED field. * Makefile.in (config.c): Depend on the Makefile. Fri Jul 14 18:28:32 1995 Brendan Kehoe * cmds.c (GNATS_resp): Don't check the responsible given to us, since it may be an old one that's not in either list. Fri Jul 14 18:10:16 1995 Brendan Kehoe * file-pr.c (gnats): If we got a null responsible field, just go with what we were given for the PERSON, since we don't want to make not having things listed in the responsibles file be painful. * files.c (find_responsible): Return 0 only on success; otherwise return -1. Fri Jul 14 16:01:02 1995 Brendan Kehoe * configure.in: Delete setting of HOESTNAME. * configure: Regenerate. Thu Jul 13 12:17:07 1995 Brendan Kehoe * gnatsd.c (main): Make sure they give us the space between the command and its arguments. * cmds.c (GNATS_auth): Say what host had authentication fail. * gnats-el.in (gnats:gnats-mode): Also call gnats::set-submitters. (gnats::mail-PR-changed): CC anyone listed in the notify field for a submitter, so they can see all traffic related to that ID. * gnats-el.in (gnats:unlock-buffer): Only ask to unlock the PR if it hasn't been unlocked already. * file-pr.c (gnats): Don't put name in parenthesis for Responsible name. (append_notify): Also check that responsible->key is non-nil. * file-pr.c (append_report): Cast 0 to time_t for call to time. (gnats): Expand arrival_time to 30 from 26. Use strftime to set the arrival date, so it'll match the `>Last-Modified:' field. * file-pr.c: Include query.h. (check_if_reply): Use get_category to look up the PR based on its number, not accepting the category they told us. (start_data): New null function. Wed Jul 12 19:07:44 1995 Ken Raeburn * Makefile.in (getdate.c): Pass "-d" so y.tab.h gets created. * client.c (client_init) [HAVE_KERBEROS]: Prefix authentication error message with program name. Use strerror instead of perror. * cmds.c (GNATS_auth) [HAVE_KERBEROS]: Don't include ticket encoding in error message; that was for debugging only. Wed Jul 12 11:55:03 1995 Brendan Kehoe * Makefile.in (VERSION): Update to 3.92. * contrib/wwwgnats: Add March 15th release from Dan Kegel (dank@alumni.caltech.edu). * gnats-el.in (gnats:edit-pr): Give a message that we're fetching the PR. * Makefile.in (EMACS): Define variable to use ../emacs19/src/emacs if it's there. (gnats.elc): Use that instead of just `emacs'. Mon Jul 10 13:18:18 1995 Brendan Kehoe * gnats.h: Include pwd.h here. * client.c, cmds.c, files.c, npr-edit.c: Not here. * gnatsd.h: Include things like netinet/in.h here. * gnatsd.c, client.c, cmds.c: Not here. * query.h: Don't include gnatsd.h here. Move client.c prototypes to gnatsd.h. * gnatsd.h: Put client.c prototypes here. * client.c, cmds.c, gnatsd.c: Include gnatsd.h here. * Makefile.in (VERSION): Update to 3.91. * client.c (get_reply, case CODE_INVALID_RESPONSIBLE): Handle case. (get_reply): Exit non-zero on codes we can't understand. * cmds.c (GNATS_mlpr): Use CODE_INVALID_RESPONSIBLE (GNATS_resp): Check the responsible address we're given. * edit.c (check_pr): Use get_responsible_address, not find_responsible. * files.c (find_responsible): Make it static. * globals.h (find_responsible): Delete decl. Fri Jul 7 22:37:40 1995 Brendan Kehoe * edit.c (modify_pr): Adjust date format for last-modified. Fri Jul 7 21:45:51 1995 Brendan Kehoe * gnats-el.in (gnats:unlock-pr): Fix list creation if we want to attach the host. (gnats:unlock-pr-force): Likewise. (gnats::check-pr): Likewise. Fri Jul 7 10:40:53 1995 Brendan Kehoe * pr-edit.c (main): Don't exit if we got no args. * gnats-el.in (gnats::lock): Pass --host=gnats:network-server to npr-edit. (gnats::check-pr): Likewise. (gnats::file-pr): Likewise. (gnats:unlock-pr): Likewise. (gnats:unlock-pr-force): Likewise. (gnats:query-pr): Likewise to nquery-pr. (gnats:net-view-pr): Likewise. Add `>Last-Modified:' field, to track when PRs are edited/changed. * pr.h (PR_Name): Add LAST_MODIFIED value. (LAST_MODIFIED_STRING): Define to `>Last-Modified:'. * pr.c (init_pr): Set LAST_MODIFIED name and type. * edit.c (modify_pr): Set the Last-Modified field just before we write it out. N.B.: We don't for SQL. * query.c (print_pr): Also write out last modified. * Makefile.in (edit.o, npr-edit.o, query.o): Also depend on pr.h. * gnatsd.conf: New file. * Makefile.in (install-gnats-bin): Install gnatsd in $(libdir)/gnats. Put sample gnatsd.conf in gnats-adm if necessary. * configure.in: Update other messages to use AC_MSG_*. * configure: Regenerate. * gnatsd.c (allowed): Only allow i < 3. * configure.in: Also check for mktemp. * configure: Regenerate. * autoconf.h.in: Regenerate. * cmds.c (get_text) [!HAVE_MKTEMP]: Declare new var NAME, copying it into PATH after calling tmpnam. * internal.c (write_index) [!HAVE_MKTEMP]: Likewise. * queue-pr.c (drop_msg) [!HAVE_MKTEMP]: Likewise. * cmds.c (GNATS_mlpr): Add missing CODE_ERROR arg. * gnatsd.c (main): Move checking of the index, and give a message before we exit if it failed. * Makefile.in (LIBSRC): Add edit.c, getdate.c, internal.c, query.c, version.c. (LIBOBJS): Similar for .o files. (SOURCES, OBJECTS): Take them out of these. (pr-age, pr-edit, query-pr, nquery-pr, gnatsd, queue-pr, pr-addr, pr-age, pr-mail, npr-edit, pr-stat, gen-index): Update dependencies. * internal.c (unlock_quit): Add SIG argument, to avoid warnings. * main.c (unlock_death): Likewise. * getdate.y, getdate.c: Update files. * getdate.h: New file. * Makefile.in (getdate.c): Update rule to also move getdate.h. * queue-pr.c (run_gnats): Just call closedir. * gen-index.c (do_category): Likewise. * gnats-dirs.h: Delete defs related to CLOSEDIR_VOID. * autoconf.h.in (CLOSEDIR_VOID): Delete decl. * configure.in: Take out AC_FUNC_CLOSEDIR_VOID. * configure: Regenerate. * configure.in: Add AC_ARG_WITH mentions of the --with options. Wed Jul 5 15:18:51 1995 Brendan Kehoe * query.c (print_pr, FORMAT_SQL): Use field_value, to avoid nulls. * config.c.in (def_release): New, set to DEFAULT_RELEASE. * config.c: Regenerated. * Makefile.in (GNATS_DEFS): Also define DEFAULT_RELEASE. * configure.in (DEFAULT_RELEASE): Init to unknown. * cmds.c (do_query): Don't say end of list in here, since we may have told them it was a bogus one beneath lookup_pr_path. * query.c (get_pr): No need to call clean_pr, we do it inside read_pr. * cmds.c (verify): Set the AV variable to the full path, rather than having daemon_pr end up asking yet again for the path. Wed Jul 5 08:04:32 1995 Brendan Kehoe * cmds.c (GNATS_catg): Don't verify the category, it kills the ability to use a regexp. Mon Jul 3 09:10:49 1995 Brendan Kehoe * cmds.c (get_text): Free BUF and PATH when proper. (get_text, case PR_timeout): Jump to DIE. * client.c (tohex): Don't specify the length for the constant array. * cmds.c (get_text): Just allocate PATH instead of trying to use WORKNAME locally (PATH_MAX can be an expression, which is invalid as the array size on some systems). Only allocate BUF after we know we're going to use it. * Makefile.in (GNATS_DEFS): Add definition of GNATS_SERVER. * configure.in: Check for --with-gnats-server. * configure: Likewise. * headers.c (header_value): Cast return of strdup. * pr.c (field_value): Likewise. * client.c (server_reply): Likewise. * cmds.c (GNATS_resp, GNATS_catg, GNATS_conf, GNATS_svty, GNATS_stat, GNATS_prio, GNATS_subm, GNATS_text, GNATS_mtxt): Likewise. * gen-index.c (main): Likewise. * Makefile.in (config.status): Add rule to reconfigure if the configure script has changed. * btime.c (get_response_time): Declare SECONDS to be time_t. * npr-edit.c (usage): Add missing newline. Fri Jun 30 11:40:27 1995 Brendan Kehoe * cmds.c (unify_addrs): Renamed from `sanitize'. Actually write code for it now, sorting and unifying the list. (addr_cmp): New function. (GNATS_mlpr): Change usage of unify_addrs. Make sure we free each after we print it. * headers.c (raw_header_value): New function. (header_value): Use it, consing up a null if we need to. * cmds.c (GNATS_mlpr): Insert anyone listed in the `X-GNATS-Notify:' header. (GNATS_edit): Don't give an error about a bad PR anymore; we do that beneath lookup_pr_path. * gnats.h (raw_header_value): Add decl. * cmds.c (GNATS_mlpr): Free PATH when we're done. * gnats-el.in (gnats::get-header): Move decl above gnats:submit-pr. * cmds.c (GNATS_mlpr): Use lookup_pr_path and get_pr. Make sure we end ADDRS with a null. * gnats-el.in (gnats:net-view-pr): Only rename the buffer if it doesn't have a slash in it. * gnats-el.in (gnats::rename-buffer): New function. (gnats:net-view-pr): Call it to rename the buffer to the category and id, not just the number. (gnats:gnats-mode): Replace the code with that call. * query.c (get_category): Use the INDEX_CHAIN if we have it, rather than re-read the index. Speeds up a lot of things. * gnatsd.h (CODE_GNATS_LOCKED): Define. * internal.c (is_gnats_locked): New function. * gnats.h (is_gnats_locked): Add decl. * cmds.c (GNATS_edit): Call it before we say it's ok to send us anything. * client.c (get_reply): Handle CODE_GNATS_LOCKED. * gnats-el.in (gnats::cannot-lock): Define error. (gnats:submit-pr): Add ellipsis. (gnats::pr-edit): Catch when we can't create the lock file. * internal.c: Include gnatsd.h. (is_daemon): Add decl. (lock_gnats): Make return value int. Emit daemon errors if IS_DAEMON is true. Give the error in the message. (unlock_gnats): Don't exit if IS_DAEMON. * main.c (is_daemon): Define. * queue-pr.c (is_daemon): Likewise. * gnats-el.in (gnats::pr-edit): Recognize the error that we can't create the lock file. (gnats::cannot-lock): Add error. * gnats.h (lock_gnats): Fix return value. * gnatsd.h (CODE_GNATS_LOCKED): Declare. * cmds.c (GNATS_edit): New label editout; go there if locking fails, don't keep going. * cmds.c (GNATS_edit): Turn back on the code to remove GIVEN. * pr-age.c (report_age): Only use get_pr, not it and do_pr_internal. * pr-stat.c (do_stat): Likewise. * query-pr.c (query_pr): Only use do_pr_internal, not it and get_pr. * query.c (get_pr): Delete EXISTP argument. (do_pr_internal): Delete third arg EXISTP. (print_pr): Delete third arg to get_pr. (do_pr): Likewise to do_pr_internal. * pr-age.c (report_age): Remove third arg to get_pr and do_pr_internal. * cmds.c (lookup_pr_path): Use fopen instead of get_pr. (daemon_pr): Delete third arg to get_pr. * query.h (get_pr): Likewise. * pr-age.c (report_age): Likewise. * query.c (do_pr_internal): Likewise. * query-pr.c (query_pr): Likewise. * pr-stat.c (do_stat): Likewise. * gnats-el.in (gnats::mail-PR-changed): New arg NOTIFY. Push it onto the CC list if it's set. (gnats:submit-pr): Pass any value for "X-GNATS-Notify" to it. * headers.h (X_GNATS_NOTIFY): Add decl. * headers.c (init_header): Give it default of `X-GNATS-Notify:'. * Makefile.in (file-pr.o, npr-edit.o, query.o): Depend on headers.h. Thu Jun 29 15:16:06 1995 Brendan Kehoe * gnats-el.in (gnats:unlock-pr-force): Don't be interactive. (gnats:unlock-buffer): Put the leading dots back in, duh. (gnats::delete-file): New function. (gnats:unlock-buffer): Use it instead of doing concat repeatedly. (gnats:net-view-pr): Refer to ID, not PR. (gnats:keep-sent-messages): Don't refer to vm-keep-sent-messages. * gnats-el.in (gnats::pr-edit): New arg FORCE. (gnats::pr-edit): Recognize "PR is not locked", and only signal of FORCE is nil. (gnats::unlock-all-buffers): Pass T to FORCE. (gnats::kill-buffer-hook): Likewise when killing it. (gnats:kill-buffer): Likewise. (gnats-mode-map): Make `C-c C-q' call gnats:unlock-buffer-force. (gnats:unlock-pr-force): New function, passing T to FORCE in gnats::pr-edit. (gnats:unlock-buffer): Call gnats:unlock-pr-force. (gnats::unlock-all-buffers): Likewise. * client.c (get_reply): Don't try to get the PR number. * gnats-el.in (gnats::get-list-from-file): Add a period between BN and FILENAME. New arg DESC, used in the Parsing line. (gnats:unlock-buffer): Don't use leading periods on the suffix for eac file. (gnats::set-responsibles, gnats::set-categories, gnats::set-submitters): Take off the leading period, passing name along with the file. (gnats::reset-variables): New function. Wed Jun 28 08:41:25 1995 Brendan Kehoe * gnatsd.c (cmds): Set FLAG_NEED_AUTHORIZATION on LCAT, LSUB, and LRES. Tue Jun 27 11:58:10 1995 Brendan Kehoe * gnats-el.in (gnats::query-pr-default-options): Don't add --host for the network one. Mon Jun 26 08:18:00 1995 Brendan Kehoe * gnats-el.in (gnats:net-view-pr): New function. (gnats:view-pr): Use it when appropriate instead of view-file. * Makefile.in (prefix, exec_prefix): Fix settings. * man/Makefile.in (prefix, exec_prefix): Likewise. (Makefile): Add rule. * gnatsd.c (allowed) [HAVE_KERBEROS]: Set FOUND as well. (start_connection): Don't bother setting HOST_VERIFIED anymore. (main): Check KERBEROS_HOST before complaining about authentication. Don't complain about using HELO. * cmds.c (host_verified): Removed decl. (GNATS_helo): Change saying we're not needed anymore. * client.c (client_init): Don't write HELO. * Makefile.in (lists.o): Add dependencies. * gnats-el.in (gnats::vmish-restore-mail-buffer): Take argument BUF. (gnats::vmish-rename-mail-buffer): Likewise. (gnats::vmish-mail): Pass it after doing the get-buffer here. (gnats::rw): Move definition above gnats::pr-edit, where we use it. (gnats::mode-name): Add definition. * gnats-el.in (gnats:edit-pr): Put the PR number in the name of the `*edit-pr*' buffer. (gnats:unlock-buffer): Likewise for `*edited-pr*' buffer. (gnats::get-list-from-file): Save gnats:::backupname before we change to the grok buffer. (gnats::vmish-mail-other-window): Make BUF local to here. (gnats::vmish-mail): And here. (gnats::vmish-rename-mail-buffer): Not here. Sun Jun 25 19:40:22 1995 Brendan Kehoe * gnats-el.in (gnats::vmish-rename-mail-buffer): Make BUF a local variable. (gnats::vmish-mail-other-window): Remove unneeded BUF. (gnats::vmish-mail): Likewise. Fri Jun 23 08:07:17 1995 Brendan Kehoe * gnats-el.in (gnats:gnats-mode): Don't set the backupname here. (gnats::pr-edit): Delete arg NETBUF; don't use it. Adjust to recognize both messages about a non-existant PR. (gnats::lock): Delete arg NETBUF. (gnats:unlock-buffer): Delete the lists as well if we're doing the network one. (gnats::set-responsibles): If it's the network one, get the list that we transferred over rather than using the responsible file. (gnats::set-categories): Likewise for categories. (gnats::set-submitters): Likewise for submitters. (gnats::get-list-from-file): Use the backupname rather than gnats-adm stuff if it's the network one. (gnats:edit-pr): Declare NEWFILE as a full-level local var. Fixup the condition-case to deal with both fairly well. Most important: set PERMANENT-LOCAL on gnats:::backupname, so the kill of all local vars in gnats::gnats-mode doesn't wipe it out. * gnats-el.in (gnats::lock): Add --get-lists to the network run. (gnats::set-responsibles): Pass `.res' to get-list-from-file if doing the network. (gnats::set-categories): Likewise for `.cat'. (gnats::set-submitters): Likewise for `.res'. (gnats::get-list-from-file): Use gnats:::backupname and the suffix if we've got a network server. (gnats:unlock-buffer): Delete the other files as well. * Makefile.in (VERSION): Boost to 3.90. * lists.c: New file. * Makefile.in (LIBSRC): Add lists.c. (LIBOBJS): Add lists.o. * gnats.h (get_gnats_file): Add decl. * query-pr.c (main): If we asked for a list, call get_gnats_file. * npr-edit.c (long_options): Add -g/--get-lists. (main): Handle it. (get_list): New function. Thu Jun 22 07:56:32 1995 Brendan Kehoe * cmds.c (GNATS_auth): Fix some argument passing. * query-pr.c (long_options): Add --list-categories, --list-responsible, --list-submitters. (main): Deal with j, k, and l in the getopts. (usage): List them. * nquery-pr.c: Likewise. (list_format): Define this here, since we don't use query.o. (ask_about): Send LCAT/LRES/LSUB to the server. * query.c (list_format): Define variable. * query.h (LIST_CATEGORIES, LIST_SUBMITTERS, LIST_RESPONSIBLE): Define. (list_format): Add extern decl. * gnatsd.c (cmds): Add LRES and LSUB. * cmds.c (GNATS_lres, GNATS_lsub): New functions. (noargs): New function to say the command takes no arguments. (GNATS_nocl): Use it. (GNATS_help): Add LRES and LSUB. * Makefile.in (install-tools-bin): Don't install npr-edit as setuid gnats, since it doesn't need to be. * gnats-el.in (gnats:gnats-mode): Only do things on gnats:::backupname if it's non-nil. (gnats:view-pr, gnats:edit-pr): Don't dive after the category if gnats:network-server is set; we don't really need to go after it anyway. In gnats:edit-pr, set gnats:::backupname here if we're doing the network stuff; set it to nil otherwise. * npr-edit.c (main): Default result to 1, not 0. Don't exit if we didn't get any arguments. Check OUTFP, not FP, for -o. * gnats-el.in (gnats::lock): Add `-o gnatsXXXXX' if we're doing the network one. (gnats:submit-pr): Clear gnats:::pr-locked after filing it, if it's the network. * client.c (outfp): The file to print the results to; stdout by default. (read_server): Use it. (get_reply, case CODE_INFORMATION): Likewise. * query.h (outfp): Add decl. * npr-edit.c (long_options): Add -o/--outfile. (main): Recognize it. * gnats-el.in (gnats::pr-edit): Also don't kill it if NETBUF is true. * client.c (get_reply, case CODE_LOCKED_PR): Cut off \n. * cmds.c (GNATS_edit): Use chk_nargs. * npr-edit.c (main): Don't try to lock/unlock GNATS itself in here. (net_check_pr): Call init_gnats. * gnats-el.in (gnats::pr-edit): Recognize npr-edit as well. Only check that the file exists if we're not using the network. (gnats::lock): Add optional arg NETBUF, passing it into gnats::pr-edit. (gnats:edit-pr): Add optional arg NETBUF. Shift things around if we're doing the network stuff, and pass the buffer into gnats::lock. * client.c (PUNT): Only print it if debug is set. (get_reply, case CODE_LOCKED_PR): Notice when they're locked. * gnats-el.in (gnats::pr-edit): Run npr-edit if gnats:network-server is set. * client.c (client_exit): Flush servread. (safe_exit): Call client_exit. (get_reply, case CODE_PR_NOT_LOCKED): Recognize the result and say that it was locked. * npr-edit.c: New file; network version of pr-edit.c. * Makefile.in (npr-edit, npr-edit.o): New rules. (install-tools-bin): Install npr-edit. Also make it setuid gnats. (uninstall): Uninstall npr-edit too. (doclean): Also remove npr-edit. * cmds.c (get_text): Don't set the umask to 0. * gnatsd.c (main): Likewise. * gnatsd.h (CODE_PR_NOT_LOCKED): Declare. * cmds.c (GNATS_edit): Check to make sure that the PR is locked before we agree to edit it. Don't lock it here. (GNATS_lock): Pass the second arg to daemon_lock_pr. (daemon_lock_pr): New arg W, passed to lock_pr instead of "GNATS daemon". * nquery-pr.c (main): Add `H:' to the getopt args. * pr-edit.c (main): Give usage if they didn't give us any arguments. Add `LU' to getopt args. * gnats-el.in (gnats:network-server): Add variable. (gnats::query-pr-default-options): Add --host if gnats:network-server is true. (gnats:query-pr): Run nquery-pr if gnats:network-server is true. * cmds.c: Flush after some printfs that then wait for input other than what we do in main. (get_text): Return NULL, don't exit. * gnatsd.h (CODE_INVALID_RESPONSIBLE): Define. * cmds.c (get_text): Finish creation and use of the tmp file. (GNATS_edit): Also remove `given'. Reorganize the code a bit. * edit.c (check_pr): Adjust code for the daemon. (modify_pr): Rename var `outfile' to `prfile'. (check_pr, lock_pr, unlock_pr): Likewise. Wed Jun 21 09:21:44 1995 Brendan Kehoe * cmds.c (GNATS_helo): Also mention what host connected when we say that the given hostname was denied. (GNATS_auth): Put srvtab in gnats-adm, not in gnats_root. Tue Jun 20 14:20:16 1995 Brendan Kehoe * client.c (get_reply): Deal with getting REPLY_CONT replies for GREETING. * gnatsd.c (main): Have syslog note when a command is attempted without authentication turned on. * gnatsd.c (start_connection): Tell them they need to use authentication if kerberos_host is true. (allowed) [HAVE_KERBEROS]: Set kerberos_host to 1. (main): Set host_verified and client_authorized if not_inetd. * gnatsd.c (kerberos_host) [HAVE_KERBEROS]: Add definition. (main) [HAVE_KERBEROS]: Zero out kerberos_host and client_authorized. * cmds.c (kerberos_host): Add decl. Thu May 4 13:52:30 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * aclocal.m4: Use AC_MSG_RESULT for checking of `diff -u'. * configure: Regenerate. * cmds.c (GNATS_subm): Don't check the submitter, it may be a regexp. Mon May 1 11:07:04 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * configure.in: Add AC_FUNC_CLOSEDIR_VOID. * configure: Regenerate. * autoconf.h.in: Regenerate using autoheader. * gnats-dirs.h: Redo using better approach. * acconfig.h: New file, doing undef of HAVE_KERBEROS. * autoconf.h.in: Regenerate using autoheader. * gnatsd.c (client_authorized): Only declare if HAVE_KERBEROS. (main): Only complain about not having authorization if HAVE_KERBEROS. * cmds.c (client_authorized) [HAVE_KERBEROS]: Add extern decl. Fri Apr 28 15:05:17 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * configure.in: Define HAVE_KERBEROS if the krb library check succeeded. Move the setting of KRBINCLUDE up. Don't check for alloca.h in AC_HAVE_HEADERS, since we added AC_ALLOCA. * autoconf.h.in: Cleanup, moving things around and adding a few. * config.c.in (gnats_root): Initialize with NULL, not 0. (configure): Use xfree instead of free. (string_extract_double_quoted): Likewise. * config.c: Generate new one. * configure.in: Add AC_ALLOCA. Try for connect before going for nsl and socket. Add a messages that we're checking for krb.h. * configure: Generate new one. * Makefile.in (KRBINCLUDE): Add setting. (INCLUDEDIR): Add KRBINCLUDE. * gnatsd.c (client_authorized): Declare. (FLAG_NEED_AUTHORIZATION): Define. (struct _command): Add `flags' field. (cmds): Add FLAG_NEED_AUTHORIZATION to QURY, SUMM, FULL, SQLF, LOCK, EDIT, UNLK, MLPR, MLCT, MLSU, TYPE, RESP, CATG, ORIG, and SUBM. (get_name): Fix order of args to strcpy. (main): Check FLAG_NEED_AUTHORIZATION before doing the action. * cmds.c (MAXLINE): Delete decl. (GNATS_auth): Don't define GNATS_KRB4_PRINCIPAL_NAME. (GNATS_auth) [HAVE_KERBEROS]: Rewrite. * client.c (get_reply) [case CODE_NO_KERBEROS]: Give a Kerberos-specific error. (tohex, hexdigit, fromhex): New functions. (client_init) [HAVE_KERBEROS]: Rewrite. * gnatsd.h (GNATS_KRB4_PRINCIPAL_NAME, GNATS_KERB4_VERSIONID): Define. Mon Apr 17 18:09:24 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * mail-query.sh: Add `set -f' as we get going. Wed Apr 12 20:54:50 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * configure.in: Use stuff in autoconf 2.3, changing things where necessary. Added AC_SUBST of HAVE_KERBEROS. * configure: Generated new one. Wed Mar 22 12:17:45 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (GNATS_helo): Say what we think the hostname is when we deny the connection. * client.c (reply): Put definition here. * sub-type.c (serv_write, serv_read): Remove definitions, they're in client.c. (gnats_server): Remove decl, it's in query.h. * nquery-pr.c (serv_write, serv_read, gnats_server): Remove decls. (reply): Remove definition. * pr-mail.c (reply): Remove definition. Mon Feb 20 11:21:11 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (GNATS_help): Mention TYPE. Thu Feb 16 00:04:20 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (basename): Delete decl, it's in gnats.h. Wed Feb 15 15:48:28 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (start_connection): Use LOG_INFO, not LOG_NOTICE. * cmds.c (GNATS_helo): Only use LOG_INFO priority for verified hostnames; still use LOG_ERR for denied hostnames. * gen-index.c (next_category): Check for EOF first, then allocate the variables. Create new label RETRY, to grab the next line, and change all gotos to choose that instead of NO_ENTRY. (catfile): New variable. (long_options): Recognize -c/--catfile. (get_categories): Use it if it's set. (usage): Mention the new arg. * gnatsd.c: Don't include errno.h, it's in gnats.h. * gnats.h: Include stdarg.h or vararg.h here. * internal.c, misc.c: Not here. * btime.c, file-pr.c, nquery-pr.c, query-pr.c: Don't include time.h, it's in globals.h. * client.c, edit.c, file-pr.c, files.c, gen-index.c, headers.c, internal.c, main.c, nquery-pr.c, pr-edit.c, pr-mail.c, pr.c, gnatsd.c, query-pr.c, queue-pr.c, sub-type.c: Don't try to include sys/types.h, it's in gnats.h. * edit.c, internal.c, pr-edit.c, pr.c, file-pr.c: Don't include sys/stat.h, it's in gnats.h. * client.c, cmds.c, edit.c, file-pr.c, files.c, gen-index.c, globals.h, headers.c, main.c, misc.c, nquery-pr.c, pr-addr.c, pr-edit.c, pr-mail.c, pr.c, gnatsd.c, query-pr.c, queue-pr.c, sub-type.c: Don't include stdio.h here, it's in gnats.h. * gnats.h: Include signal.h here. * file-pr.c, index.c, internal.c, main.c, misc.c, gnatsd.c: Not here. * file-pr.c, headers.c, pr.c: Don't include limits.h, it's in pathmax.h. * gnats.h: Include getopt.h here. * edit.c, main.c, nquery-pr.c, pr-addr.c, pr-age.c, pr-edit.c, pr-mail.c, pr-stat.c, gnatsd.c, query-pr.c, queue-pr.c, sub-type.c: Don't include it in here. * gnats.h [HAVE_SYSLOG_H]: Include syslog.h here. * edit.c, file-pr.c, files.c, headers.c, internal.c, main.c, misc.c, pr-edit.c, pr.c, gnatsd.c, queue-pr.c, resp-lookup.c: Not in these. * gen-index.c, queue-pr.c, main.c: Don't include unistd.h in here. * globals.h: Don't include files.h, gnats.h already does. * gnats.h: Include pathmax.h here. * cmds.c, edit.c, file-pr.c, files.c, gen-index.c, index.c, internal.c, misc.c, pr-age.c, pr-edit.c, pr-stat.c, gnatsd.c, query-pr.c, query.c, queue-pr.c: Not here. * globals.h: Don't include pr.h or headers.h, gnats.h does. * file-pr.c: Don't include headers.h. * headers.c: Likewise. * globals.h (basename): Delete decl, it's in gnats.h. * gnats.h: Include regex.h here; don't try for rx.h. * gnatsd.c, file-pr.c, query.c, query-pr.c: Not here. * edit.c, globals.h, main.c, pr-edit.c: Don't try to include here, it's in gnats.h. * cmds.c (GNATS_helo): Note to syslog for a successful or unsuccessful connection. Mon Feb 13 00:20:28 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * getdate.y (const) [!__GNUC__]: Undef if we aren't using gcc. * getdate.c: Regenerated. * Makefile.in (file-pr.o): Also depend on gnats.h. (getdate.c): Expect 10, not 9, conflicts. * gnats.h: Add stuff to handle alloca. * autoconf.h.in (HAVE_ALLOCA_H): Add undef. * configure.in: Look for alloca.h. * configure: Generated new one. * pr.c (read_pr): Call clean_pr before reading it in. * cmds.c (GNATS_lcat): New function, to give the list of available categories. * gnatsd.c (cmds): Add LCAT. (GNATS_lcat): Add decl. (GNATS_help): List the command. * cmds.c, config.c, file-pr.c, files.c, gen-index.c, headers.c, index.c, internal.c, main.c, misc.c, queue-pr.c, resp-lookup.c: Don't need to include globals.h, it's in gnats.h. * pr.c: Doesn't need to include either globals.h or pr.h. * index.c (index_chain): Put the decl in here. * globals.h (index_chain): Add extern decl. * pr-age.c, pr-stat.c, gnatsd.c: Not in these. * pr-edit.c (basename): Don't need the decl in here. * gnatsd.c (version_string): Don't need decl, it's in globals.h. * gen-index.c, nquery-pr.c, pr-addr.c, pr-edit.c, pr-mail.c, query-pr.c, sub-type.c: Likewise. * files.c (find_category): Renamed from `find_categories'. * cmds.c, edit.c, file-pr.c: Change callers. * internal.c (add_to_index): Wipe out BUF before we try to write to it. * files.c (find_responsible): Also check of PERSON is a null string. * files.c (get_responsible_address): Make sure the alias is set if we want to see if it's defined to be a null. Sun Feb 12 23:28:15 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c: Also include sys/param.h for MAXHOSTNAMELEN. Tue Feb 7 15:31:32 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * files.c (init_responsibles): Zero out the path before writing to it. * query.c (get_category): Close the file before we may return. * query-pr.c (main): Say no PRs matched here. (query_pr): Not here. * edit.c (check_pr): Cut off the name in parenthesis. * file-pr.c (arg_quote): Do 2*(strlen + 1). * Makefile.in (install-info): Depend on gnats.info. (install-gnats-bin): Tell them to run mkcat. * mkdist.sh (lispdir): Set to site-lisp. (all): Depend on send-pr.elc. (install): Install send-pr.el*. (clean): Also remove install-sid, and remove send-pr.el*. * client.c (client_init): Say what host we're connecting to. * configure.in: Only try for Kerberos stuff if they used --with-kerberos. * gnats-el.in (gnats::mode-name): Add declaration before fset. (gnats-mode): Do fset with unquoted mode-name. (gnats:gnats-mode): Use unquoted mode-name. (gnats::unlock-all-buffers): Likewise. (make-auto-save-file-name): Make a method of `gnats::'. Rewrite a bit. * files.c (find_responsible): No longer static. Rewrite to accept an argument of a Responsible*. Return an int to match the other find_* routines. (get_responsible_address): Use new method for find_responsible. * globals.h (find_responsible): Add decl. * headers.c (read_header): Return int; give -1 if we're at the EOF, otherwise return 0. * file-pr.c (append_report): Use the return value of read_header. * gen-index.c (do_category): Likewise. * main.c (main): Likewise. * query.c (get_pr): Likewise. * gnats.h (read_header): Change declaration. * pr-edit.c (main): Don't lock/unlock if we're just doing CHECK. * gnats.h: Include globals.h. * globals.h (pr): Declare `pr' here. * pr-age.c (pr): Don't declare here. * pr-stat.c (pr): Likewise. * query-pr.c (pr): Likewise. * query.c (pr): Likewise. * edit.c (check_pr): Verify the category, submitter, and responsible as well. Thu Feb 2 13:05:04 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (main): If we're not running as inetd, set current_host to be myname. * gnatsd.h (CODE_AUTH_TYPE_UNSUP): Declare. Add support for Kerberos. * autoconf.h.in (HAVE_KERBEROS): Declare. * configure.in: See if we have Kerberos. * configure: Generate new one. * client.c [HAVE_KERBEROS]: If declared, include the right files. (get_reply): Recognize CODE_NO_KERBEROS with CODE_NO_ACCESS. (client_init) [HAVE_KERBEROS]: Do AUTH and Kerberos setup. * cmds.c [HAVE_KERBEROS]: If declared, include the right files. (GNATS_auth) [HAVE_KERBEROS]: Deal with Kerberos authentication. * client.c: Also include sys/param.h, since MAXHOSTNAMELEN under SunOS4 is in there. Force them to use HELO, and verify what they told us is true. * gnatsd.c (current_host): Add decl. (start_connection): Set CURRENT_HOST. (host_verified): New variable. (main): Use fprintf, not printf. * query.h (current_host): Add decl. * cmds.c (GNATS_helo): Call name_verify, and complain if it doesn't match what they gave us. (name_verify): New function. (host_verified): Add decl. * gnatsd.h (get_line): Add decl. (CODE_LOCKED_PR): Add decl. * gnats.h (clean_pr): Add decl. * cmds.c: Include globals.h. (chk_nargs): Add decl. Make it static. (GNATS_edit): Delete vars P and STATUS. (GNATS_mlpr): Delete vars I and PERSON. * Makefile.in (cmds.o): Depend on globals.h * file-pr.c (free_responsible): Don't declare it here. * globals.h (free_responsible): Declare it here. * edit.c (lock_pr): Give CODE_LOCKED_PR for locked files. * sub-type.c: Include query.h instead of gnatsd.h. (main): Delete unused var ARG. (sockfd): Delete variable decl. (MAXLINE): Delete decl. * client.c (client_exit): If debug is set, tell how we're saying QUIT. * gnatsd.h (CODE_HELLO): Add declaration. * cmds.c (GNATS_helo): Use it. (get_reply): Listen to CODE_HELLO. * client.c (client_init): Find out our hostname and say HELO. (get_reply): Handle CODE_NO_ACCESS. * cmds.c: Include netdb.h, not sys/param.h. (GNATS_helo): Use fprintf, not printf. (GNATS_quit): Likewise. (chk_nargs): Likewise. * query-pr.c (query_pr): Just say that no PRs matched. * index.c (find_pr_category): Make local category static, and initialize it to 0 before we go into the loop. * Makefile.in (all-tools): Don't depend on pr-stat. (install-tools-bin): Don't install it. (uninstall): Don't try to remove it. Mon Dec 19 13:56:09 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (DISTFILES): Add pr-stat.c. (all-tools): Add pr-stat as a dependency. (pr-stat, pr-stat.o): Add rules. (doclean, uninstall): Add pr-stat. * pr-stat.c: New file. Wed Nov 9 12:27:52 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * client.c (get_reply): Give the name of the category or submitter that they asked about, but didn't exist. * cmds.c (GNATS_mlsu): Use CODE_INVALID_SUBMITTER, not CODE_ERROR. Tue Nov 8 14:16:49 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * file-pr.c (check_if_reply): Cast xfree args to char*. * gnatsd.c (Argify): Likewise. * gen-index.c (next_category): Likewise. Move common client stuff into one file. * client.c: New file. * Makefile.in (sub-type, pr-mail, nquery-pr): Depend on client.o. * query.h: Include gnatsd.h. (MAXLINE): Put decl in here. (server_reply, read_server, get_reply, safe_exit, client_init, client_exit): Add decls. (gnats_server, serv_write, serv_read, sockfd): Likewise. * pr-mail.c: Include query.h. * Many files: Just include query.h, not that and gnatsd.h. * sub-type.c, nquery-pr.c, pr-mail.c, pr-age.c: Move stuff into client.c. Replace stuff with calls to client_init and client_exit. * nquery-pr.c, pr-age.c, pr-mail.c, sub-type.c: Take out unistd/string includes, they're in gnats.h. (serv_write, serv_read, sockfd): Make extern. (name): Make global extern. * gnats.h [HAVE_STRING_H || STDC_HEADERS]: Add checks for index and rindex. * files.c (get_adm_record): Use strncasecmp, not strncmp. * sub-type.c: New file to find the type of a submitter. * cmds.c (GNATS_type): New function. * gnatsd.c (cmds): Add TYPE. (GNATS_type): Add decl. * Makefile.in (DISTFILES): Add sub-type.c. (sub-type): New rule. (all-tools): Build it. (install-tools-bin): Install sub-type. (uninstall): Delete it. (doclean): Likewise. Wed Oct 19 09:49:22 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * edit-pr.sh (pr): Say the PR wasn't in the index, not just `file not found'. (debug_print): Declare variable to let you see where things are going. Tue Oct 18 13:12:16 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (GNATS_unlk): Free PATH after we've unlocked it. * query-pr.c (xmalloc, basename): Delete decls, since they're in gnats.h. * headers.c (clean_header): New method to wipe out the VALUE entries. No need to reset the NAME in every one. (init_header): Take it out of here. (read_header): Call clean_header instead. * pr.c (clean_pr): New method to do the same for the PR entry. (init_pr): Taken it out of here. * query.c (get_pr): Call clean_pr instead of init_pr. * gnats.h (clean_header, clean_pr): Add decl. * cmds.c (verify): Call xfree instead of free. (daemon_pr): Likewise. (GNATS_edit): Likewise. (GNATS_orig): Likewise. (GNATS_clss): Likewise. * config.c (configure): Likewise. (string_extract_double_quoted): Likewise. * edit.c (lock_pr): Likewise. (unlock_pr): Likewise. * file-pr.c (run_atpr): Likewise. (check_if_reply): Likewise. (notify_responsible): Likewise. (append_report): Likewise. (free_submitter): Likewise. (free_category): Likewise. * files.c (free_responsible): Likewise. * gen-index.c (do_category): Likewise. (next_category): Likewise. (get_categories): Likewise. * headers.c (set_continued_header): Likewise. * index.c (create_index_entry): Likewise. (next_index_entry): Likewise. (open_index): Likewise. * pr.c (read_pr): Likewise. * query-pr.c (query_pr): Likewise. * gnatsd.c (Argify): Likewise. * query.c (do_pr): Likewise. * queue-pr.c (run_gnats): Likewise. * gnatsd.c (Argify): Call xmalloc instead of malloc. * headers.c (lookup_header): Return -1 right away if STRING is null; only check its length once. * pr.c (read_pr): Make sure we free UNFORMATTED if we don't end up using it. Only alloc space for BUFFER and UNFORMATTED after we know we're going to be able to look at a file. Mon Oct 10 10:26:46 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * contrib/prmon: Match *.K and *.U, not "*.K" and "*.U". Thu Oct 6 15:24:12 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * misc.c (get_next_field): If the line ends with a newline, take it off. * pr-addr.c (long_options): Put null entry at the end. Wed Oct 5 13:41:40 1994 Brendan Kehoe (brendan@lisa.cygnus.com) Enable remote editing of PRs. * cmds.c (get_text): New function to read a PR in from the link. (GNATS_edit): Actually do everything. (lookup_pr_path): New function. (verify): Use lookup_pr_path. (daemon_pr): Likewise. Only look the PR's path up if we aren't already being given one. * gnatsd.h (MsgType): Put decl here. * gnatsd.c (MsgType): Not here. (is_daemon): Add 1 definition. (main): Set up the umask. * edit.c: New file. * pr-edit.c (modify_pr, check_pr, lock_pr, unlock_pr, get_path): Move the methods into there. Add support for checking IS_DAEMON. (is_daemon): Add 0 definition. * gnats.h: Add decls for stuff in edit.c. (CODE_NO_INDEX, CODE_FILE_ERROR): Declare. (is_daemon): Add extern decl. * Makefile.in (gnatsd, pr-edit): Reference edit.o. (gnatsd): Now add internal.o. * Makefile.in (install-tools-bin): Also install nquery-pr. Wed Oct 5 12:21:04 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * mkdist.sh (FILES): Add INSTALL and MANIFEST. * gnats-el.in (gnats::mail-PR-changed): Set DEFAULT-DIRECTORY before switching buffers. (gnats::real-pr-addr): Likewise, before call-process. (gnats::pr-edit): Likewise, before running COMMAND. Thu Sep 29 18:39:44 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * configure: Generate a new one using the LISPDIR fix from aclocal.m4. Wed Sep 28 13:24:47 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (do_query): Don't talk about PRs coming, since start_data does that for us now. * query.c (print_path): Define it here. * nquery-pr, query-pr: Not in these. * nquery-pr.c (main): Don't accept -P/--print-path for network queries. Tue Sep 27 13:13:05 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * query.c (print_pr): Send the emacs fmt if PRINT_PATH is set. * query.h (print_path): Declare here. Fri Sep 23 13:01:52 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * nquery-pr.c (get_reply): Say that no PRs matched. * query.c (print_pr): Call start_data here. (do_pr): Not here. * query-pr.c (query_pr): Say no PRs matched if !FOUND and P is null. * query.c (regcmp) [USE_RX]: Cast 1 to char*. (regfind) [USE_RX]: Likewise. * pr-age.c: Include getopt.h. (business_time): Declare. (long_options): define. (main): Run down the arglist. (usage): Give new arglist. * cmds.c (sanitize): New function, to avoid many repeated addresses for MLPR, et al. (GNATS_mlpr): Print out the results of calling sanitize. * Makefile.in (all-gnats): Build gnatsd. Removed config-send-pr, since it's brought in by all-tools. (all-tools): Build nquery-pr. * pr-mail.c (get_reply, case CODE_INFORMATION): Take off the linefeed in what we receive. Tue Sep 20 12:25:20 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * query-pr.c (main): Set, don't OR, the different FORMATs. * query.c (class): Declare. (do_pr_internal): Look at the CLASS of the PR if asked. * query-pr.c (long_options, usage): Add -L. * nquery-pr.c (class): Declare. (long_options, usage): Add -L. (ask_about): Send the CLSS command if asked. * cmds.c (GNATS_clss): Add function. (GNATS_help): Add CLSS command. * p-usage.texi (Searching criteria): Document -L/--class. * gnatsd.c (cmds): Recognize CLSS. (GNATS_clss): Add decl. * gnats-el.in (gnats::mail-reply-using-mhe): Look for the `Reply-To:' header before FROM to set REPLY-TO. Mon Sep 19 15:21:03 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * pr-age.c: New file. * Makefile.in (DISTFILES): Add pr-age.c. (all-tools): Also build pr-age. (install-tools-bin): Add pr-age and pr-mail. (uninstall): Delete them. (doclean): Likewise. (pr-age.o): Add dependencies. * cmds.c (outfile, skip_closed, quiet): Deleted. (outfile): Add extern decl. * gnatsd.c: Include query.h. (originator, text_search, m_text_search, searching): Deleted. (main): Set QUIET here, and check if INDEX_CHAIN is null. * query-pr.c (outfile, originator, text_search, m_text_search, searching, skip_closed, quiet): Deleted. (outfile): Add extern decl. (main): Same change as for gnatsd.c. * query.c (text_search, m_text_search, searching, skip_closed, quiet, originator): Decls moved into here. (outfile): Extern changed to decl here. * pr-edit.c (usage): Fix name. * cmds.c (GNATS_*): Use `=', not `|=', for FORMAT_*. * gnats.h (basename, xrealloc, xmalloc, xfree): Add decls here. * globals.h (xmalloc, xrealloc, xfree): Removed. * cmds.c (GNATS_mlpr, GNATS_mlct, GNATS_mlsu): Don't emit spaces after the CODE_INFORMATION. (GNATS_subm): Complain if there's no such submitter. (GNATS_catg): Likewise for category. * gnatsd.h (CODE_INVALID_SUBMITTER): Define. * nquery-pr.c (get_reply): Handle CODE_INVALID_SUBMITTER. (GNATS_mlpr): Remember to emit a period at the end of the line. * pr-mail.c (get_reply): Likewise. * gnatsd.h (Reply): Add decl. Add TYPE field. * nquery-pr.c (Reply): Take it out of here. (REPLY_CONT, REPLY_END): Declare types. * pr-mail.c: New file. * Makefile.in (pr-mail): Add rule. (all-tools): Add pr-mail. (DISTFILES): Add pr-mail.c. * nquery-pr.c (get_reply): Handle CODE_INFORMATION. * query.c (get_pr): Look at ~FORMAT_FULL to give READ_PR. * cmds.c (GNATS_mlpr): Use submitter.contact only if it's set. Same for category.notify. (GNATS_full, GNATS_summ, GNATS_sqlf): Just set QUERY_FORMAT, don't do an or on it. Tue Sep 13 11:50:27 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (verify): New arg SILENT; only emit the error if !SILENT. (do_query): Don't be silent. (GNATS_mlpr): Do be silent. Support getting the list of folks to email about a given PR, category, or submitter. * cmds.c (GNATS_mlpr, GNATS_mlct, GNATS_mlsu): New functions. (GNATS_help): Mention the MLPR, MLCT, and MLSU commands. * gnatsd.c (cmds): Replace MAIL with MLPR, MLCT, and MLSU. * file-pr.c (free_responsible): Moved from here... * files.c: To here. * cmds.c (chk_nargs): Declare arg AC, and add arg WHAT, giving that to the printfs. (GNATS_*): Give appropriate arg to chk_nargs. * query.c (get_pr): Use P, not PR, for its argument. * query.h (start_data): Add extern decl. * Makefile.in (query.o): Add dependency on query.h. (query-pr.o): Likewise. * query.c (outfile): Add extern decl. (print_pr): Move function to here. * query-pr.c (print_pr): From here. (found_match): Deleted. (main): Don't set it. * cmds.c (print_pr): And from here. * query.h (print_pr): Add decl. * query.c (get_pr): Add function, with EXISTP (unused right now) and SILENT arguments. (do_pr_internal): Call get_pr with QUIET as the SILENT argument. * query-pr.c (get_pr): Removed. (quiet): Add decl. (print_pr, query_pr): Pass QUIET down into get_pr. (query_pr): Say if we couldn't find the PR. * cmds.c: Likewise. * query.h (get_pr): Add decl. * query.h: New file. * nquery-pr.c, cmds.c, query.c, query-pr.c: Include it. * gnats.h (FORMAT_REG, FORMAT_SUMM, FORMAT_FULL, FORMAT_SQL, query_format, Sql_Types, originator, text_search, m_text_search, skip_closed, searching): Move decls from here to query.h. (disbar, sql_types, sql_time, make_path, numeric, regcmp, regfind, get_category, pr_matches, check_text, do_pr, do_pr_internal): Likewise. * Makefile.in (gnatsd.o, cmds.o): Add dependencies. * query.c (query_format): Declare. * query-pr.c (full_report, sql_format, summary): Deleted. (get_pr): Check the FORMAT_FULL bit. (print_pr): Use them. (main): Set and check the bits instead of the variables. Use local FORMATS to see if they chose more than one. * cmds.c (query_format): Delete. (get_pr): Check the FORMAT_FULL bit. (print_pr): Use the new format bits. (GNATS_qury, GNATS_summ, GNATS_full, GNATS_sqlf): Set their bits. * nquery-pr.c (full_report, sql_format, summary): Deleted. (query_format): Add decl, since we don't use query.c. (skip_closed): Add decl. (ask_about): Check the bits now. (main): Same as in query.c. * gnats.h (FORMAT_REG, FORMAT_SUMM, FORMAT_FULL, FORMAT_SQL): Declare. (query_format): Add extern decl. * query.c: New file. * Makefile.in (query-pr, gnatsd): Add query.o. (query.o): Add dependencies. * query-pr.c, cmds.c (sql_types, sql_time): Moved to query.c. (Sql_Types): Move typedef to gnats.h. (case_fold, regcmp, regfind): Move regexp stuff to query.c. (get_category, disbar, pr_matches, check_text): Others moved to be in query.c. (net_do_pr_internal, do_pr_internal): Glommed into one do_pr_internal, adding the EXISTP argument to the query-pr one. * gnats.h: Add decls for new fns in query.c. (Sql_Types): Added typedef. (originator, text_search, m_text_search, skip_closed, program_name, searching): Add extern decls. * globals.h (program_name): Deleted decl. * cmds.c (start_data): New function; emit the fact that things are starting. * query-pr.c (start_data): New function; don't do anything for the normal one. * query.c (do_pr): Call start_data. * cmds.c (net_print_pr): Renamed to print_pr. (daemon_pr): Call that instead. * gnatsd.c (cmds): Add SQLF command. (GNATS_sqlf): Add decl. * cmds.c (GNATS_sqlf): New function. (QueryType): Add type `Sql'. (sql_types, sql_time, disbar): New functions. (get_pr): Also tell read_pr if M_TEXT_SEARCH was set. (net_print_pr): Print out SQL format. (GNATS_help): Mention SQLF. * nquery-pr.c (ask_about): Give the SQLF command if SQL_FORMAT is set. * Makefile.in (nquery-pr, gnatsd): Add `getdate.o'. * nquery-pr.c (GNATS_SERVER_PORT): Don't define, it's in gnatsd.h now. Fri Sep 9 09:37:17 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * config.c (gnats_root): Init with NULL, not 0. Thu Sep 8 12:51:53 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * file-pr.c (append_report): Also include the `Cc:' header in the message appended. Initialize CC and SUBJECT with a space, in case they weren't included in the message. Thu Sep 1 14:26:06 1994 Jason Merrill (jason@deneb.cygnus.com) * edit-pr.sh (Subject): Use "Re: g++/1234" format so check_if_reply can deal. Fri Aug 26 17:19:12 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (GNATS_auth): New function. (GNATS_help) [HAVE_KERBEROS]: Mention the AUTH command. * gnatsd.c (cmds): Add AUTH command. (GNATS_auth): Add decl. * gnatsd.h (CODE_NO_KERBEROS): Declare. Wed Aug 10 09:33:27 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.h (GNATS_SERVICE): Define to be "support". (GNATS_SERVER_PORT): Define this here. * nquery-pr.c (main): Use it instead of "gnats". (GNATS_SERVER_PORT): Don't define it here. * gen-index.c (usage): New arg STAT. (main): Use it. * gnatsd.c: Include . (main): Set return value to void, not int. (match): Return 1 if we matched it all the way through. * pr-addr.c (main): Add extern decl of basename. * nquery-pr.c (ask_about): Delete unused arg SOCKFD. (main): Don't give it one. (server_reply): Delete unused var SAVE. * gnats.h (close_mail_file): Add extern decl. * file-pr.c (check_if_reply): Delete unused argument FP. * main.c (main): Don't pass one to it here. * globals.h (check_if_reply): Or mention it here. * cmds.c (qualify): Note if the PR was FOUND here. * gnats.h: Include ctype.h here. * file-pr.c, nquery-pr.c, query-pr.c: Not in these. * query-pr.c (query_pr): Set local variable FOUND as appropriate, to exit non-zero if we found no matches. * cmds.c (net_do_pr_internal): Use regfind, not regcmp. * query-pr.c (do_pr_internal): Likewise. * cmds.c (GNATS_help): Add missing CODE_INFORMATION for SUBM. * gen-index.c (get_categories): Free the path after we've gotten the list of categories. * pr.c (read_pr): Remember to reset MULTI_TEXT if we've found a new field. (read_pr): For Enum types, kill anything from a space on, since we only expect a single word. Fri Aug 5 16:41:35 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * queue-pr.c (run_gnats): Skip files named `core', emitting a message about it along the way. Tue Aug 2 08:30:01 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (GNATS_help): Mention ORIG. * nquery-pr.c (usage): Add --skip-closed to the list. * nquery-pr.c (ask_about): Send the originator. * cmds.c (GNATS_orig): Accept the full name, with spaces in it. * headers.c (header_name, header_value, set_header): Don't need to check for name < 0. * pr.c (field_value, set_field): Likewise. * nquery-pr.c: Include unistd.h and string.h/strings.h. (bzero, bcopy): Define. * nquery-pr.c (safe_exit): For now, don't look for a reply. * nquery-pr.c (get_reply): Call safe_exit when the PR is invalid or unreadable. Rewrite their error messages to match query-pr. (safe_exit): Flush the read before sending QUIT, to get its real reply. * cmds.c (do_query): Only emit the trailing newline pair after the PR's been emitted if it wasn't a full report, since that would just be an extra one. * nquery-pr.c (read_server): Remove PRELIM argument. (get_reply): Don't pass it in here. Handle the server's gift a bit better, and only emit \n, not \r\n. * nquery-pr.c (serv_read, serv_write, sockfd): New global variables. (send_command, writen, readline): Deleted functions. (server_reply): Delete argument SOCKFD. (read_server): Likewise. (safe_exit): Likewise. (get_reply): Likewise. Change use of server_reply. Flush the server before trying to read from it. (ask_about): Use fprintf and SERV_WRITE, not send_command. (safe_exit): Likewise. (main): Likewise. (struct Reply): Delete member LEN. (server_reply): Don't set it. * misc.c (ret): New variable. (init_network): New function, used if necessary. (init_gnats): Call init_network. * pr.c (doret): Control if just \n should be emitted, or both \r \n. (write_pr): Use RET. * gnatsd.c (main): Set DORET. * gnats.h (init_network): Add decl. * nquery-pr.c (get_reply): Remove DOEXIT argument. (safe_exit): Set DOING_EXIT once, so we know what's going on. * gnatsd.c (searching): Add declaration. * cmds.c (searching): Add extern decl. (pr_matches): Check !SEARCHING in addition to !S. (qualify): New function, to do searching among the list they gave us. (verify): Check that av[i] is non-null before trying to do anything with it. (do_query): Call qualify before verify. If we didn't get a match, for whatever reason, make sure we say so. (GNATS_resp, GNATS_catg, GNATS_conf, GNATS_svty, GNATS_stat, GNATS_orig, GNATS_prio, GNATS_subm, GNATS_nocl, GNATS_text, GNATS_mtxt): Set SEARCHING. Wed Jul 6 16:08:58 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (get_pr): We don't need to call init_header anymore, since it's now called inside read_header. (myname): Add extern decl. (regcmp): Don't let regfree try to free case_fold, as in regfind. * gnatsd.c (allowed, match): New functions to add some modicum of security for the daemon. (start_connection): Check if they're allowed to have a connection. * config.h (ACCESS_FILE): Add definition. Thu Jun 23 20:03:00 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (main): Make MYNAME global. * cmds.c (GNATS_helo): Say who we are with the greeting. * gnatsd.c (GNATS_help): Update the info for TEXT/MTXT. * nquery-pr.c (xrealloc): Add decl. Implement support for text searches via the daemon. * gnatsd.c (SEAR, MSRC): Look for TEXT and MTEXT instead. (main): Call re_set_syntax to init the regexp searches. * nquery-pr.c (searching): Deleted var. (text_search, m_text_search): New variables. (ask_about): Send the `TEXT' and `MTXT' commands. (main): Don't set SEARCHING variable. Enable -t and -m setting M_TEXT_SEARCH. * cmds.c (regfind, check_text, net_do_pr_internal): Add functions. (net_do_pr): Call net_do_pr_internal, not get_pr directly, so we can see if we're doing text searches. (GNATS_sear, GNATS_msrc): Rename to GNATS_text and GNATS_mtxt. * cmds.c, gnatsd.c: Don't include the regex stuff here. * gnatsd.h: Include it here. Fri Jun 17 15:10:35 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (get_name): Declare HOST arg as a pointer. Copy the name into BUF only after we know how long it will need to be. Give memcmp the correct address for comparing the hostname against possible ones which we have found. Thu Jun 16 14:02:25 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (start_connection): Rewrite to pay attention to things. (get_name): New function. (do_command): Deleted function. * gnatsd.h (CODE_NO_ACCESS): Define. * gnatsd.c (main): Don't worry about SIGCLD/SIGCHLD. Do ignore SIGPIPE, though, since read will tell us all about it. * cmds.c (GNATS_help): New function. * gnatsd.c (cmds): Add GNATS_help to the list. * gnatsd.h (CODE_INFORMATION): Added. * cmds.c (get_pr): Don't refuse confidential PRs this way. Fri Jun 10 11:53:36 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * nquery-pr.c (main): If gethostbyname fails, print an error message rather than dumping core. Wed Jun 8 12:56:25 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gnatsd.c (GNATS_skcl): Deleted declaration. (cmds): Use NOCL/GNATS_nocl instead. * cmds.c (GNATS_nocl): Renamed from GNATS_skcl. * nquery-pr.c (ask_about): Send NOCL instead of SKCL. * Makefile.in (doclean): Delete nquery-pr and gnatsd as well. * pr-edit.c (xmalloc): Remove decl, since it's in gnats.h now. * nquery-pr.c (main): If we didn't get any arguments, give the usage. Only init the index variable if we're going to be doing anything in here. (long_options, usage): Accept -E/--entire instead. * query-pr.c (main): Likewise. * man/query-pr.man: Don't talk about no options showing you the entire database. (Nobody's really liked that, anyway.) Tue Jun 7 13:12:57 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * cmds.c (skip_closed): New variable. (pr_matches): Pay attention to --skip-closed. (GNATS_skcl): New function. * gnatsd.c (GNATS_skcl): Add decl. (cmds): Add GNATS_skcl. * misc.c (read_string): Undo previous change, we do want the newline. * gnats.h (xmalloc): Add declaration. * configure.in: Also look for -lnsl for Solaris to go with -lsocket. * configure.in: Look for sys/select.h. * autoconf.h.in: Added HAVE_SYS_SELECT_H. * gnatsd.c (HAVE_SYS_SELECT_H): If defined, include sys/select.h to get the typedef of `fd_set'. * gnatsd.c, nquery-pr.c, gnatsd.h: New files for the network server. * Makefile.in (nquery-pr, gnatsd, nquery-pr.o): New rules. (query-pr): Re-order dependencies a bit. (GNATS_SERVER): New user-definable variable. (GNATS_DEFS): Define GNATS_SERVER. * configure.in (GNATS_SERVER): Added. * config.c.in (GNATS_SERVER): Define. * configure, config.c: Generated new ones. Mon May 23 11:35:51 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * gen-index.c (do_category): Close the directory when we're done, to keep from running out of space. Also adjust some errors being printed out so they mention the name of the program that's giving them. Mon May 2 19:17:24 1994 Jason Merrill (jason@deneb.cygnus.com) * mail-query.sh (PATH): Don't expect the environment to contain a reasonable PATH. Tue Apr 19 13:18:53 1994 Jason Molenda (crash@sendai.cygnus.com) * misc.c (read_string): if the string ends with \n, remove the \n. Fri Apr 15 16:41:00 1994 Jonathan I. Kamens (jik@cam.ov.com) * gnats-el.in (gnats::get-header-using-mail-fetch-field): New function which only searches the header, not the entire body of the PR. Wed Apr 6 18:39:00 1994 Jason Merrill (jason@deneb.cygnus.com) * mail-query.sh: Initialize $to and $args to "" Wed Apr 6 17:19:18 1994 Cheryl Bien (bien@aero.org) * edit-pr.sh: Put quotes around $usage. Fri Mar 25 15:26:27 1994 Jason Merrill (jason@deneb.cygnus.com) * file-pr.c (arg_quote): Make sure that we're not allocating 0 bytes. Fri Mar 18 11:49:28 1994 Jason Merrill (jason@deneb.cygnus.com) * pr-edit.c (modify_pr): If the match is on PR #1, modify index_chain. Mon Mar 14 11:59:13 1994 Jason Molenda (crash@sendai.cygnus.com) Sun 13 Mar 94 18:37:22 1994 Cheryl Bien (bien@aero.org) * at-pr.sh: Check DEBUG_MODE to see if == `1' instead of checking non-zeroness. Thu Mar 3 15:24:24 1994 Jason Molenda (crash@sendai.cygnus.com) Thu Mar 2 15:25:37 1994 Kevin Kells (kells@ise.ch) * misc.c (get_token): Allow tokens to be just ``token:'' intead of ``token: ''. Thu Mar 3 12:47:26 1994 Jason Merrill (jason@deneb.cygnus.com) * queue-pr.c: Remove definition of queue_dir. * config.h: Add declaration for queue_dir. * Makefile.in (QUEUE_DIR): New make variable. (GNATS_DEFS): Add QUEUE_DIR. * configure.in: Set up QUEUE_DIR. Tue Mar 1 10:19:52 1994 Jason Molenda (crash@sendai.cygnus.com) * gen-index.c (usage): add newline at end of usage message. Mon Feb 28 15:14:13 1994 Jason Merrill (jason@deneb.cygnus.com) * main.c (main): Only call configure() once. * getdate.y: Remove workaround for old bison bug that breaks new bison code. Thu Feb 24 08:02:54 1994 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::tr): Regexp-quote the from character. Fri Feb 4 15:58:31 1994 Jason Merrill (jason@deneb.cygnus.com) * queue-pr.c (main): -d now sets gnats_root. * Makefile.in (GNATS_DEFS): Define X_GNATS_ROOT rather than GNATS_ROOT. * config.c.in (configure): Check environment variable GNATS_ROOT, macro X_GNATS_ROOT. Add QUEUE_DIR variable. Fri Feb 4 15:49:42 1994 Jonathan I. Kamens (jik@security.ov.com) * file-pr.c (append_report): Don't mess with the memory allocated by set_field. * mkdist.sh (FILES): Replace send-pr.man with send-pr.1 Fri Jan 28 14:16:51 1994 Jason Merrill (jason@deneb.cygnus.com) * xmalloc.c (xmalloc): Don't abort on xmalloc (0). Mon Jan 17 15:29:32 1994 Jason Merrill (jason@deneb.cygnus.com) * man/Makefile.in (SRCSL): Subst in $(prefix). Thu Jan 13 11:29:37 1994 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::query-pr-default-options): Add space at end. * p-admin.texi (Default behavior): Fix typo. * p-inst.texi (Aliases): Add missing "s. Mon Jan 10 17:24:52 1994 Jason Merrill (jason@deneb.cygnus.com) * configure.in: Clean up. * p-inst.texi (Installing utils): Fix calling syntax for crontab. Fri Jan 7 12:56:22 1994 Jason Merrill (jason@deneb.cygnus.com) * query-pr.c (main): If get_index fails, exit(1). Thu Jan 6 18:29:00 1994 Jason Merrill (jason@deneb.cygnus.com) * file-pr.c (notify_responsible): Fix Resent-Cc and Resent-Reply-To fields. * mail-query.sh: Fix oopses. * aclocal.m4: Remove all macros but AC_DIFF_OPT, include ../send-pr/aclocal.m4 * gnats-el.in (gnats:bury-edited-prs): New variable to control burying of edited PRs. (gnats:unlock-buffer): Use it. Wed Jan 5 14:12:33 1994 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::vmish-rename-after-send): Copy code for retaining N sent mail buffers from VM 5.35. (gnats::kept-mail-buffers): New variable. (gnats:keep-sent-messages): New option. Wed Jan 5 14:12:33 1994 Jonathan I. Kamens (jik@security.ov.com) * file-pr.c, files.c, index.c, internal.c, main.c, misc.c, pr.c: Fix memory leaks. * file-pr.c, gnats.h, internal.c, main.c, misc.c: Clean up mail usage. * files.c, misc.c, pr.c: Clean up use of get_next_field. * file-pr.c (create_report): Fix comment. * headers.c (read_header): Eat trailing newlines. * Makefile.in (install-info): Fix installs from source dir. * query-pr.c (regcmp, regfind): Don't let regfree try to free case_fold. * mail-query.sh: Add helpful messages. * gnats-el.in (gnats:gnats-mode): Fix documentation string. * pr-edit.c (usage): Add --lockdb and --unlockdb options. * p-admin.texi (mkdist): Update usage information. * mkdist.sh: Support --submitter option, reorganize usage. * getdate.y: Update. * aclocal.m4 (AC_LISPDIR): New macro. * configure.in: Use it. * Makefile.in (TEXINPUTS): Also search $(srcdir). (various): Don't bother removing target first. (config.c): Use $@. (version.texi): Don't use $@. (lispdir): Use @LISPDIR@. Wed Jan 5 14:17:39 1994 Tim Mason * edit-pr.sh: Fix logic for sending notification. Tue Dec 14 15:39:32 1993 Jason Merrill (jason@deneb.cygnus.com) * index.c (find_pr_category): Make buf static. Fri Dec 10 11:49:15 1993 Jason Merrill (jason@deneb.cygnus.com) * Version 3.2 Mon Dec 6 16:39:33 1993 Jason Merrill (jason@deneb.cygnus.com) * version 3.01.10 * mail-query.sh: Use MAIL_AGENT, put $(bindir) first on path. * Makefile.in (mail-query): Support that. * getdate.c: Generate a new one. Wed Dec 1 14:25:19 1993 Jason Merrill (jason@deneb.cygnus.com) * version 3.01.9 * man/Makefile.in: Fix clean targets. * Makefile.in: Fix clean targets. Tue Nov 30 11:22:07 1993 Jason Merrill (jason@deneb.cygnus.com) * file-pr.c (run_atpr): Quote any ' characters in the arguments. (arg_quote): Fn to do that. * Makefile.in (mkdist): Remove VERSION subst. * mkdist.sh (install): Fix ($ typo. (send-pr): Fix sed delimiters, remove VERSION subst. (send-pr.1): Remove rule. (send-pr.el): Add datadir subst, remove VERSION. * query-pr.c (long_options): --multitext takes an option. * configure.in (GNATS_ROOT): Fix default. Fri Nov 26 02:15:20 1993 Jason Merrill (jason@deneb.cygnus.com) * config.c.in (configure): Don't use a number for the length of gnats-adm/config, since it can change. Tue Nov 23 13:37:56 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::get-pr-category): If we get a false match on the category number, don't loop indefinitely. Mon Nov 22 00:26:08 1993 Jason Merrill (jason@deneb.cygnus.com) * file-pr.c (PAT): Allow 0-9 in category name. * gnats-el.in (gnats::real-pr-addr): Return nil if arg is "". Fri Nov 19 12:17:34 1993 Jason Merrill (jason@deneb.cygnus.com) * config.c.in (safe_strtok): A strtok which never returns NULL. (configure): Use it. * Makefile.in: Change XTRAFLAGS to LDFLAGS. (install-gnats-bin): Don't show ***s when there's no error. Tue Nov 16 14:11:48 1993 Jason Merrill (jason@deneb.cygnus.com) * edit-pr.sh (checking): Massage psychotic shells. Fri Nov 12 16:20:44 1993 Jason Merrill (jason@deneb.cygnus.com) Fri Nov 12 16:08:23 1993 "Jonathan I. Kamens" (jik@security.ov.com) * pr-edit.c (main): Add -L and -U options to lock and unlock the entire database. Fri Nov 12 16:04:51 1993 Jim Meyering (meyering@idefix.comco.com) * Makefile.in: Tweak for short-name systems, use temp files to avoid leaving targets in incomplete state. Fri Nov 12 15:48:01 1993 "Jonathan I. Kamens" (jik@security.ov.com) * edit-pr.sh: Use hostname for pr-edit --lock. Wed Nov 10 20:23:55 1993 Jason Molenda (crash@cygnus.com) * edit-pr.sh: Don't try to call pr-addr on the originator of the PR. Wed Nov 10 11:43:40 1993 Jason Merrill (jason@deneb.cygnus.com) * most all: Make gcc -Wall happier. * configure.in: Add AC_HAVE_LIBRARY(malloc) for IRIX. * headers.c (read_header): Overhaul to handle PR fields in headers better and clean up ugly code. Tue Nov 9 11:45:47 1993 Jason Merrill (jason@deneb.cygnus.com) * query-pr.c (regfind): Dynamically allocate fastmap. Thu Nov 4 11:33:05 1993 Jim Meyering (meyering@idefix.comco.com) * query-pr.c: Add decls for xmalloc and basename. (disbar): Return str, parenthesize assignment in condition. * pr.c (read_pr): Make sure that array indices are unsigned char. * pr-edit.c: Add decls for basename and xmalloc. (main): Lose cast of basename retval. (main): Initialize fname to NULL. * gnats.h (SKIP_WHITE_SPACE): Parenthesize macro arg, make sure that array index is unsigned char. * Makefile.in (mostlyclean): Also remove *.aux files. * headers.c (read_header): Remove unused `received' var. Wed Nov 3 13:47:47 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-gnats-bin): Deal with not running as root or gnats. (install-tools-bin): Ditto. Tue Nov 2 11:43:58 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats:view-pr): If already loaded, look at beginning of PR. * pr-edit.c (check_pr): Fix up output. * pr-addr.c (main): Accept options. * file-pr.c (gnats): Use key for responsible field, not alias. * gnats-el.in (gnats::real-pr-addr): Call the C pr-addr program if the responsible party can't be found in the file. (gnats::bm): (buffer-substring (match-beginning x) (match-end x)). (gnats::pr-edit): All functions that use the pr-edit binary call this now. * files.c (get_responsible_address): Check the responsible file first, and fill in the alias field if necessary. * Makefile.in (install-gnats-bin): Break up installation of examples and config file. (config): Update. (GNATS_DEFS): Include BINDIR, B*_* Add entries for business hours stuff * configure.in: Add business hours stuff. * config.h: Remove #defines of business hours, BINDIR * config.c.in: Add bindir. * edit-pr.sh: Also look in $VISUAL for editor. Mon Nov 1 10:05:10 1993 Jeffrey Osier (jeffrey@thepub.cygnus.com) * gnats/*.texi, send-pr/*.texi, gnats/man/*.man: up to date. Sun Oct 31 22:17:26 1993 Jason Merrill (jason@deneb.cygnus.com) * file-pr.c (run_atpr): Remove gnats_root from before BINDIR. * queue-pr.c: Ditto. Fri Oct 29 11:27:23 1993 Jason Merrill (jason@deneb.cygnus.com) * internal.c (lock_gnats): Wait 10 seconds for the lock to go away before dying. * query-pr.c (main): Don't allow -d before -R. * internal.c (unlock_gnats): If no lock, don't exit, just return. (block_signals): Don't ignore signals, just trap them. (unblock_signals): More signals. (unlock_quit): Like unlock_death, but quieter. * mail-query.sh: Strip leading space from headers. * gnats-el.in (gnats::fields): Add "mistaken". Allow local usernames as completions for responsible field. Wed Oct 27 18:49:57 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (gnats.info): Fix. (gnats.dvi): Fix. Wed Oct 27 17:08:29 1993 Jeffrey Osier (jeffrey@cygnus.com) * gnats-usage.texi, gnats-install.texi, gnats-admin.texi: New Doc Structure (names will change shortly) * gnats.texi: updated Wed Oct 27 15:58:44 1993 Jeffrey Osier (jeffrey@cygnus.com) * Makefile.in: fix dvi and info targets Tue Oct 26 14:03:04 1993 Jason Merrill (jason@deneb.cygnus.com) * main.c (long_options): Disable -m option * gnats-el.in (gnats:kill-buffer): Kill the right buffer * configure.in: Change gnats-root to gnats-db * *: Change $(GNATS_ROOT)/gnats-dist to $(datadir)/gnats/dist * Makefile.in (config): Include SUBMITTER field (install-gnats-bin & others): Change GNATS_ROOT to libdir * pr-edit.c (usage): Update usage (main): standardsify -V and -h options Mon Oct 25 17:46:01 1993 Jason Merrill (jason@rtl.cygnus.com) * edit-pr.sh (mail_to): Put back calls to $PR_ADDR Thu Oct 21 15:40:48 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::rw): Don't check retval; call-process-region non-deterministically returns 1 or 0 when called on /bin/false under 19.19. Rrrrrrrrrrgh. * query-pr.c (query_pr): If numeric argument & searching, don't keep looking for another matching PR after you've found one. Output a \n after printing out a PR in all cases. (main): Don't output \n's. Wed Oct 20 11:43:25 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (TEXINPUTS): Fix $(srcdir) references (gnats.dvi): Add TEXINPUTS=$(TEXINPUTS) * configure.in (MAIL_AGENT): Also look in /usr/ucblib. * pr-edit.c (main): Block signals earlier and unblock them later. I've locked GNATS twice because of this bug. * Makefile.in (uninstall): Don't use {} * files.c (find_responsible): Zero out new Responsible struct. * pr-addr.c (main): Make it work. It never worked before. * edit-pr.sh (old_resp): Avoid infinite loop on less intelligent seds. Make the recipient decision actually work. Remove $HOSTNAME bunk. * misc.c (open_mail_file): Use "w" mode for popen, not "w+". * query-pr.c (check_text): Fix logic. * file-pr.c (append_report): If a PR mysteriously acquires an invalid Submitter field, cope. Tue Oct 19 15:42:20 1993 Jason Merrill (jason@deneb.cygnus.com) * mkdist.sh: Change libdir to datadir, subst it into send-pr. * gnats-el.in (gnats::lock): Don't show trailing ^J in errors. (gnats::lock): Add case for existence of gnats.lock. (gnats::pr-addr): Don't require use of responsible file. (gnats::getpwnam): New function. (gnats::get-responsible-from-passwd): New function. (gnats::user-name-p): New function. Tue Oct 19 14:36:52 1993 Jeffrey Osier (jeffrey@thepub.cygnus.com) * Makefile.in: relocated TEXINPUTS to be more globally useful Mon Oct 18 16:15:16 1993 Jason Merrill (jason@deneb.cygnus.com) * edit-pr.sh (MAIL_AGENT): Add quotes. (old_resp, new_resp): Strip out spaces again. (reply_to): Go back to old way of determining since $#%^&* AIX sed doesn't deal with labels on the command line. * query-pr.c (do_pr): Make return value reasonable. * files.c: Remove duplicate #include of "pathmax.h". * file-pr.c: Remove duplicate #include of . * configure.in: Don't assume that sendmail will be found. * aclocal.m4 (AC_FIND_PROGRAM): Don't use AC_PROGRAM_CHECK. * Makefile.in: makedepend. Sat Oct 16 01:32:06 1993 Jason Merrill (jason@deneb.cygnus.com) * query-pr.c: Change -t option to -m, add -t option for searching Text fields. (do_pr_internal): Fix idiot bug. (regfind): Don't exit if re_search dies. (query_pr): Fix another idiot bug. Fri Oct 15 14:49:52 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-tools-bin): Allow (partial) installation as normal user. pr-edit must still be installed as root. * configure.in: Lose AC_GCC_TRADITIONAL. Thu Oct 14 22:14:32 1993 Jason Merrill (jason@deneb.cygnus.com) * query-pr.c: Add some code to use Rx package, but don't actually use it -- GNU regex is faster on sample queries I tried. (pr_matches): Deal with skip_closed. (regfind): Use a fastmap. (do_pr): Farm out the checks to do_pr_internal. (query_pr): Clean up code, make -t work with list of PRs. (main): Remove RE_DOT_NEWLINE from syntax, since it causes re_match_2 to become very unhappy when trying to match something like "f.*xyzzy" against a 1MB string which contains an f, but no xyzzy. * mkcat.sh: Give an accurate error message if $DATADIR/gnats doesn't exist. * files.c (find_submitter): Zero out submitter struct before assigning to parts of it. * Makefile.in (install-tools-bin): Also create $(datadir)/gnats, so it's there for mkcat. Wed Oct 13 11:54:15 1993 Jason Merrill (jason@deneb.cygnus.com) * misc.c: Change MAIL_AGENT to mail_agent * configure.in (MAIL_AGENT): Look for sendmail * edit-pr.sh: Use MAIL_AGENT. * config.h: Add decl for mail_agent. * Makefile.in (all-tools): Put gnats.elc back. (gnats.elc): Use send-pr-el.in instead of send-pr.el. * config.c.in: Add MAIL_AGENT, lose unions which were confusing gcc. * at-pr.sh (MAIL_AGENT): Use. * aclocal.m4 (AC_FIND_PROGRAM): New macro. * Makefile.in (MAIL_AGENT): New var. (GNATS_VARS): Include MAIL_AGENT. (GNATS_DEFS): Ditto. (config): ". (at-pr): Use MAIL_AGENT. (edit-pr): ". (mkcat): Change LIBDIR to DATADIR. (rmcat): ". * mkcat.sh: Put category list in $(datadir). * rmcat.sh: Ditto. * gnats-el.in (gnats::mail-PR-changed): Use gnats::make-temp-name. (gnats:gnats-mode): Ditto. (gnats::tmpdir): New variable, containing $TMPDIR or /tmp. (gnats::make-temp-name): Use gnats::tmpdir for location. * mkdist.sh: Install man page properly, substitute variables properly, install things with the proper mode. * xmalloc.c (xfree): New function, doesn't free null pointer. * headers.c (init_header): Stem memory leak. (header_value): Use strdup so that no one tries to realloc a string constant. (set_header): Stem memory leak. * pr.c (init_pr, field_value, set_field): Ditto. * configure.in (SUBMITTER): Set to '$(GNATS_SITE)'. Tue Oct 12 13:53:24 1993 Jason Merrill (jason@deneb.cygnus.com) * aclocal.m4: Remove AC_PARSEARGS and AC_NOTICE now that Autoconf 1.6 has been released. * queue-pr.c (run_gnats): Remove gnats.lock if file-pr broke and left it behind. * xmalloc.c: Use abort() instead of error(), so that it gets caught in file-pr. * gen-index.c, pr-edit.c, queue-pr.c: umask (022) * error.c: Lose * Makefile.in: Lose error.c, add GNATS_INSTALL to GNATS_VARS, move gnats.elc creation to install time (kludge) * internals.c (gnats_locked): New function * query-pr.c: Use RE_SYNTAX_POSIX_EXTENDED | RE_BK_PLUS_QM. Promise I won't change it anymore. Fri Oct 8 15:17:48 1993 Jason Merrill (jason@deneb.cygnus.com) * query-pr.c: Add text_search variable, which holds the regexp to search for. (long_options): Add --text, -t options (get_pr): Call init_pr before read_pr (regfind): Like regcmp, but uses re_search (check_text): Check all MultiText fields & Synopsis field for text_search (do_pr): Call check_text (main): Set text_search on -t option, use RE_SYNTAX_POSIX_BASIC (i.e. sed syntax) rather than the variant of egrep I was using before. (usage): Document -t and --text options. * gnats-el.in (gnats:unlock-buffer): Error, rather than message, on abort so that kill-buffer doesn't go ahead and kill it anyway. (gnats:query-pr): Work under Emacs 18 Tue Oct 5 10:47:46 1993 Jason Merrill (jason@deneb.cygnus.com) * edit-pr.sh: Wrap things in double quotes Mon Oct 4 12:32:44 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in: Wrap call-process calls in gnats::rw, which simulates a numerical return value for Emacs 18. (mh-insert-fields): autoload Fri Oct 1 15:05:22 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (VERSION): Bump to 3.01.5 Thu Sep 30 14:49:44 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats:unlock-buffer): Set 'e' key in unlocked PR buffer to edit the PR again (gnats::mail-PR-changed): Fix logic error Tue Sep 28 12:59:39 1993 Jason Merrill (jason@deneb.cygnus.com) * rmcat.sh: Fix dumb bug, massage Solbourne SunOS bdamage * man/Makefile.in (uninstall): Now does something * Makefile.in (gnats.elc): New target (uninstall): Now does something * config.c.in: Add fields for business hours config. * btime.c: Move business hours config from here (get_response_time): Fix stupid mistake * config.h: Add declarations for business hours configuration Mon Sep 27 17:05:57 1993 Jason Merrill (jason@deneb.cygnus.com) * globals.h: Remove the response buffer from the get_response_time prototype. * file-pr.c (gnats): Lose the response_time variable. * btime.c (get_response_time): Overhaul...hopefully it works now. * mkdist.sh (install): The man page is named send-pr.man. Fri Sep 24 13:19:13 1993 Jason Merrill (jason@deneb.cygnus.com) * pr.c (read_pr): Don't stop reading the pr when you hit the Organization field. * gnats-el.in (gnats::tr): New function, does basically the same thing as tr(1) (make-auto-save-file-name): Redefine global function so that buffers with /'s in their names can be auto-saved. (gnats::fields): Copy send-pr::fields by printing it to a string and reading it back. Is there a better way? Mon Sep 20 13:17:36 1993 Jason Merrill (jason@deneb.cygnus.com) * btime.c (get_response_time): Make 't' static and copy the output of localtime() into it so that it is not written over by the ctime() call later in the function. Thu Sep 16 14:51:59 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::mail-PR-changed-mail-setup): Fix typo (gnats::get-pr-category): Ditto Tue Sep 14 16:49:13 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats:gnats-mode): Kludge to avoid errors when trying to autosave buffer (gnats::pr-addr): Make it work (gnats::get-alist): Optimize further (gnats::get-list): Ditto * edit-pr.sh (reply_to): Clean up sed script somewhat * config.c.in: Disable ANSI initializers until gcc is fixed * Makefile.in (OBJECTS): Add regex.o * file-pr.c (check_if_reply): Use a regular expression * aclocal.m4: Make AC_PARSEARGS match next version of autoconf Mon Sep 13 15:47:18 1993 Jason Merrill (jason@deneb.cygnus.com) * pr-edit.c (main, others): Made return values reasonable Fri Sep 10 16:39:31 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::vmish-mail-other-window): Rename mail buffer to something more informative, kludgily working around sendmail.el's refusal to support multiple mail buffers in an intelligent way (gnats::vmish-rename-after-send): Indicate that it's been sent (gnats::generate-new-buffer-name): Brought back (gnats::mail-reply-using-mail): Fixed get-char/get-line typo Support Apparently-To: header (gnats::mail-other-window-using-mhe): Made consistent with mail version (gnats::mail-reply-using-mhe): Support Apparently-To: (gnats:view-pr): Make emacs 18 happy; don't rename the buffer in view-hook. (gnats:view-pr): Don't pollute general view-mode-map Thu Sep 9 14:04:08 1993 Jason Merrill (jason@deneb.cygnus.com) * man/Makefile.in (INSTALL): Explicitly set * configure.in: Don't call AC_PROG_INSTALL * Makefile.in (TAGS): Also grab ../send-pr/send-pr-el.in (install-gnats-bin): Depend on ../install.sh (INSTALL): Explicitly set * query-pr.c (regcmp): Support case folding * config.m4: Conform to ANSI initializer rules (hmph) * gnats-el.in (gnats::get-pr-category): Massive speedup from using search-forward rather than re-search-forward (gnats::get-alist): Ditto (various): Be more precise with kill-buffer Wed Sep 8 14:07:03 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (TAGS): Include headers and elisp in tags file * query-pr.c (sql_types): ignore case * gnats-el.in (gnats::get-list-from-file): Be informative, use gnats::get-alist (gnats::get-alist): New function, loads all information rather than just first field (gnats::pr-addr): Use gnats::responsibles rather than program (various): avoid use of files (gnats::update-responsible): Set responsible field for new category (gnats::category-responsible): Return person responsible for cat (gnats::no-such-category): new error condition Fri Sep 3 14:10:07 1993 Jason Merrill (jason@deneb.cygnus.com) * man/Makefile.in: Lose duplicated code * main.c (main): Lose -m option, deal with -f failure * file-pr.c (notify_responsible): Remove chaff * Makefile.in (all): Use a make variable for all & install Put $(datadir) in config file Move directory creation stuff into separate targets Lose duplicate code Collapse man page targets * gnats-el.in (gnats::isme): New function (gnats::mail-PR-changed): Proper checking for sending mail to me Thu Sep 2 13:59:49 1993 Jason Merrill (jason@deneb.cygnus.com) * queue-pr.c (fork_gnats): Return process exit status * headers.c (init_header): Remove trailing space from SM_FROM header * gnats-el.in (gnats:unlock-buffer): Use gnats:keep-edited-buffers (gnats::mail-functions): Change to list (gnats:view-pr): Handle viewing PR that's being edited * config.c.in (configure): Allow repeated calls * configure.in: Support --with-gnats-root * aclocal.m4: Fix AC_PARSEARGS Wed Sep 1 13:22:32 1993 Jason Merrill (jason@deneb.cygnus.com) * at-pr.sh (RESP_ADDR): Support DEBUG_MODE * gnats-el.in (gnats::fields): Mess with fields more (gnats::submitters): Added variable Tue Aug 31 12:12:29 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::fields): Move all values and defaults into this monolithic table. Change most instances of gnats::find-field to gnats::field-contents (gnats::change-field-and-update-audit-trail): Lose (gnats::update-audit-trail): Create, reference in gnats::fields * queue-pr.c (run_gnats): If file-pr exits with status 2, rename to a dot file (so it will be ignored in future) and notify gnats-admin. * main.c (unlock_death): Punt * various: Change some exit(1)s to exit(2) or exit(3) to be more informative. * pr.c (read_pr): Recognize non-multitext fields inside a multitext field -- Organization comes early. Check whether a new field is the same as the current one. * file-pr.c (append_report): Prepend all correspondence with a blank space so that PRs submitted that way don't mess things up. Fri Aug 27 08:34:32 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::get-list-from-file): Use insert-file-contents * Makefile.in (install-gnats): Install gen-index * gnats-el.in (gnats:view-pr): Type 'e' to edit the currently viewed PR, update mode line * pr.c (read_pr): Don't process non-multitext fields inside a multitext field. Don't process multitext fields more than once. * gnats-el.in (gnats::mail-PR-changed): Smarter detection of me (gnats::mail-PR-changed): Fix notification of resp&state changes together (gnats::mail-PR-changed-mail-setup): Send from same window (gnats::mail-PR-changed-mhe-setup): Ditto (gnats:unlock-buffer): Always bury buffer Thu Aug 26 11:26:48 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::query-pr-history): New variable (gnats:view-pr): New logic for error message (gnats:edit-pr): Ditto. (gnats:query-pr): Use query-pr-history * various: Check for "" rather than NULL returns from {field,header}_value. * pr.c (field_value): Always return a string, "" if nothing else. * headers.c (header_value): Ditto. * Makefile.in: Fix various typos, add missing defaults (queue-pr): Link in version.o (version.texinfo): Renambe to version.texi * query-pr.c (main): Add 'restricted' option for use with mail server -- user is not allowed to redirect output, look at a different root directory, or view confidential PRs. For best results, use as first argument. * misc.c (open_mail_file): If in debug mode, mail to gnats_admin and stick another set of headers onto the beginning of the message. * config.c.in: Add definition of debug_mode * config.h: Ditto * Makefile.in (mail-query): Add target (lispdir): Use $(datadir)/emacs/lisp. * mail-query.sh: Real simple mail server for query-pr * file-pr.c (check_if_reply): Deal with re:cat/num subject headers * queue-pr.c (main): Add -V option. * main.c (main): Print help messages to stderr. * globals.h (MAIL_AGENT): Use -oi rather than -i, which doesn't exist. Wed Aug 25 12:00:53 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::get-pr-category): Use insert-file-contents instead of insert-file Tue Aug 24 12:10:55 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats:addr): Add definition (gnats-mode-map): Bind ^C^T to gnats:category-change-from-to (gnats:mail-reply): Handle prefix argument that using-mail version looks for (gnats::mail-reply-using-mail): Don't be interactive (gnats::mail-reply-using-mhe): Ignore argument (gnats::push): Move to send-pr-el.in (gnats::mail-PR-changed): Mail PR changes to bugs, handle addresses better (gnats::mail-PR-changed-mail-setup): If mail-other-window returns nil, abort PR submission (gnats:category-change-from-to): Create (gnats:view-pr): Rename buffer to include category (gnats:edit-pr): Remove useless progn's Fix error conditions Switch to other window if desired PR is there * internal.c (punt): Put two newlines after Subject line so that buggy sendmails don't think that "pr-edit:" is another header line. * Makefile.in (config): Don't put LIBDIR in the config file, since it is shared across architectures. Change default for GNATS_ROOT to $(statedir)/gnats/gnats-root * configure.in: ditto Sun Aug 22 01:00:59 1993 Jason Merrill (jason@rtl.cygnus.com) * edit-pr.sh (reply_to): More Fun with sed(1) to handle continuation lines, avoid use of grep when not needed. * headers.c (read_header): Handle continuation lines beginning with a space, not just a tab. Fri Aug 20 11:36:14 1993 Jason Merrill (jason@deneb.cygnus.com) * edit-pr.sh (reply_to): Fun with sed(1). Notify originator of state changes. * README: Fix acronym * gnats.h: Take bzero back out Thu Aug 19 14:58:29 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats::mail-reply-using-mail): Make uninteractive (gnats::mail-other-window-using-mail): ditto (gnats::mail-reply-using-mhe): Ignore single arg (gnats:mail-reply): Accept arg, pass to subroutine (gnats:category-change-from-to): Do completing update of category initially bound to C-c C-t (gnats::mail-PR-changed): Redo address generation * Makefile.in (GNATS_VARS): Add SUBMITTER to list * gnats-el.in (gnats::mail-PR-changed): Mail diffs to bugs * query-pr.c (regcmp): Use re_match rather than re_search Use memset rather than bzero Wed Aug 18 13:51:56 1993 Jason Merrill (jason@deneb.cygnus.com) * pr.h (PR_Name): Put FIX before AUDIT_TRAIL so edit-pr.sh doesn't get confused * regex.h: #define const if not __STDC__ * btime.c, pr-addr.c, pr-edit.c, resp-lookup.c: #include "config.h" * man/Makefile.in: Change @GNATS_*@ to xGNATS_*x man/*.man: ditto * gnats-el.in (gnats:unlock-buffer): Only bury buffer if it's displayed Only delete file if it exists * configure.in: Add section for determining subset of tools to build * man/Makefile.in (VPATH): Replace @srcdir@ with $(srcdir) (man1ext, man8ext): Add, use per GNU coding standards (all): Replace $(GNATS) with @GNATS_ALL@ (install): Replace $(GNATS) with @GNATS_INSTALL@ (install-tools-man): Change to install-tools * Makefile.in (config): Add $(libdir) (gnats.el): Don't subst $(bindir) or $(GNATS_ADDR) (install-tools-man): Remove (FLAGS_TO_PASS): Remove $(GNATS) (GNATS): Remove (all): Replace $(GNATS) with @GNATS_ALL@ (install): Replace $(GNATS) with @GNATS_INSTALL@ (install-tools): Replace install-tools-man with install-man * gnats-el.in: Reorganize namespace (put stuff under gnats:) Move duplicated functions, variables into ../send-pr/send-pr-el.in (require 'send-pr) Make gnats-mail customisation stuff table-driven Nuke backups stuff (gnats::state-following): Make dotted (gnats::check-pr): Don't save-excursion for the whole function Use defsubst for some of the smaller functions * aclocal.m4: Add modified AC_NOTICE and AC_PARSEARGS macros (based on Autoconf 1.5 versions) * configure.in: Use AC_INIT Mon Aug 16 11:18:11 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in: Change some defconsts to defvars to users can set, say, GNATS-ROOT beforehand Fix string-match syntax Lose gnats-dont-reply-to-names; we want replies to be CC'd to `bugs' * query-pr.c (usage): Fix it * mkcat.sh: Always create new categories files for send-pr * misc.c (get_next_field): Change `delim' from char to int * gnats.h: Change proto for get_next_field to char*, char*, int * gnats-el.in (query-pr): Use -d option * pr.c (check_enum_types): Only check up to first space in value (to accomodate duplicate (NUM)) * gnats-el.in (gnats-unlock-buffer): If not in buf, go there. (gnats-mode-kill-buffer-hook): Force unlock, to avoid having to answer yes twice about killing a modified PR. (gnats-unlock-buffer): Add &optional force argument Fri Aug 13 15:08:59 1993 Jason Merrill (jason@deneb.cygnus.com) * query-pr.c (print_pr): Add calls to disbar() in sql output routines to avoid outputting '|'s inside fields (regcmp): Wrapper for regexp routines (pr_matches): Use regcmp rather than strcmp (main): Set up regex syntax (query_pr): Use regcmp for the number (main): Always get index (numeric): Is it a number or a pattern? Wed Aug 11 12:36:24 1993 Jason Merrill (jason@deneb.cygnus.com) * configure.in: Protect []'s in expr lines from m4 * pr.h (PR_Name): Add FIX to enum, add FIX_STRING #define (PR 1310) * pr.c (read_pr): Change check of specific categories to ignore if prune is true to check for pr[i].datatype == MultiText (init_pr): Add values for >Fix: field (PR 1310) * main.c (main): Catch SIGHUP, SIGTERM, SIGINT, and SIGQUIT, too. (unlock_death): Uncatch them. * gnats-el.in (gnats-submit-pr): Changing the state to the same state is interesting to the customer. Don't unlock the PR until mail has been sent. * headers.c (read_header): Call init_header() (PR 2711) Tue Aug 10 12:07:45 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (query-pr): Use BINDIR to specify the location of the query-pr binary * file-pr.c (append_report): Don't die if headers are missing (i.e. To:) * main.c (long_options): Change 'usage' to 'help' and '?' to 'h' to conform to the GNU coding standards and the code in main(). (main): made --version and --help options exit successfully. * query-pr.c (long_options): Changed print-path to not require an argument (PR 3165) * gnats-el.in: Changed 'gnats-unlock' to 'unlock-pr' since it's now interactive. (gnats-mode): Change paragraph-separate and paragraph-start to include "^>[-A-Za-z]:" (PR 3166) Mon Aug 9 18:09:15 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in (gnats-unlock-buffer): If buffer modified, ask user before unlocking (PR 2320) Improve gnats-mode documentation (PR 2320) Fri Aug 6 12:57:45 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in: Reworked edit-pr, gnats-{un,}lock to use condition-case and error conditions Removed all traces of gnats-mode-write-file-hook Changed the names of some temp buffers to contain an initial space * Makefile.in, aclocal.m4, configure.in, gnats-el.in: Use AC_DIFF_OPT macro to set DIFFOPT to the most human-friendly mode available to the default diff(1). * gnats-el.in (gnats-finish): Rename to gnats-submit-pr to match the documentation Fix declaration of invalid-fields error (gnats-mode): Fix use of kill-emacs-hook under Emacs 18 (gnats-mail-PR-changed): Use pr-addr for finding email addresses Use diff -u instead of -c (gnats-pr-addr): New function (gnats-change-field-and-update-audit-trail): Don't change the case of replacement text (gnats-generate-new-buffer-name): Removed, since it is no longer used (view-pr): Use view-file (gnats-submit-pr): Don't force backup -- we want to diff against the version checked out, not the most recently saved. * edit-pr.sh: Change all instances of GNATS_ADDR to PR_ADDR to avoid clashing with configuration variable Thu Aug 5 17:52:03 1993 Jason Merrill (jason@deneb.cygnus.com) * gnats-el.in: Varied and sundry fixes, viz: Understand Emacs 19, support new capabilities like add-hook, generate-new-buffer-name, local-write-file-hooks and kill-buffer-hook Rename gnats-mode-write-file-hook to gnats-finish and bind to ^C^C, since v19's basic-save-buffer chokes if a hook changes buffer-file-name to nil When starting a new buffer for a PR, kill the old one. Don't rename the buffer when you're done Bury the buffer when you're done * Makefile.in (clean): Don't remove config (distclean): Remove config * configure.in: Use AC_PROGRAMS_CHECK to (hopefully) find hostname rather than assuming it exists. Check for config files in ${srcdir} and build dir as well Wed Aug 4 14:53:30 1993 Jason Merrill (jason@deneb.cygnus.com) * Various: Change version number to 3.02 * gnats.texi: @include version.texinfo for version number. * Makefile.in (lispdir): change to site-lisp * headers.c (read_header): Break on "headers" beginning with '>' * gnats.h: add prototype for configure(). * misc.c: remove definition of gnats_root. * main.c: remove definitions of flag_{ack,notify}. * globals.h: remove definition of GNATS_ADMIN. * *.c: move #include "config.h" to beginning of file. Add call to configure() in main(). replace cpp macros with references to external variables. * config.m4: New file containing macros used in config.c.in for generating config.c. * config.c.in: New file containing routines for parsing configuration file. Can be easily portablized by removing dependence on GNATS_ROOT. * config.h: Changed all the cpp macros to external variables, include "autoconf.h" * edit-pr.sh, mkcat.sh, mkdist.sh, rmcat.sh: source GNATS_ROOT/gnats-adm/config * at-pr.sh, edit-pr.sh, mkcat.sh, rmcat.sh, gnats-el.in: replace @'s with x's to avoid collision with config.status * Makefile.in: Changed defaults for GNATS_ROOT and kin to be subst-able by configure, added NOTIFY, ACKNOWLEDGE, DEFAULT_SUBMITTER, KEEP_RECEIVED_HEADERS and GNATS_ADMIN to the group, added M4 variable, made BISON and the INSTALL triplets subst-able, added statedir var, added config.[co] to LIB{SRC,OBJS}, added . and $(srcdir) to INCLUDEDIR, replaced LIBIBERTY with the usual version, added GNATS_DEFS, added `config' to all-gnats dependencies, removed $(LIBIBERTY) from various dependency lists, added rules for config.{,c,o}, filled some rules, replaced @'s with x's in sed directives, added autoconf.h to the dependency list for the objects, added config installation to install-gnats rule, replaced gnats.dvi rule with $(TEXI2DVI)-based one, fixed up *clean rules, added MAKEINFO and TEXI2DVI variables. * aclocal.m4: Removed file again. * configure.in: Add large amounts of kludgey sh code to guess the old gnats configuration. Changed AC_SCO_SOCKET to AC_HAVE_LIBRARY(socket) Added AC_PROG_YACC Use autoheader -> autoconf.h.in Wed Aug 4 11:53:36 1993 Brendan Kehoe (brendan@blues.cygnus.com) * query-pr.c (get_pr): Call init_header before read_header, so we get clean information for each one. Tue Aug 3 08:35:24 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-el.in (gnats-mail-reply-using-mail): Add MSGID to the let list, so it's not considered a free variable. (gnats-mail-reply-using-mhe): Likewise. (edit-pr): Add MSG to the let list. Fri Jul 23 16:01:08 1993 Jason Merrill (jason@wahini.cygnus.com) * aclocal.m4: Created file with definition of AC_SCO_SOCKET Wed Jul 21 19:02:31 1993 Jason Merrill (jason@wahini.cygnus.com) * files.c (find_submitter): Fix handling of null response time field in GNATS_ROOT/gnats-adm/submitters * Makefile.in: Fixed typo, added $(srcdir)/'s for other-dir builds * internal.c (punt): Create "To:" line if not using /bin/mail, so that mail to gnats-admin will actually go to gnats-admin * man/Makefile.in: Added and removed $(srcdir)/'s so it would build properly in another directory Wed Jun 16 15:51:13 1993 K. Richard Pixley (rich@cygnus.com) * gnats-el.in (GNATS-MAIL-ADDR, GNATS-ROOT, LIBDIR): Add asterix in documentation which will declare these to be user settable options. (GNATS-ROOT, LIBDIR): changed from defvar to defconst. We do not change these values programmatically. (gnats-responsibilities): changed from defconst to defvar. We do change these values programmatically. (gnats-pr-locked, gnats-pr-errors, gnats-buffer-pr, gnats-audit-trail, gnats-backupname): static variable names now prefixed with gnats- to prevent stray collisions. Added missing defvar line. (gnats-start-of-PR-fields): Added missing defvar line. (gnats-dont-reply-to-names): changed setq to defvar. Tue Jun 15 12:43:14 1993 K. Richard Pixley (rich@sendai.cygnus.com) * Makefile.in (VPATH): Replace so that subdir builds work once again. Wed May 26 12:42:01 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr-addr.c (main): Also chop at the parenthesis, since we can't assume there'll be a space between the name and the real name. Tue May 18 13:35:28 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr-edit.c (unlock_pr): Check for a non-existant LOCK_PATH before we try to stat it. Don't call punt. Tue May 4 12:48:11 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * edit-pr.sh (checking): Fix quoting bug. Wed Apr 14 12:11:07 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (VERSION): Bump version to 3.01. * gnats-fc.eps (Title): Likewise. * query-pr.c (do_pr): Do a case-insensitive match against the originator name. * gen-index.c (long_options): Add -V/--version. (main): Grok it. * man/rmcat.man, man/gen-index.man: New files. * man/Makefile.in (SRCS8): Add rmcat.8 and gen-index.8. (MAN8): Add rmcat.man and gen-index.man. * query-pr.c (main): If we're doing a summary, output a final newline after we run down the list of PRs that they gave us. Tue Apr 13 12:13:42 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-el.in (gnats-mode-write-file-hook): Fix appending the hook. * internal.c, misc.c: Check both __STDC__ and _AIX to see if we should use stdarg instead of varargs. * Makefile.in (realclean): Don't delete TAGS. (distclean): Don't delete getdate.c. (all-gnats): Move edit-pr back with the other tools. * globals.h (APPEND_STRING): Added macro. * file-pr.c (APPEND_STRING): Delete it from here. * headers.c: Include config.h. (read_header): Rewrite to accept tab-continued headers. (set_continued_header): New function; special-cases Received: headers to accept as many as you want to give it. If KEEP_RECEIVED_HEADERS is false, it only does an assignment. (lookup_header): Deleted prototype, moved the function up so we don't need it. * config.h (KEEP_RECEIVED_HEADERS): Added. * Makefile.in (headers.o): Added dependencies. * query-pr.c (get_category): If we couldn't open the index, return a NULL. Mon Apr 12 14:55:33 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr.h (PR_Type): Typedef the enum. (PR_entry): Change `datatype' member accordingly. * file-pr.c (reply_to_submitter): Send mail to the address in the `Reply-To:' header if there is one; otherwise, just use the `From:' address. * pr-edit.c (main): When calling check_pr, arrange to exit non-zero if the PR didn't check out ok. * rmcat.sh: New file, mate to mkcat. * Makefile.in (DISTFILES): Add rmcat. (all-gnats): Likewise. (rmcat): New rule. (install-gnats): Install it. (clean): Delete rmcat. * mkdist.sh: Use XFOOX instead of @FOO@ for substs from GNATS. Use YFOOY for the substs mkdist does on the Makefile it creates. * Makefile.in (mkdist): Use XFOOX. We don't need to subst in LIBDIR. * query-pr.c (get_category): Don't say we couldn't find the PR in the index, since we'll later say we couldn't read it anyway. (query_pr): Check the return of get_category, and complain if it was null. Return an int ourselves. (main): If we got some errors, then exit with a non-zero status. * gnats-el.in (gnats-mail-PR-changed): Check if CC is null before adding the responsible person to it, so we don't try to send mail to `nil'. * edit-pr.sh: Use an arrow instead of wrapping from/to in braces. * gnats-el.in (gnats-change-field-and-update-audit-trail): Likewise. * main.c (main): If there's a PR.lock file, then leave and try again later, so we don't invite problems. Include unistd.h. Fri Apr 9 14:48:00 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * query-pr.c (print_path): New variable. (main): Set it if -P/--print-path. (print_pr): If `print_path' is true, then print out something that the emacs next-error function can grok. (usage): Update for the new options. * gnats-el.in (query-pr): Pass the -P option, and fix things so they'll work under both emacs 18 and emacs 19. * query-pr.c (skip_closed): New variable. (main): Set it if -x/--skip-closed. (query_pr): Use it to avoid closed PRs. * Makefile.in (DEFAULT_RELEASE, DEFAULT_ORGANIZATION): Don't wrap with quotes. (GNATS_VARS): Don't do it here either. * queue-pr.c: Include pathmax.h. (drop_msg): Use mktemp instead of tempnam. * internal.c (write_index): Likewise. Wed Apr 7 13:13:08 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gen-index.c: New file, to emit an index for an existing database. * Makefile.in (gen-index): New rule. (all-gnats): Added gen-index. (clean): Likewise. * queue-pr.c: Include unistd.h, sys/wait.h, and sys/param.h by hand; include gnats-dirs.h instead of queue.h. * queue.h: Renamed to gnats-dirs.h. * Makefile.in (DISTFILES): Change it. (queue-pr.o): Depend upon gnats-dirs.h instead. * Makefile.in (DEFAULT_ORGANIZATION): New variable. (GNATS_VARS): Pass it. * edit-pr.sh: Always send mail to the responsible person of a PR. * edit-pr.sh: Include the synopsis (both old and new if they changed) in the mail we send. Wrap from/to for responsible changes in <>'s, for names that have dashes in them (e.g., gnats-admin). Don't put an empty line between the synopsis and the change message. * gnats-el.in (gnats-change-field-and-update-audit-trail): Likewise. * query-pr.c (do_pr): Return an int (0 or 1 appropriately). (query_pr): Check for do_pr's return to see if we should output a newline or not. * queue-pr.c (drop_msg): Do a rename of the file to file, instead of file to directory. * edit-pr.sh (locked): Use cmp -s instead of the output of cmp to see if the PR has been changed. (mail_to): Don't send all status changes to gnats-admin. * query-pr.c (usage): Add originator options to the usage. * mkdist.sh (Makefile): Quote __EOF__ to avoid variable substitution inside the here document. After creating the Makefile, substitute in GNATS_SITE, the VERSION, and the release. (FILES): Change send-pr.elisp to send-pr-el.in. (send-pr): Likewise. (libdir): Add definition in the Makefile. (install-sid): Substitute bindir using commas to avoid sed problems. * Makefile.in (mkdist): Also substitute VERSION. * file-pr.c (gnats): Don't use S_IFDIR in the mode for pending or the category directory. * Makefile.in (GNATS_VARS): Put quotes around $(DEFAULT_RELEASE), in case it happens to have spaces in it. * files.c (get_responsible_address): Cut off anything after a comma in a passwd entry's gecos field, to avoid phone #s and such. * pr-edit.c (modify_pr): Copy the responsible field before chopping off the full name for the index. Mon Mar 29 15:01:10 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * file-pr.c (notify_responsible): Add a `Resent-From:' header. (append_report): Likewise. * query-pr.c (print_pr): Also print out the arrival date. Thu Mar 25 15:21:58 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-el.in (view-pr): Give the error as being from view-pr, not edit-pr. * edit-pr.sh (full_id): Look for "/$1:", not "$1:", to avoid matching spuriously against an incomplete set. (everywhere): Change temp filenames to be short enough not to go over 14 chars when we create the .old and .tmp files. (Subject): Use full_id, not full_pr. * file-pr.c (append_report): Only send mail to the person responsible for the PR, and to the submitter contact. * file-pr.c (append_report): Preserve the header values we recorded just before coming into append_report, so we use those for our outgoing headers, instead of the ones from the PR. Fri Mar 19 17:06:49 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-el.in (edit-pr): Say that GNATS itself is locked when we aren't given a username by pr-edit. (gnats-find-field): Return a null string, not t or nil. (gnats-get-reply-to): When using mail-fetch-field, pass arg ALL as nil, so we only get one copy of it if there's a `Sender:' field. When deciding what to return, check if REPLY-TO is both nil and an empty string. Wed Mar 17 15:34:14 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * file-pr.c (notify_responsible): Say "business hours". * Makefile.in (install-gnats): Install edit-pr also. * queue-pr.c (fork_gnats): Fix an off-by-one error. (main): Likewise. * misc.c (open_mail_file): Make sure BUFFER has enough room for the mail agent *and* all of the recipients, rather than arbitrarily pick 256 as a probably bogus value. Mon Mar 15 15:06:41 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * file-pr.c (append_report): Chop off the full name before getting the responsible address. (notify_responsible): Don't put `Re:' in the message going to the responsible people. Sat Mar 6 15:15:43 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (VERSION): Bump version to 3.00. * gnats-fc.eps (Title): Likewise. * gnats-el.in (view-pr): Add sample autoload. * edit-pr.sh (MAIL): Rename to MAIL_AGENT. (PR_EDIT, GNATS_ADDR): Fix directory names to be lower-case `gnats'. (locked): New variable. (option parsing): Use grep to find the '/' in the ID they gave us. Look for "$1:", not just $1, so we don't hit 1440 when looking for 144, for example. (trap): Add two traps to catch some signals. (HOSTNAME): New variable, grokked appropriately. (locking PR): Pass our username for the locking. (editing): If they didn't change anything, don't do anything with it. (checking): New variable; set the errors variable inside the loop. Search for quit with a case. ({old,new}_state, {old,new}_resp): Delete all whitespace. (audit trail): Append it properly. (filing): Redirect `$new' into PR_EDIT. * gnats.elisp: Renamed to gnats-el.in. * Makefile.in: Changed everywhere. * Makefile.in (clean): Also delete gnats.elc. * gnats.elisp (gnats-get-reply-to): Go to the beginning of the buffer before looking for the `From:' and `Reply-To:' headers. Fri Mar 5 09:53:45 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.elisp (gnats-mode-write-file-hook): In the cleanup-form, also check that the buffer's in gnats-mode before trying to change its write-file-hooks. (view-pr): New function. * file-pr.c (append_report): Put their message in the Audit-Trail, instead of under Unformatted. * headers.c (header_name): New function. * gnats.h: Added its prototype. * mkdist.sh (GNATS_SITE): Add. * file-pr.c (append_report): Include the `To:' header in what we append to the PR. Send mail to the right people about the new text in the PR. (notify_responsible): Free the stuff append_notify gives us. (append_notify): If notify hasn't had anything written to it, return a NULL. * gnats.elisp (gnats-get-reply-to): Correct how we return REPLY-TO then FROM to actually pass FROM if REPLY-TO is empty. (gnats-mail-PR-changed): If CC is null, pass an empty string to mh-send-other-window, not nil. (gnats-mode-write-file-hook): In the cleanup-form for the unwind-protect, make sure we're in the GNATS buffer before setting the WRITE-FILE-HOOKS, so we don't screw up the mail. Append it to the hook, don't cons it. (gnats-mode): Name the buffer so it's useful in a listing. Append our hook to WRITE-FILE-HOOKS, don't cons it. (edit-pr): If we're already editing a PR, just go to that buffer. * query-pr.c (print_pr): Trim off the full name from the responsible string for sql output. (main): Output a final newline if sql_format, since we don't supply it in print_pr. (do_pr): New function. (query_pr): Call it appropriately. Now properly handle having both a search list and search qualifiers. (found_match): New variable. * at-pr.sh: Say analyzed, not authorized. Wed Mar 3 14:20:44 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.elisp (edit-pr): Change arg NUMBER to ID; modify doc. * file-pr.c (notify_responsible): Add the proper From: field to the message, so it doesn't look like it's coming from the gnats user. * query-pr.c (long_options): Add -O/--originator. (originator): New variable. (main): Grok it, setting originator. (get_pr): New function. (print_pr): New argument `opened'; if not true, call get_pr. (query_pr): If originator is set, then read in the PR and check the originator field as well. * query-pr.man: Document it. * at-pr.sh: Don't look for and use the category, the argument we were given already has it on it. * edit-pr.sh: Say what user locked a PR. * Makefile.in (pr-edit): Depend upon version.o as well. * pr-edit.c (main): Parse new arg to -l, the username. (main, case 'l' and 'u'): Don't set fname, there wasn't an optarg then. (lock_pr): Write the username into the lock file. If the lock file already exists, tell who locked it on the stderr. * gnats.elisp (gnats-delete-buffer): Instead of killing the buffer, make it read-only and in text mode. (gnats-buffer-major-mode): Return the major mode for BUFFER. (gnats-kill-buffer): Call gnats-delete-buffer. (gnats-mode-map): Bind `C-c C-q' to gnats-delete-buffer. (gnats-unlock-all-buffers): New function, to cycle down the buffer list and call gnats-delete-buffer on each GNATS buffer. (gnats-mode): Add gnats-unlock-all-buffers to kill-emacs-hook. (gnats-patch-exec-path): Kill the error buffer when we're done. (gnats-check-pr): Kill the err buffer if the PR checked ok. (gnats-generate-new-buffer-name): New function. (gnats-delete-buffer): Call it. (gnats-mail-PR-changed): Do send mail in the other window, now that we're keeping the PR buffer. (gnats-mode-write-file-hook): Don't try to relock the buffer, we should only ever see this hook once. (edit-pr): If the PR is already locked, find out who locked it if we possibly can. Tue Mar 2 13:06:13 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.elisp (gnats-mail-PR-changed): Default CC to nil, to avoid having an empty `Cc:' header. * query-pr.c (main): Add 'q'. Only allow one formatting option. Only call query_pr once in any case. (long_options): Add new summary option -q/--summary. (print_pr): Don't emit a newline for the SQL stuff. Add printing of summary info. * query-pr.man: Document the new option. Mon Mar 1 16:45:54 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Rename gnats-addr to pr-addr, gnats-edit to pr-edit, and the gnats program to file-pr. Mon Mar 1 02:37:45 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * Makefile.in (gnats.info): No longer needs -I flag for makeinfo. (gnats.dvi): Needed "../send-pr" added to $TEXINPUTS. Sun Feb 28 15:44:42 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * globals.h (MAIL_AGENT): Define to use sendmail. (USE_BIN_MAIL): It's baaaaack, it's not defined. * internal.c (punt): Don't output a `.' at the end of the message. * gnats.c (reply_to_submitter, notify_responsible): Likewise. * misc.c (close_mail_file): Instead, do it here, if necessary. (open_mail_file): Only use the recipients arg when using /bin/mail. Sat Feb 27 00:28:19 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install-tools): Make gnats-edit set-uid gnats here too. * man/Makefile.in (TOOLSL, TOOLS1): Deleted. (install-tools): Use SRCS1 instead. * headers.c (read_header): If the line after a Received: header isn't a tabbed id, then just use it normally, don't swallow it. Only set `received' to TRUE, never turn it off again. (read_header): Cast strdup to a char*. * pr.c (init_pr): Don't init ANALYSIS, SOLVED_WHEN, or SOLVED_HOW. * pr.h (PR_Name): Delete them. (ANALYSIS_STRING, SOLVED_HOW_STRING, SOLVED_WHEN_STRING): Deleted. * mkdist.sh (FILES): Look for install-sid.sh, not install-sid. * gnats-edit.c (lock_pr): Return an int; if the lock file already exists, just exit with non-zero, don't send gnats-admin mail. * gnats.elisp (gnats-mode): They're `kept-{new,old}-versions'. (edit-pr): Put the temp file in /usr/tmp, since backup-buffer refuses to create backup files in /tmp. (gnats-mail-PR-changed): Don't mail in the other window. Call gnats-kill-buffer after the mail's set up. (gnats-kill-buffer): Make interactive; if the PR is locked, unlock it. Delete the backup file we created as well. Kill the error buffer we were working with. (gnats-mode): Bind `C-c C-q' and `C-x k' to gnats-kill-buffer. (gnats-mode-write-file-hook): Call save-buffer with 64, to create the backup file; call gnats-kill-buffer if we aren't sending mail. Force the write-file-hooks reversion to be true, since we could have a null list of hooks. If gnats-check-pr failed, then bring up the error buffer in the other window, so they can fix things up. (gnats-get-list): Go to the buffer we were passed if we're not already in it. (gnats-delete-backups): New function. (gnats-kill-buffer): Use it. * query-pr.c (print_pr): Pass !full_report into read_pr, so we know if we should prune the reading or not. * gnats.elisp (edit-pr): Use make-temp-name instead of random for generating the temporary filename. (gnats-mode): Use make-variable-buffer-local instead of make-local-variable. (gnats-kill-buffer): New function. (gnats-mode-write-file-hook): Call it. * index.c (create_index_entry): Modify a copy of the responsible field, not the field itself. * gnats-edit.c (modify_pr): Prune off the full name so the index doesn't get it. * gnats.c (reply_to_submitter): New arg `responsible'. Create a Reply-To: header that has GNATS_ADDR and the responsible person on it. (gnats): Pass it down. (append_notify): Initialize notify_len to 0. * gnats-edit.c (modify_pr): Init lock_file to NULL; only call unlink when we're not using force. When looking for the PR in the index, be careful not to use prev_index before we actually set it. * pr.c (read_pr): If the PR had an Unformatted field, don't wipe it out; instead, tack it onto the end of the things we've been progressively adding to it. * headers.c (lookup_header): Do a case-insensitive match on the header name. * gnats-edit.c (check_pr): Also warn if the Number field is missing. * gnats.c (gnats): Check for a '\0' at the beginning of the line for the synopsis and subject as well. Fri Feb 26 13:06:00 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-edit.c (modify_pr): Unlink the .old file when we're done. * internal.c (write_index): Pass gnats_root into sprintf; include the trailing slash. Copy the file if a rename didn't work. * Makefile.in (mkdist): New rule. (all): Depend upon it. (install): Don't use install-man. (install-gnats): Instead, use it here. (install-tools-man): New rule. (install-tools): Use it. (tools-man-pages): New rule. (all-tools): Use it. * man/Makefile.in (install-tools-man, all-tools): New rules. * gnats.elisp (gnats-pr-errors): New variable. (LIBDIR): New variable, substituted in by make. (gnats-indent, gnats-states, gnats-state-following): New variables. (gnats-check-pr): Run `gnats-edit --check' on the current PR, and set gnats-pr-errors if there were any. (gnats-file-pr): Call `gnats-edit' to file the PR, returning NIL if it failed. (gnats-mode-write-file-hook): Call gnats-check-pr first to check it, then gnats-file-pr to put it into the database; finally, unlock it. If the PR was locked since the last time we tried to write the file, tell the user about it. (gnats-mode): Don't require send-pr anymore. Set up a new local variable BUFFER-PR. (gnats-keyword, gnats-before-keyword, gnats-after-keyword): New vars. (gnats-get-list): Renamed to gnats-get-list-from-file; added new fn named this, to do the actual list creation. (gnats-set-responsibles, gnats-set-categories): Use ...-from-file. (gnats-lock): New function. (edit-pr): Lock the PR before trying to edit it. If it's already locked, tell the user. * Makefile.in (gnats.el): Substitute LIBDIR in. * Makefile.in (FLAGS_TO_PASS): New variable. (install-man): Pass them also. * Makefile.in (install-man): New rule. (install): Fire on it. (install-gnats): Install mkdist. (install-tools): Install edit-pr. * gnats.c (gnats): Use field_value, instead of a direct usage of `pr'. Thu Feb 25 15:38:32 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.c (gnats): Don't wipe out the responsible field if it comes in with a valid one already. Wed Feb 24 20:34:41 1993 Tim Wicinski (tim@cygnus.com) * pr.c (init_pr): Don't set pr[ORIGINATOR].name = Text, set its datatype. Wed Feb 24 13:04:50 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * main.c (main): Don't close fp here. * gnats.c (gnats): Instead, do it here. (append_report): And here. * files.c (init_responsibles): Close the responsible file after we're done reading it. * pr.c (init_pr): Set the type of ORIGINATOR to be Text. * configure.in (AC_SCO_SOCKET): Add new check. (AC_HAVE_LIBRARY): Instead of a generic -lsocket check. * main.c (unlock_death): New function, to unlock GNATS when we get a serious signal. (main): Use it as the handler for various deadly signals. * gnats.c (run_atpr): Rename `pr' parameter to `bug_name'. Fix an off-by-one error. Tue Feb 23 16:14:37 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * queue-pr.c (run_gnats): Say each file that's being processed if flag_debug's set. * gnats.c (run_atpr): Look for /usr/bin/at then /bin/at. * pr.c (init_pr): Set the datatype for SOLVED_WHEN, not ANALYSIS, for the SOLVED_WHEN field. * gnats.c (append_notify): Allocate buf dynamically, since we'll be using it a few times; don't leave it on the frame. * internal.c (unlock_gnats): Don't complain about the file not being there, since we often call unlock_gnats via punt, which can get called before lock_gnats. * gnats.c (append_notify): If the person isn't in the responsibles file, don't give up on them, just include that address (it may be an alias). * gnats.c (get_bug_number): Don't try to read from the current file that we just created. (append_notify): Make START begin as a null ptr, so we don't try to use it later. Don't dereference it if it's still null. (notify_responsible): Don't create an In-Reply-To: header if we didn't get enough info from their message. Tue Feb 23 15:33:56 1993 Tim Wicinski (tim@cygnus.com) * Makefile.in: make sure gnats-edit and queue-pr depend on internal.o to relink. Tue Feb 23 15:11:21 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * internal.c (punt): Don't try to write to a null file ptr. Remember to unlock gnats before exiting. Tue Feb 23 15:08:15 1993 Tim Wicinski (tim@cygnus.com) * files.c (get_adm_record): change bumping of array constant to prevent returning the old 'off-by-one' value. Tue Feb 23 12:33:10 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (LIBPROGS): Deleted var. (LIBS): Make many rules use it the way they should. (install-gnats): Create $(libdir)/gnats first. Chmod gnats-edit in libdir now. (gnats.info): Look in ../send-pr. * configure.in (AC_HAVE_LIBRARY): Look for -lsocket and -linet for syslog. * gnats.h (get_next_field): Fix prototype. Tue Feb 23 12:15:56 1993 Tim Wicinski (tim@cygnus.com) * queue-pr.c: changed queue directory to be 'queue-pr', like it is in the Makefile. fixed FIXME to call punt if chdir fails. Tue Feb 23 10:44:08 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install, install-tools): Drop in gnats.el. (lispdir): New variable. * Makefile.in (install, all): Change to install-gnats and all-gnats. (ALL, INST): New vars. * Makefile.in (install): Put gnats-edit and gnats-addr in $(libdir)/gnats, so we can export GNATS_ROOT safely. (all-tools, install-tools): New rules. * edit-pr.sh (LIBDIR): Added. (GNATS_EDIT): Changed to look in libdir. (GNATS_ADDR): Likewise. * Makefile.in (all): Added edit-pr. (edit-pr): New rule. (at-pr): Substitute libdir in. (clean): Delete edit-pr. * at-pr.sh: Run gnats-addr out of LIBDIR. * misc.c (mkdir): Added fn, used only with HAVE_MKDIR set. * configure.in (AC_HAVE_FUNCS): Look for mkdir. * Makefile.in (DISTFILES): Add getdate.c and TAGS. * mkcat.sh: Only check for the existance of $LIBDIR/gnats. Mon Feb 22 13:59:35 1993 Tim Wicinski (tim@cygnus.com) * Makefile.in: remove internal.o from where it is not needed anymore. * files.c: should of checked it the first time... Mon Feb 22 13:47:02 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-addr.c (main): If get_responsible_address doesn't give us anything, don't try to keep going. * mkdist.sh: Finish things up; drop in all files that're necessary, include the categories list, and generate a Makefile for the whole thing. Mon Feb 22 02:13:35 1993 Tim Wicinski (tim@cygnus.com) * query-pr.c: call punt instead of log_msg (LOG_ERR). missed last time. * queue-pr.c: another miss of calling punt instead of log_msg. * gnats.h: moved extern defs of procs in internal.c into globals.h * globals.h: received new external procedure defines. * misc.c: removed copy_file out of here.... * internal.c: ...and placed it in here. * main.c(main): call init_responsibles () here now, and punt if it doesn't build the chain up. * files.c(find_responsibles): now if responsible_chain is NULL, go back and do the old method of scanning the responsibles file line by line. useful for gnats-addr. (init_responsibles): returns a 0 or 1 depending on success of building the linked list. * misc.c: moved procedure punt () from here. removed calls to unlock_gnats from log_msg. changed open_mail_file to return NULL if popen() fails. * internal.c: moved punt () to here. added includes for varargs. * gnats.c(gnats): changed call to log_msg to punt instead. * gnats-edit.c: removed unneed define to config.h * files.c(find_responsibles): don't punt if init_responsibles () fails, just return NULL. removed all calls to punt, have NULL returned instead. * main.c: change LOG_ERR to LOG_INFO and exit. * files.c: fixed prototype for init_responsibles. * internal.c: forgot \n on the fprintf statements. * Makefile.in: include internal.o to everything that uses libgnats.a for the time being. this needs to be worked out still (release/build issue). * internal.c (lock_gnats/unlock_gnats): rewritten to now lock and unlock gnats-adm/gnats.lock. * query-pr.c: made to use lock_gnats and unlock_gnats. * gnats-edit.c: likewise. * main.c: ditto. * misc.c (punt) * (log_msg): use unlock_gnats. * gnats.h: fixed typo. * globals.h: removed unused define GNATS_LOCK. * gnats.c (get_bug_number): remove all references to file locking in this procedure. Perform this task once per run. Mon Feb 22 01:35:47 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * index.c (get_index): If we couldn't open the index, then return a null Index*. * gnats-internal.c: Renamed to internal.c. * Makefile.in: Change accordingly. * gnats.elisp (gnats-err-buffer): New constant. (gnats-mode): Still require 'send-pr for now. (gnats-set-responsibles): Grok the responsible list instead of trying to run query-pr. (gnats-set-categories): New function, grok categories instead of running send-pr. (gnats-get-list): New function, return a list of the first entries from FILENAME. (gnats-get-pr-category): New function, return the category for a problem report given NUMBER. (has-slash): Return T if STRING contains a '/'. (edit-pr): Change around to look in the newly structured GNATS database, and edit a copy of the file, not the file itself. (query-pr): Run query-pr, not query_pr. Mon Feb 22 01:08:12 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * edit-pr.sh: added support for gnats-edit (untested) Mon Feb 22 00:14:04 1993 Tim Wicinski (tim@cygnus.com) * gnats-internal.c: new file containing functions not really need for libgnats.a, but useful for many of the gnats internal programs. * index.c: moved write_index. * gnats.c: moved add_to_index, lock_gnats, and unlock_gnats. * gnats-edit.c: moved add_to_index. * misc.c: moved block_signals and unblock_signals. * gnats.h: update prototypes. * Makefile.in: added gnats-internal.c, moved and changed and cleaned up SOURCES and OBJECTS. * gnats.c(notify_responsible): now goes thru the lists of people needing to be notified, and calls get_responsible_address for each one. * gnats.c(append_notify): new procedure to assist in building the addresses. Sun Feb 21 23:49:44 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * .Sanitize: keep new file MANIFEST * README: a little jazzier * INSTALL: "install" section from gnats.texi * MANIFEST: New file. * gnats.texi: a wee bit o' cleanup * gnats.info: current with gnats.texi Sun Feb 21 23:15:06 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr.c (check_enum_types): Use strcasecmp to avoid case problems with the value of a field (e.g., `critical' vs an emphatic `CRITICAL'). Sun Feb 21 22:50:49 1993 Tim Wicinski (tim@cygnus.com) * files.c (find_responsible): rewritten to use new routine to build linked list of responsible persons. (get_responsible_address): changed to only return NULL if not found, let calling proc deal with rejects. (init_responsibles): new routine to read in responsibles file into linked list. (next_record): new function used by init_responsibles. basically ripped off from get_adm_record. * files.h (Responsible): added field 'next' to structure * globals.h: added external definition for head of responsibles linked list. Sun Feb 21 14:25:01 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * query-pr.c (pr_matches): Make it an exclusive test, not an inclusive one. * misc.c (get_token): Don't skip whitespace before a field's name; if it's got whitespace in front of it, it's probably part of the PR itself and should not qualify as a normal PR field. * index.c (create_index_entry): If there's no responsible field, then just leap. * pr.c (check_enum_types): Clear out the `next' field of bad_enums_end each time we have a new one. * queue-pr.c (strip_trailing_slashes): Delete function. (copy_reg): Put in misc.c as copy_file. (fork_gnats): Use strerror (errno) instead of just the errno for punt calls. Just return the status, don't worry about what it might mean yet. (drop_msg): Give the name of the queue file and the errno string when a rename failed. When unlinking the queue file fails, log it as an error, not as info. * gnats.h (copy_file): Add prototype. * misc.c (punt): Make it use varargs, calling vfprintf. * gnats-edit.c (modify_pr): Allocate the paths when we actually need them; give lock_path, not path, to punt for trying to find the lock file. Copy the file if rename failed with EXDEV. (main): Just exit if the filename given as an arg to `-f' for checks. (lock_pr, unlock_pr): Fix messages. (long_options): Change "usage" to "help" and "file" to "filename". (usage): Fix usage to have gnats-edit options, not gnats options. (version): It's "gnats-edit", not "edit-pr". (force): New variable, to bypass checking for an old entry for the PR. (add_to_index): Added function, same as in gnats.c but I don't want it going into the library. Sun Feb 21 00:05:03 1993 Tim Wicinski (tim@cygnus.com) * queue-pr.c: fixed typo * pr.c(read_pr): now use prune variable to skip large fields. only called via query-pr. * queue-pr.c: use punt and log_msg instead of error. * gnats-edit.c: make correct use of punt. Sat Feb 20 22:39:06 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (clean-man): Added rule. * gnats-edit.c (usage): Don't declare with a prototype; make static. (index_chain): Make local to modify_pr. (main): Call usage, delete usage for gnats. * man/Makefile.in: New file. * Makefile.in (SENDPR_VARS): Renamed to GNATS_VARS. (all): Depend upon man-pages instead of man/gnats.8. (man-pages): New rule. (install): Don't install any man pages. (clean): Don't delete them. * config.h (DEFAULT_SUBMITTER): New option. * gnats.c (gnats): Use it instead of `UNKNOWN'. * gnats.h (UNKNOWN): Deleted. * pr.c (init_pr): Set SUBMITTER's default value to DEFAULT_SUBMITTER. * Makefile.in (install): Install gnats-addr. (at-pr): Depend upon Makefile, so variable changes get caught. (mkcat, gnats.el, man/gnats.8): Likewise. (clean): Delete gnats-edit. Sat Feb 20 22:02:24 1993 Tim Wicinski (tim@cygnus.com) * Makefile.in: added gnats-edit, as well as added install rules. Sat Feb 20 20:42:05 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * mkcat.sh: Add the category to the list in gnats-dist and to the one in $LIBDIR/gnats. Don't use awk to get the categories list. * Makefile.in (mkcat): Also substitute LIBDIR and GNATS_SITE. * config.h (USE_BIN_MAIL): Deleted. * globals.h (MAIL_AGENT): Define to BIN_MAIL. * misc.c (open_mail_file): Use the /bin/mail case, but use MAIL_AGENT instead of BIN_MAIL. (punt): Likewise. * gnats.c (reply_to_submitter): Likewise. (notify_responsible): Likewise. * All files: change `remote' to `responsibles'. * pr.c (read_pr): Make prune an int. * gnats.h (read_pr): Change prototype. * gnats.c (gnats): Cast call to strdup to return `char *'. * Makefile.in (clean): Also remove gnats-addr and query-pr. * index.c (create_index_entry): Change return type to void. (find_pr_category): Return NULL with bad cases. (open_index): Return a NULL file ptr if it can't open the file. * gnats.h (create_index_entry): Change prototype. * query-pr.c (main): Cast nulls. Sat Feb 20 19:09:48 1993 Tim Wicinski (tim@cygnus.com) * gnats-edit.c: latest checkin. all but --modify should be fine. * gnats-edit.c: --lock, --unlock, and --check seem to be working now. The setuid stuff should be looked at more closely. * gnats.c: moved signal blocking procedures to misc.c * misc.c: placed signal blocking procedures. * index.c: removed local signal blocking procedures. * gnats.h: added prototypes for block_signals and unblock_signals. Sat Feb 20 18:42:07 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (VPATH): Don't put it in here. (GNATS_SITE, DEFAULT_RELEASE): New variables. (SENDPR_VARS): New variable to pass into send-pr's Makefile. (all): Add config-send-pr, change gnats.8 to man/gnats.8. (config-send-pr): New rule. (install): Don't put the samples in if there are files already there. Also install the man pages. (install-info): New rule. (gnats.8): Changed to man/gnats.8, changed usage inside it. * gnats.elisp (gnats-responsibles): New variable. (gnats-set-variable-from-shell): New function. (gnats-set-responsibles): New function. Sat Feb 20 18:33:17 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * gnats.texi: minor changes to install section * gnats.info: New file. Sat Feb 20 03:26:02 1993 Tim Wicinski (tim@cygnus.com) * gnats-edit.c: slowly lumbering towards something useful. still needs work, but more is now understood of what is required by it. Fri Feb 19 23:05:01 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr.c (check_enum_types): Return a `struct bad_enum *'. * gnats.h (bad_enums): Delete ref. (check_enum_types): Change prototype. * gnats.c (gnats): Set it. Fri Feb 19 22:43:58 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * gnats.texi: teach me to compile BEFORE I check in... * gnats.texi: added query-pr and edit-pr info * at-pr.man: removed, what was I thinking... Fri Feb 19 15:20:39 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * at-pr.sh: Use /bin/mail, and mention what category the PR is in. * pr.c (check_enum_types): New arg `check'. Add a msg to bad_enums if check is true. (bad_enums, bad_enums_end): New vars. * gnats.h: Declare bad_enums. (bad_enum): New type. (check_enum_types): Change prototype. * gnats-edit.c (modify_report): Send in a 2 for check. * gnats.c (reply_to_submitter, notify_responsible): Tell them about the bad enums. * gnats.c (notify_responsible): Add timezone to time for analysis. * pr.c (check_enum_types): Check if the value's an empty string also. * pr.c (init_pr): There's no `System:' field. * pr.h (SYSTEM, SYSTEM_STRING): Deleted. * main.c (long_options, main): New --help option. * query-pr.c, queue-pr.c: Likewise. * pr.c (write_pr): Only write out the requested field's value if it's non-null. * query-pr.c (query_pr): Also check if S is non-null before trying to do every PR. * at-pr.sh: Grok the responsible person, using gnats-addr. No longer check for an empty synopsis, since GNATS won't let it have one anymore. * gnats-addr.c (main): Only take the first piece, ignore any real name stuff. * gnats.c (run_atpr): Don't bother giving at-pr the responsible person, it no longer needs it. Deleted arg `resp'. Change prototype. (gnats): Don't pass responsible down. * Makefile.in (LIBSRC): New variable. (TAGS): Use it. * gnats-addr.c: New file. * Makefile.in (DISTFILES): Add gnats-addr.c. (all): Add target. (gnats-addr): Add rule. (SOURCES, OBJECTS, LIBOBJS): Put files.o in the library. * globals.h (Remote, get_remote_addr): Move to gnats.h. * query-pr.c (main): Trim the program name with basename. * queue-pr.c (main): Likewise. * query-pr.c (long_options): Add --full and --sql. (full_report): New variable. (main): Set it if -i/--sql. Run thru the whole index if they're not searching for something special. (get_category): If full_report is true, print the entire thing out, instead of just the choice bits. If sql_format's true, print out its special format. (sql_types, sql_time): New functions. (usage): Update it. * getdate.y: New file. * Makefile.in (DISTFILES, distclean, getdate.c, query-pr): Take care of it. * configure.in (AC_HAVE_FUNCS): Look for ftime. * index.c (write_index): Use tempnam instead of mktemp. Fri Feb 19 02:49:36 1993 Tim Wicinski (tim@cygnus.com) * gnats-edit.c: new program, suppsoedly setuid. This code has NOT been tested. It is checked in as a start. More will come later. * index.c: new function write_index to write an index chain to disk. currently only write a temp file. * gnats.h: new prototype for write_index. Thu Feb 18 22:36:27 1993 Tim Wicinski (tim@cygnus.com) * pr.c(read_pr): added prune option to read_pr to speed up reads during queries and edits. not used yet. * gnats.c: added extra flag to read_pr. * query-pr.c: added extra flag to read_pr. * gnats.h: added extra flag to prototype. * Makefile.in(LIBOBJS): added entry for index.o * index.c: new file, containing all current index related functions. * gnats.h: extern definition for get_index added. rearranged some other externs definitions. * misc.c: removed all old function calls that are now in index.c. * query-pr.c: moved function get_index to index.c Thu Feb 18 22:30:11 1993 Brendan Kehoe (brendan@cygnus.com) * main.c (main): Change getopt string, -D doesn't take an arg. * pr.c (read_pr): Only trim until we see a non-whitespace char, not all the way back leaving only the first word. Thu Feb 18 18:34:27 1993 Tim Wicinski (tim@cygnus.com) * query-pr.c: used PATH_MAX instead of root_len, quicker to calculate. Removed structure Search, used Index instead since it is almost identical. get_index now returns Index*, and is ready to move to misc.c * query-pr.c(query_pr): builds a proper path if variable p contains a partial path (ie, based on GNATS_ROOT). * query-pr.c(main): if -d is called, recalculate the root_len to prevent malloc woes. * gnats.c(free_remote): don't try to free ptr's if they point to GNATS_ADMIN. * gnats.c(gnats): set the category field when it is changed to pending in the case where the category exists, but the directory doesn't. * gnats.c (gnats): if synopsis is NULL, then dup the Subject string, so subject doesn't get the newline stripped. this caused problems in writing out the PR. * headers.c(header_init): removed X_MODE. * headers.h: removed X_MODE. Thu Feb 18 18:21:25 1993 Jeffrey Osier (jeffrey@cygnus.com) * edit-pr.sh: uses @GNATS_ROOT@ rather than leaving it blank * gnats.texi: more minor clean-up Thu Feb 18 15:27:49 1993 Tim Wicinski (tim@cygnus.com) * files.c(get_remote_address): since get_adm_record dups a null string, an empty field will not be just NULL, but "". Change the check if remote->alias is there, to check for empty string. Perhaps it still should check if remote->alias == NULL... * misc.c(create_index_entry): append newline to index entry, since fputs does not do this for us. * pr.c(read_pr): added check so oldi is not used if still -1. * gnats.c(gnats): moved add_to_index so where it get run regardless of the pr being submitted is still pending or not. Thu Feb 18 14:22:00 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (clean): Use `$(LIBGNATS)'. Thu Feb 18 01:36:15 1993 Tim Wicinski (tim@cygnus.com) * Makefile.in(clean): libgnats.a isn't getting deleted during a 'make clean'. * headers.c(read_header): added check to see if any headers were actually found, and if not, rewind the file. * misc.c(create_index_entry): pull out responsible information before writing the index, and strip the fullname which is now part of the field value. * gnats.c(notify_responsible): changed the xmalloc back to STR_MAX for the time being. this still needs to be dealt with. Wed Feb 17 22:58:50 1993 Tim Wicinski (tim@cygnus.com) * gnats.c(add_to_index): move call to create_index_entry from outside of fputs call, which core dumps on sgi currently. * gnats.c(gnats): if 'synopsis' is null, use subject, but strip newline (opposite of previous fix). Wed Feb 17 17:57:33 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr.c (read_pr): Trim off spaces from the end of field values before storing them. * gnats.c (gnats): If `subject' is NULL, then they didn't give us one; synopsis is either-or. Append the newline to the `Subject:'. * Makefile.in (all): Add query-pr. * gnats.c (add_to_index): Don't index the class, add confidentiality and priority. * pr.h (Index): Add members `confidential' and `priority', delete `class'. * misc.c (next_index_entry): Grok the new fields, don't set the class. * query-pr.c (pr_matches): Search for the new entries. * misc.c (create_index_entry): New fn. * gnats.c (add_to_index): Call it. * Makefile.in (gnats.8): Update rule. (clean): Remove it. Wed Feb 17 14:53:03 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * edit-pr.man query-pr.man gnats8.man queue-pr.man at-pr.man mkdist.man mkcat.man: New files in man/. * edit-pr.sh: Changed $EDITOR call for changed-why messages to just ask for terminal input using `cat'. * edit-pr.sh: Took out stderr redirect on $EDITOR calls. Wed Feb 17 10:48:00 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * configure.in (AC_ALLOCA): Removed. Wed Feb 17 08:35:37 1993 Tim Wicinski (tim@cygnus.com) * gnats.h: Removed defines for alloca, since it is never used now. * gnats.c(reply_to_submitter): Removed arg `fullname', since it now gets set in the responsible field as part of gnats. Changed prototype. Tue Feb 16 20:11:47 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * gnats.man: added new `man' directory, moved gnats.man * edit-pr.sh: New file. Tue Feb 16 17:09:25 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * misc.c (next_index_entry): Return an `Index *'; dynamically allocate buf, don't use the frame. * gnats.h (next_index_entry): Change prototype. (Index): New member `next'. * query-pr.c: New file. * Makefile.in (DISTFILES): Added queue-pr and query-pr.c. (query-pr): Added rule. * globals.h (mail_agent, gnats_root, Logging_Methods, log_method): Moved into gnats.h. * main.c (mail_agent, gnats_root, log_method): Init in misc.c instead. * misc.c: Include pathmax.h. (open_index): New function to open the index file for reading. (next_index_entry): New function to return the next index entry in the index file. (find_pr_category): Quickly yield the category for a given PR. (close_index): Close the index file. * pr.h (Index): New type. * gnats.h (open_index, close_index, find_pr_category, next_index_entry): Add prototypes. Tue Feb 16 16:06:17 1993 Tim Wicinski (tim@cygnus.com) * gnats.c (gnats): Handle cases if subject or synopsis are blank, and fill in accordingly (or not at all, if both are blank). * pr.c (notify_responsible): Changed size of buf to be from STR_MAX to be 32 (for english, i count 26, this will give a little more space if need be). * btime.c (get_response_time): Deal with edge cases like PRs getting submitted at BDAY_END. Also changed some of the structure so weirder edge case like bugs submitted at 5pm friday might get dealt with better. Tue Feb 16 15:20:10 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.h (is_space): New array. (SKIP_WHITE_SPACE): New macro, to do array lookups. (init_space): Add prototype. * misc.c (SKIPWHITESPACE): Deleted macro. (init_space): New function. (init_gnats): Call it. (get_token): Use the new SKIP_WHITE_SPACE instead of a while loop. * pr.c (SKIPWHITESPACE): Deleted macro. (read_pr): Use the new one instead. * pr.c (write_pr): Line the field values up. Tue Feb 16 14:55:53 1993 Tim Wicinski (tim@cygnus.com) * pr.c (read_pr): Fixed so it doesn't swallow a completely bogus PR. Tue Feb 16 14:41:39 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * man/gnats.man: added new `man' directory, moved gnats.man Tue Feb 16 14:33:49 1993 Tim Wicinski (tim@cygnus.com) * misc.c (get_next_field): checks for end of string before attempting to skip over white space. Tue Feb 16 11:26:38 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.c (safe_env): Deleted. * globals.h (append_report): Add prototype. * main.c (main): Delete unused var `reply'. * misc.c (get_next_field): Don't make arg `delim' unsigned. (read_string): Delete unused var `i'. * gnats.h: Include memory.h if HAVE_MEMORY_H is defined. * headers.c (write_header): Only pass name if the value's empty. * headers.c (readHeader): Rename to `read_header'. (LookUpMailHeader): Rename to `lookup_header'. (writeHeader): Rename to `write_header'. (initHeader): Rename to `init_header'. (GetHeaderValue): Rename to `header_value'. (SetHeaderValue): Rename to `set_header'. * misc.c (GetToken): Rename to `get_token'. * pr.c (readPR): Rename to `read_pr'. (writePR): Rename to `write_pr'. (initPR): Rename to `init_pr'. (LookUpPRHeader): Rename to `field_name'. (GetPRValue): Rename to `field_value'. (SetPRValue): Rename to `set_field'. * gnats.c (Free*): Rename to `free_foo'. * gnats.h: Change prototypes. * misc.c (init_gnats): New function. * gnats.h (init_gnats): Add prototype. * main.c (main): Call it, instead of initPR and initHeader. * main.c (debug_level): Move into misc.c. (logfile): Move into misc.c, renaming to `gnats_logfile'. * globals.h (debug_level): Move decl into gnats.h. * gnats.h (gnats_logfile): Add extern decl. * gnats.c (notify_responsible): Avoid null dereferences. Tue Feb 16 10:32:49 1993 Tim Wicinski (tim@cygnus.com) * pr.c (LookUpPRHeader): Should not take the length of a string before checking it. strcmp called w/o its length argument. Mon Feb 15 22:18:01 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * gnats.man: Deleted rcs info, added note about mkdist. * gnats.man: `gnats (l)' up to date for version 3.0 Mon Feb 15 20:12:58 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr.h (ALTERNATE_SUBMITTER): New macro, used for backwards compatability. * pr.c (LookUpPRHeader): Only take the length of STRING once. Make it return a PR_Name, not a short. If STRING matches with `ALTERNATE_SUBMITTER', then return that it matches as the SUBMITTER PR field name. * Makefile.in (OBJECTS, LIBOBJS): Move headers.o, misc.o, and pr.o into LIBOBJS. Move version.o into OBJECTS. (LIBGNATS): New variable and rule. (AR_FLAGS): New variable. (all, gnats, queue-pr): Depend upon and use $(LIBGNATS) instead of $(LIBOBJS). * files.c (find_remote): Make a static fn. * globals.h (find_remote): Delete prototype. * gnats.h: Move most prototypes into globals.h. * globals.h (bool, TRUE, FALSE): Move into gnats.h. * misc.c (lock_gnats, unlock_gnats, block_signals, unblock_signals): Move into gnats.c. * gnats.c: Make each of them static. * gnats.h: Delete their prototypes. * resp-lookup.c: Don't need to include globals.h. * gnats-queue.c: Renamed to queue-pr.c. * msg.h: Renamed to headers.h. * msg.c: Renamed to headers.c. Include headers.h instead of msg.h. * gnats.h: Include headers.h instead of msg.h. * Makefile.in: Changed names throughout. * gnats.c (gnats): Call check_enum_types. * pr.c (readPR): Not here. (check_enum_types): Include the PR number in the report about a bad field. * gnats.h (check_enum_types): Add prototype. * pr.c (check_enum_types): Reset `found' for each field. Pass the default_value for the token, not two values. Always set it to the default value, since every enumerated field should have one. (PRentry): Move struct to pr.h, renaming it to `PR_entry'. * misc.c (get_next_field): Make arg `delim' be an unsigned char, not an int. * pr.c (SetPRValue): Avoid calling xmalloc until we know we need to use the token. * gnats.c (notify_responsible): Renamed `snotify' to `subnotify'; check for an empty subnotify or cnotify. New arg `subcontact', the contact for a submitter should also receive the message. Make it legal to have a null submitter contact. (gnats): Pass it in, calling get_remote_address for their address, if it's in there. * resp-lookup.c: Don't include pwd.h. (get_responsible): Just call get_remote_address. since we never use the Remote info * files.c: Include pwd.h here instead. (get_address): New function, was the body of get_responsible. Instead of dup'ing PERSON twice, just set key and alias to be the same ptr if PERSON was in the alias file. Say remote entry not found, not responsible person not found. (get_adm_record): Check that read_string returns >0, to avoid infinite loop. Mon Feb 15 20:02:55 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * gnats.man: Added old one, will change. Mon Feb 15 04:22:33 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * misc.c (append_string): Deleted, not used any more. * gnats.h (append_string): Deleted prototype. * mkdist: New file. * Makefile.in (infodir): Added variable. * msg.c (decode_site): Deleted function; this will be done differently later. * msg.c (writeHeader): If the value of the header's null, just output the header name. * gnats.c (notify_responsible): If the Subject's empty (or non-existant), emit the missing newline. * pr.h (PR_Name): Change use of `CUSTOMER_ID' to `SUBMITTER'. * pr.c (initPR): Likewise. * gnats.c (gnats): Likewise. (add_to_index): Also put the submitter in the index. Don't end the line with a trailing colon. Sun Feb 14 16:44:01 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats.c (notify_responsible): Only talk about when they should send a response if verify_analysis() is true. * gnats.c (verify_analysis): Check for strcmp == 0 explicitly, and don't reverse the logic. * files.c (get_adm_record): Delete the trailing newline. * gnats.c (reply_to_submitter, notify_responsible): Clean up when to insert a newline for a header. * main.c (flag_ack, flag_notify, flag_no_atpr): Give default values as specified by config.h. (long_options): Delete options `notify', `no-atpr', and `acknowledge'. (main): Change getopt string. * gnats.c (gnats, notify_resonsible): Use them. * globals.h (flag_ack, flag_notify): Declare. (flag_no_atpr): Delete. * misc.c (close_mail_file): Call fflush before pclose. * gnats.c (run_atpr): Don't call fclose on the pipe. * files.c (get_adm_record): Also ignore empty lines. * Makefile.in (at-pr, mkcat, gnats.el): Look in srcdir for the originals. Create temporary outputs, moving them to their real names, on the off chance a sed command failed. * Makefile.in (MAKEINFO, TEXIDIR): New variables. (info, dvi): Depend upon gnats.texi. (gnats.info, gnats.dvi): Add rules. (install): Install gnats.info* into infodir. Fix arbitrary line truncation. * misc.c (read_string): Don't delete the trailing newline. If the line is empty, return a length of 1. * msg.c (readHeader): Change what it thinks is a blank line. Don't emit a newline between the `Received:' header and its continuation, since it now ends in a newline itself. (writeHeader): Don't emit a newline after any header. * pr.c (readPR): Only go after tokens if the length's > 1. Don't add any newlines; if it's a non-MultiText field, then take the newline off then---they're the only fields that have a value that needs it removed. * msg.c (initHeader): Delete extra space after `References:'. (writeHeader): Don't put a space between the name and value if it's SM_FROM (aka, `From '). * pr.h (PR_START_FIELD): New macro. * pr.c (readPR): Only try to resolve tokens if they could possibly be a PR field (they begin with PR_START_FIELD), so we can (among other things) avoid trying to match every RFC-822 header. Instead of assigning `l' and then just setting it again, pass line itself down into GetToken. * misc.c (read_string): Return the length of the string. Decrement `i' if it's got a newline at the end. * pr.c (readPR): Get the length of the line here, to avoid calling strlen twice on the same string. If len was 0, then avoid doing the lookups. Call xrealloc instead of doing it by hand. * gnats.h (read_string): Change prototype. * msg.c (readHeader): Make `i' an int, not a short. * gnats-queue.c (fork_gnats): Pass `-D' into gnats if gnats-queue was given an arg to set flag_debug. * Makefile.in (clean): Delete mkcat. * gnats.c (gnats): Fix call to punt, it should be fatal when it can't create pending. * main.c (main): Use punt, not error. * gnats.h (close_mail_file, log_msg): Add prototypes. (find_submitters): Fix typo, it's find_submitter. * gnats.h: Don't include pr.h. * pr.c (readPR1): Deleted, the new readPR works. (struct PRentry): Delete field `created'. (initPR): Don't set it, we don't need it. (readPR): Use memcpy, not bcopy. * Makefile.in (all, mkcategories, install): Change to mkcat. * gnats.h: Include sys/types.h for things like dev_t that might show up in sys/stat.h. * mkcat.sh (GNATS_ROOT, CATEGORIES): Adjust so they work. Don't use getopts. Delete lines with only whitespace, not just precisely empty lines. * Makefile.in (install): Install mkcategories. Also install the sample files. * config.h (USE_BIN_MAIL): Default this to FALSE. * gnats.c (create_report): Don't clear errno. * misc.c (log_msg): Don't pay attention to errno. Sun Feb 14 03:34:29 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * gnats.c (reply_to_submitter): Don't mention the support site in the automatic acknowledgment message. Sat Feb 13 13:08:51 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (DISTFILES): Don't include COPYING.LIB. * resp_lookup.c: New file. * gnats.c: Don't include pwd.h. (get_responsible): Move to resp_lookup.c. (gnats): Call it with a pointer to the category instead. * gnats.h (get_responsible): Change prototype. * Makefile.in (SOURCES, OBJECTS): Add resp_lookup. * misc.c (punt): New function. * gnats.c, files.c, main.c, misc.c: Rather than use LOG_ERR, always send GNATS_ADMIN mail about the problem by calling punt, except in mail areas. * main.c (main): If the debug_level won't let us emit the usage, then let GNATS_ADMIN know about incorrect usage. * gnats.c (get_bug_number): Call block_signals/unblock_signals. * config.h (ACKNOWLEDGE): Add define. * gnats.c (gnats): Use it around the call to reply_to_submitter. * globals.h (LOG_DEBUG): Delete. * globals.h (LOG_ERR, LOG_INFO, LOG_DEBUG): If they don't have syslog, define these to be ascending numbers, for debug purposes. (LOG_NONE): New define, value for debug_level at release time. * main.c (main): For debug option, set debug_level to LOG_INFO, don't expect them to give us an argument. * gnats.c (create_report): Clear out errno after calling stat, since (if the test worked) it will have ENOENT anyway. * pr.c (initPR): Delete debug message. * misc.c: Include signal.h. (block_signals, unblock_signals): Ignore/enable user interrupts. * gnats.h (block_signals, unblock_signals): Declare them. * gnats.c (create_report, add_to_index, notify_responsible, reply_to_submitter): Call block_signals/unblock_signals. * Makefile.in (all): Add gnats.el target. * gnats.elisp (report-pr, file-pr): Delete fns and autoloads. * field.c: Rename to gnats.c. * Makefile.in (SOURCES, OBJECTS, field.o): Change accordingly. * gnats-queue.c (fork_gnats): Dup fd 2, not fd 3. * field.c (verify_analysis): New function. (gnats): Use it as a predicate for running at_pr. Call notify_responsible with the contract type, response time, and expiry. (notify_responsible): New args `type', `rtime', and `expired'. Tell the person responsible when the first analysis should be sent, if NOTIFY is defined. * Makefile.in (.c.o): Pass in GNATS_ADDR. * field.c (reply_to_submitter): Use it for the `From:' field. * field.c (gnats): If a PR fell into pending, don't do anything but send it to GNATS_ADMIN. (notify_responsible): If there was nothing for SNOTIFY or CNOTIFY, don't try to Cc: to them. * msg.c (close_mail_file): New function, to match open_mail_file. * files.c (reply_to_submitter, notify_responsible): Use it. * main.c (main): Likewise, for MAIL logging. * field.c (notify_responsible, reply_to_submitter): If USE_BIN_MAIL isn't defined, pass NULL, not an empty string. * main.c (flag_no_atpr): Default to FALSE. * msg.c (readHeader): Reset `received', so we can swallow as many sets of `Received:' headers as we want. * misc.c (copy_string): Delete. * gnats.h (copy_string): Delete prototype. * field.c, files.c, msg.c, pr.c: Change all callers to use strdup instead of copy_string. * gnats-queue.c (fork_gnats): Return the status of the gnats child. (run_gnats): Get the value from fork_gnats, and only unlink the file if the child ran okay. * at-pr.sh: Full rewrite. * btime.c: Don't include time.h or assert.h. (get_response_time): Return the tm struct for when their time's up. Don't call assert. * gnats.h: Instead, include time.h here. (get_response_time): Add prototype. * main.c (at_pr): Deleted. * globals.h (at_pr): Deleted. (flag_run_atpr): Add decl. * field.c (run_atpr): New function. (safe_env): New array. (gnats): Call it. Don't say it's expired if the `rtime' field of SUBMITTER is -1, since that means *don't have one*. New variable `arrival_time', to make the code a little more readable. New variable `number', so we can pass it into run_atpr. Use the value returned by get_response_time for run_atpr to munge. * files.c (get_adm_record): Start ERR at 0, not -1, and adjust code accordingly. * misc.c (log_msg): Fixup for __STDC__ vs non-std. * msg.c (initHeader): Delete debug message. * misc.c (log_msg): Use varargs instead. New arg `HAS_ARG'. * gnats.h (log_msg): Delete prototype. * pr.c, main.c, files.c: Fix all calls to not include a useless third argument. * main.c (flag_at_notify): Renamed to `flag_no_atpr'. (long_options): Changed. * field.c (gnats): Change usage. * globals.h (flag_run_atpr): Renamed. * Makefile.in (*.c deps): Changed to *.o, add config.h as well. (gnats-queue.o): Add header dependencies. * field.c: Don't include sys/file.h, we don't need it. (check_if_reply): Don't call append_report; instead, return the path. (get_bug_number): Rename `lck' to `lock_file'. Use STR_MAX instead of 256 for the dimensions for `sbuf'. (append_report): Make global. * main.c (main): If check_if_reply is non-null, call append_report. * gnats.h (check_if_reply): Change prototype. (append_report): Add prototype. * main.c (main): Turn on all disabled options. Use getopt_long. (long_options): Created struct. (main): Revise usage. (customer_id): Rename to `submitter'. (at_pr): Create with `gnats_root', not `GNATS_ROOT'. (autocreate, notify, at_notify): Rename to `flag_'foo. Make int, not bool. * gnats-queue.c (long_options): Give 'd' and 'f' back to getopt for --directory and --file. Set `HAS_ARG' and `VAL' fields properly. * field.c (gnats): Rename uses of `autocreate' to `flag_autocreate' * globals.h (autocreate): Likewise; make int. * mkcategories.sh: Renamed to mkcat.sh, for filename length limits. * Makefile.in (mkcategories): Use mkcat.sh instead of mkcategories.sh. (DISTFILES): Change it. Fri Feb 12 12:26:26 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * submitters, categories, remote: New sample files. * files.c (get_adm_record): Make static. * misc.c (lock, unlock): Rename to `lock_gnats' and `unlock_gnats'. * gnats.h (get_adm_record): Delete prototype. (lock, unlock): Change names. * mkcategories.sh (GNATS_ROOT): Replace with substitute string. * Makefile.in (all): Add mkcategories. (mkcategories): New rule. (DISTFILES): Add at-pr.sh, mkcategories.sh, error.c, xmalloc.c, gnats.elisp, gnats.texi (install): Add chowns as appropriate. (*.c dependencies): Modify appropriately, setting all of $(SOURCES) dependant upon gnats.h and globals.h. * files.h (CU_*, CA*_): Deleted unused macros. * globals.h (bool): Made a short, not a char. (gnats_max): Deleted. * Makefile.in (clean): Also use mostlyclean. Delete *.dvi and mkcategories as well. (mostlyclean): Get rid of TeXinfo cruft. (realclean): Delete GNATS info files, and processed indices. * gnats.els: Rename to gnats.elisp. Thu Feb 11 21:56:48 1993 Jeffrey Osier (jeffrey@cygnus.com) * created gnats.texi, outline only...details on the way Thu Feb 11 12:58:55 1993 Tim Wicinski (tim@cygnus.com) * mkcategories: new shell script to create category directories based on categories file. * globals.h: remove extern mail_agent since we will now just use a #define only for that one. * main.c: ifdef'ed out all unused options. will be removed in the next few days barring any unforseen situations. * pr.h: removed an unneeded define, cleaned up the strings some. * field.c(create_report): check for file existence here instead of everywhere where it gets called. * files.h: removed bogus fields from structures, and changed a few defines, cleaned up some comments. * globals.h: changed prototype of SetPRValue. * pr.c(SetPRValue): changed return call to be of type bool. Also checks when an Enum type is being set, and makes sure it is getting set with a correct value. Thu Feb 11 12:44:18 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-queue.c (fork_gnats): Don't chdir to QUEUE_DIR. (run_gnats): Instead, do it here and opendir on ".". * main.c (at_pr): Make local to main, it's never used elsewhere. * globals.h (AT_PR, at_pr): Deleted. * globals.h (BINDIR): Define just as "/gnats-bin". * main.c (main): Build the at_pr name using GNATS_ROOT also. * gnats-queue.c (fork_gnats): Likewise. Thu Feb 11 00:08:57 1993 Tim Wicinski (tim@cygnus.com) * main.c (main): Threw out the options `-T' (trace), `-o' (redirected output), and `-p' (print comment). * globals.h (NOTIFY, AB, CHECK_IS_REPLY): Deleted old macros. Wed Feb 10 23:27:11 1993 Tim Wicinski (tim@cygnus.com) * Makefile.in (install): Also create the dir `gnats-queue'. * msg.h (X_MODE_STRING, SM_FROM_STRING, RETURN_PATH_STRING, RECEIVED_STRING, MSG_ID_STRING, DATE_STRING, FROM_STRING, SENDER_STRING, REPLY_TO_STRING, TO_STRING, APPAR_TO_STRING, CC_STRING, IN_REP_TO_STRING, SUBJECT_STRING, REFERENCES_STRING, COMMENTS_STRING, KEYWORDS_STRING, X_SEND_PR_STRING): Deleted macros. * msg.c (initHeader): Replaced macros with real strings. * files.c (find_categories/find_submitters): Don't default the `notify' field to gnats-admin if it's empty---leave it empty. * field.c (notify_responsible): Check if the notify field's empty before trying to send mail. Wed Feb 10 13:42:59 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * gnats-queue.c (fork_gnats): chdir to queue_dir before firing off gnats. (run_gnats): Unlink the queued file when it's been processed by gnats. Wed Feb 10 00:11:33 1993 Tim Wicinski (tim@cygnus.com) * misc.c: fixed type with #else stmt. * field.c (reply_to_submitter/notify_responsible): * misc.c (open_mail_file): * main.c: * globals.h: replaced all references of global variable use_bin_mail with #define USE_BIN_MAIL instead. This seems to be more of a compile time and not run time feature. * field.c: added places when it sends me mail for the time being, until we get it all straightened out. Tue Feb 9 14:32:26 1993 Tim Wicinski (tim@cygnus.com) * pr.c(readPR): totally rewritten in order to make it faster. use buffer mgmt instead of lame string handling functions. works fast on big files. * pr.h: added those evil and insidious '>' back to the front of the PR fields. * main.c(main): added third arg to log_msg call. * field.c(gnats): rearranged site debug msg. changed comments. * gnats.h: added extern for log_msg. * Makefile.in: added install rules (first pass). Sample files and man pages need to be added still. * gnats-queue.c: added #define for MAXBSIZ for time being. Mon Feb 8 11:54:20 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * field.c (gnats): If the bits for MODE aren't defined, force it. * gnats.h (alloca): Undef before defining if __GNUC__. * msg.c (readHeader): Call xmalloc instead of alloca. * gnats-queue.c (fork_gnats): Likewise. (drop_msg): Likewise. * gnats-queue.c (run_gnats): Cast strdup to a char*. * main.c (main): Don't try to stringify ("foo" "bar" -> "foobar") for the usage. * pr.c (initPR): Likewise, for AUDIT_TRAIL. * at_pr.sh: Renamed to at-pr.sh. * Makefile.in (at_pr): Renamed to at-pr. (clean): Delete at-pr instead. * Makefile.in (gnats-queue): Add compilation rule. * Makefile.in (clean): Delete gnats-queue. (DISTFILES): Add queue.h. * gnats-queue.c (drop_msg): Unlink the queue file from /tmp when it's done being moved. * gnats-queue.c, queue.h: New files. * Makefile.in (gnats-queue): New rule. Use LIBOBJS. (LIBOBJS): Move error.o, xmalloc.o, and version.o to here. (OBJECTS): Delete them from here. * main.c (main): New arg `f', to receive input from a file. * configure.in (AC_DIR_HEADER): Add. * gnats.els (GNATS-DB): Deleted variable. (edit-pr): Use GNATS-ROOT instead. * Makefile.in (GNATS_ROOT, GNATS_ADDR): New vars. (.c.o, at_pr, gnats.el): Pass them. * gnats.els: New file. * config.h (GNATS_ROOT): Deleted. * at_pr.sh: New file. * Makefile.in (at_pr): New rule. (all): Add it to all. (clean): Delete at_pr. * globals.h (BDAY_START, BDAY_END, BWEEK_START, BWEEK_END): Deleted. * btime.c: Moved here. * config.h: New file. * Makefile.in (DISTFILES): Added it and other headers. * field.c, files.c, main.c: Include it. * globals.h (GNATS_ROOT, NOTIFY): Move there. (CYGNUS_SUPPORT, SUN_CUSTOMER, INDENT): Deleted. * main.c (SUN_CUSTOMER): Deleted. * globals.h (AT_PR): Deleted. * main.c (main): Set it up at run-time. Rename local `at_pr' to `at_notify'. (at_pr): Don't init yet. * configure.in (AC_REPLACE_FUNCS): Deleted. * main.c (version): Output newline. * Makefile.in: Add dependencies for misc files. * pr.h (PR_type): Create enum instead of defines. pr.c (TEXT, MULTI_TEXT, ENUM, INT, RECEIVER): Change uses. (PRentry): Change types. * field.c (reply_to_submitter): Only use FULLNAME if it's non-null. * error.c, xmalloc.c: New files. * Makefile.in (SOURCES, OBJECTS): Add them. * gnats.h: Add checks for getting string.h/strings.h, getopt, et al. * btime.c: Include it. * files.c: Include pathmax.h. Merge in stuff from src/Makefile.in. * Makefile.in (VERSION, SOURCES, OBJECTS): Add vars. (DISTFILES): Add SOURCES. Sat Feb 6 01:19:44 1993 Tim Wicinski (tim@cygnus.com) * field.c (add_to_index): New function which adds new PRs into a small index that query_pr can probably use. A definite first pass. * gnats.h: Include globals.h. * main.c (AT_PR): Changed to `at_pr'. * globals.h (AT_PR): Likewise. * field.c (get_responsible): Changed fn to return structure remote that includes full name of responsible person. This new feature will be mailed out to submitters in acknowledgements. * gnats.h: Added new as well as more function prototypes. * misc.c: Check system call returns. * main.c: Removed old and crusty variables and defines. * globals.h: Removed some old defines and variables that are unused. Added comments describing definable options. * files.h: Removed all instances of the word "Customer". * files.c: Likewise. * field.c (gnats): Changed `Customer' to `Submitter'. Changed handling with respect to get_responsible. Fri Feb 5 09:24:54 1993 Tim Wicinski (tim@cygnus.com) * main.c: added code which does checking to see if incoming message is a reply to a preevious PR. moves some code from procedure gnats() over here. * btime.c: changed contributor address, added small code to remove trailing newline from ctime(3C). * field.c: rewrite parts of procedure gnats. more checking about correct bug category to insert bugs; added procedure append_report (used in main); changed ack message sent submitters; removed unused variables and cleaned up code to make it meet facist coding standards. lots changed here. * misc.c,pr.c: changed contributor. * files.c: rename of all readFname functions, changed names to find_Fname, added procedure get_adm_record that does all file parsing. Other cleanup as well. * globals.h: removed GNATS_DB, GNATS_ADM, and MAX_ADM_FILES defines, added define for NOTIFY. * gnats.h: changed function prototypes for procedures in files.c. Sun Jan 31 00:17:04 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * pr.c (writePR): If it's a MULTI_TEXT field, output a newline before starting to print the field's value out. (initPR): A RELEASE is a single TEXT line, not MULTI_TEXT. * field.c (get_bug_number): Only try to grab a lock on the lock file if it already existed---if we opened for writing, don't bother. * configure.in (AC_HAVE_HEADERS): Look for memory.h. * btime.c, field.c, files.c, main.c, msg.c, pr.c: Include system.h. * main.c: Include gnats.h. * gnats.h (xmalloc, xrealloc): Declare. * main.c (main): Return void. * mkdir.c: Include ansidecl.h. (mkdir): Make arg DMODE be mode_t (FIXME). * basename.c: Use HAVE_STRING_H, not USG. * lib/Makefile.in (.c.o): Look in ../../include. * main.c (main): Call openlog with LOG_PID, not LOG_ODELAY. If LOG_USER isn't defined, we've got the old syslog (e.g., Ultrix v3 & 4), so don't give openlog the facility argument. If we don't have syslog facilities, don't accept them as possible alternatives for error messages. (log_level): Only define if HAVE_SYSLOG_H. * msg.c, field.c, files.c, pr.c: Include syslog.h. * misc.c (log_msg): Don't try to use SYSLOG if it's not there. * globals.h (LOG_ERR, LOG_INFO, LOG_DEBUG): Define to 0 if we don't have syslog.h. (LOGGING): Default to MAIL if they don't have syslog. (log_level, LOG_LEVEL): Don't mention (or set) if we don't have syslog. * conf.h: Delete. * btime.c, field.c, files.c, main.c, misc.c, msg.c, pr.c: Don't use it. * Makefile.in (distclean, realclean): Add rules to clean top-level. Sat Jan 30 15:06:07 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * src/Makefile.in (srcdir, VPATH, OBJECTS): Add vars. (gnats): Use `OBJECTS', not `OBJS'. (LIBIBERTY): Deleted. * misc.c: Include system.h. Wrap HAVE_SYSLOG_H around syslog.h. * pathmax.h: New file. * configure.in: Use AC_HAVE_HEADERS instead of individual AC_HEADER_CHECKs. Use AC_ALLOCA; add AC_OUTPUT; don't use AC_USG. * man/Makefile.in: New file. * alloca.c, error.c, getopt.c, getopt1.c, getopt.h, system.h: New files. * lib/Makefile.in (SOURCES, OBJECTS, DISTFILES): Add them. (getopt1.o): New rule. Total reorganization, to match other GNU things and use autoconf. * Makefile.in: Rewritten. * configure.in: Now use autoconf. * configure, README, INSTALL, COPYING, COPYING.LIB: New files. * lib/{mkdir.c, Makefile.in, basename.c, strstr.c, xmalloc.c}: New files. * man/: New dir for manuals (eventually). * include/: Deleted, moved headers into src/. * misc.c (xmalloc, xrealloc): Deleted, now in libgnats.a. * Makefile.in (VERSION): Add variable. (version.c): Add rule for creation. (SRCS, OBJS): Add version.[co] to lists. * globals.h (VERSION): Delete macro. (version_string): Add var decl. * main.c (version): New fn to print out version_string from version.c. * misc.c (version): Delete fn. * gnats.h (version): Delete decl. * main.c, globals.h: Rename macros from `D_FOO' to just `FOO'. * main.c (GNATS_ROOT, GNATS_DB, GNATS_ADM, MAIL_AGENT, BIN_MAIL, LOG_LEVEL): Rename to lowercase names. (VERSION, GNATS_ADMIN): Delete, use the macros. (LOGGING): Renamed to log_method. Changed uses in necessary files. * globals.h: Change decls. * globals.c: Move this stuff into main.c. (PENDING, UNKNOWN): Move into gnats.h as macros. * Makefile.in (SRCS, OBJS): Delete globals.[co]. * gnats.h (COL, COLB, ES, NILSTR, NL, QUOTE, SL, SPACE, TAB): Delete. Change all files to use the characters, rather than obscuring things by using these macros. * field.c, files.c, main.c, msg.c, pr.c: Make many functions be static. Include ansidecl.h to get PARAMS; use PARAMS. * gnats.h (PROTO): Delete; change uses of PROTO to PARAMS. Add a bunch of prototypes. * msg.c (readHeader): Pass LINE into GetToken, and check line against '\0', to avoid an unnecessary assignment. * btime.c: Include assert.h. * misc.c (SKIPWHITESPACE): Wrap uses of `l' with parenthesis. Check that `*(l)' isn't a null byte, not `*line'. * misc.c (xmalloc, xrealloc): New functions. Every file uses them instead of malloc/realloc now. * gnats.h (xmalloc, xrealloc): Add decls/prototypes. * field.c: Use `PROTO' for function prototypes. * gnats.h (PROTO): Define to include args if __STDC__. * btime.c (get_response_time): Bail if response_buf is NULL. Local Variables: mode: indented-text left-margin: 8 fill-column: 74 version-control: never End: gnats-4.1.0/gnats/Makefile.in0000644000175000017500000005363510207435253016560 0ustar chewiechewie00000000000000# Makefile for GNU GNATS. # Copyright (C) 2001, 2002 Milan Zamazal # Copyright (C) 1993, 94, 95, 96, 1997, 1999, 2000 Free Software Foundation # Inc. # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU gnats; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. srcdir = @srcdir@ VPATH = @srcdir@ #**** Start of system configuration section. # Where the default gnats database is located. # default: $(sharedstatedir)/gnatsdb GNATS_DEFAULT_DB_DIR = @GNATS_DEFAULT_DB_DIR@ # The gnats-adm dir that is part of the default database install. GNATS_DEFAULT_ADM_DIR = $(GNATS_DEFAULT_DB_DIR)/gnats-adm # The default network service to use. DEFAULT_GNATS_SERVICE = @GNATS_SERVICE@ # The username for the gnats user. GNATS_USER = @GNATS_USER@ # NOTE: Don't wrap DEFAULT_RELEASE or DEFAULT_ORGANIZATION with # quotes, or things will break. # The default release for the `>Release:' field of a PR, for send-pr. # default: unknown-1.0 DEFAULT_RELEASE = @DEFAULT_RELEASE@ # The default organization for PRs. # default: unknown DEFAULT_ORGANIZATION = @DEFAULT_ORGANIZATION@ # Configuration for business hours calculation # default: 8-5, Mon-Fri BDAY_START = @BDAY_START@ BDAY_END = @BDAY_END@ BWEEK_START = @BWEEK_START@ BWEEK_END = @BWEEK_END@ # The command line used to run a mailer which gets the address list from # mail headers # default: /usr/{lib,sbin}/sendmail -oi -t DEFAULT_MAIL_AGENT = @DEFAULT_MAIL_AGENT@ # The list of databases. GLOBAL_DB_LIST_FILE = @GLOBAL_DB_LIST_FILE@ # The global access file with users and passwords. GNATSD_USER_ACCESS_FILE = @GNATSD_USER_ACCESS_FILE@ # The global access file controlling which hosts have access to gnatsd. GNATSD_HOST_ACCESS_FILE = @GNATSD_HOST_ACCESS_FILE@ #**** End of GNATS-specific configuration variables. CC = @CC@ AR = ar AR_FLAGS = rc # Set RANLIB = echo if your system doesn't have or need ranlib. RANLIB = @RANLIB@ YACC = @YACC@ DIFFOPT = @DIFFOPT@ LEX = @LEX@ AWK = @AWK@ # These are set by autoconf. DEFS = @DEFS@ -DGNATSD_USER_ACCESS_FILE=\"${GNATSD_USER_ACCESS_FILE}\" -DGNATSD_HOST_ACCESS_FILE=\"${GNATSD_HOST_ACCESS_FILE}\" -DDEFAULT_GNATS_SERVICE=\"${DEFAULT_GNATS_SERVICE}\" -DGLOBAL_DB_LIST_FILE=\"${GLOBAL_DB_LIST_FILE}\" -DGNATS_USER=\"${GNATS_USER}\" LIBS = @LIBS@ @LEXLIB@ KRBINCLUDE = @KRBINCLUDE@ M4 = @M4@ INSTALL = $(srcdir)/../install-sh -c INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ SUB_INSTALL = `echo $(INSTALL) | sed 's,^\([^/]\),../\1,'` SUB_INSTALL_DATA = `echo $(INSTALL_DATA) | sed 's,^\([^/]\),../\1,'` CFLAGS = @CFLAGS@ GCC_CFLAGS = @GCC_CFLAGS@ LDFLAGS = @LDFLAGS@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ libexecdir = @libexecdir@ statedir = @datadir@ sysconfdir = @sysconfdir@ program_transform_name = datadir = @datadir@ includedir = @includedir@ lispdir = @lispdir@ # End of system configuration section. VERSION = @PACKAGE_VERSION@ SHELL = /bin/sh #### Host-, target-, and site-specific makefiles are inserted here. SOURCES = btime.c cmds.c file-pr.c gen-closed-date.c gen-index.c getclose.c gnatsd.c pr-age.c pr-edit.c pr-stat.c query-pr.c queue-pr.c EXTRA_OBJS = @EXTRA_OBJS@ LIBSRC = edit.c getdate.c gnugetopt.c gnugetopt1.c internal.c misc.c pr.c index.c lists.c query.c version.c regex.c adm.c client.c pr-init.c database.c fconfig.c fconfigl.c mail.c field.c mk_auth.c LIBOBJS = edit.o getdate.o gnugetopt.o gnugetopt1.o internal.o misc.o pr.o index.o lists.o query.o version.o regex.o adm.o client.o pr-init.o database.o fconfig.o fconfigl.o mail.o field.o $(EXTRA_OBJS) INCLUDEDIR = -I. -I$(srcdir) $(KRBINCLUDE) # Variables that the send-pr Makefile will want to have changed. GNATS_VARS = \ "GNATS_DEFAULT_DB_DIR=$(GNATS_DEFAULT_DB_DIR)" \ "DEFAULT_RELEASE=$(DEFAULT_RELEASE)" \ "DEFAULT_ORGANIZATION=$(DEFAULT_ORGANIZATION)" \ "SUBMITTER=$(SUBMITTER)" \ "GNATS_INSTALL=$(GNATS_INSTALL)" FLAGS_TO_PASS = \ "SHELL=$(SHELL)" \ "INSTALL=$(SUB_INSTALL)" \ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ "INSTALL_DATA=$(SUB_INSTALL_DATA)" GNATS_ALL = @GNATS_ALL@ EXTRA_STUFF = EXTRA_INSTALL = all: $(GNATS_ALL) all-gnats: all-tools gnatsd queue-pr mail-query gen-index \ at-pr mkcat mkdb rmcat gen-closed-date \ check-db delete-pr dbconfig gnats-databases gnats-pwconv $(EXTRA_STUFF) all-tools: libgnats.a query-pr pr-age pr-edit edit-pr file-pr getclose \ config-send-pr mail-agent dbconfig diff-prs libgnats.a: $(LIBOBJS) -rm -f tmplibgnats.a libgnats.a $(AR) $(AR_FLAGS) tmplibgnats.a $(LIBOBJS) $(RANLIB) tmplibgnats.a mv tmplibgnats.a libgnats.a .c.o: $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $< version.c: Makefile echo 'const char *version_string = "$(VERSION)";' > $@-t mv $@-t $@ query-pr: query-pr.o regex.o libgnats.a $(CC) $(LDFLAGS) -o $@ query-pr.o regex.o \ libgnats.a $(LIBS) gnatsd: gnatsd.o cmds.o regex.o file-pr.o btime.o libgnats.a $(CC) $(LDFLAGS) -o $@ gnatsd.o cmds.o regex.o file-pr.o btime.o \ libgnats.a $(LIBRX) $(LIBS) queue-pr: queue-pr.o libgnats.a $(CC) $(LDFLAGS) -o $@ queue-pr.o \ libgnats.a $(LIBS) pr-age: pr-age.o regex.o libgnats.a $(CC) $(LDFLAGS) -o $@ pr-age.o regex.o \ libgnats.a $(LIBS) getclose: getclose.o regex.o libgnats.a $(CC) $(LDFLAGS) -o $@ getclose.o regex.o \ libgnats.a $(LIBS) pr-edit: pr-edit.o file-pr.o btime.o libgnats.a $(CC) $(LDFLAGS) -o $@ pr-edit.o file-pr.o btime.o \ libgnats.a $(LIBS) pr-stat: pr-stat.o regex.o libgnats.a $(CC) $(LDFLAGS) -o $@ pr-stat.o regex.o \ libgnats.a $(LIBS) gen-index: gen-index.o libgnats.a $(CC) $(LDFLAGS) -o $@ gen-index.o libgnats.a \ $(LIBS) gen-closed-date: gen-closed-date.o libgnats.a $(CC) $(LDFLAGS) -o $@ gen-closed-date.o libgnats.a \ $(LIBS) at-pr: at-pr.sh Makefile @echo Creating at-pr... @sed -e 's,xVERSIONx,$(VERSION),g' \ -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ -e 's,xGNATS_USERx,$(GNATS_USER),g' \ -e 's,xBINDIRx,$(bindir),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' $(srcdir)/at-pr.sh > $@-t @mv $@-t $@ @chmod a+x $@ check-db: check-db.sh Makefile @echo Creating check-db.. @sed -e 's,xVERSIONx,$(VERSION),g' \ -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ -e 's,xGNATS_USERx,$(GNATS_USER),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' \ -e 's,xBINDIRx,$(bindir),g' $(srcdir)/check-db.sh > $@-t @mv $@-t $@ @chmod a+x $@ delete-pr: delete-pr.sh Makefile @echo Creating delete-pr... @sed -e 's,xVERSIONx,$(VERSION),g' \ -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ -e 's,xGNATS_USERx,$(GNATS_USER),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' $(srcdir)/delete-pr.sh > $@-t @mv $@-t $@ @chmod a+x $@ diff-prs: diff-prs.sh Makefile @echo Creating diff-prs... @sed -e 's,xAWKx,$(AWK),g' $(srcdir)/diff-prs.sh > $@-t @mv $@-t $@ @chmod a+x $@ mkcat: mkcat.sh Makefile @echo Creating mkcat... @cat $(srcdir)/mkcat.sh > $@-t @mv $@-t $@ @chmod a+x $@ mkdb: mkdb.sh Makefile @echo Creating mkdb... @sed -e 's,xGNATS_USERx,$(GNATS_USER),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' \ -e 's,xGLOBAL_DB_LIST_FILEx,$(GLOBAL_DB_LIST_FILE),g' \ -e 's,xSYSCONFDIRx,$(sysconfdir),g' $(srcdir)/mkdb.sh > $@-t @mv $@-t $@ @chmod a+x $@ rmcat: rmcat.sh Makefile @echo Creating rmcat... @cat $(srcdir)/rmcat.sh > $@-t @mv $@-t $@ @chmod a+x $@ edit-pr: edit-pr.sh Makefile @echo Creating edit-pr... @sed -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ -e 's,xBINDIRx,$(bindir),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' \ -e 's,xVERSIONx,$(VERSION),g' $(srcdir)/edit-pr.sh > $@-t @mv $@-t $@ @chmod a+x $@ file-pr: file-pr.sh Makefile @echo Creating file-pr... @sed -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' \ -e 's,xVERSIONx,$(VERSION),g' $(srcdir)/file-pr.sh > $@-t @mv $@-t $@ @chmod a+x $@ mail-query: mail-query.sh Makefile @echo Creating mail-query... @sed -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ -e 's,xBINDIRx,$(bindir),g' \ -e 's,xLIBEXECDIRx,$(libexecdir),g' \ $(srcdir)/mail-query.sh > $@-t @mv $@-t $@ @chmod a+x $@ mail-agent: mail-agent.sh Makefile @echo Creating mail-agent... @sed -e 's,xDEFAULT_MAIL_AGENTx,$(DEFAULT_MAIL_AGENT),g' \ $(srcdir)/mail-agent.sh > $@-t @mv $@-t $@ @chmod a+x $@ dbconfig: dbconfig.in Makefile @echo Creating dbconfig... @sed -e 's,xBDAY_STARTx,$(BDAY_START),g' \ -e 's,xBDAY_ENDx,$(BDAY_END),g' \ -e 's,xBWEEK_STARTx,$(BWEEK_START),g' \ -e 's,xBWEEK_ENDx,$(BWEEK_END),g' \ -e 's,xLIBEXECDIRx,$(libexecdir)/gnats,g' \ $(srcdir)/dbconfig.in > $@-t @mv $@-t $@ gnats-databases: gnats-databases.in Makefile @echo Creating gnats-databases... @sed -e 's,xGNATS_DEFAULT_DB_DIRx,$(GNATS_DEFAULT_DB_DIR),g' \ $(srcdir)/gnats-databases.in > $@-t @mv $@-t $@ gnats-pwconv: gnats-pwconv.o libgnats.a $(CC) $(LDFLAGS) -o $@ gnats-pwconv.o \ libgnats.a $(LIBS) getdate.c: getdate.y @echo expect 10 shift/reduce conflicts $(YACC) -o getdate.c $(srcdir)/getdate.y # On some systems with ancient yaxxen, badly-generated .c code have we. fconfig.o: fconfig.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(CPPFLAGS) $(DEFS) $< # # Ayum yum yum and a bottle of rum! # fconfig.c: fconfig.y @rm -f fconfig.c fconfig.h fconfig.tab.c fconfig.tab.h $(YACC) -p fconf -b fconfig -d $(srcdir)/fconfig.y @if [ -f y.tab.c -a ! -f fconfig.c ] ; then \ mv y.tab.c fconfig.c ; \ mv y.tab.h fconfig.h ; \ fi @if [ -f fconfig.tab.c ] ; then \ mv fconfig.tab.c fconfig.c ; \ mv fconfig.tab.h fconfig.h ; \ fi fconfigl.c: fconfigl.l $(LEX) -t $(srcdir)/fconfigl.l >fconfigl.c config-send-pr: @if [ ! -d ../send-pr ]; then \ echo "The send-pr directory doesn't seem to be there!" ; \ exit 1 ; \ else \ ( cd ../send-pr ; $(MAKE) $(GNATS_VARS) gnats-build ) ; \ true ; \ fi # Misc targets. GNATS_INSTALL = @GNATS_INSTALL@ install: $(GNATS_INSTALL) install-arch-dep: $(GNATS_INSTALL)-arch-dep install-tools: install-tools-arch-indep install-tools-bin install-tools-arch-dep: install-tools-bin install-tools-arch-indep: all-tools $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(datadir)/gnats $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(sysconfdir)/gnats/defaults @if [ `whoami` = root -o `whoami` = $(GNATS_USER) ] ; then \ echo "chown $(GNATS_USER) $(DESTDIR)$(datadir)/gnats" ; \ chown $(GNATS_USER) $(DESTDIR)$(datadir)/gnats ; \ else \ echo "*** Warning: Must chown $(GNATS_USER) $(DESTDIR)$(datadir)/gnats" ; \ fi $(INSTALL_DATA) $(srcdir)/gnats.el $(DESTDIR)$(lispdir)/gnats.el for i in categories submitters responsible gnatsd.user_access addresses states classes dbconfig ; do \ if [ -f "$$i" ] ; then \ $(INSTALL_DATA) $$i $(DESTDIR)$(sysconfdir)/gnats/defaults/$$i ; \ else \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(sysconfdir)/gnats/defaults/$$i ; \ fi ; \ done install-tools-bin: all-tools $(INSTALL_PROGRAM) query-pr $(DESTDIR)$(bindir)/query-pr $(INSTALL_PROGRAM) getclose $(DESTDIR)$(bindir)/getclose $(INSTALL_SCRIPT) edit-pr $(DESTDIR)$(bindir)/edit-pr $(INSTALL_SCRIPT) diff-prs $(DESTDIR)$(libexecdir)/gnats/diff-prs $(INSTALL_SCRIPT) mail-agent $(DESTDIR)$(libexecdir)/gnats/mail-agent $(INSTALL_PROGRAM) file-pr $(DESTDIR)$(libexecdir)/gnats/file-pr $(INSTALL_PROGRAM) pr-age $(DESTDIR)$(libexecdir)/gnats/pr-age $(INSTALL_PROGRAM) pr-edit $(DESTDIR)$(libexecdir)/gnats/pr-edit @if [ `whoami` = root -o `whoami` = $(GNATS_USER) ] ; then \ echo "chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/pr-edit" ; \ echo "chmod 4555 $(DESTDIR)$(libexecdir)/gnats/pr-edit" ; \ chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/pr-edit ; \ chmod 4555 $(DESTDIR)$(libexecdir)/gnats/pr-edit ; \ else \ echo "*** Warning: Must make pr-edit suid $(DESTDIR)$(GNATS_USER)" ; \ fi EXTRA_INSTALL = install-gnats: install-gnats-bin install-gnats-arch-indep $(EXTRA_INSTALL) install-gnats-arch-dep: install-gnats-bin $(EXTRA_INSTALL) install-gnats-arch-indep: all-gnats install-tools-arch-indep @if [ -f $(DESTDIR)$(GLOBAL_DB_LIST_FILE) ]; then \ echo "Not putting gnats-databases file in $(DESTDIR)$(GLOBAL_DB_LIST_FILE), it's already there." ; \ true ; \ else \ if [ `whoami` = root -o `whoami` = $(GNATS_USER) ] ; then \ $(INSTALL_DATA) -o $(GNATS_USER) gnats-databases \ $(DESTDIR)$(GLOBAL_DB_LIST_FILE) ; \ else \ $(INSTALL_DATA) gnats-databases $(DESTDIR)$(GLOBAL_DB_LIST_FILE) ; \ echo "*** Warning: Must chown $(GNATS_USER) $(DESTDIR)$(GLOBAL_DB_LIST_FILE)" ; \ fi \ fi @if [ -f $(DESTDIR)$(GNATSD_HOST_ACCESS_FILE) ]; then \ echo "Not putting gnats.host_access file in $(DESTDIR)$(GNATSD_HOST_ACCESS_FILE), it's already there." ; \ true ; \ else \ if [ `whoami` = root -o `whoami` = $(GNATS_USER) ] ; then \ $(INSTALL_DATA) -o $(GNATS_USER) $(srcdir)/gnatsd.host_access \ $(DESTDIR)$(GNATSD_HOST_ACCESS_FILE) ; \ else \ $(INSTALL_DATA) $(srcdir)/gnatsd.host_access \ $(DESTDIR)$(GNATSD_HOST_ACCESS_FILE) ; \ echo "*** Warning: Must chown $(GNATS_USER) $(DESTDIR)$(GNATSD_HOST_ACCESS_FILE)" ; \ fi \ fi @echo "*** If you're a first-time user, you'll want to create a new database"; @echo "*** with $(libexecdir)/gnats/mkdb." install-gnats-bin: all-gnats install-tools-bin $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(libexecdir)/gnats $(INSTALL_PROGRAM) gnatsd $(DESTDIR)$(libexecdir)/gnats/gnatsd $(INSTALL_SCRIPT) at-pr $(DESTDIR)$(libexecdir)/gnats/at-pr $(INSTALL_SCRIPT) check-db $(DESTDIR)$(libexecdir)/gnats/check-db $(INSTALL_SCRIPT) delete-pr $(DESTDIR)$(libexecdir)/gnats/delete-pr $(INSTALL_SCRIPT) mkcat $(DESTDIR)$(libexecdir)/gnats/mkcat $(INSTALL_SCRIPT) mkdb $(DESTDIR)$(libexecdir)/gnats/mkdb $(INSTALL_SCRIPT) rmcat $(DESTDIR)$(libexecdir)/gnats/rmcat $(INSTALL_PROGRAM) queue-pr $(DESTDIR)$(libexecdir)/gnats/queue-pr $(INSTALL_PROGRAM) gen-index $(DESTDIR)$(libexecdir)/gnats/gen-index $(INSTALL_SCRIPT) mail-query $(DESTDIR)$(libexecdir)/gnats/mail-query $(INSTALL_PROGRAM) gnats-pwconv $(DESTDIR)$(libexecdir)/gnats/gnats-pwconv @if [ `whoami` = root -o `whoami` = $(GNATS_USER) ] ; then \ echo "chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/queue-pr $(DESTDIR)$(libexecdir)/gnats/file-pr $(DESTDIR)$(libexecdir)/gnats/gen-index" ; \ echo "chmod 4555 $(DESTDIR)$(libexecdir)/gnats/queue-pr $(DESTDIR)$(libexecdir)/gnats/file-pr $(DESTDIR)$(libexecdir)/gnats/gen-index" ; \ echo "chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/gnatsd" ; \ echo "chmod 555 $(DESTDIR)$(libexecdir)/gnats/gnatsd" ; \ chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/queue-pr ; \ chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/gen-index ; \ chmod 4555 $(DESTDIR)$(libexecdir)/gnats/queue-pr ; \ chmod 4555 $(DESTDIR)$(libexecdir)/gnats/gen-index ; \ chown $(GNATS_USER) $(DESTDIR)$(libexecdir)/gnats/gnatsd ; \ chmod 555 $(DESTDIR)$(libexecdir)/gnats/gnatsd ; \ else \ echo "*** Warning: must make queue-pr and gen-index suid $(GNATS_USER)." ; \ fi # regex.c is pretty badly broken, and I don't feel like fixing it. regex.o: $(srcdir)/regex.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(CPPFLAGS) $(DEFS) $< # Flex 2.5.4's scanner seems to be a bit broken too. fconfigl.o: fconfigl.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(CPPFLAGS) $(DEFS) $< # More misc bugs that aren't under my control exactly. getdate.o: getdate.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(CPPFLAGS) $(DEFS) $< # Compile GNU getopt functions without GCC flags to handle old-style defs. gnugetopt.o: gnugetopt.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(CPPFLAGS) $(DEFS) $< gnugetopt1.o: gnugetopt1.c gnugetopt.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(CPPFLAGS) $(DEFS) $< # These is here because Suckass' make is wacky in the head. client.o: $(srcdir)/client.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/client.c query-pr.o: $(srcdir)/query-pr.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/query-pr.c pr-age.o: $(srcdir)/pr-age.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/pr-age.c pr-edit.o: $(srcdir)/pr-edit.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/pr-edit.c getclose.o: $(srcdir)/getclose.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/getclose.c gnatsd.o: $(srcdir)/gnatsd.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/gnatsd.c cmds.o: $(srcdir)/cmds.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/cmds.c queue-pr.o: $(srcdir)/queue-pr.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/queue-pr.c gen-index.o: $(srcdir)/gen-index.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/gen-index.c gen-closed-date.o: $(srcdir)/gen-closed-date.c $(CC) -c $(INCLUDEDIR) $(CFLAGS) $(GCC_CFLAGS) $(CPPFLAGS) $(DEFS) $(srcdir)/gen-closed-date.c # Don't use rm -rf in case there's other stuff in the directories uninstall: -rm -f $(DESTDIR)$(bindir)/edit-pr -rm -f $(DESTDIR)$(bindir)/query-pr -rm -f $(DESTDIR)$(bindir)/getclose -rm -f $(DESTDIR)$(libexecdir)/gnats/gnats-edit-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/pr-age -rm -f $(DESTDIR)$(libexecdir)/gnats/pr-edit -rm -f $(DESTDIR)$(libexecdir)/gnats/at-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/check-db -rm -f $(DESTDIR)$(libexecdir)/gnats/delete-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/file-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/nfile-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/gnats-file-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/queue-pr -rm -f $(DESTDIR)$(libexecdir)/gnats/mkcat -rm -f $(DESTDIR)$(libexecdir)/gnats/mkdb -rm -f $(DESTDIR)$(libexecdir)/gnats/rmcat -rm -f $(DESTDIR)$(libexecdir)/gnats/gen-index -rm -f $(DESTDIR)$(libexecdir)/gnats/mail-query -rm -f $(DESTDIR)$(libexecdir)/gnats/gnats-pwconv -rmdir $(DESTDIR)$(libexecdir)/gnats TAGS: $(SOURCES) $(LIBSRC) etags -f TAGS $(SOURCES) $(LIBSRC) *.h gnats.el ; info: dvi: # Don't use $@ or it'll try to overwrite the version in $(srcdir). version.texi: echo "@set VERSION $(VERSION)" > version.texi-t mv version.texi-t version.texi # Clean things up. clean: mostlyclean -rm -f *.o core queue-pr gnats at-pr mkcat mkdb gnats-pwconv -rm -f rmcat file-pr mail-query check-db delete-pr diff-prs -rm -f libgnats.a -rm -f pr-age pr-stat query-pr pr-edit gnats-edit-pr edit-pr gen-index -rm -f gnatsd getclose gen-closed-date -rm -f gnats-file-pr file-pr nfile-pr *.dvi version.c -rm -f gnats-databases dbconfig mail-agent -rm -f *.elc -rm -f TAGS mostlyclean: -rm -f *.toc *.log *.vr *.fn *.cp *.tp *.ky *.pg *.i *.s *.aux *.cps distclean: clean -rm -f Makefile config.status config.cache autoconf.h config config.log -rm -rf =* .\#* \#* *~* -rm -f *.orig *.rej -rm -f TAGS maintainer-clean realclean: distclean -rm -f getdate.c fconfig.c fconfig.h fconfigl.c # FIXME dist: echo need to do something for dist diststuff: getdate.c config.status: configure @if [ -r config.status ]; then \ sh ./config.status --recheck ; \ else \ echo You must configure GNATS. Look at the INSTALL file for details. ; \ exit 1 ; \ fi # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: Makefile : $(srcdir)/Makefile.in config.status $(SHELL) config.status # Dependencies $(srcdir)/gnatsd.h: $(srcdir)/pcodes.h btime.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h btime.o: $(srcdir)/pr.h btime.o: $(srcdir)/ansidecl.h client.o: $(srcdir)/gnats.h $(srcdir)/gnatsd.h client.o: $(srcdir)/query.h autoconf.h file-pr.o: $(srcdir)/ansidecl.h $(srcdir)/pr.h file-pr.o: $(srcdir)/gnats.h file-pr.o: $(srcdir)/regex.h gen-index.o: $(srcdir)/ansidecl.h gen-index.o: $(srcdir)/pr.h $(srcdir)/gnats.h gen-index.o: $(srcdir)/gnats-dirs.h gen-closed-date.o: $(srcdir)/ansidecl.h gen-closed-date.o: $(srcdir)/pr.h $(srcdir)/gnats.h gen-closed-date.o: $(srcdir)/gnats-dirs.h getclose.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h getclose.o: $(srcdir)/query.h getdate.o: autoconf.h gnugetopt.o: autoconf.h $(srcdir)/gnugetopt.h gnugetopt1.o: autoconf.h $(srcdir)/gnugetopt.h index.o: $(srcdir)/pr.h index.o: autoconf.h index.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h internal.o: $(srcdir)/pr.h internal.o: autoconf.h misc.o: $(srcdir)/ansidecl.h misc.o: $(srcdir)/pr.h misc.o: $(srcdir)/gnats.h pr-age.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h pr-age.o: $(srcdir)/query.h pr-edit.o: $(srcdir)/ansidecl.h $(srcdir)/gnats.h pr-edit.o: pr-edit.o: $(srcdir)/pr.h pr-edit.o: autoconf.h pr-stat.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h pr-stat.o: $(srcdir)/query.h pr.o: $(srcdir)/ansidecl.h $(srcdir)/pr.h pr.o: $(srcdir)/gnats.h pr.o: autoconf.h query.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h query.o: $(srcdir)/query.h query.o: $(srcdir)/regex.h $(srcdir)/pr.h query-pr.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h query-pr.o: $(srcdir)/pr.h query-pr.o: $(srcdir)/query.h query-pr.o: $(srcdir)/regex.h lists.o: $(srcdir)/gnats.h $(srcdir)/query.h cmds.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h cmds.o: $(srcdir)/gnatsd.h $(srcdir)/query.h gnatsd.o: $(srcdir)/gnats.h $(srcdir)/ansidecl.h gnatsd.o: $(srcdir)/gnatsd.h queue-pr.o: autoconf.h queue-pr.o: $(srcdir)/gnats-dirs.h queue-pr.o: $(srcdir)/ansidecl.h queue-pr.o: $(srcdir)/pr.h queue-pr.o: $(srcdir)/gnats.h regex.o: $(srcdir)/regex.h $(srcdir)/ansidecl.h edit.o: $(srcdir)/gnats.h $(srcdir)/gnatsd.h edit.o: $(srcdir)/pr.h mail.o: $(srcdir)/config.h $(srcdir)/gnats.h $(srcdir)/query.h mail.o: $(srcdir)/pcodes.h gnats-4.1.0/gnats/acconfig.h0000644000175000017500000000204007304012466016416 0ustar chewiechewie00000000000000/* GNATS specific autoconf symbols. Copyright (C) 2001 Milan Zamazal Copyright (C) 1995, 1996 ??? (FIXME, see ChangeLog.v3) This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ /* Define if you have MIT Kerberos version 4 available. */ #undef HAVE_KERBEROS /* Define if your system has socklen_t (glibc?) */ #undef HAVE_SOCKLEN_T /* Define if strftime supports %z. */ #undef HAVE_STRFTIME_WITH_Z gnats-4.1.0/gnats/aclocal.m40000644000175000017500000000424507333062006016342 0ustar chewiechewie00000000000000dnl aclocal.m4 generated automatically by aclocal 1.4-p4 dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A dnl PARTICULAR PURPOSE. #serial 1 # This test replaces the one in autoconf. # Currently this macro should have the same name as the autoconf macro # because gettext's gettext.m4 (distributed in the automake package) # still uses it. Otherwise, the use in gettext.m4 makes autoheader # give these diagnostics: # configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX # configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX undefine([AC_ISC_POSIX]) AC_DEFUN([AC_ISC_POSIX], [ dnl This test replaces the obsolescent AC_ISC_POSIX kludge. AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) ] ) # serial 1 AC_DEFUN(AM_PATH_LISPDIR, [# If set to t, that means we are running in a shell under Emacs. # If you have an Emacs named "t", then use the full path. test "$EMACS" = t && EMACS= AC_PATH_PROGS(EMACS, emacs xemacs, no) if test $EMACS != "no"; then AC_MSG_CHECKING([where .elc files should go]) dnl Set default value lispdir="\$(datadir)/emacs/site-lisp" emacs_flavor=`echo "$EMACS" | sed -e 's,^.*/,,'` if test "x$prefix" = "xNONE"; then if test -d $ac_default_prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $ac_default_prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi else if test -d $prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi fi AC_MSG_RESULT($lispdir) fi AC_SUBST(lispdir)]) gnats-4.1.0/gnats/addresses0000644000175000017500000000110707036755607016414 0ustar chewiechewie00000000000000# Use this file to store mappings between sender's email addresses # and submitter IDs. # # Entries are of the form: # #submitter-id:address-fragment # # where submitter-id is a valid submitter ID, and address-fragment # is a full or partial e-mail address. Fragments are compared to the # end of the "From:" header of a Problem Report in an attempt to # identify the submitter based solely on email address. # The string matched is merely user@host portion of the From: header, # it does not contain any other text (such as <> or the full name # portion of the address). gnats-4.1.0/gnats/adm.c0000644000175000017500000002123310207433626015407 0ustar chewiechewie00000000000000/* Interface to generic administrative file handling. Copyright (C) 1999, 2000 Free Software Foundation, Inc. Written by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" /* Allocate a new AdmEntry containing FIELDS number of fields. */ AdmEntry * alloc_adm_entry (int fields) { AdmEntry *res = (AdmEntry *) xmalloc (sizeof (AdmEntry)); int x; res->fieldcount = fields; res->admFields = (char **) xmalloc (sizeof (char *) * fields); res->next = NULL; for (x = 0; x < fields; x++) { res->admFields[x] = NULL; } return res; } /* Returns a copy of ENT. */ static AdmEntry * copy_adm_entry (AdmEntry *ent) { int x; AdmEntry *res = alloc_adm_entry (ent->fieldcount); res->field = ent->field; for (x = 0; x < ent->fieldcount; x++) { res->admFields[x] = (ent->admFields[x] == NULL) ? NULL : xstrdup (ent->admFields[x]); } return res; } /* Frees all of the data in ENT, and then the entry itself. The entry may not be part of a chain. */ void free_adm_entry (AdmEntry *ent) { int x; if (ent != NULL) { if (ent->next != NULL) { abort (); } for (x = 0; x < ent->fieldcount; x++) { free (ent->admFields[x]); } free (ent->admFields); free (ent); } } /* Parse LINE into a new AdmEntry node; FIELD is the PR field that the entry belongs to. */ AdmEntry * build_adm_entry (const char *line, FieldIndex field) { AdmEntry *res; /* First figure out how many fields are in it. */ int fieldcnt = 1; const char *currlineptr = line; char **ptr; while ((currlineptr = strchr (currlineptr, ':')) != NULL) { fieldcnt++; currlineptr++; } res = alloc_adm_entry (fieldcnt); res->field = field; ptr = res->admFields; currlineptr = line; while (currlineptr != NULL) { *ptr = get_next_field (&currlineptr, ':'); ptr++; } return res; } /* Read through the adm files, looking for the first line that matches KEY. Return the matching record, or NULL if one was not found. */ AdmEntry * get_adm_record (FieldIndex field, const char *key) { FILE *fp; char *filename; char *path; char *line; size_t keylen; AdmEntry *res = NULL; int notdone = 1; filename = fieldDefForIndex (field)->adm_db_name; if (filename == NULL) { return NULL; } path = gnats_adm_dir (fieldDefForIndex (field)->database, filename); /* append a delimiting ':' to the end of string to make sure the match is fully correct. */ keylen = strlen (key); fp = fopen (path, "r"); free (path); if (fp == NULL) { return NULL; } while (notdone && (line = read_line (fp, NULL)) != NULL) { /* Not sure we need to explicitly ignore comments here, but it doesn't hurt either. */ if (line[0] != '#' && line[keylen] == ':' && strncasecmp(line, key, keylen) == 0) { res = build_adm_entry (line, field); if (res->fieldcount != fieldDefForIndex (field)->adm_db_fields) { /* ??? XXX What else to do here? Wrong number of fields... */ free_adm_entry (res); res = NULL; } notdone = 0; } free (line); } fclose (fp); return res; } /* Construct a chain of AdmEntry entries for the administrative database associated with field FIELD. Returns NULL if there was an error, the chain of entries otherwise. */ static AdmEntry * build_chain_for_field (FieldDef field, FieldIndex fieldIndex) { FILE *fp; char *path; char *line; AdmEntry *res = NULL, **cur = &res; path = gnats_adm_dir (field->database, field->adm_db_name); fp = fopen (path, "r"); free (path); if (fp != NULL) { while ((line = read_line (fp, NULL)) != NULL) { if (line[0] != '#' && line[0] != ' ' && line[0] != '\n') { AdmEntry *newEnt = build_adm_entry (line, fieldIndex); /* Ignore records with too few fields */ if (newEnt != NULL && newEnt->fieldcount == field->adm_db_fields) { *cur = newEnt; cur = &((*cur)->next); } else { free_adm_entry (newEnt); } } free (line); } fclose (fp); } return res; } /* Constructs a chain of AdmEntries from the administrative database associated with field FIELD. Returns either the chain of entries, or a NULL pointer on error. */ AdmEntry * build_chain (FieldIndex field) { return build_chain_for_field (fieldDefForIndex (field), field); } /* Search the chain of AdmEntry nodes in CHAIN for KEY. Returns a copy of the entry if found, NULL otherwise. */ AdmEntry * find_chain_entry (AdmEntry *chain, const char *key) { while (chain != NULL) { if (strcasecmp (chain->admFields[0], key) == 0) { return copy_adm_entry (chain); } chain = chain->next; } return NULL; } /* Search the chain of AdmEntry nodes in CHAIN for KEY. Returns the actual entry if found, NULL otherwise. */ AdmEntry * find_chain_entry_nocopy (AdmEntry *chain, const char *key) { while (chain != NULL) { if (strcasecmp (chain->admFields[0], key) == 0) { return chain; } chain = chain->next; } return NULL; } /* Returns a non-zero value if CHAIN contains an entry that matches KEY. */ int has_chain_entry (AdmEntry *chain, const char *key) { while (chain != NULL) { if (strcasecmp (chain->admFields[0], key) == 0) { return 1; } chain = chain->next; } return 0; } static StringList * buildEnumFieldList (FieldDef field, AdmEntry *chain) { AdmEntry *c = chain; StringList *res = NULL, **ptr = &res; for (c = chain; c != NULL; c = c->next) { *ptr = new_string_list_ent (xstrdup (c->admFields[field->key_field]), NULL); ptr = &((*ptr)->next); } return res; } /* Initialize the administrative database for field FIELD. */ void initAdmField (FieldDef field) { if (field->adm_contents == NULL) { field->adm_contents = build_chain_for_field (field, InvalidFieldIndex); if (field->adm_contents != NULL) { field->enumValues = buildEnumFieldList (field, field->adm_contents); if (! field->allow_any_value && field->default_value == NULL) { field->default_value = xstrdup (field->adm_contents->admFields[0]); } } } } void freeAdmFieldDesc (AdmFieldDesc *desc) { freeStringList ((StringList *) desc); } void freeAdmEntryChain (AdmEntry *ent) { while (ent != NULL) { AdmEntry *n = ent->next; ent->next = NULL; free_adm_entry (ent); ent = n; } } /* Grab the value of field I From PR, then find the corresponding entry in the adm file associated with field I. If one is found, return the subfield value SUBFIELDNAME. Otherwise, a NULL value is returned. */ const char * getAdmSubfieldValue (PR *pr, FieldIndex i, const char *subfieldName) { AdmFieldDesc *desc; const char *prFieldValue; AdmEntry *ent; int x; if (i == NULL) return NULL; desc = fieldDefForIndex (i)->adm_field_des; prFieldValue = field_value (pr, i); if (prFieldValue != NULL && desc != NULL) { ent = find_chain_entry_nocopy (fieldDefForIndex (i)->adm_contents, prFieldValue); if (ent != NULL) { for (x = 0; x < ent->fieldcount && desc != NULL; x++, desc = desc->next) { if (strcasecmp (desc->name, subfieldName) == 0) { return ent->admFields[x]; } } } } return NULL; } int printAdmSubfield (FILE *outfile, const char *eolTerminator, FieldIndex i, AdmEntry *ent, const char *optSubfieldName) { int x; AdmFieldDesc *desc = fieldDefForIndex (i)->adm_field_des; if (desc == NULL && optSubfieldName != NULL) { return -1; } for (x = 0; x < ent->fieldcount && (optSubfieldName == NULL || desc != NULL); x++) { if (optSubfieldName == NULL) { fprintf (outfile, (x == 0) ? "%s" : ":%s", ent->admFields[x]); } else if (strcmp (desc->name, optSubfieldName) == 0) { fprintf (outfile, "%s", ent->admFields[x]); break; } if (desc != NULL) { desc = desc->next; } } fprintf (outfile, "%s", eolTerminator); return 0; } gnats-4.1.0/gnats/adm.h0000644000175000017500000001063107111405574015415 0ustar chewiechewie00000000000000/* Interface to the administrative databases. Copyright (C) 1999 Free Software Foundation, Inc. Contributed by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef _ADM_H_ #define _ADM_H_ #include "gnats.h" typedef struct admEntry { /* Which PR field this entry belongs to. */ FieldIndex field; /* The number of fields in this entry. */ int fieldcount; /* The data. */ char **admFields; /* Optional next pointer, if we have a list of these. */ struct admEntry *next; } AdmEntry; typedef StringList AdmFieldDesc; /* Enums describing each of the hardcoded ADM databases we know about. The number corresponds to which field in the AdmEntry it belongs to. */ enum ClassAdmFields { ClassAdmKey = 0, ClassAdmType = 1, ClassAdmDescription = 2 }; enum StateAdmFields { StateAdmKey = 0, StateAdmType = 1, StateAdmDescription = 2 }; enum CategoryAdmFields { CategoryAdmKey = 0, CategoryAdmFullname = 1, CategoryAdmPerson = 2, CategoryAdmNotify = 3 }; enum ResponsibleAdmFields { ResponsibleAdmKey = 0, ResponsibleAdmFullname = 1, ResponsibleAdmAlias = 2 }; enum SubmitterAdmFields { SubmitterAdmKey = 0, SubmitterAdmFullname = 1, SubmitterAdmType = 2, SubmitterAdmRtime = 3, SubmitterAdmContact = 4, SubmitterAdmNotify = 5 }; enum DatabaseListFields { DatabaseListKey = 0, DatabaseListDesc = 1, DatabaseListPath = 2, DatabaseServer = 3, /* optional */ DatabasePort = 4 /* optional */ }; enum HostListFields { HostListKey = 0, HostListAccessLevel = 1, HostListUnused = 2 }; /* Return the adm record matching KEY from field FIELD; if one is not found, return NULL. This function gets the entry by reading through each entry of the file sequentially, so it is rather slow. The returned entry should be freed with free_adm_entry () when it is no longer needed. */ extern AdmEntry *get_adm_record (FieldIndex field, const char *key); /* Frees an adm record entry. */ extern void free_adm_entry (AdmEntry *ent); /* Construct an AdmEntry item using the contents of LINE. FIELD is the field value placed into the entry; it is legal for it to be InvalidFieldIndex. Fields within an entry are separated with a ':'. */ extern AdmEntry *build_adm_entry (const char *line, FieldIndex field); /* Build a chain of AdmEntry entries containing the contents of the adm file associated with FIELD. */ extern AdmEntry *build_chain (FieldIndex field); /* Search CHAIN for an entry containing KEY as its key. If found, a copy of the entry is returned; otherwise, NULL is returned. The entry should be freed with free_adm_entry() when it is no longer needed. */ extern AdmEntry *find_chain_entry (AdmEntry *chain, const char *key); /* Search CHAIN for an entry containing KEY as its key. If found the entry in the chain is returned, otherwise NULL is returned. */ extern AdmEntry *find_chain_entry_nocopy (AdmEntry *chain, const char *key); /* Return a non-zero value if CHAIN contains an entry with KEY as its key. */ extern int has_chain_entry (AdmEntry *chain, const char *key); /* Allocate an AdmEntry with FIELDS number of fields. */ extern AdmEntry *alloc_adm_entry (int fields); /* Free the AdmEntry chain pointed to by ENT. */ extern void freeAdmEntryChain (AdmEntry *ent); /* Free the AdmFieldDesc entry DESC. */ extern void freeAdmFieldDesc (AdmFieldDesc *desc); extern void initAdmField (FieldDef fieldDef); /* Return the adm entry's subfield SUBFIELDNAME for the adm entry matching the value of FIELD in PR. */ extern const char *getAdmSubfieldValue (PR *pr, FieldIndex field, const char *subfieldName); extern int printAdmSubfield (FILE *outfile, const char *eolTerminator, FieldIndex i, AdmEntry *ent, const char *optSubfieldName); #endif gnats-4.1.0/gnats/at-pr.sh0000644000175000017500000000630407560341664016073 0ustar chewiechewie00000000000000#!/bin/sh # Check whether a PR has been analyzed within the acknowledgment period. # Copyright (C) 1993, 1994, 1995, 1999, 2002 Free Software Foundation, Inc. # Contributed by Brendan Kehoe (brendan@cygnus.com). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. prog=at-pr USAGE="Usage: $prog [-h|--help] [-d|--database database_name] arguments Arguments coming in are (all are required): 1 - response time 2 - PR number 3 - submitter-id 4 - full name of the submitter 5 - contact for the submitter 6 - address for GNATS_ADMIN " PATH=/bin:/usr/bin; export PATH if [ $# -eq 0 ] then echo "$USAGE" >&2 exit 1 fi if [ "x$1" = "x-h" -o "x$1" = "x--help" ] then echo "$USAGE" exit 0 fi # process command line options while [ $# -gt 6 ]; do case "$1" in -d | --database) if [ $# -eq 7 ] then echo "ERROR: value required for $1 option" >&2 echo "$USAGE" >&2 exit 1 fi shift GNATSDB="$1" ;; -d=* | --database=*) GNATSDB="`echo $1 | sed 's/^[-a-z]*=//'`" ;; -*) echo "$USAGE" >&2; exit 1 ;; esac shift done export GNATSDB VERSION=xVERSIONx LIBEXECDIR="xLIBEXECDIRx/gnats" QUERY_PR="xBINDIRx/query-pr" eval `$QUERY_PR --print-sh-vars` if [ "x$GNATSDB_VALID" = x0 ] then echo "Invalid database name $GNATSDB" exit 1 fi if [ $# != 6 ]; then echo "ERROR: $prog called with the incorrect number of arguments" >&2 echo "$USAGE" >&2 exit 1 fi # See if the PR number is still valid. $QUERY_PR --format Number $2 > /dev/null 2>&1 if [ $? != 0 ] then # Maybe the PR is gone? exit 0 fi # Grab the current state of the PR, and the synopsis. # XXX ??? !!! Instead of calling query-pr 3 times, why not do it once and # use read or something? STATE="`$QUERY_PR --format State $2`" SYNOPSIS="`$QUERY_PR --format Synopsis $2`" RESPONSIBLE="`$QUERY_PR --format Responsible $2`" RESP_ADDR=`$QUERY_PR --responsible-address "$RESPONSIBLE"` # $DEBUG_MODE is set to 0 when debug is off in the config file if [ "x$DEBUG_MODE" = "x1" ]; then STEALTH_HEADER="From: $6 (GNATS Management) To: $6 Subject: mail output from at-pr " fi if [ "$STATE" = "${DEFAULTSTATE}" ]; then $LIBEXECDIR/mail-agent << __EOF__ ${STEALTH_HEADER}From: $6 (GNATS Management) To: $5, $RESP_ADDR, $6 Subject: PR $2 not analyzed in $1 hours PR $2 was not analyzed within the acknowledgment period of $1 business hours. The pertinent information is: Submitter-Id: $3 Originator: $4 Synopsis: $SYNOPSIS Person responsible for the PR: $RESPONSIBLE -- The GNU Problem Report Management System (GNATS) __EOF__ fi exit 0 gnats-4.1.0/gnats/autoconf.h.in0000644000175000017500000001435510207435253017103 0ustar chewiechewie00000000000000/* autoconf.h.in. Generated from configure.in by autoheader. */ /* GNATS specific autoconf symbols. Copyright (C) 2004 Free Software Foundation, Inc. Copyright (C) 2001 Milan Zamazal Copyright (C) 1995, 1996 ??? (FIXME, see ChangeLog.v3) This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ /* Define if you have MIT Kerberos version 4 available. */ #undef HAVE_KERBEROS /* Define if your system has socklen_t (glibc?) */ #undef HAVE_SOCKLEN_T /* Define if strftime supports %z. */ #undef HAVE_STRFTIME_WITH_Z /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ #undef CRAY_STACKSEG_END /* Define to 1 if using `alloca.c'. */ #undef C_ALLOCA /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define to 1 if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF /* Define to 1 if you have the `basename' function. */ #undef HAVE_BASENAME /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H /* Whether unsetenv is present in headers. */ #undef HAVE_DECL_UNSETENV /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `ftime' function. */ #undef HAVE_FTIME /* Define to 1 if you have the `getopt' function. */ #undef HAVE_GETOPT /* Define to 1 if you have the `getopt_long' function. */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `krb_get_err_text' function. */ #undef HAVE_KRB_GET_ERR_TEXT /* Define to 1 if you have the `crypt' library (-lcrypt). */ #undef HAVE_LIBCRYPT /* Define to 1 if you have the `gen' library (-lgen). */ #undef HAVE_LIBGEN /* Define to 1 if you have the header file. */ #undef HAVE_LIBGEN_H /* Define to 1 if you have the `inet' library (-linet). */ #undef HAVE_LIBINET /* Define to 1 if you have the `intl' library (-lintl). */ #undef HAVE_LIBINTL /* Define to 1 if you have the `malloc' library (-lmalloc). */ #undef HAVE_LIBMALLOC /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_MACHINE_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the `mkstemp' function. */ #undef HAVE_MKSTEMP /* Define to 1 if you have the `mktemp' function. */ #undef HAVE_MKTEMP /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* 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 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 header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* 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 you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF /* 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 version of this package. */ #undef PACKAGE_VERSION /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Define to 1 if on MINIX. */ #undef _MINIX /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define to `unsigned' if does not define. */ #undef size_t gnats-4.1.0/gnats/btime.c0000644000175000017500000000771407266362147015770 0ustar chewiechewie00000000000000/* Compute the number of business days needed to respond to a PR. Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. Contributed by Tim Wicinski (wicinski@barn.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #define HOURS_WORK_WEEK ((businessDayEnd (database) - businessDayStart (database)) * (businessWeekEnd (database) - businessWeekStart (database)+1)) #define OFFHOURS (24 - (businessDayEnd (database) - businessDayStart (database))) #define SECONDS_DAY 86400 /* 24 * 60 * 60 */ #define SECONDS_HOUR 3600 /* 60 * 60 */ #define SECONDS_WEEK (SECONDS_DAY * 7) struct tm * get_response_time (const DatabaseInfo database, unsigned int rtime) { struct tm *t; static struct tm res_t; time_t seconds; unsigned int err, wday, hour; seconds = time (0); t = localtime (&seconds); wday = t->tm_wday; hour = t->tm_hour; /* Round it out to the nearest hour. */ err = 60 - t->tm_min; if (err <= 30) { seconds += (err * 60); hour++; } else seconds -= (t->tm_min * 60); /* FIXME - This will compute the response time, but it is a bit overwrought with bloat. This can be trimmed down. */ /* Skip ahead by weeks */ seconds += SECONDS_WEEK * (rtime / HOURS_WORK_WEEK); rtime %= HOURS_WORK_WEEK; /* Check when the bug report arrived; if PR arrives before bweek starts, add time until start of business week. */ /* add in the hours from the night before. do this before checking for end of week in case bug is marked at WEEK_END, after businessDayEnd () (ie, after friday at 5). */ if (hour >= businessDayEnd (database)) { seconds += ((24 - hour) + businessDayStart (database)) * SECONDS_HOUR; hour = businessDayStart (database); wday++; } /* If PR arrives before bday starts, then do some simple rounding up to the beginning of the business day. */ else if (hour < businessDayStart (database)) { seconds += (businessDayStart (database) - hour) * SECONDS_HOUR; hour = businessDayStart (database); } while (1) { /* Same as above, but the end of week is slightly different. */ if (wday > businessWeekEnd (database)) { /* Same as addition above, but compute end of week and beginning of week seperately for now (offdays?). */ seconds += ((wday - businessWeekEnd (database)) + businessWeekStart (database)) * SECONDS_DAY; wday = businessWeekStart (database); } /* Add up here, to the end of the first day, the number of days until the bweek starts, and then the hours until the bday begins. */ else if (wday < businessWeekStart (database)) { seconds += (businessWeekStart (database) - wday) * SECONDS_DAY; wday = businessWeekStart (database); } /* Actual computing of the business hours. Note that some response times might stretch into the weekend (thus the loop). */ err = businessDayEnd (database) - hour; if (err > 0 && err < rtime) { /* The # of hours is more than are left today. */ rtime -= err; /* Skip to the next day. */ seconds += ((err + OFFHOURS) * SECONDS_HOUR); hour = businessDayStart (database); wday++; } else { seconds += rtime * SECONDS_HOUR; break; } } memcpy (&res_t, localtime (&seconds), sizeof (struct tm)); return &res_t; } gnats-4.1.0/gnats/builtin-fields.h0000644000175000017500000000421107111405574017563 0ustar chewiechewie00000000000000/* Define the full set of builtin fields. Copyright (C) 1999, 2000 Free Software Foundation, Inc. Contributed by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef BUILTIN_FIELDS_H #define BUILTIN_FIELDS_H #define NUM_BUILTIN_FIELDS 16 typedef struct pr_builtin_field *PR_BuiltinField; #include "field.h" /* Make sure these definitions match the ones in pr-init.c! (In particular, the numbers have to match the order that the names appear in the list.) */ #define NUMBER(DATABASE) (getBuiltinField ((DATABASE), 0)) #define CATEGORY(DATABASE) (getBuiltinField ((DATABASE), 1)) #define SYNOPSIS(DATABASE) (getBuiltinField ((DATABASE), 2)) #define CONFIDENTIAL(DATABASE) (getBuiltinField ((DATABASE), 3)) #define SEVERITY(DATABASE) (getBuiltinField ((DATABASE), 4)) #define PRIORITY(DATABASE) (getBuiltinField ((DATABASE), 5)) #define RESPONSIBLE(DATABASE) (getBuiltinField ((DATABASE), 6)) #define STATE(DATABASE) (getBuiltinField ((DATABASE), 7)) #define SUBMITTER(DATABASE) (getBuiltinField ((DATABASE), 8)) #define ARRIVAL_DATE(DATABASE) (getBuiltinField ((DATABASE), 9)) #define CLOSED_DATE(DATABASE) (getBuiltinField ((DATABASE), 10)) #define LAST_MODIFIED(DATABASE) (getBuiltinField ((DATABASE), 11)) #define ORIGINATOR(DATABASE) (getBuiltinField ((DATABASE), 12)) #define DESCRIPTION(DATABASE) (getBuiltinField ((DATABASE), 13)) #define AUDIT_TRAIL(DATABASE) (getBuiltinField ((DATABASE), 14)) #define UNFORMATTED(DATABASE) (getBuiltinField ((DATABASE), 15)) #endif gnats-4.1.0/gnats/categories0000644000175000017500000000220507374555634016567 0ustar chewiechewie00000000000000# Possible categories for a PR. # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # category:description:responsible:notify # # * `category' is the name of the classification for the PR. The # first category listed will be the default assigned to PRs that # arrive without one set. This is traditionally called "pending". # # * `description' can be a normal text description for the # category, like "Development Tools" for the `tools' category. # # * `responsible' gives the name (which can be found in the responsible # file) of the person who will be given responsibility for any PR # appearing in this category. # # * `notify' are other email addresses which should be given copies of # any PR in this category. These names are also mapped through the # responsible file when trying to determine the email address to use. # pending:Category for faulty PRs:gnats-admin: # # Sample categories: # #doc:Documentation Bug:jeffrey:pesch #gcc:The GNU C compiler:wilson:tiemann #g++:The GNU C++ compiler:brendan:tiemann, mrs #test:*Test Category:gnats-admin: gnats-4.1.0/gnats/check-db.sh0000644000175000017500000001231107652740217016502 0ustar chewiechewie00000000000000#!/bin/sh # # $Id: check-db.sh,v 1.9 2003/04/27 11:35:43 andrewg Exp $ # # Check the database for old lock files or index inconsistencies # Copyright (C) 2001 Peter Novodvorsky # Copyright (C) 2001 Milan Zamazal # Copyright (C) 1993, 1997 Free Software Foundation, Inc. # Contributed by Jonathan Kamens (jik@security.ov.com). # Further hacked by Milan Zamazal (pdm@zamazal.org). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # This script takes no arguments. It attempts to lock the GNATS # database for five minutes; if it fails, it sends a mail message # notifying the administrator of the failure and exits. # # Once the database is locked, the script searches the database for # lock files that are more than 24 hours old. Any old lock files are # reported to the administrator in a mail message. # # After checking for old lock files, it calls gen-index and compares # the results with gnats-adm/index; any inconsistencies are reported # to the administrators in a mail message. # # After checking the index file for inconsistencies, the script # unlocks the database and exits. BINDIR=xBINDIRx LIBEXECDIR=xLIBEXECDIRx/gnats PATH=${LIBEXECDIR}:/usr/local/bin:/bin:/usr/bin; export PATH TMPDIR=${TMPDIR-/tmp} TMPFILE=$TMPDIR/gnats-check-db-$$ PROGRAM=check-db USAGE="Usage: $PROGRAM [-h|--help] [-d|--database DATABASENAME | --all-databases]" # # Process command line options # if [ "$1" = "-h" -o "$1" = "--help" ]; then echo "$USAGE" exit 0 fi CHECKALL=no while [ $# -gt 0 ]; do case "$1" in --all-databases) CHECKALL=yes ;; -d | --database) if [ $# -lt 2 ]; then echo "ERROR: value required for $1 option" >&2 echo "$USAGE" >&2 exit 1 fi shift GNATSDB="$1" ;; -d=* | --database=*) GNATSDB="`echo $1 | sed 's/^[-a-z]*=//'`" ;; -*) echo "$USAGE" >&2 exit 1 ;; esac shift done QUERY_PR="$BINDIR/query-pr" if [ $CHECKALL = yes ]; then for D in `$QUERY_PR --list-databases | sed '1,$s/^\([^:][^:]*\):.*$/\1/'`; do $PROGRAM -d "$D" $* done exit fi export GNATSDB if [ "x$GNATS_ROOT" = "x" ]; then eval `$QUERY_PR --print-sh-vars` GNATS_ROOT=$GNATSDBDIR fi if [ "x$GNATSDB_VALID" = x0 ]; then mail-agent < $TMPFILE if [ -s $TMPFILE ]; then cat - $TMPFILE < $TMPFILE gen-index --export --numerical > $TMPFILE.2 if diff $TMPFILE $TMPFILE.2 > $TMPFILE.3; then true else cat - $TMPFILE.3 <' are from a fresh index generated with $LIBEXECDIR/gen-index. EOF fi rm -f ${TMPFILE}* $LIBEXECDIR/pr-edit --unlockdb exit 0 gnats-4.1.0/gnats/classes0000644000175000017500000000261506620401143016056 0ustar chewiechewie00000000000000# Possible classes for a PR. # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # class[:type[:description]] # # that is, either of the following is okay: # # sw-bug # sw-bug:class # sw-bug:class:Software bug # sw-bug::Software bug # # * `class' is the name of the class; it can contain alphanumerics, # "-", "_", and ".", but no other characters. # # * `type' is the optional name of the class type; it can contain # alphanumerics, "-", "_", and ".", but no other characters. The # only defined class type is "class", but it's not actually used # for anything. # # `description' is an optional one-line description of what this # class means. Any character is okay in the description; a newline # ends it, however. GNATS does not currently use the description, # other than to include it in the --list-classes command, but # certain external tools (such as TkGnats) look for it, so it's # a good idea include one for every class. # # The first listed class is the default class for an incoming Problem # Report. sw-bug::Problem requiring a correction to software. doc-bug::Problem requiring a correction or improvement in documentation. support::A support problem or question. change-request::Suggested change in functionality. mistaken::Not a problem, bad PR submission. duplicate::Duplicate of another existing PR. gnats-4.1.0/gnats/client.c0000644000175000017500000007327107746726431016152 0ustar chewiechewie00000000000000/* Common functions for each GNATS client. Copyright (C) 1994, 1995, 1999, 2000, 2002 Free Software Foundation, Inc. Copyright (C) 2001 Dan Martinez Contributed by Brendan Kehoe (brendan@cygnus.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS 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 detailmails. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnatsd.h" #include "query.h" #include #ifdef HAVE_MACHINE_ENDIAN_H #include /* for htons */ #endif #ifdef HAVE_KERBEROS #include #include #ifndef HAVE_KRB_GET_ERR_TEXT #define krb_get_err_text(status) krb_err_txt[status] #endif int remember_krb_auth_ret = 0; /* yes, I like lisp. go away. */ #endif /* For the GNATS server we'll be talking with. */ static FILE *serv_write, *serv_read; /* If we're reading in a PR, this is it. */ static PR *prBeingRead = NULL; /* If we're reading in a list of PRs, this is where it goes. */ static StringList **prList; /* The descriptor for talking to the server in non-stdio ways. */ static int sockfd, dupfd; /* If 1, send information as we make the query. */ int debug = 0; static int forkedGnatsd = 0; static void free_reply (Reply *r) { free (r->text); free ((char*)r); } static Reply * server_reply (void) { char *recvline; char *p, c; Reply *res = NULL; recvline = read_line (serv_read, NULL); if (recvline == NULL) { fprintf (stderr, "%s: error reading from server\n", program_name); /* This is probably not a good idea, eh? XXX ??? !!! */ safe_exit (); } c = recvline[0]; if (isascii ((int) c) && isdigit((int) c)) { for (p = &recvline[0]; *p && isascii ((int) *p) && isdigit ((int) *p); p++) continue; if (*p) { size_t i; res = (Reply *) xmalloc (sizeof (Reply)); if (*p == '-') { res->type = REPLY_CONT; } else { if (*p != ' ') { fprintf (stderr, "%s: bad type of reply from server\n", program_name); } res->type = REPLY_END; } *p = '\0'; res->state = atoi (recvline); res->text = xstrdup (p + 1); i = strlen (res->text) - 2; if (res->text[i] == '\r' || res->text[i] == '\n') { res->text[i] = '\0'; } else if (res->text[i + 1] == '\n') { res->text[i + 1] = '\0'; } } } free (recvline); return res; } static void readPRFromServer (PR *pr) { char *recvline; int notdone = 1; while (notdone && ((recvline = read_line (serv_read, NULL)) != NULL)) { if (debug) { fprintf (stderr, "%s: received `%s'\n", program_name, recvline); } if (memcmp (recvline, ".\r\n\0", 4) == 0) { finishReadPR (pr, 0); notdone = 0; } else { size_t linelen = strlen (recvline); int i; if (linelen > 0) { if (recvline[linelen - 2] == '\r') { /* Only correct this if we're actually at the end of a line. */ recvline[linelen - 2] = '\n'; recvline[linelen - 1] = '\0'; linelen--; } } /* Remove escape character added by write_multiline() */ i = 0; if (recvline[0] == '.') { i = 1; } addLineToPR (pr, recvline, recvline + i, linelen - i, 0); recvline = NULL; } if (recvline != NULL) { free (recvline); } } } static void readPRListFromServer (void) { char *recvline; int notdone = 1; while (notdone && ((recvline = read_line (serv_read, NULL)) != NULL)) { if (debug) { fprintf (stderr, "%s: received `%s'\n", program_name, recvline); } if (memcmp (recvline, ".\r\n\0", 4) == 0) { notdone = 0; } else { size_t linelen = strlen (recvline); int i; if (linelen > 0) { if (recvline[linelen - 2] == '\r') { /* Only correct this if we're actually at the end of a line. */ recvline[linelen - 2] = '\n'; recvline[linelen - 1] = '\0'; linelen--; } } /* Remove escape character added by write_multiline() */ i = 0; if (recvline[0] == '.') { i = 1; } while (recvline[i] != '\0' && isspace ((int)(unsigned char) recvline[i])) { i++; } if (isdigit ((int) recvline[i])) { *prList = new_string_list_ent (xstrdup (recvline + i), NULL); prList = &((*prList)->next); } } } } static void read_server (FILE *outfp) { char *recvline; int notdone = 1; while (notdone && ((recvline = read_line (serv_read, NULL)) != NULL)) { if (debug) { fprintf (stderr, "%s: received `%s'\n", program_name, recvline); } if (memcmp (recvline, ".\r\n\0", 4) == 0) { notdone = 0; } else { int i; if (recvline[1]) { size_t linelen = strlen (recvline) - 2; if (recvline[linelen] == '\r') { /* Only correct this if we're actually at the end of a line. */ recvline[linelen] = '\n'; recvline[linelen + 1] = '\0'; } } /* Remove escape character added by write_multiline() */ i = 0; if (recvline[0] == '.') { i = 1; } fprintf (outfp, "%s", recvline + i); } free (recvline); } } /* Return the code of the response from the server, or 0 if there wasn't any. */ int get_reply (FILE *outfp) { Reply *r; int done = 0; int retval = 0; /* Make sure anything we've written has gone to them. */ if (fflush (serv_write) == EOF || ferror (serv_write)) { fprintf (stderr, "%s: error writing to server\n", program_name); } while (! done) { r = server_reply (); if (r != NULL) { if (r->type != REPLY_CONT) { done = 1; } if (debug) { fprintf (stderr, "%s: received %d `%s'\n", program_name, r->state, r->text); } switch (r->state) { case CODE_GREETING: case CODE_OK: case CODE_SEND_PR: case CODE_SEND_TEXT: case CODE_SEND_CHANGE_REASON: case CODE_INFORMATION_FILLER: break; case CODE_CLOSING: if (debug) { fprintf (stderr, "%s: server closing down\n", program_name); } break; case CODE_PR_READY: case CODE_TEXT_READY: /* read it til we get a . */ if (prBeingRead != NULL) { readPRFromServer (prBeingRead); } else if (prList != NULL) { readPRListFromServer (); } else { if (outfp != NULL) read_server (outfp); else { fprintf (stderr, "%s: unexpected %d received\n", program_name, r->state); safe_exit(); } } break; case CODE_INFORMATION: if (outfp != NULL) fprintf (outfp, "%s\n", r->text); break; case CODE_NONEXISTENT_PR: case CODE_UNREADABLE_PR: case CODE_LOCKED_PR: case CODE_FILE_ERROR: case CODE_ERROR: case CODE_NO_ADM_ENTRY: case CODE_INVALID_FIELD_NAME: case CODE_INVALID_PR_CONTENTS: case CODE_INVALID_ENUM: case CODE_INVALID_DATE: case CODE_INVALID_EXPR: case CODE_INVALID_DATABASE: case CODE_INVALID_FIELD_EDIT: fprintf (stderr, "%s: %s\n", program_name, r->text); safe_exit (); break; case CODE_PR_NOT_LOCKED: fprintf (stderr, "%s: PR is not locked\n", program_name); safe_exit (); break; case CODE_GNATS_LOCKED: fprintf (stderr, "%s: database is locked\n", program_name); safe_exit (); break; case CODE_NO_PRS_MATCHED: fprintf (stderr, "%s: no PRs matched\n", program_name); safe_exit (); break; case CODE_NO_KERBEROS: fprintf (stderr, "%s: no Kerberos support, authentication failed\n", program_name); /* FALLTHROUGH */ case CODE_NO_ACCESS: #ifdef HAVE_KERBEROS if (remember_krb_auth_ret) fprintf (stderr, "%s: error (%s) while attempting krb4-auth\n", program_name, krb_get_err_text (remember_krb_auth_ret)); else fprintf (stderr, "%s: access denied\n", program_name); #else fprintf (stderr, "%s: access denied\n", program_name); #endif safe_exit (); break; default: fprintf (stderr, "%s: cannot understand %d `%s'\n", program_name, r->state, r->text); safe_exit (); break; } retval = r->state; free_reply (r); } else { if (debug) { fprintf (stderr, "%s: null reply from the server\n", program_name); } retval = 0; done = 1; } } return retval; } void safe_exit (void) { static int doing_exit = 0; if (! doing_exit) { doing_exit = 1; client_exit (); exit (1); } } #ifdef HAVE_KERBEROS void tohex (char *ptr, char *buf, int sz) { static const char hex[] = "0123456789abcdef"; int c; while (sz--) { c = *ptr++ & 0xff; *buf++ = hex[c >> 4]; *buf++ = hex[c & 15]; } *buf++ = 0; } int hexdigit (char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } void fromhex (char *ptr, char *buf, int sz) { int val; while (sz--) { val = hexdigit (*buf++); val <<= 4; val |= hexdigit (*buf++); *ptr++ = val; } } #endif static int clientConnect (ErrorDesc *err, const char *hostname, int port) { FILE *file; #if 1 if (hostname[0] == '/' || hostname[0] == '.') { int sockets[2]; setuid (getuid ()); setgid (getgid ()); socketpair (PF_UNIX, SOCK_STREAM, 0, sockets); forkedGnatsd = fork (); if (forkedGnatsd == 0) { unsetenv ("GNATSDB"); close (0); close (1); dup (sockets[0]); dup (sockets[0]); execl (hostname, hostname, "--not-inetd", NULL); _exit (1); } else { sockfd = sockets[1]; } } else #endif { struct sockaddr_in server; struct hostent *host; memset ((char *) &server, 0, sizeof (server)); server.sin_family = AF_INET; if (isdigit ((int) hostname[0])) { server.sin_addr.s_addr = inet_addr (hostname); } else { host = gethostbyname (hostname); if (host == NULL) { setError (err, CODE_INVALID_DATABASE, "%s: No such host", hostname); return -1; } memcpy (&server.sin_addr, host->h_addr, sizeof (server.sin_addr)); } server.sin_port = htons (port); if (debug) { fprintf (stderr, "opening connection to %s\n", hostname); } sockfd = socket (AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { setError (err, CODE_ERROR, "could not open a socket"); return -1; } if (connect (sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { setError (err, CODE_ERROR, "Couldn't connect to server on %s, port %d", hostname, port); close (sockfd); return -1; } } if ((file = fdopen (sockfd, "r")) == NULL) { setError (err, CODE_ERROR, "read fdopen() failed"); close (sockfd); return -1; } serv_read = file; dupfd = dup (sockfd); if (dupfd < 0) { setError (err, CODE_ERROR, "dup() failed"); close (sockfd); return -1; } if ((file = fdopen (dupfd, "w")) == NULL) { setError (err, CODE_ERROR, "write fdopen() failed"); close (sockfd); close (dupfd); return -1; } serv_write = file; /* Get the hello. */ get_reply (stdout); #ifdef HAVE_KERBEROS { /* This is ugly, because krb_sendauth/krb_recvauth don't maintain a sensible connection state if authentication fails. This is unacceptable here. So I've broken out most of the interesting bits of those routines here. I've also added a hex encoding of the data exchanged instead of the standard authenticator format, to maintain the text-only protocol used in GNATS. */ Reply *r; char *realm, *p, *me; int ret, i; struct sockaddr_in laddr; int laddrlen = sizeof (laddr); char hname[MAXHOSTNAMELEN]; /* for canonicalization by krb_mk_auth */ /* Scratch space for Kerberos library, required to be provided by the application. Keep it all together so we can erase it all at once later. */ struct { CREDENTIALS cred; MSG_DAT msg_data; Key_schedule sched; KTEXT_ST tkt, packet; char buf[MAX_KTXT_LEN * 2 + 10]; } k; k.packet.mbz = 0; #define PUNT(reason,subreason) do{if (debug) fprintf(stderr,"%s: %s (%s)\n", program_name, reason, subreason);goto krb_exit;}while(0) #define SKIP(reason) PUNT("skipping Kerberos authentication",reason) #define FAIL(reason) PUNT("Kerberos authentication failed", reason) /* This probably ought to be a crypto checksum of the authenticator, but a constant should be nearly as secure. */ #define CKSUM 0x10291966 strcpy (hname, host->h_name); realm = krb_realmofhost (hname); ret = krb_mk_auth (KOPT_DO_MUTUAL, &k.tkt, GNATS_KRB4_PRINCIPAL_NAME, hname, realm, CKSUM, GNATS_KRB4_VERSIONID, &k.packet); remember_krb_auth_ret = ret; if (ret) SKIP (krb_get_err_text (ret)); ret = krb_get_cred (GNATS_KRB4_PRINCIPAL_NAME, hname, realm, &k.cred); /* This should always work unless the ticket file has been changed out from under the client at just the wrong time. */ if (ret) abort (); /* Since we don't currently have an interface for specifying a "local name" on the server distinct from the Kerberos principal name, just use the principal. */ me = k.cred.pname; if (debug) { fprintf (stderr, "%s: writing `AUTH krb4-simple'\n", program_name); } fprintf (serv_write, "AUTH krb4-simple\r\n"); fflush (serv_write); r = server_reply (); if (!r || r->state == CODE_AUTH_TYPE_UNSUP) { SKIP ("not supported by server"); } else if (r->state == CODE_ERROR) { fprintf (stderr, "%s: server authentication error: %s\n", program_name, r->text); goto krb_exit; } else if (r->state != CODE_OK) { abort (); } else { free_reply (r); } if (getsockname (sockfd, (struct sockaddr *) &laddr, &laddrlen) < 0) { fprintf (stderr, "%s: getsockname: %s", program_name, strerror (errno)); exit (1); } k.buf[0] = 'x'; /* This would be better with a base-64 encoding, but I'm too lazy to write it write now. */ tohex (k.packet.dat, k.buf + 1, k.packet.length); fprintf (serv_write, "%s\r\n%s\r\n", me, k.buf); fflush (serv_write); i = fgetc (serv_read); if (i == 'x') /* ok */ k.buf[0] = i; else { /* error return */ ungetc (i, serv_read); r = server_reply (); fprintf (stderr, "%s: %s\n", program_name, r->text); goto krb_exit; } p = fgets (k.buf + 1, sizeof (k.buf) - 1, serv_read); if (!p) /* eof */ goto krb_exit; p = strchr (k.buf + 1, '\r'); if (p) *p = 0; k.packet.length = (strlen (k.buf) - 1) / 2; fromhex (k.packet.dat, k.buf + 1, k.packet.length); ret = krb_check_auth (&k.packet, CKSUM, &k.msg_data, k.cred.session, k.sched, &laddr, &server); if (ret) fprintf (stderr, "%s: authentication failed: %s\n", program_name, krb_get_err_text (ret)); /* Now that authentication has succeeded (presumably), get an "ok" response if authorization succeeds, or an error if it fails. (Not everyone listed in the Kerberos database is necessarily permitted to retrieve information from GNATS.) */ get_reply (stdout); krb_exit: /* Zero out the Kerberos scratch area, since it includes authentication information we don't want going into core files etc. */ memset ((char *) &k, '?', sizeof (k)); } #endif return 0; } void client_exit (void) { /* Do nothing, if we're not a network client. */ if (serv_read != NULL && serv_write != NULL) { /* That's it, say bye-bye. */ if (debug) { fprintf (stderr, "%s: writing `QUIT'\n", program_name); } fflush (serv_read); fprintf (serv_write, "QUIT\r\n"); fclose (serv_write); fclose (serv_read); serv_write = NULL; serv_read = NULL; } if (forkedGnatsd != 0) { int status; wait (&status); } } /* change database command to recognize databse aliases for network client commands like nquery-pr. */ void client_chdb (const char *newRoot) { if (newRoot == NULL) { newRoot = "default"; } /* send the change db command and get server's reply */ if (debug) { fprintf (stderr, "%s: writing `CHDB %s'\n", program_name, newRoot); } fprintf (serv_write, "CHDB %s\r\n", newRoot); get_reply (stdout); /* this will exit on error */ } static void client_user (const char *user, const char *passwd) { /* send the user command and get server's reply */ if (debug) { fprintf (stderr, "%s: writing `USER %s %s'\n", program_name, user, passwd); } fprintf (serv_write, "USER %s %s\r\n", user, passwd); get_reply(stdout); /* this will exit on error */ } /* Scan the environment and the global database configuration file for the info needed to connect to the gnatsd server. */ void scanEnv (char **user, char **passwd, char **hostname, int *port, char **database) { char *vals[5]; char *evar = *database == NULL ? getenv ("GNATSDB") : *database; bool is_net_conn = databaseSpecIsNetConn (evar); if (evar == NULL || evar[0] == '\0' || is_net_conn) { if (*hostname == NULL) { const char *specS = databaseSpecServer (evar); if (specS != NULL) { *hostname = xstrdup (specS); } } if (*port == -1) { const char *pname = databaseSpecPort (evar); if (pname != NULL) { if (isdigit ((int) (pname[0]))) { *port = atoi (pname); } else { struct servent *s = getservbyname (pname, "tcp"); if (s != NULL) { *port = ntohs (s->s_port); } } } } } else { char *place = evar; int x; for (x = 0; x < 5; x++) { if (place != NULL) { char *nplace = strchr (place, ':'); if (nplace != NULL) { vals[x] = xmalloc (nplace - place + 1); memcpy (vals[x], place, nplace - place); vals[x][nplace - place] = '\0'; place = nplace + 1; } else { vals[x] = xstrdup (place); place = NULL; } } else { vals[x] = xstrdup (""); } } if (*hostname == NULL) { *hostname = vals[0]; } else { free (vals[0]); } if (*port == -1 && vals[1][0] != '\0') { *port = atoi (vals[1]); } free (vals[1]); if (*database == NULL && vals[2][0] != '\0') { *database = vals[2]; } else { free (vals[2]); } if (*user == NULL && vals[3][0] != '\0') { *user = vals[3]; } else { free (vals[3]); } if (*passwd == NULL && vals[4][0] != '\0') { *passwd = vals[4]; } else { free (vals[4]); } } if (*user == NULL) { /* This is just wrong, but we'll live with it. XXX ??? !!! */ char *lname = getlogin (); if (lname != NULL) { *user = xstrdup (lname); } else { struct passwd *p; p = getpwuid (getuid ()); if (p != NULL) { *user = xstrdup (p->pw_name); } } } if (*passwd == NULL) { *passwd = xstrdup ("*"); } if (*database == NULL && ! is_net_conn) { *database = ((evar == NULL || evar[0] == '\0') ? xstrdup ("default") : xstrdup (evar)); } if (*port == -1) { struct servent *s = getservbyname (DEFAULT_GNATS_SERVICE, "tcp"); if (s != NULL) { *port = ntohs (s->s_port); } } } int client_init_gnats (ErrorDesc *err, const char *userArg, const char *passwdArg, const char *hostnameArg, int port, const char *databaseArg) { char *user = NULL; char *passwd = NULL; char *hostname = NULL; char *database = NULL; int res = -1; if (userArg != NULL) { user = xstrdup (userArg); } if (passwdArg != NULL) { passwd = xstrdup (passwdArg); } if (hostnameArg != NULL) { hostname = xstrdup (hostnameArg); } if (databaseArg != NULL) { database = xstrdup (databaseArg); } scanEnv (&user, &passwd, &hostname, &port, &database); if (hostname == NULL) { setError (err, CODE_INVALID_DATABASE, "Can't determine hostname to connect to"); } else if (port < 0) { setError (err, CODE_INVALID_DATABASE, "Can't determine port number to connect to"); } else if (user == NULL) { setError (err, CODE_INVALID_DATABASE, "Can't determine username to send to the server"); } else if (passwd == NULL) { setError (err, CODE_INVALID_DATABASE, "Can't determine password to send to the server"); } else if (clientConnect (err, hostname, port) == 0) { client_chdb (database); client_user (user, passwd); res = 0; } if (user != NULL) { free (user); } if (passwd != NULL) { free (passwd); } if (hostname != NULL) { free (hostname); } if (database != NULL) { free (database); } return res; } static DatabaseInfo lockedDatabase = NULL; int client_lock_gnats (const DatabaseInfo database, ErrorDesc *err) { if (lockedDatabase != NULL) { abort (); } lockedDatabase = database; return lock_gnats (database, err); } void client_unlock_gnats (void) { ErrorDesc err; DatabaseInfo database = lockedDatabase; lockedDatabase = NULL; if (database != NULL) { if (unlock_gnats (database, &err) < 0) { client_print_errors (database, err); } } } void client_print_errors (const DatabaseInfo database, ErrorDesc err) { switch (getErrorCode (err)) { case CODE_NO_INDEX: case CODE_FILE_ERROR: fprintf (stderr, "%s: %s\n", program_name, getErrorMessage (err)); punt (database, 1, getErrorMessage (err)); break; case CODE_INVALID_FIELD_CONTENTS: { BadFields badFieldList = getBadFieldList (err); while (badFieldList != NULL) { fprintf (stderr, "%s: invalid value `%s' in field %s\n", program_name, badFieldValue (badFieldList), fieldDefForIndex (badFieldIndex (badFieldList))->name); badFieldList = nextBadField (badFieldList); } } break; case CODE_INVALID_ENUM: printf ("%s: invalid fields:\n", program_name); { BadFields badFieldList = getBadFieldList (err); while (badFieldList != NULL) { FieldIndex f = badFieldIndex (badFieldList); printf ("\tNote: There was a bad value `%s' for the field `%s'.\n\tIt was set to the default value of `%s'.\n", badFieldValue (badFieldList), fieldDefForIndex (f)->name, fieldDefForIndex (f)->default_value); badFieldList = nextBadField (badFieldList); } } break; default: fprintf (stderr, "%s: %s\n", program_name, getErrorMessage (err)); break; } } void sendRemoteListQuery (ListTypes whichList, FILE *outfile) { const char *listName = listTypeToString (whichList); if (listName != NULL) { if (debug) { fprintf (stderr, "%s: writing `LIST %s'\n", program_name, listName); } fprintf (serv_write, "LIST %s\r\n", listName); if (outfile != NULL) { get_reply (outfile); } } } static void sendQueryFormat (const char *name) { if (debug) { fprintf (stderr, "%s: writing `QFMT %s'\n", program_name, name); } fprintf (serv_write, "QFMT %s\r\n", name); get_reply (NULL); } void sendRemoteQuery (const char *queryString, const char **args, const char *query_format_name, FILE *outfile) { char *buf; int i = 0; size_t buflen; if (queryString != NULL && queryString[0] != '\0') { if (debug) { fprintf (stderr, "%s: writing `EXPR %s'\n", program_name, queryString); } fprintf (serv_write, "EXPR %s\r\n", queryString); get_reply (NULL); } sendQueryFormat (query_format_name); /* I'm not entirely sure why we go through this foolishness of building up a string containing the command, only to just print it out--why not call fprintf() a bunch of times? It'd probably be faster. XXX ??? !!! */ buf = xstrdup ("QUER"); buflen = 4; while (args != NULL && args[i] != NULL) { size_t arglen = strlen (args[i]); buf = xrealloc (buf, buflen + arglen + 2); buf[buflen] = ' '; memcpy (buf + buflen + 1, args[i], arglen + 1); buflen += arglen + 1; i++; } if (debug) { fprintf (stderr, "%s: writing `%s'\n", program_name, buf); } fprintf (serv_write, "%s\r\n", buf); free (buf); if (outfile != NULL) { get_reply (outfile); } } void clientGetAdmField (FILE *outfile, const char *admField, const char *admSubfield, const char *admKey) { if (admSubfield == NULL) { admSubfield = ""; } fprintf (serv_write, "ADMV %s %s %s\r\n", admField, admKey, admSubfield); get_reply (outfile); } /* Read PR PRNUM from the GNATS server, and return it. */ PR * clientReadPR (const char *prNum) { PR *res; prBeingRead = allocPR (NULL); fprintf (serv_write, "RSET\r\n"); get_reply (NULL); fprintf (serv_write, "QFMT full\r\n"); get_reply (NULL); fprintf (serv_write, "QUER %s\r\n", prNum); initReadPR (prBeingRead); get_reply (NULL); res = prBeingRead; prBeingRead = NULL; return res; } /* Return a list of PRs that match the specified query expression. */ StringList * clientGetPRList (const char *expr) { StringList *res = NULL; fprintf (serv_write, "RSET\r\n"); get_reply (NULL); sendRemoteQuery (expr, NULL, "Number", NULL); prList = &res; get_reply (NULL); return res; } void netSetEditEmailAddr (const char *addr) { fprintf (serv_write, "EDITADDR %s\r\n", addr); get_reply (NULL); } static void netSendPRCmd (const char *cmd, FILE *file, int show_information) { char *line; if (debug) { fprintf (stderr, "%s: writing `%s'\n", program_name, cmd); } fprintf (serv_write, "%s\r\n", cmd); get_reply (stdout); /* XXX */ while ((line = read_line (file, NULL)) != NULL) { write_multitext (serv_write, line, "\r\n"); free (line); } fprintf (serv_write, ".\r\n"); /* if get_reply finds errors it writes messages and doesn't return */ get_reply (show_information ? stdout : NULL); } void netCheckPR (FILE *file, int initial) { netSendPRCmd (initial ? "CHEK INIT" : "CHEK", file, 1); } void netEditField (FILE *fp, const char *prnum, const char *fieldname, const char *editEmailAddr, int append, char *reason) { const char *cmd; char *line; int reply; netSetEditEmailAddr (editEmailAddr); if (append) { cmd = "APPN"; } else { cmd = "REPL"; } fprintf (serv_write, "%s %s %s\r\n", cmd, prnum, fieldname); do { reply = get_reply (stdout); switch (reply) { case CODE_SEND_TEXT: while ((line = read_line (fp, NULL)) != NULL) { write_multitext (serv_write, line, "\r\n"); free (line); } fprintf (serv_write, ".\r\n"); break; case CODE_SEND_CHANGE_REASON: if (reason) fprintf (serv_write, "%s\r\n.\r\n", reason); else { fprintf (stderr, "%s: server wants a change-reason for %s," " but none was supplied.\n", program_name, fieldname); safe_exit (); } break; case CODE_OK: break; default: fprintf (stderr, "%s: bad reply from server: %d.\n", program_name, reply); safe_exit (); break; } } while (reply != CODE_OK); } void netSubmitNewPR (FILE *file, int show_prnum) { netSendPRCmd ("SUBM", file, show_prnum); } void netModifyPR (FILE *file, const char *prNum, const char *editEmailAddr) { char *buf; netSetEditEmailAddr (editEmailAddr); asprintf (&buf, "EDIT %s", prNum); netSendPRCmd (buf, file, 1); free (buf); } void netLockDB (void) { if (debug) { fprintf (stderr, "%s: writing `LKDB'\n", program_name); } fprintf (serv_write, "LKDB\r\n"); get_reply (stdout); } void netUnlockDB (void) { if (debug) { fprintf (stderr, "%s: writing `UNDB'\n", program_name); } fprintf (serv_write, "UNDB\r\n"); get_reply (stdout); } void netLockPR (const char *prNum, const char *username, const char *processID) { if (processID != NULL) { fprintf (serv_write, "LOCK %s %s %s\r\n", prNum, username, processID); } else { fprintf (serv_write, "LOCK %s %s\r\n", prNum, username); } get_reply (stdout); } void netUnlockPR (const char *prNum) { if (debug) { fprintf (stderr, "%s: writing `UNLK %s'\n", program_name, prNum); } fprintf (serv_write, "UNLK %s\r\n", prNum); get_reply (stdout); } void netDeletePR (const char *prNum, const char *editUserEmailAddr) { netSetEditEmailAddr (editUserEmailAddr); if (debug) { fprintf (stderr, "%s: writing `DELETE %s'\n", program_name, prNum); } fprintf (serv_write, "DELETE %s\r\n", prNum); get_reply (stdout); } void netFieldFlags (const char *fieldname) { fprintf (serv_write, "FIELDFLAGS %s\r\n", fieldname); get_reply (stdout); } void netValidValues (const char *fieldname) { fprintf (serv_write, "FVLD %s\r\n", fieldname); get_reply (stdout); } void netFieldDescription (const char *fieldname) { fprintf (serv_write, "FDSC %s\r\n", fieldname); get_reply (stdout); } void netFieldType (const char *fieldname) { fprintf (serv_write, "FTYP %s\r\n", fieldname); get_reply (stdout); } gnats-4.1.0/gnats/cmds.c0000644000175000017500000011646707724054426015621 0ustar chewiechewie00000000000000/* Commands for the GNATS server. Copyright (C) 1994, 95, 95, 1997, 2001, 2002 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org) and other contributors. This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS 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 detailmails. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnatsd.h" #include "query.h" #include "mail.h" #ifdef HAVE_KERBEROS #include #include #ifndef HAVE_KRB_GET_ERR_TEXT #define krb_get_err_text(status) krb_err_txt[status] #endif #endif extern int require_db; static QueryExpr query = NULL; #ifdef HAVE_KERBEROS extern int client_authorized; #endif static int chk_nargs (int, const char*); static char *get_text_memory (ErrorDesc *err); static QueryFormat *queryFormat = NULL; static char *editEmailAddr = NULL; static DatabaseInfo currentDatabase = NULL; static char *currentUsername = NULL; static char *currentPassword = NULL; static int chk_nargs (int ac, const char *what) { if (ac == 1) { return 1; } else { if (ac > 1) { printf ("%d Only one %s allowed.\r\n", CODE_CMD_ERROR, what); } else { printf ("%d One %s required.\r\n", CODE_CMD_ERROR, what); } return 0; } } static void print_server_errors (ErrorDesc err) { switch (getErrorCode (err)) { case CODE_INVALID_ENUM: { BadFields badFieldList = getBadFieldList (err); while (badFieldList != NULL) { BadFields nextField = nextBadField (badFieldList); FieldIndex f = badFieldIndex (badFieldList); printf ("%d%cThere is a bad value `%s' for the field `%s'.\r\n", CODE_INVALID_ENUM, nextField != NULL ? '-' : ' ', badFieldValue (badFieldList), fieldDefForIndex (f)->name); badFieldList = nextField; } break; } default: printf ("%d %s\r\n", getErrorCode (err), getErrorMessage (err)); break; } freeErrorDesc (err); } static int daemon_lock_gnats (bool verbose) { ErrorDesc err; int err_code; if ((err_code = lock_gnats (currentDatabase, &err)) == 0) { if (verbose) printf ("%d GNATS database is now locked.\r\n", CODE_OK); } else { printf ("%d %s\r\n", getErrorCode (err), getErrorMessage (err)); } return err_code; } static int daemon_unlock_gnats (bool verbose) { ErrorDesc err; int err_code = unlock_gnats (currentDatabase, &err); if (err_code == 0) { if (verbose) printf ("%d GNATS database is now unlocked.\r\n", CODE_OK); return 0; } else if (err_code > 0) { printf ("%d GNATS database is already unlocked\r\n", CODE_OK); return 0; } else { printf ("%d %s\r\n", getErrorCode (err), getErrorMessage (err)); return -1; } } static void noargs (const char *s) { printf ("%d %s takes no arguments.\r\n", CODE_CMD_ERROR, s); } static char * get_text (void) { FILE *tf; char *path; char *buf; const char *tmpdir; MsgType r; int done = 0; int error = 0; tmpdir = temporary_directory (); asprintf (&path, "%s/gnatsXXXXXX", tmpdir); if ((tf = fopen_temporary_file (path, "w", 0600)) == (FILE *) NULL) { /* give error that we can't create the temp and leave. */ /* XXX ??? !!! Where did we `give error'?? Ugh caveman verb noun! */ free (path); return NULL; } while (! done && ! error) { r = get_line (&buf, 2 * 60 * 60); if (r == PR_ok) { if (buf[0] == '.' && (buf[1] == '\r' || buf[1] == '\n' || buf[1] == '\0')) { done = 1; } else { /* Remove escape character added by write_multiline() */ int i = 0; if (buf[0] == '.') { i = 1; } fputs (buf + i, tf); fputs ("\n", tf); if (ferror (tf)) { error = 1; } } } else { if (r == PR_timeout) { printf ("%d Read timeout.\r\n", CODE_TIMEOUT); } error = 1; } if (buf != NULL) { free (buf); buf = NULL; } } if (feof (stdin) || ferror (stdin)) { printf ("%d error reading\n", CODE_ERROR); error = 1; } else if (ferror (tf)) { printf ("%d error writing\n", CODE_ERROR); error = 1; } else if (fflush (tf) != 0) { printf ("%d error flushing read input\n", CODE_ERROR); error = 1; } fclose (tf); if (buf != NULL) { free (buf); } if (! error) { return path; } else { if (unlink (path) && errno != ENOENT) { syslog (LOG_ERR, "can't remove %s: %m", path); } free (path); return NULL; } } /* Print out the entry returned from a query operation. WHICH is the number of the entry (1 for the first matching entry, 2 for the second, etc). PR is the PR entry for the matching entry. QUERY_FORMAT is the query format that was passed in when the query was executed. This function is also invoked when the queries are complete; in this case I will be NULL, and WHICH will represent the total number of matching records. */ static void server_print_query (int which, PR *pr, QueryFormat *query_format) { if (pr != NULL) { if (which == 1) { printf ("%d PRs follow.\r\n", CODE_PR_READY); } else { printf ("\r\n"); } print_pr (stdout, pr, query_format, "\r\n"); } else { if (which == 0) { printf ("%d No PRs match.\r\n", CODE_NO_PRS_MATCHED); } else { printf ("\r\n.\r\n"); } } } void GNATS_qfmt (int ac, char **av) { ErrorDesc err; if (! chk_nargs (ac, "query format")) { return; } queryFormat = findQueryFormat (currentDatabase, av[0], &err); if (queryFormat != NULL) { printf ("%d Ok.\r\n", CODE_OK); } else { print_server_errors (err); } } void GNATS_user (int ac, char **av) { ErrorDesc err; if (ac == 0) { printf ("%d-The current user access level is:\r\n", CODE_INFORMATION_FILLER); printf ("%d %s\r\n", CODE_INFORMATION, access_level_str (user_access)); } else if ((ac == 1) || (ac == 2)) { if (databaseValid (currentDatabase)) { if (gnatsdChdb (databaseName (currentDatabase), av[0], ac == 2 ? av[1] : "", 0, &err) != 0) { print_server_errors (err); } } else { if (currentUsername != NULL) { free (currentUsername); } if (currentPassword != NULL) { free (currentPassword); } currentUsername = xstrdup (av[0]); if (ac == 2) { currentPassword = xstrdup (av[1]); } else { currentPassword = (char *)""; } printf ("%d Current database is not valid; use CHDB to set the database\r\n", CODE_OK); } } else { printf ("%d Need one or two arguments, username and optionally a password\r\n", CODE_CMD_ERROR); } } static void set_confidential_access (QueryExpr *search) { if (user_access < ACCESS_VIEWCONF) { QueryExpr newQ = parseQueryExpression (currentDatabase, "builtinfield:Confidential ~ \"no\"", NULL); *search = booleanQuery (QueryAnd, *search, newQ); } } static void do_server_query (int ac, char **av) { ErrorDesc err; if (queryFormat == NULL) { printf ("%d No query format specified\r\n", CODE_INVALID_QUERY_FORMAT); return; } set_confidential_access (&query); if (iterate_prs (currentDatabase, ac, av, query, queryFormat, server_print_query, &err) < 0) { print_server_errors (err); } } void GNATS_quit (int ac ATTRIBUTE_UNUSED, char **av ATTRIBUTE_UNUSED) { printf ("Hi, I'M GNATS_quit.\r\n"); } void GNATS_quer (int ac, char **av) { do_server_query (ac, av); } void GNATS_lock (int ac, char **av) { char *l = NULL; int i, len; ErrorDesc err; int result; if (ac < 2) { printf ("%d Must lock with PR number, username, and process locking it.\r\n", CODE_CMD_ERROR); return; } if (! prExists (currentDatabase, av[0], &err)) { print_server_errors (err); return; } if (ac > 2) { /* XXX FIXME -- we need a cleaner approach to this. */ /* XXX FIXME -- we need to rewrite this "program" from scratch. */ for (i = 2, len = 0; i < ac; i++) { len += strlen (av[i]); } l = (char *) xmalloc (sizeof (char) * len + ac - 2); strcpy (l, av[2]); for (i = 3; i < ac; i++) { strcat (l, " "); strcat (l, av[i]); } } if ((result = lock_pr (currentDatabase, av[0], av[1], l, &err)) != 0) { PR *pr = readPRWithNum (currentDatabase, av[0], 0, &err); if (pr != NULL) { printf ("%d PRs follow.\r\n", CODE_PR_READY); print_named_format_pr (stdout, pr, "full", "\r\n", &err); printf (".\r\n"); free_pr (pr); } else { result = 0; if (unlock_pr (currentDatabase, av[0], &err) != 0) { /* ??? XXX !!! */ setError (&err, CODE_NONEXISTENT_PR, "Invalid PR %s.", av[0]); } } } if (result == 0) { print_server_errors (err); } if (l != NULL) { free (l); } } void GNATS_subm (int ac, char **av ATTRIBUTE_UNUSED) { char *tempfile; FILE *fp; ErrorDesc err; int new_pr_num; if (ac != 0) { noargs ("SUBM"); return; } if (is_gnats_locked (currentDatabase)) { printf ("%d GNATS is currently locked; try again later.\r\n", CODE_GNATS_LOCKED); return; } printf ("%d Ok.\r\n", CODE_SEND_PR); fflush (stdout); tempfile = get_text (); if (tempfile == NULL) { return; } fp = fopen (tempfile, "r"); if (fp != NULL) { if (daemon_lock_gnats (FALSE) == 0) { if ((new_pr_num = submit_pr (currentDatabase, fp, &err)) != 0) { printf ("%d-The added PR number is:\r\n", CODE_INFORMATION_FILLER); printf ("%d %d\r\n", CODE_INFORMATION, new_pr_num); fflush (stdout); } else { print_server_errors (err); } daemon_unlock_gnats (FALSE); } } else { printf ("%d Failed reading saved text.\r\n", CODE_FILE_ERROR); } unlink (tempfile); free (tempfile); } void GNATS_unlk (int ac, char **av) { ErrorDesc err; if (! chk_nargs (ac, "PR to be unlocked")) return; if (! prExists (currentDatabase, av[0], &err)) { print_server_errors (err); return; } if (unlock_pr (currentDatabase, av[0], &err) != 0) { printf ("%d PR %s unlocked.\r\n", CODE_OK, av[0]); } else { print_server_errors (err); } } void GNATS_lkdb (int ac, char **av ATTRIBUTE_UNUSED) { if (ac != 0) { noargs ("LKDB"); return; } daemon_lock_gnats (TRUE); } void GNATS_undb (int ac, char **av ATTRIBUTE_UNUSED) { if (ac != 0) { noargs ("UNDB"); return; } daemon_unlock_gnats (TRUE); } /* Change to the specified DATABASE. USERANME and PASSWORD are used to authenticate to the database. If QUIET is non-zero, we do not print an acknowledgement that the change succeeded. A non-zero value is returned if we could not change to the requested database, and ERR will then describe the error. */ int gnatsdChdb (const char *nameOfDb, const char *username, const char *passwd, int quiet, ErrorDesc *err) { int dbValid = 0; DatabaseInfo new_db = init_gnats ("gnatsd", nameOfDb, err); if (username != NULL) { if (currentUsername != NULL) { free (currentUsername); } currentUsername = xstrdup (username); if (currentPassword != NULL) { free (currentPassword); } if (passwd != NULL) { currentPassword = xstrdup (passwd); } else { currentPassword = NULL; } } if (currentUsername == NULL) { currentUsername = xstrdup (""); } if (currentPassword == NULL) { currentPassword = xstrdup (""); } if (new_db != NULL) { Access_Level access; /* make sure that a host that is allowed to access one database does not switch to a database where permission is not granted */ if (! verifyHostAndUser (new_db, current_host, current_addr, currentUsername, currentPassword, &access)) { const char *database_name = databaseName(new_db); /* Hmmm. Should we still do this here? ??? XXX !!! */ syslog (LOG_ERR, "host %s (%s) not allowed access for %s", current_host, current_addr, database_name); setError (err, CODE_NO_ACCESS, "You are not permitted to access database %s.\r\n", database_name); freeDatabaseInfo (new_db); } else { /* Clear the gnatsd --require-db flag and set user access to host default access for new db */ require_db = 0; user_access = access; /* Don't free the current database if it's the same as the new one. */ if (currentDatabase != new_db) { freeDatabaseInfo (currentDatabase); queryFormat = NULL; } currentDatabase = new_db; /* Default an editing users email address */ editEmailAddr = get_responsible_addr (currentDatabase, 0, 0, username); if (! quiet) { printf ("%d-Now accessing GNATS database '%s'\r\n", CODE_OK, databaseName (new_db)); printf ("%d User access level set to '%s'\r\n", CODE_OK, access_level_str (access)); } dbValid = 1; } } return ! dbValid; } /* change database command */ void GNATS_chdb (int ac, char **av) { ErrorDesc err; const char *user = NULL; const char *passwd = NULL; if (ac != 1 && ac != 2 && ac != 3) { printf ("%d One, two, or three arguments required.\r\n", CODE_CMD_ERROR); return; } if (ac == 3) { user = av[1]; passwd = av[2]; } else if (ac == 2) { user = av[1]; } if (gnatsdChdb (av[0], user, passwd, 0, &err) != 0) { print_server_errors (err); } } void GNATS_chek (int ac, char **av ATTRIBUTE_UNUSED) { char *given; FILE *fp; ErrorDesc err; int initial = 0; if (ac > 1) { printf ("%d CHEK takes either 0 or 1 argument.\r\n", CODE_CMD_ERROR); return; } if (ac == 1) { /* XXX ??? !!! Should look at the argument. */ initial = 1; } printf ("%d Ok.\r\n", CODE_SEND_PR); fflush (stdout); given = get_text (); if (given == NULL) { return; /* XXX */ } fp = fopen (given, "r"); if (fp != NULL) { if (! check_pr_file (currentDatabase, fp, &err, initial)) { print_server_errors (err); printf ("%d Errors found checking PR text.\r\n", CODE_INVALID_PR_CONTENTS); } else { printf ("%d PR text checked OK.\r\n", CODE_OK); } fclose (fp); if (unlink (given) && errno != ENOENT) { syslog (LOG_ERR, "can't remove %s: %m", given); } } else { printf ("%d Failed reading saved text.\r\n", CODE_FILE_ERROR); } free (given); return; } void GNATS_edit (int ac, char **av) { char *given; FILE *fp; ErrorDesc err; if (! chk_nargs (ac, "PR to be edited")) return; if (! prExists (currentDatabase, av[0], &err)) { print_server_errors (err); return; } if (! isPrLocked (currentDatabase, av[0])) { setError (&err, CODE_PR_NOT_LOCKED, "You must lock PR %s and get its current content first.", av[0]); print_server_errors (err); return; } if (is_gnats_locked (currentDatabase)) { printf ("%d GNATS is currently locked; try again later.\r\n", CODE_GNATS_LOCKED); return; } printf ("%d Ok.\r\n", CODE_SEND_PR); fflush (stdout); given = get_text (); if (given == NULL) { return; /* XXX */ } fp = fopen (given, "r"); if (fp == NULL) { printf ("%d Failed reading saved text.\r\n", CODE_FILE_ERROR); } else { if (daemon_lock_gnats (FALSE) == 0) { if (! replace_pr (currentDatabase, fp, editEmailAddr, &err)) { print_server_errors (err); printf ("%d Failed writing out PR.\r\n", CODE_WRITE_PR_FAILED); } else { printf ("%d PR %s filed.\r\n", CODE_OK, av[0]); } fclose (fp); daemon_unlock_gnats (FALSE); if (unlink (given) && errno != ENOENT) { syslog (LOG_ERR, "can't remove %s: %m", given); } } } free (given); } static void GNATS_appnOrRepl (int ac, char **av, int mode) { char *text; ErrorDesc err; FieldIndex fieldIndex; if (ac != 2) { printf ("%d Need two arguments, PR number and field\r\n", CODE_CMD_ERROR); return; } fieldIndex = find_field_index (currentDatabase, av[1]); if (fieldIndex == InvalidFieldIndex) { printf ("%d Invalid field name `%s'\r\n", CODE_INVALID_FIELD_NAME, av[1]); } else { char *changeReason = NULL; printf ("%d Ok.\r\n", CODE_SEND_TEXT); fflush (stdout); text = get_text_memory (&err); if (text != NULL) { if (requiresChangeReason (fieldDefForIndex (fieldIndex))) { printf ("%d Ok, now send the field change reason.\r\n", CODE_SEND_CHANGE_REASON); fflush (stdout); changeReason = get_text_memory (&err); if (changeReason == NULL) { free (text); text = NULL; } } } if (text != NULL) { /* Remove trailing newline. */ text[strlen(text) - 1] = '\0'; if (changeReason != NULL) { changeReason[strlen (changeReason) - 1] = '\0'; } if (daemon_lock_gnats (FALSE) == 0) { if (edit_field (currentDatabase, av[0], fieldIndex, mode, text, changeReason, editEmailAddr, &err) == 0) { print_server_errors (err); } else { printf ("%d Ok.\r\n", CODE_OK); } daemon_unlock_gnats (FALSE); } } else { print_server_errors (err); } } } void GNATS_appn (int ac, char **av) { GNATS_appnOrRepl (ac, av, 1); } void GNATS_repl (int ac, char **av) { GNATS_appnOrRepl (ac, av, 0); } void GNATS_editaddr (int ac, char **av) { if (! chk_nargs (ac, "email address")) { return; } if (editEmailAddr != NULL) { free (editEmailAddr); } editEmailAddr = xstrdup (av[0]); printf ("%d Ok.\r\n", CODE_OK); } void GNATS_delete (int ac, char **av) { if (chk_nargs (ac, "PR number")) { ErrorDesc err; int result = deletePR (currentDatabase, av[0], editEmailAddr, &err); if (result == 0) { printf ("%d PR %s deleted.\r\n", CODE_OK, av[0]); } else { print_server_errors (err); } } } void GNATS_admv (int ac, char **av) { if (ac == 2 || ac == 3) { ComplexFieldIndex ci = newComplexFieldIndex (currentDatabase, av[0]); if (parseComplexFieldIndex (ci) != 0 || simpleFieldIndexValue (ci) == InvalidFieldIndex) { printf ("%d Invalid field name `%s'\r\n", CODE_INVALID_FIELD_NAME, av[0]); } else { FieldIndex i =simpleFieldIndexValue (ci); AdmEntry *ent = get_adm_record (i, av[1]); if (ent == NULL) { printf ("%d No entry in field `%s' for `%s'.\r\n", CODE_NO_ADM_ENTRY, av[0], av[1]); } else { printf ("%d ", CODE_INFORMATION); printAdmSubfield (stdout, "\r\n", i, ent, (ac > 2) ? av[2] : NULL); } } } else { printf ("%d Need two or three arguments: fieldname, key, and optional subfield\n", CODE_CMD_ERROR); } } void GNATS_vfld (int ac, char **av) { FieldIndex field; char *newt; ErrorDesc err; size_t len; if (! chk_nargs (ac, "field name")) return; field = find_field_index (currentDatabase, av[0]); if (field == InvalidFieldIndex) { printf ("%d No such field as `%s'\r\n", CODE_INVALID_FIELD_NAME, av[0]); return; } printf ("%d Ok, send field text now.\r\n", CODE_SEND_TEXT); fflush (stdout); newt = get_text_memory (&err); if (newt != NULL) { len = strlen (newt); if (fieldDefForIndex (field)->datatype != MultiText && newt[len - 1] == '\n') { newt[len - 1] = '\0'; } if (! validateFieldValue (field, newt, &err, 0)) { print_server_errors (err); } else { printf ("%d Ok.\r\n", CODE_OK); } free (newt); } else { print_server_errors (err); } } void GNATS_fieldflags (int ac, char **av) { int x; if (ac < 1) { printf ("%d At least one field name is required.\r\n", CODE_CMD_ERROR); return; } for (x = 0; x < ac; x++) { char contchar = ((x < (ac - 1)) ? '-' : ' '); FieldIndex fnum = find_field_index (currentDatabase, av[x]); if (fnum != InvalidFieldIndex) { char *flags = getFieldFlags (fnum); printf ("%d%c%s\r\n", CODE_INFORMATION, contchar, flags); free (flags); } else { printf ("%d%cNo such field as `%s'\r\n", CODE_INVALID_FIELD_NAME, contchar, av[x]); } } } void GNATS_expr (int ac, char **av) { QueryExpr q2; if (! chk_nargs (ac, "expression")) { return; } q2 = parseQueryExpression (currentDatabase, av[0], av[0] + strlen (av[0]) - 1); if (q2 == NULL) { printf ("%d Invalid expression.\r\n", CODE_INVALID_EXPR); return; } else { query = booleanQuery (QueryAnd, query, q2); } printf ("%d Ok.\r\n", CODE_OK); } void GNATS_rset (int ac, char **av ATTRIBUTE_UNUSED) { int new_index = 0; ErrorDesc err = NULL; if (ac != 0) { printf ("%d No arguments expected for RSET.\r\n", CODE_CMD_ERROR); return; } freeQueryExpr (query); query = NULL; if (checkPRChain (currentDatabase, &err)) { new_index = 1; } if (err != NULL) { print_server_errors (err); freeDatabaseInfo (currentDatabase); currentDatabase = NULL; } else { if (new_index) { printf ("%d Reset state...reloaded the index.\r\n", CODE_OK); } else { printf ("%d Reset state.\r\n", CODE_OK); } } } static char * get_text_memory (ErrorDesc *err) { char *buf = NULL; char *res = NULL; size_t reslen = 0; MsgType r; int done = 0; int error = 0; while (! done && ! error) { r = get_line (&buf, 2 * 60 * 60); if (r == PR_ok) { char *bp = buf; size_t buflen; if (buf[0] == '.' && (buf[1] == '\r' || buf[1] == '\n' || buf[1] == '\0')) { done = 1; } else { if (bp[0] == '.') { bp++; } buflen = strlen (bp); while (bp[buflen - 1] == '\r' || bp[buflen - 1] == '\n') { buflen--; } bp[buflen++] = '\n'; res = xrealloc (res, reslen + buflen + 1); memcpy (res + reslen, bp, buflen); reslen += buflen; res[reslen] = '\0'; } } else { if (r == PR_timeout) { setError (err, CODE_TIMEOUT, "Read timeout"); } else if (r == PR_eof) { setError (err, CODE_ERROR, "Read EOF"); } error = 1; } if (buf != NULL) { free (buf); buf = NULL; } } if (error) { if (res != NULL) { free (res); } res = NULL; } else { if (res == NULL) { res = xstrdup (""); } } return res; } #ifdef HAVE_KERBEROS /* Get an input line, or die. */ static void simple_get_line (char **buf, int timo) { switch (get_line (buf, timo)) { case PR_timeout: case PR_eof: /* for these two, assume the client simply died */ exit (1); break; case PR_ok: break; default: abort (); } } void tohex (ptr, buf, sz) char *ptr, *buf; int sz; { static const char hex[16] = "0123456789abcdef"; int c; while (sz--) { c = *ptr++ & 0xff; *buf++ = hex[c >> 4]; *buf++ = hex[c & 15]; } *buf++ = 0; } int hexdigit (c) int c; { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } void fromhex (ptr, buf, sz) char *ptr, *buf; int sz; { int val; while (sz--) { val = hexdigit (*buf++); val <<= 4; val |= hexdigit (*buf++); *ptr++ = val; } } #endif void GNATS_auth (int ac, char **av) { if (! chk_nargs(ac, "authentication type name")) return; #ifdef HAVE_KERBEROS /* This isn't the right way to do this ... we ought to exchange data in printable ascii form or something like that. This'll do for now. */ else if (!strcmp (av[0], "krb4-simple")) { extern char *getusershell (); char *keyfile; char *desired_user; char *k_buf; struct sockaddr_in peer, laddr; int len = sizeof (peer); int status; char instance[INST_SZ+1], version[KRB_SENDAUTH_VLEN+1]; char *p; struct passwd *pwd; /* Must be exactly 4 bytes. */ int cksum; /* Bundle these together to make it easy to erase them later. */ struct { AUTH_DAT auth; Key_schedule sched; KTEXT_ST ticket; char buf[MAX_KTXT_LEN * 3 + 10]; } k; if (getpeername (0, (struct sockaddr *) &peer, &len) < 0) { syslog (LOG_ERR, "can't get peername: %m"); goto addr_error; } if (getsockname (0, (struct sockaddr *) &laddr, &len) < 0) { syslog (LOG_ERR, "can't get sockname: %m"); addr_error: printf ("%d Server system error checking addresses: %s\r\n", CODE_ERROR, strerror (errno)); return; } keyfile = gnats_adm_dir ("srvtab"); /* Sanity-check installation. */ { if (! fileExists (keyfile)) { syslog (LOG_ERR, "can't find Kerberos key file %s: %m", keyfile); bad_key_file: printf ("%d Server installation error, cannot access key file\r\n", CODE_ERROR); free (keyfile); return; } else if (statbuf.st_mode & 0044) { syslog (LOG_ERR, "Kerberos key file %s is readable to others; recommend changing it", keyfile); goto bad_key_file; } else if (! fileExists (keyfile)) { syslog (LOG_ERR, "can't read Kerberos key file %s: %m", keyfile); goto bad_key_file; } } printf ("%d Go for it!\r\n", CODE_OK); fflush (stdout); /* Do authentication step. */ /* This is ugly, because krb_sendauth/krb_recvauth don't maintain a sensible connection state if authentication fails. This is unacceptable here. So I've broken out most of the interesting bits of those routines here. I've also added a hex encoding of the data exchanged instead of the standard authenticator format, to maintain the text-only protocol used in GNATS. */ /* Kerberos authenticator timeout is five minutes; give the client nearly that long. */ simple_get_line (&desired_user, 4 * 60); simple_get_line (&k_buf, 4 * 60); memcpy (k.buf, k_buf, sizeof (k.buf) - 1); if (k.buf[0] != 'x') { printf ("%d Bad hex encoding.\r\n", CODE_ERROR); return; } p = k.buf + 1; fromhex (version, p, KRB_SENDAUTH_VLEN * 2); p += KRB_SENDAUTH_VLEN * 2; version[KRB_SENDAUTH_VLEN] = 0; if (memcmp ("AUTHV0.1", version, KRB_SENDAUTH_VLEN)) { printf ("%d Unrecognized `sendauth' version `%s'.\r\n", CODE_ERROR, version); return; } fromhex (version, p, KRB_SENDAUTH_VLEN * 2); p += KRB_SENDAUTH_VLEN * 2; if (memcmp (GNATS_KRB4_VERSIONID, version, KRB_SENDAUTH_VLEN)) { printf ("%d Unrecognized authentication protocol version `%s'\r\n", CODE_ERROR, version); return; } p += 8; k.ticket.length = strlen (p) / 2; fromhex (k.ticket.dat, p, k.ticket.length); strcpy (instance, "*"); status = krb_rd_req (&k.ticket, GNATS_KRB4_PRINCIPAL_NAME, instance, peer.sin_addr.s_addr, &k.auth, keyfile); free (keyfile); if (status != KSUCCESS) { syslog (LOG_ERR, "auth failed for %s: %s", current_host, krb_get_err_text (status)); printf ("%d Authentication failed: %s.\r\n", CODE_ERROR, krb_get_err_text (status)); return; } if (sizeof (cksum) != 4) abort (); cksum = ntohl (k.auth.checksum + 1); key_sched (k.auth.session, k.sched); len = krb_mk_priv ((unsigned char *) &cksum, k.buf, 4, k.sched, &k.auth.session, &laddr, &peer); if (len < 0) { printf ("%d Kerberos error making private message.\r\n", CODE_ERROR); return; } if (len + 5 > sizeof (k.buf) / 3) { syslog (LOG_ERR, "Need more internal buffer space for krb_mk_priv."); printf ("%d Server bug: krb_mk_priv overruns buffer.\r\n", CODE_ERROR); return; } p = k.buf + len + 1; tohex (k.buf, p, len); printf ("x%s\r\n", p); /* Okay, authentication step is done. Now check authorization. */ if (kuserok (&k.auth, desired_user)) { printf ("%d You are not allowed access as user `%s'.\r\n", CODE_NO_ACCESS, desired_user); return; } pwd = getpwnam (desired_user); if (!pwd) { printf ("%d Cannot find a password file entry for `%s'.\r\n", CODE_NO_ACCESS, desired_user); return; } for (setusershell (); p; p = getusershell ()) if (!strcmp (pwd->pw_shell, p)) break; endusershell (); if (p == 0) { printf ("%d Access denied for user `%s'.\r\n", CODE_NO_ACCESS, desired_user); return; } printf ("%d Okie-dokey.\r\n", CODE_OK); client_authorized = 1; user_access = ACCESS_EDIT; return; } #endif else { printf ("%d Authentication type `%s' not supported.\r\n", CODE_AUTH_TYPE_UNSUP, av[0]); return; } } void GNATS_list (int ac, char **av) { ListTypes whichList; if (! chk_nargs (ac, "list type")) { return; } whichList = stringToListType (av[0]); if (whichList != InvalidListType) { printf ("%d List follows.\r\n", CODE_TEXT_READY); /* XXX ??? !!! Need to print an error message, hmmm? */ if (getGnatsFile (currentDatabase, whichList, NULL, "\r\n") == 0) { printf (".\r\n"); } } else { printf ("%d No such list as %s\r\n", CODE_INVALID_LIST, av[0]); } } void GNATS_ftyp (int ac, char **av) { int x; if (ac < 1) { /* ohhh lazy */ chk_nargs (ac, "field name"); return; } for (x = 0; x < ac; x++) { char contchar = (x < (ac - 1)) ? '-' : ' '; FieldIndex fnum = find_field_index (currentDatabase, av[x]); if (fnum != InvalidFieldIndex) { printf ("%d%c%s\n", CODE_INFORMATION, contchar, fieldTypeAsString (fieldDefForIndex (fnum)->datatype)); } else { printf ("%d%cNo such field as `%s'\r\n", CODE_INVALID_FIELD_NAME, contchar, av[x]); } } } void GNATS_ftypinfo (int ac, char **av) { if (ac == 2) { FieldIndex fnum = find_field_index (currentDatabase, av[0]); if (fnum == InvalidFieldIndex) { printf ("%d No such field as `%s'.\r\n", CODE_INVALID_FIELD_NAME, av[0]); return; } if (strcmp(av[1], "separators") == 0) { if (fieldDefForIndex (fnum)->datatype == MultiEnum) { const char *sep = fieldDefForIndex (fnum)->multiEnumSeparator; if (sep == NULL) sep = DEFAULT_MULTIENUM_SEPARATOR; printf ("%d '%s'\r\n", CODE_INFORMATION, sep); } else { printf ("%d Property `%s' not defined for field type `%s'.\r\n", CODE_INVALID_FTYPE_PROPERTY, av[1], fieldTypeAsString (fieldDefForIndex (fnum)->datatype)); } } /* Unknown property: */ else { printf ("%d No such property as `%s'.\r\n", CODE_INVALID_FTYPE_PROPERTY, av[1]); } } else { printf ("%d Need two arguments, fieldname and property\r\n", CODE_CMD_ERROR); } } void GNATS_fdsc (int ac, char **av) { int x; if (ac < 1) { chk_nargs (ac, "field name"); return; } for (x = 0; x < ac; x++) { char contchar = (x < (ac - 1)) ? '-' : ' '; FieldIndex fnum = find_field_index (currentDatabase, av[x]); if (fnum != InvalidFieldIndex) { const char *desc = fieldDefForIndex (fnum)->description; if (desc == NULL) { desc = ""; } printf ("%d%c%s\n", CODE_INFORMATION, contchar, desc); } else { printf ("%d%cNo such field as `%s'\r\n", CODE_INVALID_FIELD_NAME, contchar, av[x]); } } } void GNATS_fvld (int ac, char **av) { FieldIndex fnum; if (! chk_nargs (ac, "field name")) { return; } fnum = find_field_index (currentDatabase, av[0]); if (fnum == InvalidFieldIndex) { printf ("%d No such field as `%s'\r\n", CODE_INVALID_FIELD_NAME, av[0]); } else { printf ("%d Valid values follow\r\n", CODE_TEXT_READY); printValidValues (stdout, fnum, "\r\n"); printf (".\r\n"); } } void GNATS_inputdefault (int ac, char **av) { int x; if (ac < 1) { chk_nargs (ac, "field name"); return; } for (x = 0; x < ac; x++) { char contchar = (x < (ac - 1)) ? '-' : ' '; FieldIndex fnum = find_field_index (currentDatabase, av[x]); if (fnum != InvalidFieldIndex) { const char *value = fieldDefForIndex (fnum)->input_default_value; if (value == NULL) { value = fieldDefForIndex (fnum)->default_value; if (value == NULL) { value = ""; } } printf ("%d%c", CODE_INFORMATION, contchar); while (*value != '\0') { if (*value == '\n') { printf ("\\n"); } else { putchar (*value); } value++; } printf ("\r\n"); } else { printf ("%d%cNo such field as `%s'\r\n", CODE_INVALID_FIELD_NAME, contchar, av[x]); } } } void GNATS_dbls (int ac, char **av ATTRIBUTE_UNUSED) { AdmEntry *dbl; ErrorDesc err; if (ac != 0) { noargs ("DBLS"); return; } dbl = getDatabaseList (&err); if (dbl == NULL) { print_server_errors (err); } else { printf ("%d List follows.\r\n", CODE_TEXT_READY); while (dbl != NULL) { printf ("%s\r\n", dbl->admFields[DatabaseListKey]); dbl = dbl->next; } printf (".\r\n"); } } void GNATS_dbdesc (int ac, char **av) { AdmEntry *dbl; AdmEntry *ent; ErrorDesc err; if (! chk_nargs (ac, "database name")) { return; } dbl = getDatabaseList (&err); if (dbl == NULL) { print_server_errors (err); } else { ent = find_chain_entry_nocopy (dbl, av[0]); if (ent != NULL) { printf ("%d %s\r\n", CODE_INFORMATION, ent->admFields[DatabaseListDesc]); } else { printf ("%d No such database as `%s'.\r\n", CODE_INVALID_DATABASE, av[0]); } } } void GNATS_help (int ac ATTRIBUTE_UNUSED, char **av ATTRIBUTE_UNUSED) { printf ("%d-The GNATS daemon accepts the following commands:\r\n", CODE_INFORMATION); printf ("%d- QUIT close the connection\r\n", CODE_INFORMATION); printf ("%d- LIST list info of the specified type\r\n", CODE_INFORMATION); printf ("%d- FTYP return the datatype of \r\n", CODE_INFORMATION); printf ("%d- FTYPINFO \r\n", CODE_INFORMATION); printf ("%d- return info about a property of the\r\n", CODE_INFORMATION); printf ("%d- specified field\r\n", CODE_INFORMATION); printf ("%d- FDSC return the description of \r\n", CODE_INFORMATION); printf ("%d- FVLD return a string or regexp describing the\r\n", CODE_INFORMATION); printf ("%d- legal values for \r\n", CODE_INFORMATION); printf ("%d- VFLD validate that the provided text is valid\r\n", CODE_INFORMATION); printf ("%d- for the specified field\r\n", CODE_INFORMATION); printf ("%d- INPUTDEFAULT [ ...]\r\n", CODE_INFORMATION); printf ("%d- List the suggested default input values\r\n", CODE_INFORMATION); printf ("%d- for the specified field(s)\r\n", CODE_INFORMATION); printf ("%d- FIELDFLAGS [ ...]\r\n", CODE_INFORMATION); printf ("%d- List the field flags for the specified\r\n", CODE_INFORMATION); printf ("%d- fields\r\n", CODE_INFORMATION); printf ("%d- ADMV []\r\n", CODE_INFORMATION); printf ("%d- Retrieve a record from a field's admin db\r\n", CODE_INFORMATION); printf ("%d- QFMT Use the specified query format to format\r\n", CODE_INFORMATION); printf ("%d- the output of the query\r\n", CODE_INFORMATION); printf ("%d- RSET reset internal settings to initial startup\r\n", CODE_INFORMATION); printf ("%d- LKDB lock the main GNATS database\r\n", CODE_INFORMATION); printf ("%d- UNDB unlock the main GNATS database\r\n", CODE_INFORMATION); printf ("%d- LOCK lock for and optional \r\n", CODE_INFORMATION); printf ("%d- and return PR text\r\n", CODE_INFORMATION); printf ("%d- UNLK unlock \r\n", CODE_INFORMATION); printf ("%d- DELETE Delete the specified \r\n", CODE_INFORMATION); printf ("%d- CHEK [initial] check PR text for errors\r\n", CODE_INFORMATION); printf ("%d- EDIT check in edited \r\n", CODE_INFORMATION); printf ("%d- EDITADDR
set e-mail address to
\r\n", CODE_INFORMATION); printf ("%d- APPN append to contents of in \r\n", CODE_INFORMATION); printf ("%d- REPL replace contents of in \r\n", CODE_INFORMATION); printf ("%d- SUBM submit a new PR\r\n", CODE_INFORMATION); printf ("%d- CHDB [ []]\r\n", CODE_INFORMATION); printf ("%d- change GNATS ROOT to \r\n", CODE_INFORMATION); printf ("%d- USER [] Sets the current user\r\n", CODE_INFORMATION); printf ("%d- USER Report current access level\r\n", CODE_INFORMATION); printf ("%d- DBLS list databases known to server\r\n", CODE_INFORMATION); printf ("%d- DBDESC return description of \r\n", CODE_INFORMATION); printf ("%d- EXPR restrict search to PRs that match the\r\n", CODE_INFORMATION); printf ("%d- query expression\r\n", CODE_INFORMATION); #ifdef HAVE_KERBEROS printf ("%d- AUTH Kerberos authentication\r\n", CODE_INFORMATION); #endif printf ("%d- The search itself is performed by QUER. It may be invoked\r\n", CODE_INFORMATION); printf ("%d- with no arguments, which will search the entire database given\r\n", CODE_INFORMATION); printf ("%d- the constraints above, or with one or more PRs in its command,\r\n", CODE_INFORMATION); printf ("%d- which will search those PRs specifically.\r\n", CODE_INFORMATION); printf ("%d End of HELP info for GNATS daemon.\r\n", CODE_INFORMATION); } gnats-4.1.0/gnats/config.h0000644000175000017500000000040707266362147016132 0ustar chewiechewie00000000000000#ifndef _CONFIG_H #define _CONFIG_H /* Bleah. glibc strikes again! All I want is popen(), damn it. */ #ifdef __linux__ #define _GNU_SOURCE #endif #define __EXTENSIONS__ /* Include the autoconf-generated configuration header. */ #include "autoconf.h" #endif gnats-4.1.0/gnats/configure0000600000175000017500000066150410212665130016402 0ustar chewiechewie00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for gnats 4.1.0. # # Report bugs to . # # Copyright (C) 2003 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 Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='gnats' PACKAGE_TARNAME='gnats' PACKAGE_VERSION='4.1.0' PACKAGE_STRING='gnats 4.1.0' PACKAGE_BUGREPORT='bug-gnats@gnu.org' # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS PROGS MAN CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA RANLIB ac_ct_RANLIB YACC LEX LEXLIB LEX_OUTPUT_ROOT M4 AWK EGREP ALLOCA EMACS lispdir GNATS_ALL GNATS_INSTALL KRB4 HAVE_KERBEROS KRBINCLUDE EXTRA_OBJS GNATS_SERVICE GNATS_USER DEFAULT_RELEASE DEFAULT_ORGANIZATION SUBMITTER DEFAULT_MAIL_AGENT BWEEK_START BWEEK_END BDAY_START BDAY_END GNATSD_USER_ACCESS_FILE GNATSD_HOST_ACCESS_FILE GLOBAL_DB_LIST_FILE GNATS_DEFAULT_DB_DIR GCC_CFLAGS SENDMAIL LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # 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. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= 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 ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -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 | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$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 ;; -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 ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) 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 ;; -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=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 ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && 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'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac 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 echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 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 # 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 its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | 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 if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP # # 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 gnats 4.1.0 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 \`..'] _ACEOF cat <<_ACEOF 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] --datadir=DIR read-only architecture-independent data [PREFIX/share] --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] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of gnats 4.1.0:";; esac cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-kerberos include code for Kerberos authentication --with-gnats-service=NAME set the network service or port to NAME --with-gnats-user=NAME set the username for GNATS from the passwd file to NAME --with-gnatsd-user-access-file=PATH set global GNATSD access file to PATH --with-gnatsd-host-access-file=PATH set global GNATSD access file to PATH --with-gnats-dblist-file=PATH specify file containing list of databases --with-gnats-default-db=PATH specify the default database directory to use --with-lispdir=PATH specify the default lisp directory to use --with-krb4 support Kerberos 4 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 CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor 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 . _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style 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 elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF gnats configure 4.1.0 generated by GNU Autoconf 2.59 Copyright (C) 2003 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 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by gnats $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { 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` hostinfo = `(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=. echo "PATH: $as_dir" done } >&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_sep= 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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$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 ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >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 # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" 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. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 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 `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 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 { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`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. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } 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 ac_config_headers="$ac_config_headers autoconf.h" # Check whether --with-kerberos or --without-kerberos was given. if test "${with_kerberos+set}" = set; then withval="$with_kerberos" fi; # Check whether --with-gnats-service or --without-gnats-service was given. if test "${with_gnats_service+set}" = set; then withval="$with_gnats_service" fi; # Check whether --with-gnats-user or --without-gnats-user was given. if test "${with_gnats_user+set}" = set; then withval="$with_gnats_user" fi; # Check whether --with-gnatsd-user-access-file or --without-gnatsd-user-access-file was given. if test "${with_gnatsd_user_access_file+set}" = set; then withval="$with_gnatsd_user_access_file" fi; # Check whether --with-gnatsd-host-access-file or --without-gnatsd-host-access-file was given. if test "${with_gnatsd_host_access_file+set}" = set; then withval="$with_gnatsd_host_access_file" fi; # Check whether --with-gnats-dblist-file or --without-gnats-dblist-file was given. if test "${with_gnats_dblist_file+set}" = set; then withval="$with_gnats_dblist_file" fi; # Check whether --with-gnats-default-db or --without-gnats-default-db was given. if test "${with_gnats_default_db+set}" = set; then withval="$with_gnats_default_db" fi; # Check whether --with-lispdir or --without-lispdir was given. if test "${with_lispdir+set}" = set; then withval="$with_lispdir" 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_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" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done 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 echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out 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. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; 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 | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$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 echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* 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 -std1 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 -std1. */ int osf4_cc_array ['\x00' == 0 ? 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 # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext 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_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 echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f 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 echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } 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 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 { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # 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. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_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 ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done 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. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$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' if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then echo "$as_me:$LINENO: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi RANLIB=$ac_ct_RANLIB else RANLIB="$ac_cv_prog_RANLIB" fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_YACC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then echo "$as_me:$LINENO: result: $YACC" >&5 echo "${ECHO_T}$YACC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_LEX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then echo "$as_me:$LINENO: result: $LEX" >&5 echo "${ECHO_T}$LEX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test -z "$LEXLIB" then echo "$as_me:$LINENO: checking for yywrap in -lfl" >&5 echo $ECHO_N "checking for yywrap in -lfl... $ECHO_C" >&6 if test "${ac_cv_lib_fl_yywrap+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char yywrap (); int main () { yywrap (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_fl_yywrap=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_fl_yywrap=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_fl_yywrap" >&5 echo "${ECHO_T}$ac_cv_lib_fl_yywrap" >&6 if test $ac_cv_lib_fl_yywrap = yes; then LEXLIB="-lfl" else echo "$as_me:$LINENO: checking for yywrap in -ll" >&5 echo $ECHO_N "checking for yywrap in -ll... $ECHO_C" >&6 if test "${ac_cv_lib_l_yywrap+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ll $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char yywrap (); int main () { yywrap (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_l_yywrap=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_l_yywrap=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_l_yywrap" >&5 echo "${ECHO_T}$ac_cv_lib_l_yywrap" >&6 if test $ac_cv_lib_l_yywrap = yes; then LEXLIB="-ll" fi fi fi if test "x$LEX" != "x:"; then echo "$as_me:$LINENO: checking lex output file root" >&5 echo $ECHO_N "checking lex output file root... $ECHO_C" >&6 if test "${ac_cv_prog_lex_root+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # The minimal lex program is just a single line: %%. But some broken lexes # (Solaris, I think it was) want two %% lines, so accommodate them. cat >conftest.l <<_ACEOF %% %% _ACEOF { (eval echo "$as_me:$LINENO: \"$LEX conftest.l\"") >&5 (eval $LEX conftest.l) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5 echo "$as_me: error: cannot find output from $LEX; giving up" >&2;} { (exit 1); exit 1; }; } fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5 echo "${ECHO_T}$ac_cv_prog_lex_root" >&6 rm -f conftest.l LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5 echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6 if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c ac_save_LIBS=$LIBS LIBS="$LIBS $LEXLIB" cat >conftest.$ac_ext <<_ACEOF `cat $LEX_OUTPUT_ROOT.c` _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_lex_yytext_pointer=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS rm -f "${LEX_OUTPUT_ROOT}.c" fi echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5 echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6 if test $ac_cv_prog_lex_yytext_pointer = yes; then cat >>confdefs.h <<\_ACEOF #define YYTEXT_POINTER 1 _ACEOF fi fi for ac_prog in gm4 gnum4 m4 do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_M4+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $M4 in [\\/]* | ?:[\\/]*) ac_cv_path_M4="$M4" # Let the user override the test with a path. ;; *) 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi M4=$ac_cv_path_M4 if test -n "$M4"; then echo "$as_me:$LINENO: result: $M4" >&5 echo "${ECHO_T}$M4" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$M4" && break done test -n "$M4" || M4="m4" 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 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AWK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then echo "$as_me:$LINENO: result: $AWK" >&5 echo "${ECHO_T}$AWK" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$AWK" && break done #AC_DIFF_OPT echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep echo "$as_me:$LINENO: checking for AIX" >&5 echo $ECHO_N "checking for AIX... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef _AIX yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 cat >>confdefs.h <<\_ACEOF #define _ALL_SOURCE 1 _ACEOF else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest* echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f 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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* 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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* 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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #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)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF 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=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${ac_cv_header_minix_config_h+set}" = set; then echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6 if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking minix/config.h usability" >&5 echo $ECHO_N "checking minix/config.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking minix/config.h presence" >&5 echo $ECHO_N "checking minix/config.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: minix/config.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## -------------------------------- ## ## Report this to bug-gnats@gnu.org ## ## -------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6 if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_minix_config_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6 fi if test $ac_cv_header_minix_config_h = yes; then MINIX=yes else MINIX= fi if test "$MINIX" = yes; then cat >>confdefs.h <<\_ACEOF #define _POSIX_SOURCE 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_1_SOURCE 2 _ACEOF cat >>confdefs.h <<\_ACEOF #define _MINIX 1 _ACEOF fi echo "$as_me:$LINENO: checking for strerror in -lcposix" >&5 echo $ECHO_N "checking for strerror in -lcposix... $ECHO_C" >&6 if test "${ac_cv_lib_cposix_strerror+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcposix $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strerror (); int main () { strerror (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_cposix_strerror=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_cposix_strerror=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_cposix_strerror" >&5 echo "${ECHO_T}$ac_cv_lib_cposix_strerror" >&6 if test $ac_cv_lib_cposix_strerror = yes; then LIBS="$LIBS -lcposix" fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo "$as_me:$LINENO: checking for working alloca.h" >&5 echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6 if test "${ac_cv_working_alloca_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *p = (char *) alloca (2 * sizeof (int)); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_working_alloca_h=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_working_alloca_h=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5 echo "${ECHO_T}$ac_cv_working_alloca_h" >&6 if test $ac_cv_working_alloca_h = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_ALLOCA_H 1 _ACEOF fi echo "$as_me:$LINENO: checking for alloca" >&5 echo $ECHO_N "checking for alloca... $ECHO_C" >&6 if test "${ac_cv_func_alloca_works+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # ifdef _MSC_VER # include # define alloca _alloca # else # if HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); # endif # endif # endif # endif #endif int main () { char *p = (char *) alloca (1); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_alloca_works=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_alloca_works=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5 echo "${ECHO_T}$ac_cv_func_alloca_works" >&6 if test $ac_cv_func_alloca_works = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_ALLOCA 1 _ACEOF else # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. ALLOCA=alloca.$ac_objext cat >>confdefs.h <<\_ACEOF #define C_ALLOCA 1 _ACEOF echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5 echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6 if test "${ac_cv_os_cray+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #if defined(CRAY) && ! defined(CRAY2) webecray #else wenotbecray #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "webecray" >/dev/null 2>&1; then ac_cv_os_cray=yes else ac_cv_os_cray=no fi rm -f conftest* fi echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5 echo "${ECHO_T}$ac_cv_os_cray" >&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* 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_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define CRAY_STACKSEG_END $ac_func _ACEOF break fi done fi echo "$as_me:$LINENO: checking stack direction for C alloca" >&5 echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6 if test "${ac_cv_c_stack_direction+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then ac_cv_c_stack_direction=0 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int find_stack_direction () { static char *addr = 0; auto char dummy; if (addr == 0) { addr = &dummy; return find_stack_direction (); } else return (&dummy > addr) ? 1 : -1; } int main () { exit (find_stack_direction () < 0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_stack_direction=1 else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_c_stack_direction=-1 fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5 echo "${ECHO_T}$ac_cv_c_stack_direction" >&6 cat >>confdefs.h <<_ACEOF #define STACK_DIRECTION $ac_cv_c_stack_direction _ACEOF fi # Some Solaris C compilers have const problems without a special ANSI option echo "$as_me:$LINENO: checking for really working const" >&5 echo $ECHO_N "checking for really working const... $ECHO_C" >&6 if test "${gnats_really_working_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { const char *foo(const char *x) { return x; } int bar(const char *x) { return x == foo(x); } ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then gnats_really_working_const=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 gnats_really_working_const=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test "$gnats_really_working_const" = no; then CFLAGS="$CFLAGS -Dconst= " fi fi echo "$as_me:$LINENO: result: $gnats_really_working_const" >&5 echo "${ECHO_T}$gnats_really_working_const" >&6 # Needed on SCO for something or other. echo "$as_me:$LINENO: checking for main in -lintl" >&5 echo $ECHO_N "checking for main in -lintl... $ECHO_C" >&6 if test "${ac_cv_lib_intl_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_intl_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_intl_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_intl_main" >&5 echo "${ECHO_T}$ac_cv_lib_intl_main" >&6 if test $ac_cv_lib_intl_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBINTL 1 _ACEOF LIBS="-lintl $LIBS" fi # If we can't find connect, try looking in -lsocket and -lnsl. The # Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has # libsocket.so which has a bad implementation of gethostbyname (it # only looks in /etc/hosts), so we only look for -lsocket if we need # it. echo "$as_me:$LINENO: checking for connect" >&5 echo $ECHO_N "checking for connect... $ECHO_C" >&6 if test "${ac_cv_func_connect+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define connect to an innocuous variant, in case declares connect. For example, HP-UX 11i declares gettimeofday. */ #define connect innocuous_connect /* System header to define __stub macros and hopefully few prototypes, which can conflict with char connect (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef connect /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char connect (); /* 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_connect) || defined (__stub___connect) choke me #else char (*f) () = connect; #endif #ifdef __cplusplus } #endif int main () { return f != connect; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_connect=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_connect=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 echo "${ECHO_T}$ac_cv_func_connect" >&6 if test $ac_cv_func_connect = yes; then : else # Needed on SCO for syslog. echo "$as_me:$LINENO: checking for main in -lsocket" >&5 echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6 if test "${ac_cv_lib_socket_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_socket_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_socket_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5 echo "${ECHO_T}$ac_cv_lib_socket_main" >&6 if test $ac_cv_lib_socket_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi # Needed under Solaris in addition to -lsocket for the network. echo "$as_me:$LINENO: checking for main in -lnsl" >&5 echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6 if test "${ac_cv_lib_nsl_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_nsl_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_nsl_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5 echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6 if test $ac_cv_lib_nsl_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi fi # Needed on ISC for syslog. echo "$as_me:$LINENO: checking for main in -linet" >&5 echo $ECHO_N "checking for main in -linet... $ECHO_C" >&6 if test "${ac_cv_lib_inet_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_inet_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_inet_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_inet_main" >&5 echo "${ECHO_T}$ac_cv_lib_inet_main" >&6 if test $ac_cv_lib_inet_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBINET 1 _ACEOF LIBS="-linet $LIBS" fi # Needed under IRIX for a usable malloc. echo "$as_me:$LINENO: checking for main in -lmalloc" >&5 echo $ECHO_N "checking for main in -lmalloc... $ECHO_C" >&6 if test "${ac_cv_lib_malloc_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmalloc $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_malloc_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_malloc_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_malloc_main" >&5 echo "${ECHO_T}$ac_cv_lib_malloc_main" >&6 if test $ac_cv_lib_malloc_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBMALLOC 1 _ACEOF LIBS="-lmalloc $LIBS" fi # Needed under Unixware 2.0 for syslog. echo "$as_me:$LINENO: checking for main in -lgen" >&5 echo $ECHO_N "checking for main in -lgen... $ECHO_C" >&6 if test "${ac_cv_lib_gen_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgen $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_gen_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_gen_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_gen_main" >&5 echo "${ECHO_T}$ac_cv_lib_gen_main" >&6 if test $ac_cv_lib_gen_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBGEN 1 _ACEOF LIBS="-lgen $LIBS" fi # Needed generally for encrypted passwords. echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5 echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6 if test "${ac_cv_lib_crypt_crypt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypt $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char crypt (); int main () { crypt (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_crypt_crypt=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_crypt_crypt=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5 echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6 if test $ac_cv_lib_crypt_crypt = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF LIBS="-lcrypt $LIBS" fi echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f 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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* 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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* 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 >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #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)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi for ac_header in crypt.h fcntl.h libgen.h limits.h memory.h netdb.h string.h syslog.h unistd.h machine/endian.h sys/select.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## -------------------------------- ## ## Report this to bug-gnats@gnu.org ## ## -------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "\" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define HAVE_DECL_UNSETENV 1 _ACEOF else cat >>confdefs.h <<\_ACEOF #define HAVE_DECL_UNSETENV 0 _ACEOF fi rm -f conftest* for ac_func in basename ftime getopt getopt_long mkdir mktemp mkstemp unsetenv asprintf vasprintf do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* 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_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo "$as_me:$LINENO: checking for library containing opendir" >&5 echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 if test "${ac_cv_search_opendir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_opendir=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char opendir (); int main () { opendir (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_opendir="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_opendir" = no; then for ac_lib in dir; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char opendir (); int main () { opendir (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_opendir="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 echo "${ECHO_T}$ac_cv_search_opendir" >&6 if test "$ac_cv_search_opendir" != no; then test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" fi else echo "$as_me:$LINENO: checking for library containing opendir" >&5 echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 if test "${ac_cv_search_opendir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_opendir=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char opendir (); int main () { opendir (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_opendir="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_opendir" = no; then for ac_lib in x; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char opendir (); int main () { opendir (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_opendir="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 echo "${ECHO_T}$ac_cv_search_opendir" >&6 if test "$ac_cv_search_opendir" != no; then test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" fi fi echo "$as_me:$LINENO: checking for size_t" >&5 echo $ECHO_N "checking for size_t... $ECHO_C" >&6 if test "${ac_cv_type_size_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((size_t *) 0) return 0; if (sizeof (size_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_size_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_size_t=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 echo "${ECHO_T}$ac_cv_type_size_t" >&6 if test $ac_cv_type_size_t = yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned _ACEOF fi echo "$as_me:$LINENO: checking for --with-lispdir" >&5 echo $ECHO_N "checking for --with-lispdir... $ECHO_C" >&6 if test -n "$with_lispdir" ; then echo "$as_me:$LINENO: result: $with_lispdir" >&5 echo "${ECHO_T}$with_lispdir" >&6 lispdir=$with_lispdir else # If set to t, that means we are running in a shell under Emacs. # If you have an Emacs named "t", then use the full path. test "$EMACS" = t && EMACS= for ac_prog in emacs xemacs do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_EMACS+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $EMACS in [\\/]* | ?:[\\/]*) ac_cv_path_EMACS="$EMACS" # Let the user override the test with a path. ;; *) 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_EMACS="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi EMACS=$ac_cv_path_EMACS if test -n "$EMACS"; then echo "$as_me:$LINENO: result: $EMACS" >&5 echo "${ECHO_T}$EMACS" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$EMACS" && break done test -n "$EMACS" || EMACS="no" if test $EMACS != "no"; then echo "$as_me:$LINENO: checking where .elc files should go" >&5 echo $ECHO_N "checking where .elc files should go... $ECHO_C" >&6 lispdir="\$(datadir)/emacs/site-lisp" emacs_flavor=`echo "$EMACS" | sed -e 's,^.*/,,'` if test "x$prefix" = "xNONE"; then if test -d $ac_default_prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $ac_default_prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi else if test -d $prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi fi echo "$as_me:$LINENO: result: $lispdir" >&5 echo "${ECHO_T}$lispdir" >&6 fi echo "$as_me:$LINENO: result: $lispdir" >&5 echo "${ECHO_T}$lispdir" >&6 fi # Linux thang. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "socklen_t" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define HAVE_SOCKLEN_T 1 _ACEOF fi rm -f conftest* else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_ext # ***** How much do we want? ***** GNATS_ALL=all-gnats GNATS_INSTALL=install-gnats # See if we want Kerberos. echo "$as_me:$LINENO: checking for --with-kerberos" >&5 echo $ECHO_N "checking for --with-kerberos... $ECHO_C" >&6 if test -n "$with_kerberos" ; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 with_krb=true else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -n "$with_krb"; then echo "$as_me:$LINENO: checking Kerberos path" >&5 echo $ECHO_N "checking Kerberos path... $ECHO_C" >&6 # Check whether --with-krb4 or --without-krb4 was given. if test "${with_krb4+set}" = set; then withval="$with_krb4" KRB4=$withval else # Default to system version if BSD-style, else /usr/kerberos always. if test ! -d /usr/kerberos && test -d /usr/include/kerberosIV ; then KRB4=/usr else KRB4=/usr/kerberos fi fi; echo "$as_me:$LINENO: result: $KRB4" >&5 echo "${ECHO_T}$KRB4" >&6 krb_h= KRBINCLUDE= # XXX this should use a different approach at some point echo "$as_me:$LINENO: checking for krb.h" >&5 echo $ECHO_N "checking for krb.h... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { int i; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then krb_h=yes krb_incdir= echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 if test -r "$KRB4/include/kerberosIV/krb.h" ; then krbincdir=$KRB4/include/kerberosIV else krbincdir=$KRB4/include fi if test "$cross_compiling" = "no" && test -r $krbincdir/krb.h; then hold_cflags=$CFLAGS CFLAGS="$CFLAGS -I$krbincdir" echo "$as_me:$LINENO: checking for krb.h in $krbincdir" >&5 echo $ECHO_N "checking for krb.h in $krbincdir... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { int i; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then krb_h=yes krb_incdir=$krbincdir echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags if test -n "$krb_incdir"; then KRBINCLUDE="-I$krb_incdir" fi fi fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -n "$krb_h"; then krb_lib= if test "$cross_compiling" = "no" && test -r $KRB4/lib/libkrb.a; then # Fake some sensible log messages. echo "$as_me:$LINENO: checking for -lkrb in $KRB4/lib" >&5 echo $ECHO_N "checking for -lkrb in $KRB4/lib... $ECHO_C" >&6 echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 krb_lib=-lkrb krb_libdir=$KRB4/lib else echo "$as_me:$LINENO: checking for main in -lkrb" >&5 echo $ECHO_N "checking for main in -lkrb... $ECHO_C" >&6 if test "${ac_cv_lib_krb_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkrb $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_krb_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_krb_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_krb_main" >&5 echo "${ECHO_T}$ac_cv_lib_krb_main" >&6 if test $ac_cv_lib_krb_main = yes; then krb_lib=-lkrb else echo "$as_me:$LINENO: checking for main in -lkrb4" >&5 echo $ECHO_N "checking for main in -lkrb4... $ECHO_C" >&6 if test "${ac_cv_lib_krb4_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkrb4 $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_krb4_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_krb4_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_krb4_main" >&5 echo "${ECHO_T}$ac_cv_lib_krb4_main" >&6 if test $ac_cv_lib_krb4_main = yes; then krb_lib=-lkrb4 fi fi fi if test x"$krb_lib" != x""; then cat >>confdefs.h <<\_ACEOF #define HAVE_KERBEROS 1 _ACEOF test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}" LIBS="${LIBS} $krb_lib" echo "$as_me:$LINENO: checking for main in -ldes" >&5 echo $ECHO_N "checking for main in -ldes... $ECHO_C" >&6 if test "${ac_cv_lib_des_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldes $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_des_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_des_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_des_main" >&5 echo "${ECHO_T}$ac_cv_lib_des_main" >&6 if test $ac_cv_lib_des_main = yes; then LIBS="${LIBS} -ldes" fi echo "$as_me:$LINENO: checking for main in -ldes425" >&5 echo $ECHO_N "checking for main in -ldes425... $ECHO_C" >&6 if test "${ac_cv_lib_des425_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldes425 $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_des425_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_des425_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_des425_main" >&5 echo "${ECHO_T}$ac_cv_lib_des425_main" >&6 if test $ac_cv_lib_des425_main = yes; then LIBS="${LIBS} -ldes425" fi echo "$as_me:$LINENO: checking for main in -lkrb5" >&5 echo $ECHO_N "checking for main in -lkrb5... $ECHO_C" >&6 if test "${ac_cv_lib_krb5_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkrb5 $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_krb5_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_krb5_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_krb5_main" >&5 echo "${ECHO_T}$ac_cv_lib_krb5_main" >&6 if test $ac_cv_lib_krb5_main = yes; then LIBS="${LIBS} -lkrb5" fi echo "$as_me:$LINENO: checking for main in -lcrypto" >&5 echo $ECHO_N "checking for main in -lcrypto... $ECHO_C" >&6 if test "${ac_cv_lib_crypto_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_crypto_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_crypto_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_main" >&5 echo "${ECHO_T}$ac_cv_lib_crypto_main" >&6 if test $ac_cv_lib_crypto_main = yes; then LIBS="${LIBS} -lcrypto" fi echo "$as_me:$LINENO: checking for main in -lcom_err" >&5 echo $ECHO_N "checking for main in -lcom_err... $ECHO_C" >&6 if test "${ac_cv_lib_com_err_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcom_err $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_com_err_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_com_err_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_com_err_main" >&5 echo "${ECHO_T}$ac_cv_lib_com_err_main" >&6 if test $ac_cv_lib_com_err_main = yes; then LIBS="${LIBS} -lcom_err" fi echo "$as_me:$LINENO: checking for krb_mk_auth" >&5 echo $ECHO_N "checking for krb_mk_auth... $ECHO_C" >&6 if test "${ac_cv_func_krb_mk_auth+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define krb_mk_auth to an innocuous variant, in case declares krb_mk_auth. For example, HP-UX 11i declares gettimeofday. */ #define krb_mk_auth innocuous_krb_mk_auth /* System header to define __stub macros and hopefully few prototypes, which can conflict with char krb_mk_auth (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef krb_mk_auth /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char krb_mk_auth (); /* 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_krb_mk_auth) || defined (__stub___krb_mk_auth) choke me #else char (*f) () = krb_mk_auth; #endif #ifdef __cplusplus } #endif int main () { return f != krb_mk_auth; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_krb_mk_auth=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_krb_mk_auth=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_krb_mk_auth" >&5 echo "${ECHO_T}$ac_cv_func_krb_mk_auth" >&6 if test $ac_cv_func_krb_mk_auth = yes; then : else # BSD Kerberos doesn't have these functions. EXTRA_OBJS="mk_auth.o $EXTRA_OBJS" fi fi fi for ac_func in krb_get_err_text do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* 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_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done fi if test "x$GCC" = "xyes" ; then GCC_CFLAGS="-W -Wall -ansi -pedantic -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wno-format" fi # ***** Guess the configuration ***** # echo guessing optimal GNATS configuration # And GNATS_SERVICE echo "$as_me:$LINENO: checking for --with-gnats-service" >&5 echo $ECHO_N "checking for --with-gnats-service... $ECHO_C" >&6 if test -n "$with_gnats_service"; then echo "$as_me:$LINENO: result: $with_gnats_service" >&5 echo "${ECHO_T}$with_gnats_service" >&6 GNATS_SERVICE=$with_gnats_service fi if test -z "${GNATS_SERVICE}"; then echo "$as_me:$LINENO: result: default to support" >&5 echo "${ECHO_T}default to support" >&6 GNATS_SERVICE=support fi # And GNATS_USER echo "$as_me:$LINENO: checking for --with-gnats-user" >&5 echo $ECHO_N "checking for --with-gnats-user... $ECHO_C" >&6 if test -n "$with_gnats_user"; then echo "$as_me:$LINENO: result: $with_gnats_user" >&5 echo "${ECHO_T}$with_gnats_user" >&6 GNATS_USER=$with_gnats_user fi if test -z "${GNATS_USER}"; then echo "$as_me:$LINENO: result: default to gnats" >&5 echo "${ECHO_T}default to gnats" >&6 GNATS_USER=gnats fi echo "$as_me:$LINENO: checking for --with-gnatsd-user-access-file" >&5 echo $ECHO_N "checking for --with-gnatsd-user-access-file... $ECHO_C" >&6 if test -n "${with_gnatsd_user_access_file}"; then echo "$as_me:$LINENO: result: $with_gnatsd_user_access_file" >&5 echo "${ECHO_T}$with_gnatsd_user_access_file" >&6 GNATSD_USER_ACCESS_FILE=$with_gnatsd_user_access_file fi if test -z "${GNATSD_USER_ACCESS_FILE}"; then echo "$as_me:$LINENO: result: default to ${sysconfdir}/gnats/gnatsd.user_access" >&5 echo "${ECHO_T}default to ${sysconfdir}/gnats/gnatsd.user_access" >&6 GNATSD_USER_ACCESS_FILE=${sysconfdir}/gnats/gnatsd.user_access fi echo "$as_me:$LINENO: checking for --with-gnatsd-host-access-file" >&5 echo $ECHO_N "checking for --with-gnatsd-host-access-file... $ECHO_C" >&6 if test -n "${with_gnatsd_host_access_file}"; then echo "$as_me:$LINENO: result: $with_gnatsd_host_access_file" >&5 echo "${ECHO_T}$with_gnatsd_host_access_file" >&6 GNATSD_HOST_ACCESS_FILE=$with_gnatsd_host_access_file fi if test -z "${GNATSD_HOST_ACCESS_FILE}"; then echo "$as_me:$LINENO: result: default to ${sysconfdir}/gnats/gnatsd.host_access" >&5 echo "${ECHO_T}default to ${sysconfdir}/gnats/gnatsd.host_access" >&6 GNATSD_HOST_ACCESS_FILE=${sysconfdir}/gnats/gnatsd.host_access fi echo "$as_me:$LINENO: checking for --with-gnats-dblist-file" >&5 echo $ECHO_N "checking for --with-gnats-dblist-file... $ECHO_C" >&6 if test -n "${with_gnats_dblist_file}"; then echo "$as_me:$LINENO: result: $with_gnats_dblist_file" >&5 echo "${ECHO_T}$with_gnats_dblist_file" >&6 GLOBAL_DB_LIST_FILE=$with_gnats_dblist_file fi if test -z "${GLOBAL_DB_LIST_FILE}"; then echo "$as_me:$LINENO: result: default to ${sysconfdir}/gnats/databases" >&5 echo "${ECHO_T}default to ${sysconfdir}/gnats/databases" >&6 GLOBAL_DB_LIST_FILE=${sysconfdir}/gnats/databases fi echo "$as_me:$LINENO: checking for --with-gnats-default-db" >&5 echo $ECHO_N "checking for --with-gnats-default-db... $ECHO_C" >&6 if test -n "${with_gnats_default_db}"; then echo "$as_me:$LINENO: result: $with_gnats_default_db" >&5 echo "${ECHO_T}$with_gnats_default_db" >&6 GNATS_DEFAULT_DB_DIR="$with_gnats_default_db" fi if test -z "${GNATS_DEFAULT_DB_DIR}"; then echo "$as_me:$LINENO: result: default to ${sharedstatedir}/gnatsdb" >&5 echo "${ECHO_T}default to ${sharedstatedir}/gnatsdb" >&6 GNATS_DEFAULT_DB_DIR=${sharedstatedir}/gnatsdb fi # Set up default values to be overridden _h=`(hostname || uname -n) 2>/dev/null | sed 1q` DEFAULT_RELEASE=unknown-1.0 DEFAULT_ORGANIZATION=unknown SUBMITTER=unknown DEFAULT_MAIL_AGENT=false BDAY_START=8 BDAY_END=17 BWEEK_START=1 BWEEK_END=5 # Extract the first word of "sendmail", so it can be a program name with args. set dummy sendmail; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_SENDMAIL+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $SENDMAIL in [\\/]* | ?:[\\/]*) ac_cv_path_SENDMAIL="$SENDMAIL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:/usr/lib:/usr/sbin:/usr/ucblib" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SENDMAIL="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi SENDMAIL=$ac_cv_path_SENDMAIL if test -n "$SENDMAIL"; then echo "$as_me:$LINENO: result: $SENDMAIL" >&5 echo "${ECHO_T}$SENDMAIL" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -n "$SENDMAIL" ; then DEFAULT_MAIL_AGENT="$SENDMAIL -oi -t" else echo "configure: error: sendmail binary not available" exit 1 fi # If the config file exists, it may have more recent info than send-pr if test -n "$verbose"; then echo " setting GNATS_SERVICE to $GNATS_SERVICE" echo " setting GNATS_USER to $GNATS_USER" echo " setting SUBMITTER to $SUBMITTER" echo " setting DEFAULT_RELEASE to $DEFAULT_RELEASE" echo " setting DEFAULT_ORGANIZATION to $DEFAULT_ORGANIZATION" echo " setting BDAY_START to $BDAY_START" echo " setting BDAY_END to $BDAY_END" echo " setting BWEEK_START to $BWEEK_START" echo " setting BWEEK_END to $BWEEK_END" echo " setting DEFAULT_MAIL_AGENT to $DEFAULT_MAIL_AGENT" fi # ***** End of configuration section ***** ac_config_files="$ac_config_files 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, don't put newlines in cache variables' values. # 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. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *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 \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" 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}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ 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[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $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} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by gnats $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet 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 Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ gnats config.status 4.1.0 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. 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=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; 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 if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "autoconf.h" ) CONFIG_HEADERS="$CONFIG_HEADERS autoconf.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; 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 fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@PROGS@,$PROGS,;t t s,@MAN@,$MAN,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@CPP@,$CPP,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@YACC@,$YACC,;t t s,@LEX@,$LEX,;t t s,@LEXLIB@,$LEXLIB,;t t s,@LEX_OUTPUT_ROOT@,$LEX_OUTPUT_ROOT,;t t s,@M4@,$M4,;t t s,@AWK@,$AWK,;t t s,@EGREP@,$EGREP,;t t s,@ALLOCA@,$ALLOCA,;t t s,@EMACS@,$EMACS,;t t s,@lispdir@,$lispdir,;t t s,@GNATS_ALL@,$GNATS_ALL,;t t s,@GNATS_INSTALL@,$GNATS_INSTALL,;t t s,@KRB4@,$KRB4,;t t s,@HAVE_KERBEROS@,$HAVE_KERBEROS,;t t s,@KRBINCLUDE@,$KRBINCLUDE,;t t s,@EXTRA_OBJS@,$EXTRA_OBJS,;t t s,@GNATS_SERVICE@,$GNATS_SERVICE,;t t s,@GNATS_USER@,$GNATS_USER,;t t s,@DEFAULT_RELEASE@,$DEFAULT_RELEASE,;t t s,@DEFAULT_ORGANIZATION@,$DEFAULT_ORGANIZATION,;t t s,@SUBMITTER@,$SUBMITTER,;t t s,@DEFAULT_MAIL_AGENT@,$DEFAULT_MAIL_AGENT,;t t s,@BWEEK_START@,$BWEEK_START,;t t s,@BWEEK_END@,$BWEEK_END,;t t s,@BDAY_START@,$BDAY_START,;t t s,@BDAY_END@,$BDAY_END,;t t s,@GNATSD_USER_ACCESS_FILE@,$GNATSD_USER_ACCESS_FILE,;t t s,@GNATSD_HOST_ACCESS_FILE@,$GNATSD_HOST_ACCESS_FILE,;t t s,@GLOBAL_DB_LIST_FILE@,$GLOBAL_DB_LIST_FILE,;t t s,@GNATS_DEFAULT_DB_DIR@,$GNATS_DEFAULT_DB_DIR,;t t s,@GCC_CFLAGS@,$GCC_CFLAGS,;t t s,@SENDMAIL@,$SENDMAIL,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # 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. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;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,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_HEADER section. # # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='[ ].*$,\1#\2' ac_dC=' ' ac_dD=',;t' # ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='$,\1#\2define\3' ac_uC=' ' ac_uD=',;t' for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } # Do quote $f, to prevent DOS paths from being IFS'd. echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } # Remove the trailing spaces. sed 's/[ ]*$//' $ac_file_inputs >$tmp/in _ACEOF # Transform confdefs.h into two sed scripts, `conftest.defines' and # `conftest.undefs', that substitutes the proper values into # config.h.in to produce config.h. The first handles `#define' # templates, and the second `#undef' templates. # And first: Protect against being on the right side of a sed subst in # config.status. Protect against being in an unquoted here document # in config.status. rm -f conftest.defines conftest.undefs # Using a here document instead of a string reduces the quoting nightmare. # Putting comments in sed scripts is not portable. # # `end' is used to avoid that the second main sed command (meant for # 0-ary CPP macros) applies to n-ary macro definitions. # See the Autoconf documentation for `clear'. cat >confdef2sed.sed <<\_ACEOF s/[\\&,]/\\&/g s,[\\$`],\\&,g t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp t end s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp : end _ACEOF # If some macros were called several times there might be several times # the same #defines, which is useless. Nevertheless, we may not want to # sort them, since we want the *last* AC-DEFINE to be honored. uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs rm -f confdef2sed.sed # This sed command replaces #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. cat >>conftest.undefs <<\_ACEOF s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, _ACEOF # Break up conftest.defines because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS echo ' :' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.defines >/dev/null do # Write a limited-size here document to $tmp/defines.sed. echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#define' lines. echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/defines.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines echo ' fi # grep' >>$CONFIG_STATUS echo >>$CONFIG_STATUS # Break up conftest.undefs because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #undef templates' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.undefs >/dev/null do # Write a limited-size here document to $tmp/undefs.sed. echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#undef' echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/undefs.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail rm -f conftest.undefs mv conftest.tail conftest.undefs done rm -f conftest.undefs cat >>$CONFIG_STATUS <<\_ACEOF # 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. */ if test x"$ac_file" = x-; then echo "/* Generated by configure. */" >$tmp/config.h else echo "/* $ac_file. Generated by configure. */" >$tmp/config.h fi cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } rm -f $ac_file mv $tmp/config.h $ac_file fi else cat $tmp/config.h rm -f $tmp/config.h fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # 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 || { (exit 1); exit 1; } fi gnats-4.1.0/gnats/configure.in0000600000175000017500000002447410212665130017006 0ustar chewiechewie00000000000000dnl Process this file with autoconf to produce a configure script. dnl dnl Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. dnl Copyright (C) 1999, 2000 Juniper Networks, inc. dnl Copyright (C) 1993, 1994, 1995, 1996, 1997 ??? (FIXME: see Changelog.v3) dnl dnl This file is part of GNU GNATS. dnl dnl GNU GNATS is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2, or (at your option) dnl any later version. dnl dnl GNU GNATS is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with GNU GNATS; see the file COPYING. If not, write to the Free dnl Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. dnl AC_PREREQ(2.5) AC_INIT(gnats,4.1.0,bug-gnats@gnu.org) AC_CONFIG_HEADER(autoconf.h) AC_ARG_WITH(kerberos, [ --with-kerberos include code for Kerberos authentication]) AC_ARG_WITH(gnats-service, [ --with-gnats-service=NAME set the network service or port to NAME]) AC_ARG_WITH(gnats-user, [ --with-gnats-user=NAME set the username for GNATS from the passwd file to NAME]) AC_ARG_WITH(gnatsd-user-access-file, [ --with-gnatsd-user-access-file=PATH set global GNATSD access file to PATH]) AC_ARG_WITH(gnatsd-host-access-file, [ --with-gnatsd-host-access-file=PATH set global GNATSD access file to PATH]) AC_ARG_WITH(gnats-dblist-file, [ --with-gnats-dblist-file=PATH specify file containing list of databases]) AC_ARG_WITH(gnats-default-db, [ --with-gnats-default-db=PATH specify the default database directory to use]) AC_ARG_WITH(lispdir, [ --with-lispdir=PATH specify the default lisp directory to use]) AC_SUBST(PROGS)dnl AC_SUBST(MAN)dnl AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_RANLIB AC_PROG_YACC AC_PROG_LEX AC_PATH_PROGS(M4, gm4 gnum4 m4, m4) AC_PROG_AWK #AC_DIFF_OPT AC_AIX AC_MINIX AC_ISC_POSIX AC_ALLOCA # Some Solaris C compilers have const problems without a special ANSI option AC_CACHE_CHECK([for really working const],gnats_really_working_const,[ AC_TRY_COMPILE([], [const char *foo(const char *x) { return x; } int bar(const char *x) { return x == foo(x); }], [gnats_really_working_const=yes], [gnats_really_working_const=no]) if test "$gnats_really_working_const" = no; then CFLAGS="$CFLAGS -Dconst= " fi]) # Needed on SCO for something or other. AC_CHECK_LIB(intl, main) # If we can't find connect, try looking in -lsocket and -lnsl. The # Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has # libsocket.so which has a bad implementation of gethostbyname (it # only looks in /etc/hosts), so we only look for -lsocket if we need # it. AC_CHECK_FUNC(connect, :, [ # Needed on SCO for syslog. AC_CHECK_LIB(socket, main) # Needed under Solaris in addition to -lsocket for the network. AC_CHECK_LIB(nsl, main) ]) # Needed on ISC for syslog. AC_CHECK_LIB(inet, main) # Needed under IRIX for a usable malloc. AC_CHECK_LIB(malloc, main) # Needed under Unixware 2.0 for syslog. AC_CHECK_LIB(gen, main) # Needed generally for encrypted passwords. AC_CHECK_LIB(crypt, crypt) AC_STDC_HEADERS AC_CHECK_HEADERS(crypt.h fcntl.h libgen.h limits.h memory.h netdb.h string.h syslog.h unistd.h machine/endian.h sys/select.h) AC_EGREP_HEADER(\, stdlib.h, AC_DEFINE(HAVE_DECL_UNSETENV,1,[Whether unsetenv is present in headers.]), AC_DEFINE(HAVE_DECL_UNSETENV,0,[Whether unsetenv is present in headers.])) AC_CHECK_FUNCS(basename ftime getopt getopt_long mkdir mktemp mkstemp unsetenv asprintf vasprintf) AC_HEADER_DIRENT AC_SIZE_T AC_MSG_CHECKING(for --with-lispdir) if test -n "$with_lispdir" ; then AC_MSG_RESULT($with_lispdir) lispdir=$with_lispdir else AM_PATH_LISPDIR AC_MSG_RESULT($lispdir) fi # Linux thang. AC_TRY_CPP([#include ], AC_EGREP_CPP(socklen_t, [#include ], AC_DEFINE(HAVE_SOCKLEN_T))) # ***** How much do we want? ***** AC_SUBST(GNATS_ALL)dnl AC_SUBST(GNATS_INSTALL)dnl GNATS_ALL=all-gnats GNATS_INSTALL=install-gnats # See if we want Kerberos. AC_MSG_CHECKING(for --with-kerberos) if test -n "$with_kerberos" ; then AC_MSG_RESULT(yes) with_krb=true else AC_MSG_RESULT(no) fi if test -n "$with_krb"; then dnl dnl set $(KRB4) from --with-krb4=value -- WITH_KRB4 dnl AC_MSG_CHECKING(Kerberos path) AC_ARG_WITH([krb4], [ --with-krb4 support Kerberos 4], KRB4=$withval, # Default to system version if BSD-style, else /usr/kerberos always. if test ! -d /usr/kerberos && test -d /usr/include/kerberosIV ; then KRB4=/usr else KRB4=/usr/kerberos fi )dnl AC_MSG_RESULT($KRB4) AC_SUBST(KRB4) krb_h= KRBINCLUDE= # XXX this should use a different approach at some point AC_MSG_CHECKING(for krb.h) AC_TRY_LINK([#include #include ],[int i;], [krb_h=yes krb_incdir= AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no) if test -r "$KRB4/include/kerberosIV/krb.h" ; then krbincdir=$KRB4/include/kerberosIV else krbincdir=$KRB4/include fi if test "$cross_compiling" = "no" && test -r $krbincdir/krb.h; then hold_cflags=$CFLAGS CFLAGS="$CFLAGS -I$krbincdir" AC_MSG_CHECKING(for krb.h in $krbincdir) AC_TRY_LINK([#include #include ],[int i;], [krb_h=yes krb_incdir=$krbincdir AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) CFLAGS=$hold_cflags if test -n "$krb_incdir"; then KRBINCLUDE="-I$krb_incdir" fi fi]) if test -n "$krb_h"; then krb_lib= if test "$cross_compiling" = "no" && test -r $KRB4/lib/libkrb.a; then # Fake some sensible log messages. AC_MSG_CHECKING(for -lkrb in $KRB4/lib) AC_MSG_RESULT(yes) krb_lib=-lkrb krb_libdir=$KRB4/lib else AC_CHECK_LIB(krb,main,krb_lib=-lkrb, AC_CHECK_LIB(krb4,main,krb_lib=-lkrb4)) fi if test x"$krb_lib" != x""; then AC_DEFINE(HAVE_KERBEROS) test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}" LIBS="${LIBS} $krb_lib" AC_CHECK_LIB(des,main,[LIBS="${LIBS} -ldes"]) AC_CHECK_LIB(des425,main,[LIBS="${LIBS} -ldes425"]) AC_CHECK_LIB(krb5,main,[LIBS="${LIBS} -lkrb5"]) AC_CHECK_LIB(crypto,main,[LIBS="${LIBS} -lcrypto"]) AC_CHECK_LIB(com_err,main,[LIBS="${LIBS} -lcom_err"]) AC_CHECK_FUNC(krb_mk_auth, :, # BSD Kerberos doesn't have these functions. EXTRA_OBJS="mk_auth.o $EXTRA_OBJS" ) fi fi AC_CHECK_FUNCS(krb_get_err_text) AC_SUBST(HAVE_KERBEROS) AC_SUBST(KRBINCLUDE) AC_SUBST(EXTRA_OBJS) fi if test "x$GCC" = "xyes" ; then GCC_CFLAGS="-W -Wall -ansi -pedantic -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wno-format" fi # ***** Guess the configuration ***** # echo guessing optimal GNATS configuration AC_SUBST(GNATS_SERVICE)dnl AC_SUBST(GNATS_USER)dnl AC_SUBST(DEFAULT_RELEASE)dnl AC_SUBST(DEFAULT_ORGANIZATION)dnl AC_SUBST(SUBMITTER)dnl AC_SUBST(DEFAULT_MAIL_AGENT)dnl AC_SUBST(BWEEK_START)dnl AC_SUBST(BWEEK_END)dnl AC_SUBST(BDAY_START)dnl AC_SUBST(BDAY_END)dnl AC_SUBST(GNATSD_USER_ACCESS_FILE)dnl AC_SUBST(GNATSD_HOST_ACCESS_FILE)dnl AC_SUBST(GLOBAL_DB_LIST_FILE)dnl AC_SUBST(GNATS_DEFAULT_DB_DIR)dnl AC_SUBST(GCC_CFLAGS)dnl # And GNATS_SERVICE AC_MSG_CHECKING(for --with-gnats-service) if test -n "$with_gnats_service"; then AC_MSG_RESULT($with_gnats_service) GNATS_SERVICE=$with_gnats_service fi if test -z "${GNATS_SERVICE}"; then AC_MSG_RESULT(default to support) GNATS_SERVICE=support fi # And GNATS_USER AC_MSG_CHECKING(for --with-gnats-user) if test -n "$with_gnats_user"; then AC_MSG_RESULT($with_gnats_user) GNATS_USER=$with_gnats_user fi if test -z "${GNATS_USER}"; then AC_MSG_RESULT(default to gnats) GNATS_USER=gnats fi AC_MSG_CHECKING(for --with-gnatsd-user-access-file) if test -n "${with_gnatsd_user_access_file}"; then AC_MSG_RESULT($with_gnatsd_user_access_file) GNATSD_USER_ACCESS_FILE=$with_gnatsd_user_access_file fi if test -z "${GNATSD_USER_ACCESS_FILE}"; then AC_MSG_RESULT(default to ${sysconfdir}/gnats/gnatsd.user_access) GNATSD_USER_ACCESS_FILE=${sysconfdir}/gnats/gnatsd.user_access fi AC_MSG_CHECKING(for --with-gnatsd-host-access-file) if test -n "${with_gnatsd_host_access_file}"; then AC_MSG_RESULT($with_gnatsd_host_access_file) GNATSD_HOST_ACCESS_FILE=$with_gnatsd_host_access_file fi if test -z "${GNATSD_HOST_ACCESS_FILE}"; then AC_MSG_RESULT(default to ${sysconfdir}/gnats/gnatsd.host_access) GNATSD_HOST_ACCESS_FILE=${sysconfdir}/gnats/gnatsd.host_access fi AC_MSG_CHECKING(for --with-gnats-dblist-file) if test -n "${with_gnats_dblist_file}"; then AC_MSG_RESULT($with_gnats_dblist_file) GLOBAL_DB_LIST_FILE=$with_gnats_dblist_file fi if test -z "${GLOBAL_DB_LIST_FILE}"; then AC_MSG_RESULT(default to ${sysconfdir}/gnats/databases) GLOBAL_DB_LIST_FILE=${sysconfdir}/gnats/databases fi AC_MSG_CHECKING(for --with-gnats-default-db) if test -n "${with_gnats_default_db}"; then AC_MSG_RESULT($with_gnats_default_db) GNATS_DEFAULT_DB_DIR="$with_gnats_default_db" fi if test -z "${GNATS_DEFAULT_DB_DIR}"; then AC_MSG_RESULT(default to ${sharedstatedir}/gnatsdb) GNATS_DEFAULT_DB_DIR=${sharedstatedir}/gnatsdb fi # Set up default values to be overridden _h=`(hostname || uname -n) 2>/dev/null | sed 1q` DEFAULT_RELEASE=unknown-1.0 DEFAULT_ORGANIZATION=unknown SUBMITTER=unknown DEFAULT_MAIL_AGENT=false BDAY_START=8 BDAY_END=17 BWEEK_START=1 BWEEK_END=5 AC_PATH_PROG(SENDMAIL,sendmail,[],$PATH:/usr/lib:/usr/sbin:/usr/ucblib) if test -n "$SENDMAIL" ; then DEFAULT_MAIL_AGENT="$SENDMAIL -oi -t" else echo "configure: error: sendmail binary not available" exit 1 fi # If the config file exists, it may have more recent info than send-pr if test -n "$verbose"; then echo " setting GNATS_SERVICE to $GNATS_SERVICE" echo " setting GNATS_USER to $GNATS_USER" echo " setting SUBMITTER to $SUBMITTER" echo " setting DEFAULT_RELEASE to $DEFAULT_RELEASE" echo " setting DEFAULT_ORGANIZATION to $DEFAULT_ORGANIZATION" echo " setting BDAY_START to $BDAY_START" echo " setting BDAY_END to $BDAY_END" echo " setting BWEEK_START to $BWEEK_START" echo " setting BWEEK_END to $BWEEK_END" echo " setting DEFAULT_MAIL_AGENT to $DEFAULT_MAIL_AGENT" fi # ***** End of configuration section ***** AC_CONFIG_FILES([Makefile]) AC_OUTPUT gnats-4.1.0/gnats/database.c0000644000175000017500000004620207570426211016416 0ustar chewiechewie00000000000000/* Basic database info. Copyright (C) 1999, 2000 Free Software Foundation, Inc. Contributed by Bob Manson . This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "mail.h" #include "pcodes.h" #include "field.h" struct databaseInfo { int debugModeFlag; int keepReceivedHeadersFlag; int notifyExpireFlag; char *binDirValue; int submitterAckFlag; unsigned int businessDay[2]; unsigned int businessWeek[2]; int createCategoryDirsFlag; int categoryDirPerms; QueryFormat *auditTrailFormat; QueryFormat *queryFormatList; char *databaseName; AdmEntry *databaseEnt; ChangeActions changeActions; FieldList requiredInputFields; DatabaseFieldInfo fieldInfo; AdmEntry *hostList; IndexDesc indexDesc; MailMessageFormat mailFormatList; InputTemplate *inputTemplate; FieldIndex builtinFields[NUM_BUILTIN_FIELDS]; /* Next and previous entries in the chain. */ struct databaseInfo *next, *prev; }; static struct databaseInfo *databaseInfoList = NULL; static AdmEntry *globalHostList = NULL; int databaseValid (const DatabaseInfo database) { return database != NULL && database->databaseEnt != NULL; } static DatabaseInfo newDatabaseInfo (void) { DatabaseInfo res = (DatabaseInfo) xmalloc (sizeof (struct databaseInfo)); int x; res->debugModeFlag = 0; res->keepReceivedHeadersFlag = 0; res->notifyExpireFlag = 0; res->binDirValue = NULL; res->submitterAckFlag = 0; res->businessDay[0] = 0; res->businessDay[1] = 0; res->businessWeek[0] = 0; res->businessWeek[1] = 0; res->createCategoryDirsFlag = 0; #ifdef S_IRWXU res->categoryDirPerms = S_IRWXU | S_IRGRP | S_IXGRP; #else res->categoryDirPerms = 0750; #endif res->auditTrailFormat = NULL; res->queryFormatList = NULL; res->databaseName = NULL; res->databaseEnt = NULL; res->changeActions = NULL; res->requiredInputFields = NULL; res->fieldInfo = NULL; res->hostList = NULL; res->indexDesc = NULL; res->mailFormatList = NULL; res->inputTemplate = NULL; for (x = 0; x < NUM_BUILTIN_FIELDS; x++) { res->builtinFields[x] = NULL; } res->next = databaseInfoList; res->prev = NULL; if (databaseInfoList != NULL) { databaseInfoList->prev = res; } databaseInfoList = res; return res; } static DatabaseInfo findDatabaseEntry (AdmEntry *databaseEnt) { DatabaseInfo res = databaseInfoList; while (res != NULL && res->databaseEnt != databaseEnt) { res = res->next; } return res; } DatabaseFieldInfo * getDatabaseFieldInfoWrite (DatabaseInfo database) { if (databaseValid (database)) { return &(database->fieldInfo); } else { return NULL; } } DatabaseFieldInfo getDatabaseFieldInfo (DatabaseInfo database) { if (databaseValid (database)) { return database->fieldInfo; } else { return NULL; } } const char * gnatsAdminMailAddr (const DatabaseInfo database) { return get_responsible_addr (database, 0, 0, "gnats-admin"); } void setDebugMode (DatabaseInfo database, int mode) { if (databaseValid (database)) { database->debugModeFlag = mode; } } void setKeepReceivedHeaders (DatabaseInfo database, int value) { if (databaseValid (database)) { database->keepReceivedHeadersFlag = value; } } void setNotifyExpire (DatabaseInfo database, int value) { if (databaseValid (database)) { database->notifyExpireFlag = value; } } void setBinDir (DatabaseInfo database, const char *value) { if (databaseValid (database)) { if (database->binDirValue != NULL) { free (database->binDirValue); } database->binDirValue = xstrdup (value); } } void setSubmitterAck (DatabaseInfo database, int value) { if (databaseValid (database)) { database->submitterAckFlag = value; } } void setBusinessDay (DatabaseInfo database, unsigned int startTime, unsigned int endTime) { if (databaseValid (database)) { database->businessDay[0] = startTime; database->businessDay[1] = endTime; } } void setBusinessWeek (DatabaseInfo database, unsigned int startDay, unsigned int endDay) { if (databaseValid (database)) { database->businessWeek[0] = startDay; database->businessWeek[1] = endDay; } } void setCreateCategoryDirs (DatabaseInfo database, int value) { if (databaseValid (database)) { database->createCategoryDirsFlag = value; } } void setAuditTrailFormat (DatabaseInfo database, QueryFormat *format) { if (databaseValid (database)) { database->auditTrailFormat = format; } } void setCategoryDirPerms (DatabaseInfo database, const char *value) { if (databaseValid (database)) { database->categoryDirPerms = strtol (value, NULL, 8); } } void addGlobalChangeActions (DatabaseInfo database, ChangeActions actions) { if (databaseValid (database)) { ChangeActions *alist = &(database->changeActions); while (*alist != NULL) { alist = &((*alist)->next); } *alist = actions; } } void setRequiredInputFields (DatabaseInfo database, FieldList list) { if (databaseValid (database)) { database->requiredInputFields = list; } } void setIndexDesc (DatabaseInfo database, IndexDesc new) { if (databaseValid (database)) { finishIndexDesc (database, new); database->indexDesc = new; } } void setInputTemplate (DatabaseInfo database, InputTemplate *list) { database->inputTemplate = list; } void setQueryFormatList (DatabaseInfo database, QueryFormat *list) { database->queryFormatList = list; } void setBuiltinDBField (DatabaseInfo database, int whichField, FieldIndex fieldIndex) { if (whichField < 0 || whichField >= NUM_BUILTIN_FIELDS) { abort (); } else { database->builtinFields[whichField] = fieldIndex; } } void setMailFormatList (DatabaseInfo database, MailMessageFormat formatList) { database->mailFormatList = formatList; } int keepReceivedHeaders (const DatabaseInfo database) { if (databaseValid (database)) { return database->keepReceivedHeadersFlag; } else { return 0; } } int debugMode (const DatabaseInfo database) { if (databaseValid (database)) { return database->debugModeFlag; } else { return 0; } } char * defaultSubmitter (const DatabaseInfo database) { if (databaseValid (database)) { AdmEntry *chain = fieldDefForIndex (SUBMITTER (database))->adm_contents; if (chain != NULL) { char *res = xstrdup (chain->admFields[SubmitterAdmKey]); return res; } else { return xstrdup ("unknown"); } } else { return NULL; } } char * mailAgent (const DatabaseInfo database) { const char *bdir = binDir (database); if (bdir != NULL) { char *agentPath; asprintf (&agentPath, "%s/mail-agent", bdir); return agentPath; } else { return NULL; } } char * defaultCategory (const DatabaseInfo database) { if (databaseValid (database)) { AdmEntry *chain = fieldDefForIndex (CATEGORY (database))->adm_contents; if (chain != NULL) { char *res = xstrdup (chain->admFields[CategoryAdmKey]); return res; } else { return xstrdup ("pending"); } } else { return NULL; } } char * defaultState (const DatabaseInfo database) { if (databaseValid (database)) { AdmEntry *chain = fieldDefForIndex (STATE (database))->adm_contents; if (chain != NULL) { char *res = xstrdup (chain->admFields[StateAdmKey]); return res; } else { return xstrdup ("open"); } } else { return NULL; } } int notifyExpire (const DatabaseInfo database) { if (databaseValid (database)) { return database->notifyExpireFlag; } else { return 0; } } const char * binDir (const DatabaseInfo database) { if (databaseValid (database)) { return database->binDirValue; } else { return NULL; } } int submitterAck (const DatabaseInfo database) { if (databaseValid (database)) { return database->submitterAckFlag; } else { return 0; } } unsigned int businessDayStart (const DatabaseInfo database) { if (databaseValid (database)) { return database->businessDay[0]; } else { return 0; } } unsigned int businessDayEnd (const DatabaseInfo database) { if (databaseValid (database)) { return database->businessDay[1]; } else { return 0; } } unsigned int businessWeekStart (const DatabaseInfo database) { if (databaseValid (database)) { return database->businessWeek[0]; } else { return 0; } } unsigned int businessWeekEnd (const DatabaseInfo database) { if (databaseValid (database)) { return database->businessWeek[1]; } else { return 0; } } int createCategoryDirs (const DatabaseInfo database) { if (databaseValid (database)) { return database->createCategoryDirsFlag; } else { return 0; } } int categoryDirPerms (const DatabaseInfo database) { if (databaseValid (database)) { return database->categoryDirPerms; } else { return 0700; } } char * gnats_adm_dir (const DatabaseInfo database, const char *filename) { const char *ddir = databaseDir (database); if (ddir != NULL) { char *ptr; asprintf (&ptr, "%s/gnats-adm/%s", ddir, filename); return ptr; } else { return NULL; } } ChangeActions globalChangeActions (const DatabaseInfo database) { if (databaseValid (database)) { return database->changeActions; } else { return NULL; } } QueryFormat * getQueryFormatList (const DatabaseInfo database) { return database->queryFormatList; } MailMessageFormat getMailFormatList (const DatabaseInfo database) { return database->mailFormatList; } static AdmEntry *dbList = NULL; static int readAdmFile (const char *filename, int fields, AdmEntry **dest, int allowOptionalFields) { char *line; FILE *f = fopen (filename, "r"); if (f == NULL) { return -1; } while ((line = read_line (f, NULL)) != NULL) { if (line[0] != '#' && line[0] != '\n' && !isspace ((int)(unsigned char) line[0])) { AdmEntry *nent = build_adm_entry (line, InvalidFieldIndex); if (nent != NULL) { if (nent->fieldcount == fields || (allowOptionalFields && (nent->fieldcount > fields))) { *dest = nent; dest = &(nent->next); } else { free_adm_entry (nent); } } } free (line); } fclose (f); return 0; } int initDatabaseList (ErrorDesc *err) { if (dbList != NULL) { freeAdmEntryChain (dbList); dbList = NULL; } /* Null out the databaseEnt pointers that just went away */ if (databaseInfoList != NULL) { DatabaseInfo info = databaseInfoList; while (info != NULL) { info->databaseEnt = NULL; info = info->next; } } if (readAdmFile (GLOBAL_DB_LIST_FILE, 3, &dbList, 1) < 0) { setError (err, CODE_FILE_ERROR, "Unable to open global configuration file %s", GLOBAL_DB_LIST_FILE); dbList = NULL; return -1; } else if (dbList == NULL) { setError (err, CODE_FILE_ERROR, "List of databases in %s is empty?!", GLOBAL_DB_LIST_FILE); return -1; } else { return 0; } } static void initGlobalHostList (void) { if (globalHostList != NULL) { freeAdmEntryChain (globalHostList); globalHostList = NULL; } if (readAdmFile (GNATSD_HOST_ACCESS_FILE, 3, &globalHostList, 0) < 0) { fprintf (stderr, "Unable to open %s\n", GNATSD_HOST_ACCESS_FILE); globalHostList = NULL; } } static void initHostList (DatabaseInfo database) { char *path; if (! databaseValid (database)) { return; } path = gnats_adm_dir (database, DB_HOST_ACCESS_FILE); if (path != NULL) { if (fileExists (path)) { if (readAdmFile (path, 3, &(database->hostList), 0) < 0) { fprintf (stderr, "Unable to open %s\n", path); } } free (path); } } AdmEntry * getHostList (const DatabaseInfo database) { if (! databaseValid (database)) { return NULL; } return database->hostList; } AdmEntry * getGlobalHostList (void) { if (globalHostList == NULL) { initGlobalHostList (); } return globalHostList; } static DatabaseInfo loadDatabase (const char *databaseName, AdmEntry *databaseEnt, ErrorDesc *err) { DatabaseInfo res = newDatabaseInfo (); res->databaseName = xstrdup (databaseName); res->databaseEnt = databaseEnt; if (! fileExists (res->databaseEnt->admFields[DatabaseListPath])) { setError (err, CODE_INVALID_DATABASE, "The directory %s does not exist for database %s", res->databaseEnt->admFields[DatabaseListPath], databaseName); freeDatabaseInfo (res); res = NULL; } else { char *path; initHostList (res); path = gnats_adm_dir (res, "dbconfig"); if (fconfigParse (res, path, NULL, err)) { freeDatabaseInfo (res); res = NULL; } else { initIndex (res); } free (path); } return res; } DatabaseInfo findOrLoadDatabase (const char *programName ATTRIBUTE_UNUSED, const char *databaseName, ErrorDesc *err) { DatabaseInfo res; AdmEntry *databaseEnt; if (databaseName == NULL) { databaseName = getenv ("GNATSDB"); if (databaseName == NULL || databaseName[0] == '\0') { databaseName = "default"; } } databaseEnt = find_chain_entry_nocopy (dbList, databaseName); if (databaseEnt == NULL) { setError (err, CODE_INVALID_DATABASE, "No such database as %s", databaseName); res = NULL; } else { res = findDatabaseEntry (databaseEnt); if (res == NULL) { res = loadDatabase (databaseName, databaseEnt, err); } } return res; } AdmEntry * getDatabaseList (ErrorDesc *err) { if (dbList == NULL) { initDatabaseList (err); } return dbList; } const char * databaseDir (const DatabaseInfo database) { if (databaseValid (database)) { return database->databaseEnt->admFields[DatabaseListPath]; } else { return NULL; } } const char * databaseName (const DatabaseInfo database) { if (databaseValid (database)) { return database->databaseName; } else { return NULL; } } const char * databaseDesc (const DatabaseInfo database) { if (databaseValid (database)) { return database->databaseEnt->admFields[DatabaseListDesc]; } else { return NULL; } } QueryFormat * getAuditTrailFormat (const DatabaseInfo database) { if (databaseValid (database)) { return database->auditTrailFormat; } else { return NULL; } } FieldList getRequiredInputFields (const DatabaseInfo database) { return database->requiredInputFields; } IndexDesc getIndexDesc (const DatabaseInfo database) { return database->indexDesc; } InputTemplate * getInputTemplate (const DatabaseInfo database) { return database->inputTemplate; } FieldIndex getBuiltinField (const DatabaseInfo database, int fieldNum) { if (fieldNum < 0 || fieldNum >= NUM_BUILTIN_FIELDS) { abort (); } else { return database->builtinFields[fieldNum]; } } static void clearHostList (DatabaseInfo database) { freeAdmEntryChain (database->hostList); database->hostList = NULL; } void clearDbList (void) { freeAdmEntryChain (dbList); dbList = NULL; } static void clearInputTemplate (DatabaseInfo database) { freeInputTemplate (database->inputTemplate); database->inputTemplate = NULL; } static void clearGlobalChangeActions (DatabaseInfo database) { freeChangeActions (database->changeActions); database->changeActions = NULL; } static void clearIndexDesc (DatabaseInfo database) { if (database->indexDesc != NULL) { freeIndexDesc (database->indexDesc); database->indexDesc = NULL; } } static void clearQueryFormatList (DatabaseInfo database) { if (database->queryFormatList != NULL) { freeQueryFormatList (database->queryFormatList); database->queryFormatList = NULL; } } static void clearAuditTrailFormat (DatabaseInfo database) { if (database->auditTrailFormat != NULL) { freeQueryFormatList (database->auditTrailFormat); database->auditTrailFormat = NULL; } } static void clearMessageFormatList (DatabaseInfo database) { if (database->mailFormatList != NULL) { freeMessageFormatList (database->mailFormatList); database->mailFormatList = NULL; } } void freeDatabaseInfo (DatabaseInfo database) { if (database != NULL) { clearPRChain (database); clearQueryFormatList (database); clearFieldList (database); clearMessageFormatList (database); clearIndexDesc (database); clearAuditTrailFormat (database); clearHostList (database); clearInputTemplate (database); clearGlobalChangeActions (database); freeFieldList (database->requiredInputFields); if (database->databaseName != NULL) { free (database->databaseName); } if (database->binDirValue != NULL) { free (database->binDirValue); } if (database->next != NULL) { database->next->prev = database->prev; } if (database->prev != NULL) { database->prev->next = database->next; } else if (databaseInfoList == database) { databaseInfoList = database->next; } database->next = NULL; database->prev = NULL; free (database); } } int databaseSpecIsNetConn (const char *name) { AdmEntry *dbEnt; ErrorDesc err; if (name == NULL || name[0] == '\0') { name = "default"; } if (initDatabaseList (&err)) { return 0; } dbEnt = find_chain_entry_nocopy (dbList, name); if (dbEnt == NULL) { return 0; } return (dbEnt->fieldcount > 3) ? 1 : 0; } const char * databaseSpecServer (const char *name) { AdmEntry *dbEnt; ErrorDesc err; if (name == NULL || name[0] == '\0') { name = "default"; } if (dbList == NULL) { initDatabaseList (&err); } dbEnt = find_chain_entry_nocopy (dbList, name); if (dbEnt == NULL) { return NULL; } return (dbEnt->fieldcount > 3) ? dbEnt->admFields[DatabaseServer] : NULL; } const char * databaseSpecPort (const char *name) { AdmEntry *dbEnt; if (name == NULL || name[0] == '\0') { name = "default"; } dbEnt = find_chain_entry_nocopy (dbList, name); if (dbEnt == NULL) { return NULL; } return (dbEnt->fieldcount > 4) ? dbEnt->admFields[DatabasePort] : NULL; } gnats-4.1.0/gnats/database.h0000644000175000017500000001372407555765525016447 0ustar chewiechewie00000000000000/* Basic database info. Copyright (C) 1999 Free Software Foundation, Inc. Contributed by Bob Manson . This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef _DATABASE_H #define _DATABASE_H struct databaseInfo; typedef struct databaseInfo * DatabaseInfo; #include "adm.h" #include "mail.h" /* Returns an entry for the database DATABASE_NAME; PROGRAM_NAME is the name of the program that's building the database entry. */ extern DatabaseInfo findDatabase (const char *program_name, const char *database_name, ErrorDesc *err); /* Return a writable pointer to the field info for this database. */ DatabaseFieldInfo *getDatabaseFieldInfoWrite (DatabaseInfo database); DatabaseFieldInfo getDatabaseFieldInfo (DatabaseInfo database); /* Initialize the list of databases. */ extern int initDatabaseList (ErrorDesc *err); /* Returns the name of the database. */ extern const char *databaseName (const DatabaseInfo database); /* Returns the human-readable description of the database. */ extern const char *databaseDesc (const DatabaseInfo database); /* Returns the directory where the database is located. */ extern const char *databaseDir (const DatabaseInfo database); /* Returns the list of databases. */ extern AdmEntry *getDatabaseList (ErrorDesc *err); /* Returns a non-zero value if the database is valid. */ extern int databaseValid (const DatabaseInfo database); /* Returns the host list for the database. */ extern AdmEntry *getHostList (const DatabaseInfo database); /* Returns the global host access control list. */ extern AdmEntry *getGlobalHostList (void); /* Returns the path to the GNATS administrative file with the base name of FILENAME. The caller takes ownership of the malloc()ed version of the path, and is responsible for freeing it. */ extern char *gnats_adm_dir (DatabaseInfo database, const char *filename); /* Set the mail agent to NEWAGENT. */ extern void setMailAgent (DatabaseInfo database, const char *newAgent); /* Enables or disables debug mode. */ extern void setDebugMode (DatabaseInfo database, int mode); /* Sets the "keep received headers flag" to VALUE. */ extern void setKeepReceivedHeaders (DatabaseInfo database, int value); extern void setNotifyExpire (DatabaseInfo database, int value); extern void setBinDir (DatabaseInfo database, const char *directory); extern void setSubmitterAck (DatabaseInfo database, int value); extern void setBusinessDay (DatabaseInfo database, unsigned int startHour, unsigned int endHour); extern void setBusinessWeek (DatabaseInfo database, unsigned int firstDay, unsigned int lastDay); extern void setCreateCategoryDirs (DatabaseInfo database, int flagValue); extern void setAuditTrailFormat (DatabaseInfo database, QueryFormat *format); extern void addGlobalChangeActions (DatabaseInfo database, ChangeActions actions); extern void setCategoryDirPerms (DatabaseInfo database, const char *value); extern void setInputTemplate (DatabaseInfo database, InputTemplate *template); extern void setQueryFormatList (DatabaseInfo database, QueryFormat *format); extern void setBuiltinDBField (DatabaseInfo database, int whichField, FieldIndex fieldIndex); extern void setMailFormatList (DatabaseInfo database, MailMessageFormat mailFormatList); extern void setRequiredInputFields (DatabaseInfo database, FieldList list); extern void setIndexDesc (DatabaseInfo database, const IndexDesc desc); extern int keepReceivedHeaders (const DatabaseInfo database); extern int debugMode (DatabaseInfo database); extern char *mailAgent (const DatabaseInfo database); extern const char *gnatsAdminMailAddr (const DatabaseInfo database); extern char *defaultSubmitter (const DatabaseInfo database); extern char *defaultCategory (const DatabaseInfo database); extern char *defaultState (const DatabaseInfo database); extern int notifyExpire (const DatabaseInfo database); extern const char *binDir (const DatabaseInfo database); extern int submitterAck (const DatabaseInfo database); extern unsigned int businessDayStart (const DatabaseInfo database); extern unsigned int businessDayEnd (const DatabaseInfo database); extern unsigned int businessWeekStart (const DatabaseInfo database); extern unsigned int businessWeekEnd (const DatabaseInfo database); extern ChangeActions globalChangeActions (const DatabaseInfo database); extern int createCategoryDirs (const DatabaseInfo database); QueryFormat *getAuditTrailFormat (const DatabaseInfo database); extern int categoryDirPerms (const DatabaseInfo database); extern FieldList getRequiredInputFields (const DatabaseInfo database); extern IndexDesc getIndexDesc (const DatabaseInfo database); extern InputTemplate *getInputTemplate (const DatabaseInfo database); extern QueryFormat *getQueryFormatList (const DatabaseInfo database); extern MailMessageFormat getMailFormatList (const DatabaseInfo database); extern FieldIndex getBuiltinField (const DatabaseInfo database, int whichField); extern void freeDatabaseInfo (DatabaseInfo database); extern DatabaseInfo findOrLoadDatabase (const char *programName, const char *databaseName, ErrorDesc *err); extern void clearDbList (void); extern int databaseSpecIsNetConn (const char *dbName); extern const char *databaseSpecServer (const char *dbName); extern const char *databaseSpecPort (const char *dbName); #endif gnats-4.1.0/gnats/dbconfig.in0000644000175000017500000005042707560311204016607 0ustar chewiechewie00000000000000# This configuration file describes the standard "out-of-the-box" configuration # for GNATS. It is responsible for describing the types of data stored # in fields, the order of fields in the index file, and the format of # results returned from query-pr. # # The format of the file is rather freeform; whitespace is unnecessary, and is # ignored. Any text after a # is considered to be a comment, and is ignored # until the end of the line. # # The first section describes various aspects of the database. database-info { # If true, mail is sent to the gnats-admin mail address instead # of the submitter. (Should be set to false or true.) debug-mode false # If true, all of the Received: headers are kept in the PR, # otherwise only the first one is kept. keep-all-received-headers false # If true, we track required PR times and notify the responsible # people when the times expire. notify-about-expired-prs false # Send the PR submitter an acknowledgement for a newly-submitted PR; # the format of the message is the "mail-format" query format. send-submitter-ack true # The directory where at-pr and mail-pr can be found. libexecdir "xLIBEXECDIRx" # The hours that define a business day, in 24-hour format. business-day-hours xBDAY_STARTx-xBDAY_ENDx # The starting and ending days of the week that define the business day. business-week-days xBWEEK_STARTx-xBWEEK_ENDx # If true, directories for categories are automatically created if they # don't already exist. create-category-dirs true # The default permission mask for new category directories. # NOTE: If local users on the GNATS server itself will be running # tools such as query-pr, you may to need set permissions to 0755. category-dir-perms "0750" } # # The second section describes each field within the PR. # # The name specified here is also used as the field header in the PR, with # a `>' prepended and a `:' appended. # field "Number" { # This entry describes a builtin field; "number" is the internal # name of the field. (The builtin names correspond to the old gnats # field names, and are case-insensitive as are field names.) builtin-name "number" # A one-line description of the field, in human-readable form. description "PR Number" # Integer values are stored in this field. integer { # This must be -1 -- code in various programs relies on the first # character of the field being a '-' if the value wasn't specified. # Really, it shouldn't have a default. default "-1" } # The field value may not be edited. read-only } field "Notify-List" { description "Addresses to notify of significant PR changes" text query-default inexact-regexp textsearch } field "Category" { builtin-name "category" description "What area does this PR fall into?" # # The possible values for this field are enumerated in a separate file. # enumerated-in-file { # # The name of the file is "categories"; it is located in the # gnats-adm subdirectory of the database. # path "categories" # # The names of the fields in the file; the file has 4 fields. # Fields within the file are separated by colons (:). # fields { "category" "fullname" "person" "notify" } # The file is keyed on this field. (This is currently ignored, but # it will eventually be used and should be present. For now, this # must always be the first field listed above.) key "category" } # This field is searched when doing a --text search in query-pr. textsearch } field "Synopsis" { builtin-name "synopsis" description "One-line summary of the PR" text # When doing queries on this field, by default regexps do not need to # match the contents of the field exactly. The other possible # value is "exact-regexp". query-default inexact-regexp textsearch } field "Confidential" { builtin-name "confidential" description "Yes/no flag indicating if the PR contents are confidential" # An enumerated field with two possible values; the default value # is "yes". enum { values { "yes" "no" } default "yes" } textsearch # This field may not be queried unless the user has full permissions # to search it. (Does this actually do anything??? Probably not.) restricted } field "Severity" { builtin-name "severity" description "How severe is the PR?" enum { values { "critical" "serious" "non-critical" } default "serious" # We don't want to suggest a default when a PR is being input. input-default "" } textsearch } field "Priority" { builtin-name "priority" description "How critical is it that the PR be fixed?" enum { values { "high" "medium" "low" } default "medium" # We don't want to suggest a default when a PR is being input. input-default "" } query-default exact-regexp textsearch } field "Responsible" { builtin-name "responsible" description "The user responsible for the PR" enumerated-in-file { path "responsible" fields { "responsible" "fullname" "alias" } key "responsible" # We have to allow any value here, because old GNATS didn't require # all possible responsible users to be listed in the responsible # file--it looks in the password database as well. # # The flag indicates that the value in the field doesn't have to # match one of the entries in the administrative file. allow-any-value } textsearch # When the field is edited, we want an audit-trail entry to be added, # and we want to require a reason for the change. on-change { add-audit-trail require-change-reason } # Terminate the entry in the index after the first space. (bleah! Probably # no longer needed. And we should handle this by allowing a format # character in the index spec instead of this option.) nospaces-in-index } field "State" { builtin-name "state" description "The current state of the PR" enumerated-in-file { path "states" fields { "state" "type" "description" } key "state" } textsearch on-change { # Add Audit-Trail entries when this field changes. add-audit-trail # Require that a reason be supplied when this field is edited. require-change-reason } # # Here's an example of how we would set the Closed-Date: field when the # State: field is changed to "closed". # # Note that a \ followed by a newline is ignored, and \n within strings # is translated to the EOL character. # # Only do the edit if the new State's type is "closed" and if # a) the previous State wasn't of type closed # or b) the Closed-Date is not yet defined # With this rule, we keep the Closed-Date if we change from a "closed" # state to another "closed" state. # on-change "State[type]==\"closed\" \ & (oldpr:State[Type]!=\"closed\" | Closed-Date==\"\")" { # # Set the Closed-Date field to the current date. (We can also # use $OldValue and $NewValue here as well, in addition to any # of the PR's field values.) # set-field "Closed-Date" { "%s" "$CurrentDate" } } # # If the new PR's State: field type is not closed...then we want to clear # the Closed-Date field. # on-change "State[type]!=\"closed\"" { # # Null it out. # set-field "Closed-Date" { "" } } } field "Class" { description "The type of bug" enumerated-in-file { path "classes" fields { "class" "type" "description" } key "class" } textsearch } field "Submitter-Id" { builtin-name "submitter-id" description "Site-specific identification of the PR author" enumerated-in-file { path "submitters" fields { "submitter" "fullname" "type" "rtime" "contact" "notify" } key "submitter" } textsearch } field "Arrival-Date" { builtin-name "arrival-date" description "Arrival date of the PR" # A date field. Dates are validated as to format before they can be # stored; the field contents may also be empty. date # The field value may not be edited. read-only } field "Closed-Date" { builtin-name "closed-date" description "Date when the PR was closed" date # The field may not be edited by the user. read-only } field "Last-Modified" { builtin-name "last-modified" description "Last modification date of the PR" date # The field may not be edited by the user. read-only } field "Originator" { builtin-name "originator" description "Name of the PR author" # The data type stored in this field is text. text query-default inexact-regexp textsearch } field "Release" { description "Release number or tag" text query-default inexact-regexp textsearch } field "Organization" { description "Organization of PR author" # Multiple lines of text may appear in the field. multitext } field "Environment" { description "Machine, OS, target, libraries" multitext } field "Description" { builtin-name "description" description "Precise description of the problem" multitext } field "How-To-Repeat" { description "Code/input/activities to reproduce the problem" multitext } field "Fix" { description "How to correct or work around the problem, if known" multitext { # Do we really want this here? default "\nUnknown" } } field "Release-Note" { multitext } field "Audit-Trail" { builtin-name "audit-trail" description "Log of specific changes to the PR" multitext } # # This is the "limbo death nuke" field where unparsed text ends up. # field "Unformatted" { builtin-name "unformatted" description "Miscellaneous text that was not parsed properly" multitext } # # The following query sections describe the output of various types of # queries. # # For a full query, all fields are printed out. The format used is # the same as a normal PR. # query "full" { fields all } # # Used for edits. The field contents are displayed "raw". # query "edit" { fields all raw } # # If a list of fields is given without any format specifier, the fields # are printed out in the same format as they would appear in a PR, # complete with headers. # # The standard query type is the one that is performed by default if no # format is specified to query-pr. # query "standard" { fields { "Number" "Category" "Synopsis" "Confidential" "Severity" "Priority" "Responsible" "State" "Class" "Submitter-Id" "Arrival-Date" "Closed-Date" "Last-Modified" "Originator" "Release" } } # # The format string uses printf-style formatting to format its # output. No headers are printed, and a trailing EOL character is # always output. \n within the string is replaced with the proper EOL # character. # # The format characters are: # %s - plain string. # %S - similar to %s, but the string is terminated at the first space # that occurs in the field contents. Used for the Responsible: # field. # %d - integer value. This is normally used to print out enumerated # fields with their integer equivalent, or to print out dates # as "seconds since Jan 1, 1970". # %D - formatted date field. # %Q - SQL-formatted date field. # %F - write the entire field with the header and a newline, just as if # it were being written to a PR. Any positional indicators and # such are ignored. # # For most %-formats the usual `-' and `+' positional specifiers may be given. # # This is the --summary format in query-pr. # query "summary" { format "%8s %-8.8S %-8.8s %-9.9s %-9.9s %-8.8s %-10.10s %s" fields { "Number" "Responsible" "Category" "State" "Severity" "Priority" "Submitter-Id" "Synopsis" } } # # The next two are historical silliness. # query "sql" { format "%-8.8s|%-16.16s|%-128.128s|%-3.3s|%1.1d|%1.1d|%-16.16S|%1.1d|%1.1d|%-16.16s|%-21.21Q|%-64.64s|%-64.64s|%-21.21Q|%-21.21Q|" fields { "Number" "Category" "Synopsis" "Confidential" "Severity" "Priority" "Responsible" "State" "Class" "Submitter-Id" "Arrival-Date" "Originator" "Release" "Last-Modified" "Closed-Date" } } query "sql2" { format "%s|%s|%s|%s|%d|%d|%S|%d|%d|%s|%Q|%s|%s|%Q|%Q|" fields { "Number" "Category" "Synopsis" "Confidential" "Severity" "Priority" "Responsible" "State" "Class" "Submitter-Id" "Arrival-Date" "Originator" "Release" "Last-Modified" "Closed-Date" } } # # The format used for Audit-Trail entries. The following parameters # are passed in, and can be used in addition to any of the PR fields: # $FieldName -- the name of the field that has changed # $OldValue -- the old value of the field # $NewValue -- the new field value # $EditUserEmailAddr -- the email address of the user editing the field # $CurrentDate -- the current date # $ChangeReason -- the reason for the change (may be blank if no reason was # supplied) # audit-trail-format { format "\ %s-Changed-From-To: %s->%s\n\ %s-Changed-By: %s\n\ %s-Changed-When: %s\n\ %s-Changed-Why:\n\ %s\n\n" fields { "$FieldName" "$OldValue" "$NewValue" "$FieldName" "$EditUserEmailAddr" "$FieldName" "$CurrentDate" "$FieldName" "$ChangeReason" } } # # This message is used when mailing an initial response back to the # PR submitter. # mail-format "initial-response-to-submitter" { from-address { fixed-address "gnats-admin" } # For addresses that are joined with |, we try each one in turn, from # left to right, until we find one that's non-empty. # Multiple addresses may be listed here. to-addresses { "Reply-To:" | "From:" | "From" | "Submitter-Id" } header { format "Subject: Re: %s/%s: %s\n" fields { "Category" "Number" "Subject:" } } body { format "Thank you very much for your problem report.\n\ It has the internal identification `%s/%s'.\n\ The individual assigned to look at your\n\ report is: %s. \n\ \n\ %F%F%F%F\n\ " fields { "Category" "Number" "Responsible" "Category" "Responsible" "Synopsis" "Arrival-Date" } } } # # The message sent to the responsible parties when a new non-pending # PR arrives. # mail-format "initial-pr-notification" { # Who the mail is from. from-address { "From:" | "From" } # We send mail to the responsible person, the addresses listed in # the contact and notify fields of the submitter adm file entry for # the Submitter-Id, and the notify person listed in the category # adm file. to-addresses { "Responsible" "Submitter-Id[contact]" "Submitter-Id[notify]" "Category[notify]" } # The reply-to address; either use the Reply-To: or From: header values # from the PR, or the Submitter-Id's mail address. reply-to { "Reply-To:" | "From:" | "Submitter-Id" } # Any additional header text we want to add. Must have a newline at the # end of each line. header { format "Subject: %s/%s: %s\nCc: %s\n" fields { "Category" "Number" "Subject:" "Notify-List" } } body { # Need to add this feature, or something like it. # ($ExpireTime != "") { # format "\tThe contract type is `%s' with a response time of %d business hours.\n" # fields { "Submitter-Id[type]" "$ExpireTime" } # } # %P is "write the entire PR". Ugh. FIXME XXX ??? !!! format "%P" # And if there's a %-format...there has to be an associated field. # Double bleah. fields { "$" } } } # # This format is used for initial PRs that end up as pending PRs. # mail-format "initial-pr-notification-pending" { # # Is this good? # from-address { "From:" | "From" } # # Boring--we only tell gnats-admin about it. # to-addresses { fixed-address "gnats-admin" } # # Questionable for a pending PR. # reply-to { "Reply-To:" | "From:" | "Submitter-Id" } header { format "Subject: %s/%s: %s (pending)\nCc: %s\n" fields { "Category" "Number" "Subject:" "Notify-List" } } body { # # See above. # # ($ExpireTime != "") { # format "\tThe contract type is `%s' with a response time of %d business hours.\n" # fields { "Submitter-Id[type]" "$ExpireTime" } # } format "%P" fields { "$" } } } # # Used when a response to a PR is received via email. # # The following parameters are passed in: # $MailFrom -- the From: line of the original message # $MailTo -- the To: line of the original message # $MailSubject: The Subject: line of the original message # $MailCC: The CC: line of the original message # $NewAuditTrail -- the text of the new audit trail entry (the body of # the message) # mail-format "appended-email-response" { from-address { "$MailFrom" } # # Should we send a copy to the user that sent in the message? # to-addresses { "Responsible" "Submitter-Id[contact]" } reply-to { "$MailFrom" } header { format "Subject: %s/%s: %s\n" fields { "Category" "Number" "$MailSubject" } } body { format "The following reply was made to PR %s/%s; it has been noted by GNATS.\n\n%s" fields { "Category" "Number" "$NewAuditTrail" } } } # # Used to send mail for a change that generates an Audit-Trail entry. # The following parameters are available: # $EditUserEmailAddr -- the email address of the user editing the PR # $OldResponsible -- the previous Responsible field entry, if it was changed # $NewAuditTrail -- the Audit-Trail: entries that have been appended # by the edits # mail-format "audit-mail" { from-address { "$EditUserEmailAddr" } # to-addresses { "Responsible" "$OldResponsible" "Category[notify]" "Submitter-Id[contact]" "$EditUserEmailAddr" "Reply-To:" | "From:" | "From" } # # ??? Good question! # reply-to { fixed-address "bugs" } header { format "Subject: Re: %s/%s\nCc: %s\n" fields { "Category" "Number" "Notify-List" } } body { format "Synopsis: %s\n\n%s\n" fields { "Synopsis" "$NewAuditTrail" } } } # # Used to send mail when a PR is deleted. # The following parameters are available: # $EditUserEmailAddr -- the email address of the user deleting the PR # $PRNum -- the number of the PR that was deleted # Can't refer to the deleted PR at this point--it's been deleted. *bam* # mail-format "deleted-pr-mail" { from-address { "$EditUserEmailAddr" } # to-addresses { fixed-address "gnats-admin" } header { format "Subject: Deleted PR %s\n" fields { "$PRNum" } } body { format "PR %s was deleted by user %s.\n" fields { "$PRNum" "$EditUserEmailAddr" } } } # # Global on-change sections are executed once for each PR edit. # # This one takes care of setting the Last-Modified field. The following # format parameters are available: # # $CurrentDate -- the current date # $EditUserEmailAddr -- the email address of the user making the change(s) # on-change { set-field "Last-Modified" { "%s" "$CurrentDate" } } # # The index entry lists the fields that appear in the index. For now, the PR # ID (consisting of "category/number") is always first in the index records, # and is not explicitly given here. # # The binary-index keyword indicates that a binary file format will be used # to store the index. This has several advantages over the old ASCII format, # not the least of which is avoiding problems with quoting field separators # (which didn't work properly in GNATS v3). # # If the old ASCII format is used (by setting binary-index to false) a '|' is # used as the separator between fields by default. An alternate field # separator may be given with the "separator" keyword. # index { # Name of the index file in the gnats-adm directory. The name is # respected, but you can only have one index entry per database (for # now). The index is keyed by PR number. path "index" # The fields in the index, in the order in which they will appear. fields { "Submitter-Id" "Responsible" "State" "Confidential" "Severity" "Priority" "Arrival-Date" "Last-Modified" "Closed-Date" "Class" "Originator" "Release" "Synopsis" } # A somewhat convoluted binary format is used when binary-index is set # to true. binary-index true } # initial-entry describes which fields should be present on initial entry; # this is used by send-pr (for example) to decide which fields to include # in the template. # # These are listed in the approximate order in which they should appear in # the template. initial-entry { fields { "Submitter-Id" "Notify-List" "Originator" "Organization" "Synopsis" "Confidential" "Severity" "Priority" "Category" "Class" "Release" "Environment" "Description" "How-To-Repeat" "Fix" } } gnats-4.1.0/gnats/delete-pr.sh0000644000175000017500000000550007563157256016733 0ustar chewiechewie00000000000000#! /bin/sh # Program to delete problem reports for GNATS. # Contributed by Kevin Hopkins (K.Hopkins@cs.nott.ac.uk). LIBEXECDIR=xLIBEXECDIRx GNATS_USER=xGNATS_USERx locked= closed= closed_state= usage="Usage: $0 [-fhV] [--version] [--help] [ -c | --closed | PR ]" version=xVERSIONx # parse command line. # for the non-flag argument, assume it's correct. if it's a full # id number, use that; if not, find the full id. # only continue if $full_id is an actual file. if [ $# -eq 0 ]; then echo "$usage" ; exit 1 fi case "$1" in -V|-v|--version|--ve*) echo "$version"; exit 0 ;; -h|--help*) echo "$usage"; exit 0 ;; -d|--database) if [ "$#" -le 1 ] ; then echo "$usage"; exit 1; fi shift ; GNATS_DB="--database=$1" ;; -d=*|--database=*) GNATS_DB="$1" ;; -c|--closed) if [ "$#" -eq "1" ] ; then closed=t else echo "$usage"; exit 1 fi ;; -*) echo "$usage"; exit 1 ;; *) pr=$1 ;; esac if [ "$closed" = "t" ] then prs=`query-pr $GNATS_DB --format Number --state closed` else if [ "x$pr" = "x" ] then echo "Must specify either a PR to delete or the --closed option."; exit 1 fi prs=$pr fi if [ "`echo -n`" = "-n" ] then echon () { echo $* \\c ; } else echon () { echo -n $* ; } fi if [ -z "$HOSTNAME" ]; then if [ -f /bin/hostname ] ; then HOSTNAME=`/bin/hostname` elif [ -f /usr/bin/hostname ] ; then HOSTNAME=`/usr/bin/hostname` # Solaris et al. elif [ -f /usr/ucb/hostname ] ; then HOSTNAME=`/usr/ucb/hostname` # Irix elif [ -f /usr/bsd/hostname ] ; then HOSTNAME=`/usr/bsd/hostname` fi fi # find a user name if [ "$USER" != "" ]; then me=$USER else if [ "$LOGNAME" != "" ]; then me=$LOGNAME else echo "edit-pr: no user name found---set LOGNAME." ; exit 1 fi fi if [ "x$me" != "x$GNATS_USER" ] then echo "To delete a PR, you must be $GNATS_USER"; exit 1 fi if [ -n "$HOSTNAME" ]; then full_me="$me@$HOSTNAME" else full_me="$me" fi # start of loop for prnum in $prs do # XXX ??? !!! Should use State[type] here instead, but then we'd have # to change the check for a valid PR number, because non-closed states # are usually returned as the empty string for a type. state=`query-pr $GNATS_DB --format State $prnum` case $state in "") echo "No such PR as $prnum" 1>&2 continue ;; [Cc]losed) closed_state=t ;; *) closed_state="" ;; esac if [ "$closed_state" = "t" ] then echon "Do you want to delete problem $prnum? [n]" read answer junk < /dev/tty case $answer in [yY]*) ;; [qQ]*) exit 0 ;; *) continue; ;; esac else echo "To delete $prnum, it must be closed."; exit 1 fi $LIBEXECDIR/gnats/pr-edit $GNATS_DB --email-addr "$full_me" --delete-pr $prnum if [ $? != 0 ] then continue; fi # end of loop done exit 0 gnats-4.1.0/gnats/diff-prs.sh0000644000175000017500000000315607733153173016562 0ustar chewiechewie00000000000000#! /bin/sh # Primitive program to diff PRs. # Copyright (C) 200 Free Software Foundation, Inc. # Contributed by Bob Manson (manson@juniper.net). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # Diff the PRs in files $1 and $2, returning a list of the changed # fields. No output is produced if the PRs are identical. xAWKx ' BEGIN { state = 0; } (state == 0) { fn = FILENAME; } ((state == 0 || state == 2) && /^>.*:/) { state++; } (fn != FILENAME) { fn = FILENAME; state++; arrayindex=""; } ((state == 1 || state == 3) && /^>.*:/) { line=$0; fieldname=$1; sub("^>", "", fieldname); sub(":.*$", "", fieldname); sub("^[^:]*:[ \t]*", "", line); arrayindex=state">"fieldname; array[arrayindex] = line; fields[fieldname]++; next; } ((state == 1 || state == 3) && arrayindex != "") { array[arrayindex] = array[arrayindex] "" $0; next; } END { for (x in fields) { if (array["1>"x] != array["3>"x]) { print x; } } } ' $1 $2 gnats-4.1.0/gnats/edit-pr.sh0000644000175000017500000001715507474177762016434 0ustar chewiechewie00000000000000#!/bin/sh # Program to edit problem reports for GNATS. # Copyright (C) 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 Free Software # Foundation, Inc. # Contributed by Jeffrey Osier (jeffrey@cygnus.com). # Majorly revised by Bob Manson (manson@juniper.net). # Further improvements by Dirk Bergstrom (dirk@juniper.net). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. debug_print=false # or echo to get output. BINDIR=xBINDIRx LIBEXECDIR=xLIBEXECDIRx GNATS_PORT= locked= version=xVERSIONx usage=" Usage: edit-pr [-V|--version] [-h|--help] [-d|--database database_name] [-H|--host hostname] [-P|--port port_number] [-v|--user userid] [-w|--passwd password] PR " # get current host name if [ -z "$HOSTNAME" ]; then if [ -f /bin/hostname ] ; then HOSTNAME=`/bin/hostname` elif [ -f /usr/bin/hostname ] ; then HOSTNAME=`/usr/bin/hostname` # Solaris et al. elif [ -f /usr/ucb/hostname ] ; then HOSTNAME=`/usr/ucb/hostname` # Irix elif [ -f /usr/bsd/hostname ] ; then HOSTNAME=`/usr/bsd/hostname` fi fi # check to see if there is a $EDITOR; if not, use vi [ -z "$VISUAL" ] && if [ -z "$EDITOR" ]; then VISUAL=vi else VISUAL="$EDITOR" fi # Parse command line. For the non-flag argument, assume it's pr PR id. if [ $# -eq 0 ]; then echo "$usage" ; exit 1 fi while [ $# -gt 0 ]; do case "$1" in -V|--version|--ve*) echo "$version"; exit 0 ;; -d | --database) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; GNATS_DB="--database=$1" ;; -d=* | --database=*) GNATS_DB="$1" ;; -H | --host) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; GNATS_HOST="--host=$1" ;; -H=* | --host=*) GNATS_HOST="--host=`echo $1 | sed 's/^[-a-z]*=//'`" ;; -P | --port) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; GNATS_PORT="--port=$1" ;; -P=* | --port=*) GNATS_PORT="$1" ;; -v | --user) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; EDIT_USER="--user=$1" ;; -v=* | --user=*) EDIT_USER="$1" ;; -w | --passwd) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; EDIT_PASSWD="--passwd=$1" ;; -w=* | --passwd=*) EDIT_PASSWD="$1" ;; -h|--help*) echo "$usage"; exit 0 ;; -*) echo "$usage"; exit 1 ;; *) if [ "`echo $1 | grep /`" != "" ]; then pr_id=`echo $1 | awk -F"/" '{print $2}' -` else pr_id=$1 fi ;; esac shift done # set command here to always pass host and port, and directory if supplied QUERY_PR="$BINDIR/query-pr $GNATS_HOST $GNATS_PORT $GNATS_DB $EDIT_USER $EDIT_PASSWD" PR_ADDR="$QUERY_PR --responsible-address" PR_EDIT="$LIBEXECDIR/gnats/pr-edit $GNATS_HOST $GNATS_PORT $EDIT_USER $EDIT_PASSWD $GNATS_DB" # These traps take care of deleting all the /tmp files trap 'rm -f $new.old $change_msg $fixfil' 0 # Don't delete $new on error signals trap 'if [ "$locked" != "" ]; then \ $PR_EDIT --unlock $pr_id ; \ locked= ; \ fi' 1 2 3 13 15 # find a user name if [ "$USER" != "" ]; then me=$USER else if [ "$LOGNAME" != "" ]; then me=$LOGNAME else echo "edit-pr: no user name found---set LOGNAME." ; exit 1 fi fi if [ -n "$HOSTNAME" ]; then full_me="$me@$HOSTNAME" else full_me="$me" fi # new = temp file to use for editing new="/tmp/ep$$" newtmp="/tmp/ep$$.tp" change_msg="/tmp/ep$$.ch" fixfil="/tmp/ep$$.fx" # lock the pr $debug_print "Locking $pr_id." lock=`$PR_EDIT --lock=$full_me --process=$$ $pr_id 2>&1 > $new` locked=t if [ "$lock" != "" ] ; then echo $lock exit 0 fi rm -f $fixfil # Now add any missing fields, along with a description. $QUERY_PR --list-fields | while read field do grep -i "^>${field}:" "$new" > /dev/null 2>&1 if [ $? != 0 ] then $QUERY_PR --field-flags "$field" | grep -i readonly > /dev/null 2>&1 if [ $? != 0 ] then type="`$QUERY_PR --field-type $field`" case $type in [Ee][Nn][Uu][Mm]) values=`$QUERY_PR --valid-values $field | tr '\n' ' ' | sed 's/ *$//g; s/ / | /g;s/^/[ /;s/$/ ]/;` valslen=`echo "$values" | wc -c` if [ "$valslen" -gt 160 ] then desc="<`$QUERY_PR --field-description $field` (one line)>"; else desc="<${values} (one line)>"; fi dpat=`echo "$desc" | tr '][*+^$|\()&/' '............'` echo "/^>${field}:/ s/${dpat}//" >> $fixfil echo "/>${field}: ${desc}" >> $new; ;; [Mm][Uu][Ll][Tt][Ii][Tt][Ee][Xx][Tt]) desc=" <`$QUERY_PR --field-description $field` (multiple lines)>"; dpat=`echo "$desc" | tr '][*+^$|\()&/' '............'` echo "s/^${dpat}//" >> $fixfil echo ">${field}:" >> $new; echo "$desc" >> $new; ;; *) desc="<`$QUERY_PR --field-description $field` (one line)>" dpat=`echo "$desc" | tr '][*+^$|\()&/' '............'` echo "/^>${field}:/ s/${dpat}//" >> $fixfil echo ">${field}: ${desc}" >> $new ;; esac else prevfld="$field"; fi fi done # here's where we actually call the editor. cp $new $new.old $VISUAL $new if cmp -s $new.old $new ; then echo "edit-pr: PR not changed" $PR_EDIT --unlock $pr_id exit 0 fi if [ -f $fixfil ] then sed -f $fixfil < $new > $newtmp mv $newtmp $new sed -f $fixfil < $new.old > $newtmp mv $newtmp $new.old rm -f $fixfil fi # error-check output by calling pr-edit --check; if mistakes exist, # call $VISUAL or exit checking=t while [ "$checking" != "" ]; do errors="`$PR_EDIT --check < $new 2>&1`" if [ "$errors" != "" ]; then echo "Hit \`return\` to fix the following errors, or type \'quit\' to quit:" echo "$errors" read fixme case "$fixme" in q* | Q*) echo "PR $pr_id not updated: changed file is in $new.changed" mv $new $new.changed $PR_EDIT --unlock $pr_id exit 0 ;; esac $VISUAL $new else checking= fi done exec 3<&0 # # Find out what fields have changed; if the changed field requires a # change reason, then ask about it. # $LIBEXECDIR/gnats/diff-prs $new.old $new | while read field do flags=`$QUERY_PR --field-flags $field` || echo "edit-pr: Invalid field name $field" 1>&2; if echo "$flags" | grep -i "requirechangereason" > /dev/null 2>&1 then echo ">${field}-Changed-Why:" >> $change_msg; echo "Why did the $field field change? (Ctrl-D to end)"; cat 0<&3 >> $change_msg; fi done if [ -f $change_msg ] then cat $change_msg >> $new fi # # Submit the changed PR. # while true; do if $PR_EDIT --email-addr "$full_me" $pr_id < $new then echo "Edit successful" # we need to unlock the PR $PR_EDIT --unlock $pr_id exit 0 else echo "Problems with edit submission." fi while true; do echo "a)bort or r)etry? " read input case "$input" in a*) echo "Cancelling edit. Changed PR is in $new." # we need to ulock the PR no matter what $PR_EDIT --unlock $pr_id exit 1 ;; r*) break ;; *) echo "Unrecognized input '$input'" ;; esac done done rm -f $new exit 0 gnats-4.1.0/gnats/edit.c0000644000175000017500000007416710207433626015611 0ustar chewiechewie00000000000000/* Tools for editing a PR. Copyright (C) 1994, 1995, 2001, 2002 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnatsd.h" #include "regex.h" #include "query.h" #include "mail.h" /* Euuugh. There's gotta be a better way to keep this around. */ static char *newAuditTrailEntries = NULL; static void sendAuditMail (PR *pr, PR *oldPR, const char *editUserEmailAddr, const char *newAuditTrailEntries, ErrorDesc *err) { FormatNamedParameter *parms = NULL; const DatabaseInfo database = pr->database; parms = allocateNamedParameter ("$EditUserEmailAddr", editUserEmailAddr, parms); parms = allocateNamedParameter ("$NewAuditTrail", newAuditTrailEntries, parms); if (strcmp (field_value (pr, RESPONSIBLE (database)), field_value (oldPR, RESPONSIBLE (database))) != 0) { parms = allocateNamedParameter ("$OldResponsible", field_value (oldPR, RESPONSIBLE (database)), parms); } composeMailMessage (pr, oldPR, "audit-mail", parms, NULL, err); freeFormatParameterList (parms); } /* Add an entry to the AUDIT_TRAIL field. PARAMS are the format parameters used when composing the entry. FMT is the format of the audit-trail entry to add. */ static int addAuditTrailEnt (PR *pr, QueryFormat *fmt, FormatNamedParameter *params, ErrorDesc *err) { char *newAuditString = NULL; char *finalAuditString; const char *t; char *currDate = get_curr_date (); if (fmt == NULL) { fmt = getAuditTrailFormat (pr->database); } /* Format the new audit entry. */ process_format (NULL, &newAuditString, pr, NULL, fmt, "\n", params); /* Squirrel it away, because we'll need to mail it later. */ append_string (&newAuditTrailEntries, newAuditString); /* Now append the formatted string to the audit-trail field. */ t = field_value (pr, AUDIT_TRAIL (pr->database)); if (t == NULL) { t = ""; } finalAuditString = xstrdup (t); append_string (&finalAuditString, newAuditString); set_field (pr, AUDIT_TRAIL (pr->database), finalAuditString, err); free (finalAuditString); free (newAuditString); free (currDate); return 0; } static int applyChangeAction (ChangeActions action, PR *pr, PR *oldPR, FieldIndex field, ErrorDesc *err, FormatNamedParameter *params) { FieldEdit *fieldEdits = action->edits; FieldList fields = action->requiredFields; while (fields != NULL) { const char *fldval = get_field_value (pr, oldPR, fields->ent, NULL, NULL); if (value_is_empty (fldval)) { setError (err, CODE_INVALID_PR_CONTENTS, "Required field %s missing from PR %s.", complexFieldIndexToString (fields->ent), field_value (pr, NUMBER (pr->database))); return 1; } fields = fields->next; } if (action->requireChangeReason && field_change_reason (pr, field) == NULL) { setError (err, CODE_INVALID_PR_CONTENTS, "Edit of field %s requires a change reason.", fieldDefForIndex (field)->name); return 1; } while (fieldEdits != NULL) { if (applyFieldEdit (pr, fieldEdits, err, params) != 0) { return 1; } fieldEdits = fieldEdits->next; } return 0; } static int addAuditEntryP (const DatabaseInfo database, FieldIndex field, ChangeActions actions) { while (actions != NULL) { if (actions->addAuditTrail) { return 1; } actions = actions->next; } if (fieldDefForIndex (field)->datatype != MultiText) { ChangeActions globalActions = globalChangeActions (database); while (globalActions != NULL) { if (globalActions->addAuditTrail) { return 1; } globalActions = globalActions->next; } } return 0; } static int applyChangeActions (PR *pr, PR *oldPR, FieldIndex field, ChangeActions actions, ErrorDesc *err, FormatNamedParameter *params) { { ChangeActions actionList = actions; while (actionList != NULL) { if (actionList->expr == NULL || pr_matches_expr (pr, oldPR, actionList->expr, params)) { if (applyChangeAction (actionList, pr, oldPR, field, err, params)) { return 1; } } actionList = actionList->next; } } if (field != InvalidFieldIndex && addAuditEntryP (pr->database, field, actions)) { ChangeActions action = actions; while (actions != NULL) { if (actions->addAuditTrail) { break; } actions = actions->next; } if (action != NULL) { addAuditTrailEnt (pr, action->auditTrailFormat, params, err); } else { addAuditTrailEnt (pr, NULL, params, err); } } return 0; } static int processFieldChange (PR *pr, PR *oldPR, FieldIndex field, ErrorDesc *err, const char *editUserEmailAddr, const char *oldValue, const char *newValue) { ChangeActions actions; FormatNamedParameter *params = NULL; int res; if (oldValue == NULL) { oldValue = ""; } if (newValue == NULL) { newValue = ""; } if (fieldDefForIndex (field)->readonly) { setError (err, CODE_READONLY_FIELD, newBadFieldEntry (field, NULL, NULL), "Field %s is read-only: `%s'->`%s'", fieldDefForIndex (field)->name, oldValue, newValue); return 1; } { char *currDate = get_curr_date (); params = allocateNamedParameter ("$CurrentDate", currDate, params); free (currDate); } params = allocateNamedParameter ("$FieldName", fieldDefForIndex (field)->name, params); params = allocateNamedParameter ("$OldValue", oldValue, params); params = allocateNamedParameter ("$NewValue", newValue, params); params = allocateNamedParameter ("$EditUserEmailAddr", editUserEmailAddr, params); { const char *reason = field_change_reason (pr, field); if (reason == NULL) { reason = ""; } params = allocateNamedParameter ("$ChangeReason", reason , params); } actions = fieldDefForIndex (field)->changeActions; res = applyChangeActions (pr, oldPR, field, actions, err, params); freeFormatParameterList (params); return res; } static int processPRChanges (const char *editUserEmailAddr, PR *old_pr, PR *new_pr, ErrorDesc *err) { DatabaseInfo database = old_pr->database; int num_fields = get_num_fields (old_pr->database); int x; ChangeActions globalActions = globalChangeActions (database); int *fieldsChanged; if (! PR_IS_FULL (old_pr)) { if (fillInPR (old_pr, err) != 0) { return 1; } } fieldsChanged = (int *) xmalloc (sizeof (int) * num_fields); for (x = 0; x < num_fields; x++) { FieldIndex field = getNthField (database, x); const char *old_value = field_value (old_pr, field); const char *new_value = field_value (new_pr, field); if (fieldDefForIndex (field)->readonly && (new_value == NULL || new_value[0] == '\0') && old_value != NULL) { if (set_field (new_pr, field, old_value, err) == 0) { free (fieldsChanged); return 1; } new_value = field_value (new_pr, field); } if (old_value == NULL && new_value != NULL && new_value[0] == '\0') { /* Ignore the new empty field. */ unsetField (new_pr, field); new_value = NULL; } if (new_value == NULL && old_value != NULL && ! prFieldHasValue (old_pr, field)) { /* Sometimes empty entries show up in the index, but they aren't "really in the PR". */ old_value = NULL; } /* This code uses strcmp instead of intFieldCompare () because we really care if the field value was changed in *any* manner, not just if they happen to compare equal according to intFieldCompare (). */ if ((old_value == NULL && new_value != NULL) || (new_value == NULL && old_value != NULL) || (new_value != old_value && strcmp (old_value, new_value) != 0)) { /* Ignore changes to readonly fields. */ if (fieldDefForIndex (field)->readonly) { fieldsChanged[x] = 0; if (old_value == NULL) { unsetField (new_pr, field); } else { set_field (new_pr, field, old_value, err); } } else { fieldsChanged[x] = 1; } } else { fieldsChanged[x] = 0; } } for (x = 0; x < num_fields; x++) { if (fieldsChanged[x]) { FieldIndex field = getNthField (database, x); const char *old_value = field_value (old_pr, field); const char *new_value = field_value (new_pr, field); if (processFieldChange (new_pr, old_pr, field, err, editUserEmailAddr, old_value, new_value) != 0) { free (fieldsChanged); return 1; } } } free (fieldsChanged); if (globalActions != NULL) { FormatNamedParameter *params = NULL; char *currDate = get_curr_date (); int res; params = allocateNamedParameter ("$CurrentDate", currDate, params); free (currDate); params = allocateNamedParameter ("$EditUserEmailAddr", editUserEmailAddr, params); res = applyChangeActions (new_pr, old_pr, InvalidFieldIndex, globalActions, err, params); freeFormatParameterList (params); if (res != 0) { return 1; } } return 0; } /* Replace an existing PR with the same PR number as NEW_PR. EDITUSEREMAILADDR is the email address of the user that is performing the edit. */ static int rewrite_pr (PR *pr, PR *new_pr, const char *editUserEmailAddr, ErrorDesc *err) { const DatabaseInfo database = new_pr->database; FILE *prfile; char *new_path = NULL; char *old_path = NULL; char *bkup_path = NULL; int res = 1; newAuditTrailEntries = NULL; if (field_value (new_pr, CATEGORY (database)) == NULL) { setError (err, CODE_INVALID_PR_CONTENTS, "Missing category from new PR contents"); return 0; } if (! isPrLocked (new_pr->database, field_value (new_pr, NUMBER (database)))) { setError (err, CODE_PR_NOT_LOCKED, "PR %s is not locked", field_value (new_pr, NUMBER (database))); return 0; } if (processPRChanges (editUserEmailAddr, pr, new_pr, err) != 0) { return 0; } /* check to see if the category changes, and if so, write the new file out, and unlink the old one. */ if (strcmp (field_value (pr, CATEGORY (database)), field_value (new_pr, CATEGORY (database))) != 0) { char *dirPath; asprintf (&dirPath, "%s/%s", databaseDir (database), field_value (new_pr, CATEGORY (database))); if (! fileExists (dirPath)) { if (createCategoryDirs (database)) { mode_t mode = categoryDirPerms (database); if (mkdir (dirPath, mode) != 0) { setError (err, CODE_FILE_ERROR, "Error creating directory for category %s: %s", field_value (new_pr, CATEGORY (database)), strerror (errno)); free (dirPath); return 0; } } else { setError (err, CODE_FILE_ERROR, "Directory for category %s does not exist", field_value (new_pr, CATEGORY (database))); free (dirPath); return 0; } } free (dirPath); } /* backup the current PR file */ old_path = gen_pr_path (pr); asprintf (&bkup_path, "%s.old", old_path); if (rename (old_path, bkup_path) < 0) { if (errno != EXDEV) { setError (err, CODE_FILE_ERROR, "Could not rename %s: %s", old_path, strerror (errno)); free (bkup_path); free (old_path); return 0; } if (copy_file (old_path, bkup_path) != 0) { setError (err, CODE_FILE_ERROR, "Could not copy %s to %s: %s", old_path, bkup_path, strerror (errno)); free (bkup_path); free (old_path); return 0; } /* Don't complain if this fails, since trying to write to it will give us the diagnostic if it's really serious. */ unlink (old_path); } /* Now build the file. */ new_path = gen_pr_path (new_pr); prfile = fopen (new_path, "w+"); if (prfile == (FILE *) NULL) { setError (err, CODE_FILE_ERROR, "Cannot write the PR to %s: %s", new_path, strerror (errno)); free (bkup_path); free (old_path); free (new_path); return 0; } /* We had to wait until now because we wanted to wait and see about changing the closed_date. XXX ??? !!! FIXME */ buildIndexEntry (new_pr); write_entire_header (prfile, new_pr, "\n"); fprintf (prfile, "\n"); write_entire_pr (prfile, new_pr, "\n"); if (fclose (prfile) == EOF) { setError (err, CODE_FILE_ERROR, "Error writing out PR %s: %s", new_path, strerror (errno)); free (bkup_path); free (old_path); free (new_path); return 0; } unlink (bkup_path); /* unlink the old file, if it is in another category dir. */ if (strcmp (field_value (pr, CATEGORY (database)), field_value (new_pr, CATEGORY (database))) != 0) { unlink (old_path); } free (bkup_path); free (old_path); free (new_path); /* write out the new index. */ replaceCurrentPRInIndex (pr, new_pr, err); if (writeIndex (database, err) != 0) { res = 0; } /* Send mail about the edit. */ if (newAuditTrailEntries != NULL) { sendAuditMail (new_pr, pr, editUserEmailAddr, newAuditTrailEntries, err); free (newAuditTrailEntries); newAuditTrailEntries = NULL; } return res; } int replace_pr (const DatabaseInfo database, FILE *fp, const char *editUserEmailAddr, ErrorDesc *err) { int res; const char *prnum = NULL; PR *curr_pr; PR *new_pr = allocPR (database); /* Read the message header in. */ if (read_header (new_pr, fp) < 0) { setError (err, CODE_EOF_PR, "Couldn't read PR header"); return 0; } read_pr (new_pr, fp, 0); prnum = field_value (new_pr, NUMBER (database)); if (prnum == NULL) { setError (err, CODE_INVALID_PR_CONTENTS, "Missing PR number from new PR contents"); return 0; } if (! prExists (database, prnum, err)) { return 0; } curr_pr = readPRWithNum (database, prnum, 0, err); if (curr_pr == NULL) { setError (err, CODE_NO_INDEX, "Unable to locate existing PR %s", prnum); return 0; } if (! check_pr (new_pr, err, 0)) { return 0; } res = rewrite_pr (curr_pr, new_pr, editUserEmailAddr, err); free_pr (curr_pr); free_pr (new_pr); return res; } /* Verify that TEXT is a valid value for field FIELD. If not, an appropriate error will be stored in ERR, and a zero value is returned. If TEXT is valid, a non-zero value will be returned. If DONTCHECKENUMS is non-zero, we don't verify that enum fields contain a valid enumerated value. */ int validateFieldValue (FieldIndex field, const char *text, ErrorDesc *err, int dontCheckEnums) { if (field == NUMBER (fieldDefForIndex (field)->database)) { if (text[0] == '-') { setError (err, CODE_INVALID_FIELD_CONTENTS, newBadFieldEntry (NUMBER (field->database), text, NULL), "Number field has invalid value"); return 0; } } switch (fieldDefForIndex (field)->datatype) { case Date: { /* We'll allow dates to be an empty string. */ if (text != NULL && text[0] != '\0') { time_t t = get_date ((char *)text, NULL); if (t < 0) { setError (err, CODE_INVALID_DATE, "Couldn't parse the %s date: %s.", fieldDefForIndex (field)->name, text); return 0; } } } break; case Integer: { if (text != NULL) { const char *tptr = text; if (tptr[0] == '-' || tptr[0] == '+') { tptr++; } while (tptr[0] != '\0') { if (! isdigit ((int) tptr[0])) { setError (err, CODE_INVALID_FIELD_CONTENTS, newBadFieldEntry (field, text, NULL), "Integer field %s had non-integer contents", fieldDefForIndex (field)->name); return 0; } tptr++; } } } break; case PRListType: { const char *tptr = text; unsigned int prcount = 0; unsigned int maxprs = fieldDefForIndex (field)->maxPrsPerLine; while (tptr != NULL) { char *prnum = get_next_field (&tptr, ' '); if (prnum[0] != '\0') { if (! prExists (fieldDefForIndex (field)->database, prnum, err)) { setError (err, CODE_INVALID_FIELD_CONTENTS, newBadFieldEntry (field, prnum, NULL), "PR list field %s had invalid PR `%s'", fieldDefForIndex (field)->name, prnum); free (prnum); return 0; } prcount++; if (maxprs > 0 && prcount > maxprs) { setError (err, CODE_INVALID_FIELD_CONTENTS, newBadFieldEntry (field, prnum, NULL), "PR list field %s has too many entries", fieldDefForIndex (field)->name); free (prnum); return 0; } } free (prnum); } break; } default: { break; } } if (fieldDefForIndex (field)->regex != NULL) { const char *rtextToCheck = text; StringList *rl; if (rtextToCheck == NULL) { rtextToCheck = ""; } for (rl = fieldDefForIndex (field)->regex; rl != NULL; rl = rl->next) { if (gnats_regcmp (rl->name, rtextToCheck, NULL) == 0) { break; } } if (rl == NULL) { setError (err, CODE_INVALID_FIELD_CONTENTS, newBadFieldEntry (field, text, NULL), "Field %s with contents `%s' didn't match any of the required regexps", fieldDefForIndex (field)->name, rtextToCheck); return 0; } } if (! dontCheckEnums) { if (fieldDefForIndex (field)->datatype == Enum || fieldDefForIndex (field)->datatype == MultiEnum) { if (! verify_enum (field, text)) { setError (err, CODE_INVALID_ENUM, newBadFieldEntry (field, text, NULL), "Invalid value `%s' for enumerated field `%s'", text, fieldDefForIndex (field)->name); return 0; } } } return 1; } /* check_pr_file - reads the PR in from FP, verifies its contents, and returns the bogus info in ERR. If INITIAL is true, this is a new PR rather than an edit of an existing one. */ int check_pr_file (DatabaseInfo database, FILE *fp, ErrorDesc *err, int initial) { PR *pr; int res; pr = allocPR (database); /* Read the message header in. */ if (read_header (pr, fp) < 0) { setError (err, CODE_EOF_PR, "Couldn't read PR header"); return 0; } read_pr (pr, fp, 0); res = check_pr (pr, err, initial); free_pr (pr); return res; } /* Check PR for invalid values; the invalid fields are set in ERR. If INITIAL_ENTRY is true, PR is a new PR instead of an edit of an existing one. */ int check_pr (PR *pr, ErrorDesc *err, int initial_entry) { const DatabaseInfo database = pr->database; BadFields enums; int x; int num_fields = get_num_fields (database); for (x = 0; x < num_fields; x++) { FieldIndex field = getNthField (database, x); if (initial_entry && field == NUMBER (database)) { continue; } if (! validateFieldValue (field, field_value (pr, field), err, 1)) { return 0; } } enums = checkEnumTypes (pr, NULL, 0); if (enums != NULL) { setError (err, CODE_INVALID_ENUM, enums, NULL); return 0; } else { return 1; } } int lock_pr (const DatabaseInfo database, const char *prID, const char *user, const char *processid, ErrorDesc *err) { char *lock_path; int count; int fdes = -1; if (prID == NULL) { return 0; } lock_path = get_lock_path (database, prID); #define MAXWAIT 2 #define GRANULARITY 1 /* try repeatedly (well, twice...) to get the lock */ for (count = 0; count < MAXWAIT / GRANULARITY; count++) { errno = 0; /* use atomic create, to avoid races */ fdes = open (lock_path, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0644); if (fdes != -1) { /* success */ break; } else { if (errno == EEXIST || errno == EINTR) { /* somebody else has the lock, or we were rudely interrupted, sleep and try again */ sleep (GRANULARITY); } else { /* something went wrong, error out */ break; } } } if (!errno) { /* success */ FILE *ifp = fdopen (fdes, "w"); if (ifp == NULL) { setError (err, CODE_FILE_ERROR, "Cannot write to lock file %s", lock_path); log_msg (LOG_ERR, 1, "error in lock_pr:", getErrorMessage (*err)); close (fdes); /* try to get rid of the lock file */ unlink (lock_path); /* XXX??? we should really go the extra mile and figure out if the lock is still there, and punt to the administrator if we can't delete it. but that's a lot of trouble for an edge case... */ return 0; } if (processid != NULL) { fprintf (ifp, "%s %s\n", user, processid); } else { fprintf (ifp, "%s\n", user); } fclose (ifp); free (lock_path); return 1; } else if (errno == EEXIST) { /* somebody else has the lock */ struct stat sb; char *date = (char *) xmalloc (GNATS_TIME_LENGTH); char buf[1024]; /* This size doesn't matter here */ char *s; FILE *fp = fopen (lock_path, "r"); /* If we couldn't open it for reading, something else is hosed, so just bail now. */ if (fp == (FILE *) NULL) { setError (err, CODE_FILE_ERROR, "Cannot read lock file %s", lock_path); log_msg (LOG_ERR, 1, "error in lock_pr:", getErrorMessage (*err)); free (lock_path); return 0; } /* read the contents of the lock file */ fgets (buf, sizeof (buf) - 1, fp); s = strchr (buf, '\n'); if (s != NULL) { s[0] = '\0'; } /* report time of lock as well */ stat (lock_path, &sb); strftime (date, GNATS_TIME_LENGTH, "%Y-%m-%d:%H:%M:%SZ", gmtime(&sb.st_mtime)); setError (err, CODE_LOCKED_PR, "PR %s is locked by '%s', since %s", prID, buf, date); fclose (fp); free (lock_path); return 0; } else { setError (err, CODE_FILE_ERROR, "Cannot create lock file %s: %s", lock_path, strerror(errno)); log_msg (LOG_ERR, 1, "error in lock_gnats:", getErrorMessage (*err)); free (lock_path); return 0; } } int unlock_pr (const DatabaseInfo database, const char *prID, ErrorDesc *err) { char *lock_path; if (prID == NULL) return 0; lock_path = get_lock_path (database, prID); if (! fileExists (lock_path)) { setError (err, CODE_PR_NOT_LOCKED, "PR %s is not locked.", prID); free (lock_path); return 0; } if (unlink (lock_path) != 0) { setError (err, CODE_FILE_ERROR, "Cannot delete lock file %s: %s.", lock_path, strerror (errno)); free (lock_path); return 0; } free (lock_path); return 1; } int edit_field (const DatabaseInfo database, const char *prnum, FieldIndex fieldIndex, int append, char *newcontents, char *changeReason, const char *editUserEmailAddr, ErrorDesc *err) { char pid[32]; const char *oldfield; int res; PR *pr, *new_pr; if (! prExists (database, prnum, err)) { free (newcontents); if (changeReason != NULL) { free (changeReason); } return 0; } if (fieldIndex == InvalidFieldIndex) { setError (err, CODE_INVALID_FIELD_NAME, "Invalid field name"); free (newcontents); if (changeReason != NULL) { free (changeReason); } return 0; } if (requiresChangeReason (fieldDefForIndex (fieldIndex)) && changeReason == NULL) { setError (err, CODE_INVALID_FIELD_EDIT, "Edit of field %s requires a change reason.", fieldDefForIndex (fieldIndex)->name); free (newcontents); return 0; } sprintf (pid, "%d", (int) getpid ()); if (lock_pr (database, prnum, "edit_field", pid, err) == 0) { free (newcontents); if (changeReason != NULL) { free (changeReason); } return 0; } pr = readPRWithNum (database, prnum, 0, err); if (pr == NULL) { unlock_pr (database, prnum, err); setError (err, CODE_UNREADABLE_PR, "Error reading PR %s.", prnum); free (newcontents); if (changeReason != NULL) { free (changeReason); } return 0; } oldfield = field_value (pr, fieldIndex); if (append) { char *totalVal; if (oldfield != NULL) { totalVal = xstrdup (oldfield); } else { totalVal = NULL; } append_string (&totalVal, newcontents); free (newcontents); newcontents = totalVal; } /* create a copy of the currently active pr so that we can modify it and do subsequent validation allowing for us to bail out cleanly */ new_pr = allocPR (database); set_field (new_pr, NUMBER (database), prnum, err); set_field (new_pr, CATEGORY (database), field_value (pr, CATEGORY (database)), err); fillInPR (new_pr, err); /* set_field () verifies that the value is valid before doing the set. */ /* set_field returns a boolean!!! */ if (set_field (new_pr, fieldIndex, newcontents, err) == 0) { res = 0; } else { if (changeReason != NULL) { setFieldChangeReason (new_pr, fieldIndex, changeReason); free (changeReason); changeReason = NULL; } res = rewrite_pr (pr, new_pr, editUserEmailAddr, err); } free_pr (pr); free_pr (new_pr); free (newcontents); if (changeReason != NULL) { free (changeReason); changeReason = NULL; } if (unlock_pr (database, prnum, err) == 0) { res = 0; } return res; } int applyFieldEdit (PR *pr, FieldEdit *edit, ErrorDesc *err, FormatNamedParameter *params) { const DatabaseInfo database = pr->database; char *buffer = NULL; char *fmt = edit->textFormat; FieldList currField = edit->fieldsForFormat; char *currDate = get_curr_date (); int res; if (edit->fieldToEditName != NULL) { edit->fieldToEdit = find_field_index (database, edit->fieldToEditName); if (edit->fieldToEdit == InvalidFieldIndex) { setError (err, CODE_INVALID_FIELD_NAME, "Invalid field name %s.\n", edit->fieldToEditName); return -1; } free (edit->fieldToEditName); edit->fieldToEditName = NULL; } if (edit->append) { append_string (&buffer, field_value (pr, edit->fieldToEdit)); } while (fmt != NULL && *fmt != '\0') { if (*fmt == '\\' && *(fmt + 1) == 'n') { append_string (&buffer, "\n"); } else if (*fmt == '%') { fmt++; if (fmt[0] == '%') { append_string (&buffer, "%"); fmt++; } else { char *vptr; char *value; char *vend; while (!isalpha ((int) *fmt)) { fmt++; } { int mustBeFreed = 0; const char *vtemp = get_field_value (pr, pr, currField->ent, params, &mustBeFreed); if (vtemp == NULL) { vtemp = ""; } if (mustBeFreed) { value = (char *) vtemp; } else { value = xstrdup (vtemp); } } vend = value + strlen (value) - 1; vptr = value; while (*value != '\0' && isspace ((int)(unsigned char) *value)) { value++; } while (vend >= value && isspace ((int)(unsigned char) *vend)) { *(vend--) = '\0'; } append_string (&buffer, value); free (vptr); fmt++; currField = currField->next; } } else { char buf[2]; buf[0] = *fmt; buf[1] = '\0'; append_string (&buffer, buf); fmt++; } } if (buffer == NULL) { buffer = xstrdup (""); } res = ! set_field (pr, edit->fieldToEdit, (buffer != NULL ? buffer : ""), err); if (buffer != NULL) { free (buffer); } free (currDate); return res; } /* Delete PR PRNUM. */ int deletePR (const DatabaseInfo database, const char *prnum, const char *editUserEmailAddr, ErrorDesc *err) { char pid[32]; FormatNamedParameter *parms = NULL; short delete_status; if (client_lock_gnats (database, err)) { return -4; } if (lock_pr (database, prnum, GNATS_USER, pid, err) == 0) { client_unlock_gnats (); return -4; } if ((delete_status = pr_delete (database, prnum, err)) < 0) { unlock_pr (database, prnum, err); client_unlock_gnats (); return delete_status; } if (unlock_pr (database, prnum, err) == 0) { client_unlock_gnats (); return -7; } client_unlock_gnats (); parms = allocateNamedParameter ("$EditUserEmailAddr", editUserEmailAddr, parms); parms = allocateNamedParameter ("$PRNum", prnum, parms); { PR *pr = allocPR (database); pr->read_in = TRUE; /* TODO: hack, read_in is private */ composeMailMessage (pr, NULL, "deleted-pr-mail", parms, NULL, err); } return 0; } ChangeActions newChangeAction (const DatabaseInfo database, const char *optExpr) { ChangeActions res = (ChangeActions) xmalloc (sizeof (struct change_actions)); if (optExpr != NULL) { res->expr = parseQueryExpression (database, optExpr, optExpr + strlen (optExpr) - 1); } else { res->expr = NULL; } res->requiredFields = NULL; res->edits = NULL; res->addAuditTrail = 0; res->auditTrailFormat = NULL; res->requireChangeReason = 0; res->next = NULL; return res; } void freeChangeActions (ChangeActions actions) { while (actions != NULL) { ChangeActions next = actions->next; freeQueryExpr (actions->expr); freeFieldEdit (actions->edits); freeFieldList (actions->requiredFields); freeQueryFormat (actions->auditTrailFormat); free (actions); actions = next; } } int requiresChangeReason (FieldDef field) { ChangeActions acts = field->changeActions; while (acts != NULL) { if (acts->requireChangeReason) { return 1; } acts = acts->next; } return 0; } gnats-4.1.0/gnats/fconfig.y0000644000175000017500000004566307610536602016326 0ustar chewiechewie00000000000000%{ #include "gnats.h" #include "index.h" #include "field.h" extern DatabaseInfo databaseBeingDefined; static FieldDef currField; static ChangeActions currChange; static FieldEdit *currEdit; static QueryFormat *qformat; static FieldList requiredFlds; static InputTemplate *inputTemplate; static MailMessageFormat mailFormat; IndexDesc indexEntry; static int badFile; struct qstring; extern char *takeQString (struct qstring *str); extern char *qStrVal (struct qstring *str); %} %union { int intval; char *sval; struct qstring *qstr; AdmFieldDesc *adm_field_des; FieldList flist; StringList *stringlist; InputTemplate *inputlist; MailAddress *mailaddr; MailAddressList *mailaddrlist; } %token FIELD STRINGTYPE QDEFAULT MATCHING ENUM MULTIENUMTOK VALUES DEFAULT %token EXACT_REGEXP INEXACT_REGEXP ALL FORMAT ENUMSEPARATORSTOK %token MULTITEXTTYPE DATETYPE ENUM_IN_FILE MULTI_ENUM_IN_FILE %token PATHTOK FIELDSTOK KEYTOK %token QSTRING INTVAL TEXTSEARCH QUERYTOK FORMATTOK INDEXTOK %token SEPARATORTOK RESTRICTEDTOK NOSPACESTOK INTEGERTOK INPUTDEFAULTTOK %token BUILTINTOK ALLOWANYVALUETOK REQUIRETOK APPENDFIELDTOK SETFIELDTOK %token CHANGETOK DESCRIPTIONTOK INPUTTOK DATABASEINFOTOK %token DEBUGMODETOK KEEPRECTOK NOTIFYEXPTOK LIBEXECDIRTOK SUBMITTERACKTOK %token BUSINESSDAYTOK BUSINESSWEEKTOK CREATECATEGORYDIRSTOK FALSETOK TRUETOK %token MAILFORMATTOK TOADDRESSESTOK FROMADDRESSTOK REPLYTOTOK FIXEDTOK %token BODYTOK HEADERTOK AUDITTRAILFMTTOK ADDAUDITTRAILTOK %token REQUIRECHANGEREASONTOK READONLYTOK BINARYINDEXTOK RAWTOK %token BADTOK AUXFLAGSTOK PRLISTTOK MAXPRSTOK EDITONLYTOK VIRTUALFORMATTOK %token CATPERMSTOK %type optChangeExpr %type QSTRING %type INTVAL %type enumFieldList enumFieldMember %type queryFieldsList FieldListMember fieldEditFieldList %type enumValueList regexpList auxFlagsList %type inputFields inputFieldsList %type booleanVal %type mailAddressTries MailAddressMember %type mailAddress %type mailAddressList %type requiredFieldsList %% config : configEnts | parseError ; configEnts : databaseInfo fieldDecStmt optQueryList auditTrailFmt mailFormatList globalChangeEnts indexDescription inputDescription ; databaseInfo : DATABASEINFOTOK '{' databaseInfoList '}' | DATABASEINFOTOK '{' parseError '}' | /* empty */ { fconferror ("Missing/bad database info section"); } ; parseError : error { badFile = 1; } ; databaseInfoList: databaseInfoEnt | databaseInfoList databaseInfoEnt ; databaseInfoEnt : DEBUGMODETOK booleanVal { setDebugMode (databaseBeingDefined, $2); } | KEEPRECTOK booleanVal { setKeepReceivedHeaders (databaseBeingDefined, $2); } | NOTIFYEXPTOK booleanVal { setNotifyExpire (databaseBeingDefined, $2); } | LIBEXECDIRTOK QSTRING { setBinDir (databaseBeingDefined, qStrVal ($2)); } | SUBMITTERACKTOK booleanVal { setSubmitterAck (databaseBeingDefined, $2); } | BUSINESSDAYTOK INTVAL '-' INTVAL { setBusinessDay (databaseBeingDefined, $2, $4); } | BUSINESSWEEKTOK INTVAL '-' INTVAL { setBusinessWeek(databaseBeingDefined,$2, $4); } | CREATECATEGORYDIRSTOK booleanVal { setCreateCategoryDirs (databaseBeingDefined, $2); } | CATPERMSTOK QSTRING { setCategoryDirPerms (databaseBeingDefined, qStrVal ($2)); } ; booleanVal : FALSETOK { $$ = 0; } | TRUETOK { $$ = 1; } ; fieldDecStmt : fieldDecList | /* empty */ { fconferror ("Missing/bad field declarations"); } ; fieldDecList : fieldDec | fieldDecList fieldDec ; fieldDec : startFieldDec '{' fieldDataList '}' { currField = NULL; } | startFieldDec '{' parseError '}' { currField = NULL; } ; startFieldDec : FIELD QSTRING { char *fname = takeQString ($2); currField = newFieldDef (databaseBeingDefined, fname); if (currField == NULL) { char *msg; asprintf (&msg, "Duplicate field definition for %s\n", fname); fconferror (msg); free (msg); } currField->default_value = NULL; } ; fieldDataList : fieldData | fieldDataList fieldData ; fieldData : fieldDataType | miscOptions | queryDefault | virtualFieldFormat ; virtualFieldFormat: VIRTUALFORMATTOK plainFormat { currField->virtualFormat = qformat; qformat = NULL; } ; fieldDataType : stringType | enumType | MULTITEXTTYPE optSimple { currField->datatype = MultiText; currField->defaultSearchType = NilSearch; } | DATETYPE { currField->datatype = Date; currField->defaultSearchType = LessThan; } | INTEGERTOK optSimple { currField->datatype = Integer; currField->defaultSearchType = NilSearch; } | PRLISTTOK prListOpts { currField->datatype = PRListType; currField->defaultSearchType = RegCmp; } ; stringType : STRINGTYPE { currField->datatype = Text; } | STRINGTYPE MATCHING '{' regexpList '}' { currField->datatype = TextWithRegex; } | STRINGTYPE MATCHING '{' parseError '}' ; regexpList : QSTRING { $$ = new_string_list_ent (takeQString ($1), NULL); currField->regex = $$; } | regexpList QSTRING { $1->next = new_string_list_ent (takeQString ($2), NULL); $$ = $1->next; } ; enumType : ENUM '{' enumcontents '}' { currField->datatype = Enum; currField->defaultSearchType = RegCmp; } | ENUM_IN_FILE '{' enumFileContents '}' { currField->datatype = Enum; currField->defaultSearchType = RegCmp; initAdmField (currField); } | MULTI_ENUM_IN_FILE '{' multiEnumFileContents '}' { currField->datatype = MultiEnum; currField->defaultSearchType = RegCmp; initAdmField (currField); } | MULTIENUMTOK '{' multienumcontents '}' { currField->datatype = MultiEnum; currField->defaultSearchType = RegCmp; if (currField->multiEnumSeparator == NULL) { currField->multiEnumSeparator = xstrdup (DEFAULT_MULTIENUM_SEPARATOR); } } | ENUM '{' parseError '}' | ENUM_IN_FILE '{' parseError '}' ; globalChangeEnts: /* empty */ | globalChangeEnts globalChangeEnt ; globalChangeEnt : changeHeader changeOpts '}' { addGlobalChangeActions (databaseBeingDefined, currChange); currChange = NULL; } ; changeClause : changeHeader changeOpts '}' { ChangeActions *p = &(currField->changeActions); while (*p != NULL) { p = &((*p)->next); } *p = currChange; currChange = NULL; } ; changeHeader : CHANGETOK optChangeExpr '{' { currChange = newChangeAction (databaseBeingDefined, $2); if ($2 != NULL) { free ($2); } } ; optChangeExpr : QSTRING { $$ = takeQString ($1); } | /* Empty */ { $$ = NULL; } ; changeOpts : changeOpt | changeOpts changeOpt ; changeOpt : REQUIRETOK '{' reqFieldNameList '}' | REQUIRETOK '{' parseError '}' | SETFIELDTOK fieldEditOpts { currChange->edits = currEdit; currEdit = NULL; } | APPENDFIELDTOK fieldEditOpts { currEdit->append = 1; currChange->edits = currEdit; currEdit = NULL; } | ADDAUDITTRAILTOK { currChange->addAuditTrail = 1; } | AUDITTRAILFMTTOK plainFormat { currChange->auditTrailFormat = qformat; qformat = NULL; } | REQUIRECHANGEREASONTOK { currChange->requireChangeReason = 1; } ; reqFieldNameList: reqFieldNameEnt | reqFieldNameList reqFieldNameEnt ; reqFieldNameEnt: QSTRING { FieldList foo = newFieldListEnt (databaseBeingDefined, qStrVal ($1), currChange->requiredFields); currChange->requiredFields = foo; } ; fieldEditOpts : fieldEditName '{' fieldEditFormat optFieldEditFieldList '}' | fieldEditName '{' parseError '}' ; fieldEditName : QSTRING { currEdit = (FieldEdit *) xmalloc (sizeof (FieldEdit)); currEdit->expr = NULL; currEdit->fieldToEditName = takeQString ($1); currEdit->append = 0; currEdit->textFormat = NULL; currEdit->fieldsForFormat = NULL; currEdit->next = NULL; } ; fieldEditFormat : QSTRING { currEdit->textFormat = takeQString ($1); } ; optFieldEditFieldList: /* empty */ { currEdit->fieldsForFormat = NULL; } | fieldEditFieldList { } ; fieldEditFieldList: QSTRING { $$ = newFieldListEnt (databaseBeingDefined, qStrVal ($1), NULL); currEdit->fieldsForFormat = $$; } | fieldEditFieldList QSTRING { $$ = newFieldListEnt (databaseBeingDefined, qStrVal ($2), NULL); $1->next = $$; } ; optSimple : /* Empty */ | '{' defaultFieldVal '}' | '{' parseError '}' ; prListOpts : /* Empty */ | '{' prListOptList '}' ; prListOptList : MAXPRSTOK INTVAL { currField->maxPrsPerLine = $2; } ; enumcontents : enumItem | enumcontents enumItem ; multienumcontents: multiEnumItem | multienumcontents multiEnumItem ; multiEnumItem : enumItem | ENUMSEPARATORSTOK QSTRING { currField->multiEnumSeparator = takeQString ($2); } ; enumItem : VALUES '{' enumValueList '}' | VALUES '{' parseError '}' | defaultFieldVal ; enumValueList : QSTRING { $$ = new_string_list_ent (takeQString ($1), NULL); currField->enumValues = $$; } | enumValueList QSTRING { $1->next = new_string_list_ent (takeQString ($2), NULL); $$ = $1->next; } ; enumFileContents: enumFileItem | enumFileContents enumFileItem ; enumFileItem : PATHTOK QSTRING { currField->adm_db_name = takeQString ($2); } | FIELDSTOK '{' enumFieldList '}' KEYTOK QSTRING { AdmFieldDesc *p; int which = 0; for (p = currField->adm_field_des; p != NULL; p = p->next) { if (strcmp (p->name, qStrVal ($6)) == 0) { break; } which++; } if (p != NULL) { currField->key_field = which; } else { char *msg; asprintf (&msg, "Invalid adm subfield %s\n", qStrVal ($6)); fconferror (msg); free (msg); } } | FIELDSTOK '{' parseError '}' | defaultFieldVal | ALLOWANYVALUETOK { currField->allow_any_value = 1; } ; multiEnumFileContents: multiEnumFileItem | enumFileContents multiEnumFileItem ; multiEnumFileItem : enumFileItem | ENUMSEPARATORSTOK QSTRING { currField->multiEnumSeparator = takeQString ($2); } ; defaultFieldVal : DEFAULT QSTRING { currField->default_value = takeQString ($2); } | INPUTDEFAULTTOK QSTRING { currField->input_default_value = takeQString ($2); } ; enumFieldList : enumFieldMember { currField->adm_db_fields = 1; currField->adm_field_des = $1; $$ = $1; } | enumFieldList enumFieldMember { $1->next = $2; $$ = $2; currField->adm_db_fields++; } ; enumFieldMember : QSTRING { $$ = (AdmFieldDesc *) xmalloc (sizeof (AdmFieldDesc)); $$->name = takeQString ($1); $$->next = NULL; } ; queryDefault : QDEFAULT EXACT_REGEXP { currField->defaultSearchType = RegCmp; } | QDEFAULT INEXACT_REGEXP { currField->defaultSearchType = RegFind; } ; miscOptions : TEXTSEARCH { currField->textsearch = 1; } | RESTRICTEDTOK { currField->restricted = 1; } | NOSPACESTOK { currField->nospaces = 1; } | BUILTINTOK QSTRING { if (setBuiltinField (currField, qStrVal ($2)) != 0) { char *msg; asprintf (&msg, "Invalid builtin fieldname %s", qStrVal ($2)); fconferror (msg); free (msg); } } | changeClause | DESCRIPTIONTOK QSTRING { currField->description = takeQString ($2); } | READONLYTOK { currField->readonly = 1; } | AUXFLAGSTOK '{' auxFlagsList '}' { currField->auxFlags = $3; } | EDITONLYTOK { currField->editonly = 1; } ; auxFlagsList : QSTRING { $$ = new_string_list_ent (takeQString ($1), NULL); currField->auxFlags = $$; } | auxFlagsList QSTRING { $1->next = new_string_list_ent (takeQString ($2), NULL); $$ = $1->next; } ; optQueryList : /* empty */ | queryList ; queryList : query | queryList query ; query : queryBegin '{' queryFmt '}' { addQueryFormat (databaseBeingDefined, qformat); qformat = NULL; } | queryBegin '{' parseError '}' { freeQueryFormat (qformat); qformat = NULL; } ; queryBegin : QUERYTOK QSTRING { qformat = (QueryFormat *) xmalloc (sizeof (QueryFormat)); qformat->name = takeQString ($2); qformat->printf = NULL; qformat->separator = NULL; qformat->fields = NULL; qformat->next = NULL; } ; queryFmt : queryFieldDesc optQueryOpts | queryOpts queryFieldDesc ; queryFieldDesc : FIELDSTOK ALL | queryfields | queryPrintf queryfields | queryfields queryPrintf ; optQueryOpts :/* empty */ | queryOpts ; queryOpts : RAWTOK { qformat->rawQuery = 1; } ; queryPrintf : FORMATTOK QSTRING { qformat->printf = takeQString ($2); } ; queryfields : FIELDSTOK '{' queryFieldsList '}' | FIELDSTOK '{' parseError '}' ; queryFieldsList : FieldListMember { qformat->fields = $1; } | queryFieldsList FieldListMember { $1->next = $2; $$ = $2; } ; FieldListMember: QSTRING { $$ = newFieldListEnt (databaseBeingDefined, qStrVal ($1), NULL); if (parseComplexFieldIndex ($$->ent) != 0) { char *msg; asprintf (&msg, "Field %s is invalid\n", qStrVal ($1)); fconferror (msg); free (msg); } } ; indexDescription: indexheader '{' indexlist '}' { setIndexDesc (databaseBeingDefined, indexEntry); indexEntry = NULL; } | indexheader '{' parseError '}' { freeIndexDesc (indexEntry); indexEntry = NULL; } | parseError ; indexheader : INDEXTOK { indexEntry = newIndexDesc (databaseBeingDefined); } ; indexlist : indexEnt | indexlist indexEnt ; indexEnt : PATHTOK QSTRING { setIndexDescPath (indexEntry, qStrVal ($2)); } | FIELDSTOK '{' indexFieldList '}' | FIELDSTOK '{' parseError '}' | indexSep ; indexFieldList : FieldListMember { addFieldToIndex (indexEntry, $1); } | indexFieldList FieldListMember { addFieldToIndex (indexEntry, $2); } ; indexSep : SEPARATORTOK QSTRING { setIndexDescSeparator (indexEntry, takeQString ($2)); } | BINARYINDEXTOK booleanVal { setIndexDescBinary (indexEntry, $2); } ; inputDescription: INPUTTOK '{' inputEnt '}' | INPUTTOK '{' parseError '}' ; inputEnt : inputFields requiredFields { setInputTemplate (databaseBeingDefined, $1); } ; requiredFields :/* empty */ | REQUIRETOK '{' requiredFieldsList '}' { setRequiredInputFields (databaseBeingDefined, requiredFlds); } | REQUIRETOK '{' parseError '}' { freeFieldList (requiredFlds); requiredFlds = NULL; } ; requiredFieldsList: FieldListMember { requiredFlds = $1; } | requiredFieldsList FieldListMember { $1->next = $2; $$ = $2; } ; inputFields : FIELDSTOK '{' inputFieldsList '}' { $$ = inputTemplate; inputTemplate = NULL; } | FIELDSTOK '{' parseError '}' { $$ = NULL; } ; inputFieldsList : QSTRING { $$ = (InputTemplate *) xmalloc (sizeof (InputTemplate)); $$->index = find_field_index (databaseBeingDefined, qStrVal ($1)); if ($$->index == InvalidFieldIndex) { char *msg; asprintf (&msg, "Field %s is invalid\n", qStrVal ($1)); fconferror (msg); free ($$); free (msg); inputTemplate = NULL; } else { inputTemplate = $$; $$->next = NULL; } } | inputFieldsList QSTRING { $$ = (InputTemplate *) xmalloc (sizeof (InputTemplate)); $$->index = find_field_index (databaseBeingDefined, qStrVal ($2)); if ($$->index == InvalidFieldIndex) { char *msg; asprintf (&msg, "Field %s is invalid\n", qStrVal ($2)); fconferror (msg); free (msg); free ($$); } else { $$->next = NULL; $1->next = $$; if (inputTemplate == NULL) { inputTemplate = $$; } } } ; mailFormatList : mailFormat | mailFormatList mailFormat ; mailFormat : mailFormatHeader '{' mailFormatBody '}' { addMessageFormat (databaseBeingDefined, mailFormat); mailFormat = NULL; } | mailFormatHeader '{' parseError '}' { freeMessageFormat (mailFormat); mailFormat = NULL; } ; mailFormatHeader: MAILFORMATTOK QSTRING { mailFormat = (MailMessageFormat) xmalloc (sizeof (struct mail_message_format)); mailFormat->name = takeQString ($2); mailFormat->toAddresses = NULL; mailFormat->fromAddress = NULL; mailFormat->replyTo = NULL; mailFormat->body = NULL; mailFormat->header = NULL; mailFormat->next = NULL; } ; mailFormatBody : mailFormatEnt | mailFormatBody mailFormatEnt ; mailFormatEnt : bodyFormat { mailFormat->body = qformat; qformat = NULL; } | headerFormat { mailFormat->header = qformat; qformat = NULL; } | TOADDRESSESTOK '{' mailAddressList '}' { mailFormat->toAddresses = $3; } | FROMADDRESSTOK '{' mailAddress '}' { mailFormat->fromAddress = $3; } | REPLYTOTOK '{' mailAddressList '}' { mailFormat->replyTo = $3; } ; bodyFormat : BODYTOK plainFormat ; headerFormat : HEADERTOK plainFormat ; plainFormat : plainFormatHeader queryFmt '}' | plainFormatHeader parseError '}' { freeQueryFormat (qformat); qformat = NULL; } ; plainFormatHeader: '{' { qformat = (QueryFormat *) xmalloc (sizeof (QueryFormat)); qformat->name = NULL; qformat->printf = NULL; qformat->separator = NULL; qformat->fields = NULL; qformat->next = NULL; } ; mailAddressList : mailAddress { $$ = (MailAddressList *) xmalloc (sizeof (MailAddressList)); $$->address = $1; $$->next = NULL; } | mailAddressList mailAddress { MailAddressList *lp = $$; while (lp->next != NULL) { lp = lp->next; } lp->next = (MailAddressList *) xmalloc (sizeof (MailAddressList)); lp->next->address = $2; lp->next->next = NULL; } ; mailAddress : FIXEDTOK QSTRING { $$ = (MailAddress *) xmalloc (sizeof (MailAddress)); $$->fixedAddress = takeQString ($2); $$->addresses = NULL; } | mailAddressTries { $$ = (MailAddress *) xmalloc (sizeof (MailAddress)); $$->fixedAddress = NULL; $$->addresses = $1; } ; mailAddressTries: MailAddressMember { $$ = $1; } | mailAddressTries '|' MailAddressMember { FieldList p = $$; while (p->next != NULL) { p = p->next; } p->next = $3; } ; MailAddressMember: QSTRING { $$ = newFieldListEnt (databaseBeingDefined, qStrVal ($1), NULL); } ; auditTrailFmt : AUDITTRAILFMTTOK plainFormat { setAuditTrailFormat (databaseBeingDefined, qformat); } ; gnats-4.1.0/gnats/fconfigl.l0000644000175000017500000001244507367355346016472 0ustar chewiechewie00000000000000%{ #include "gnats.h" #include "fconfig.h" #define YY_INPUT(buf, result, max_size) { \ extern int (*yyinpfunc)(char *, int); \ result = (yyinpfunc)((buf), (max_size)); \ } int fconfig_lineno; static struct qstring { char *str; struct qstring *prev, *next; } *qstringList; char * qStrVal (struct qstring *str) { return str->str; } char * takeQString (struct qstring *str) { char *res = str->str; if (str->prev != NULL) { str->prev->next = str->next; } else { qstringList = str->next; } if (str->next != NULL) { str->next->prev = (str->prev); } free (str); return res; } void cleanLexer (void) { struct qstring *p = qstringList; while (p != NULL) { struct qstring *next = p->next; free (p->str); free (p); p = next; } qstringList = NULL; } /* This is pretty crummy. */ static struct qstring * lexQString (char *str) { int len = strlen (str) - 1; char *dest; int z; struct qstring *res = (struct qstring *) xmalloc (sizeof (struct qstring)); res->str = xmalloc (len + 1); dest = res->str; if (qstringList == NULL) { res->next = NULL; res->prev = NULL; } else { res->next = qstringList; qstringList->prev = res; res->prev = NULL; } qstringList = res; for (z = 0; z < len; z++) { if (str[z] == '\\') { z++; if (z < len) { switch (str[z]) { case '\n': break; case 'n': *(dest++) = '\n'; break; case 't': *(dest++) = '\t'; break; case 'r': *(dest++) = '\r'; break; case '"': *(dest++) = '"'; break; case '\\': *(dest++) = '\\'; break; default: *(dest++) = '\\'; *(dest++) = str[z]; break; } } } else { *(dest++) = str[z]; } } *(dest) = '\0'; return res; } %} %option noyywrap %option nounput %x BadTok %x QuoteLex %% field { return FIELD; } text { return STRINGTYPE; } multitext { return MULTITEXTTYPE; } date { return DATETYPE; } path { return PATHTOK; } query-default { return QDEFAULT; } matching { return MATCHING; } enum { return ENUM; } multienum { return MULTIENUMTOK; } enumerated-in-file { return ENUM_IN_FILE; } multi-enumerated-in-file { return MULTI_ENUM_IN_FILE; } key { return KEYTOK; } fields { return FIELDSTOK; } values { return VALUES; } default { return DEFAULT; } input-default { return INPUTDEFAULTTOK; } exact-regexp { return EXACT_REGEXP; } inexact-regexp { return INEXACT_REGEXP; } all { return ALL; } format { return FORMATTOK; } textsearch { return TEXTSEARCH; } query { return QUERYTOK; } index { return INDEXTOK; } separator { return SEPARATORTOK; } restricted { return RESTRICTEDTOK; } integer { return INTEGERTOK; } nospaces-in-index { return NOSPACESTOK; } builtin-name { return BUILTINTOK; } allow-any-value { return ALLOWANYVALUETOK; } on-change { return CHANGETOK; } require { return REQUIRETOK; } append-to-field { return APPENDFIELDTOK; } set-field { return SETFIELDTOK; } description { return DESCRIPTIONTOK; } initial-entry { return INPUTTOK; } database-info { return DATABASEINFOTOK; } debug-mode { return DEBUGMODETOK; } keep-all-received-headers { return KEEPRECTOK; } notify-about-expired-prs { return NOTIFYEXPTOK; } send-submitter-ack { return SUBMITTERACKTOK; } libexecdir { return LIBEXECDIRTOK; } business-day-hours { return BUSINESSDAYTOK; } business-week-days { return BUSINESSWEEKTOK; } create-category-dirs { return CREATECATEGORYDIRSTOK; } false { return FALSETOK; } true { return TRUETOK; } separators { return ENUMSEPARATORSTOK; } mail-format { return MAILFORMATTOK; } to-addresses { return TOADDRESSESTOK; } from-address { return FROMADDRESSTOK; } reply-to { return REPLYTOTOK; } fixed-address { return FIXEDTOK; } body { return BODYTOK; } header { return HEADERTOK; } audit-trail-format { return AUDITTRAILFMTTOK; } add-audit-trail { return ADDAUDITTRAILTOK; } require-change-reason { return REQUIRECHANGEREASONTOK; } read-only { return READONLYTOK; } binary-index { return BINARYINDEXTOK; } aux-flags { return AUXFLAGSTOK; } pr-list { return PRLISTTOK; } max-prs-in-field { return MAXPRSTOK; } edit-only { return EDITONLYTOK; } virtual-format { return VIRTUALFORMATTOK; } raw { return RAWTOK; } category-dir-perms { return CATPERMSTOK; } [|] { return '|'; } "{"|"}" { return yytext[0]; } ["] { BEGIN(QuoteLex); } [\\][\n] { fconfig_lineno++; yymore (); } [\\]. { yymore (); } [\n] { fprintf (stderr, "Warning: unquoted newline within quoted string at line %d\n", fconfig_lineno); fconfig_lineno++; yymore (); } [^"\n\\]+ { yymore (); } ["] { fconflval.qstr = lexQString (yytext); BEGIN (0); return QSTRING; } [#].* /* A comment */ [0-9]+ { fconflval.intval = atoi (yytext); return INTVAL; } [-] { return '-'; } [ \t]+ /* The usual "eat up whitespace" */ [\n] { fconfig_lineno++; } . { BEGIN (BadTok); yymore (); } [^ \t\n#]* { fprintf (stderr, "Unrecognized token %s at line %d\n", yytext, fconfig_lineno); BEGIN (0); return BADTOK; } gnats-4.1.0/gnats/field.c0000644000175000017500000003630307111405574015736 0ustar chewiechewie00000000000000/* Routines for dealing with field definitions and contents. Copyright (C) 2000 Free Software Foundation, Inc. Contributed by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "field.h" enum complex_field_index_datatype { InvalidComplexFieldIndexDatatype, HeaderNameValue, FieldIndexValue, FieldTypeValue, StringValue }; struct complex_field_index { DatabaseInfo database; char *name; enum complex_field_index_datatype dtype; union field_list_u { Header_Name headerIndex; FieldIndex index; FieldType fieldType; } datum; char *admSubfield; int isReason; int isOldPr; int isRaw; }; struct databaseFieldInfo { FieldDef *fieldList; int fieldListSize; int lastFieldEnt; int *namePosition; }; static void insertNewFieldDef (DatabaseInfo database, FieldDef field) { DatabaseFieldInfo *dinfoPtr = getDatabaseFieldInfoWrite (database); DatabaseFieldInfo dinfo = *dinfoPtr; field->database = database; if (dinfoPtr == NULL) { abort (); } if (dinfo == NULL) { dinfo = (*dinfoPtr = (DatabaseFieldInfo) xmalloc (sizeof (struct databaseFieldInfo))); dinfo->fieldList = (FieldDef *) xmalloc (sizeof (FieldDef) * 10); dinfo->namePosition = (int *) xmalloc (sizeof (int) * 10); dinfo->fieldListSize = 10; dinfo->lastFieldEnt = 0; } else if (dinfo->lastFieldEnt >= dinfo->fieldListSize) { dinfo->fieldListSize += 10; dinfo->fieldList = (FieldDef *) xrealloc (dinfo->fieldList, sizeof (FieldDef) * dinfo->fieldListSize); dinfo->namePosition = (int *) xrealloc (dinfo->namePosition, sizeof (int) * dinfo->fieldListSize); } field->number = dinfo->lastFieldEnt; dinfo->fieldList[dinfo->lastFieldEnt] = field; { int x, y; for (x = 0; x < dinfo->lastFieldEnt; x++) { char *name = dinfo->fieldList[dinfo->namePosition[x]]->name; if (strcasecmp (name, field->name) > 0) { break; } } for (y = dinfo->lastFieldEnt - 1; y >= x; y--) { dinfo->namePosition[y + 1] = dinfo->namePosition[y]; } dinfo->namePosition[x] = dinfo->lastFieldEnt; dinfo->lastFieldEnt++; } } FieldDef newFieldDef (DatabaseInfo database, char *name) { if (find_field_index (database, name) == InvalidFieldIndex) { FieldDef res = (FieldDef) xmalloc (sizeof (struct field_def)); memset (res, 0, sizeof (struct field_def)); res->name = name; insertNewFieldDef (database, res); return res; } else { return NULL; } } static void freeFieldDef (FieldDef def) { if (def->name != NULL) { free (def->name); } if (def->description != NULL) { free (def->description); } if (def->default_value != NULL) { free (def->default_value); } freeStringList (def->enumValues); if (def->adm_db_name != NULL) { free (def->adm_db_name); } if (def->multiEnumSeparator != NULL) { free (def->multiEnumSeparator); } if (def->auxFlags != NULL) { free (def->auxFlags); } if (def->input_default_value != NULL) { free (def->input_default_value); } freeAdmFieldDesc (def->adm_field_des); freeAdmEntryChain (def->adm_contents); freeStringList (def->regex); freeChangeActions (def->changeActions); freeQueryFormat (def->virtualFormat); free (def); } FieldIndex getNthField (const DatabaseInfo database, int n) { DatabaseFieldInfo dinfo = getDatabaseFieldInfo (database); if (dinfo == NULL) { return InvalidFieldIndex; } else if (n < 0 || n >= dinfo->lastFieldEnt) { return InvalidFieldIndex; } else { return dinfo->fieldList[n]; } } char * getFieldFlags (const FieldIndex field) { FieldDef def = fieldDefForIndex (field); char *res = xstrdup (""); if (def == NULL) { return NULL; } if (def->textsearch) { append_string (&res, "textsearch "); } if (def->allow_any_value) { append_string (&res, "allowAnyValue "); } if (requiresChangeReason (def)) { append_string (&res, "requireChangeReason "); } if (def->readonly) { append_string (&res, "readonly "); } if (def->auxFlags != NULL) { StringList *l = def->auxFlags; while (l != NULL) { append_string (&res, l->name); l = l->next; } } return res; } int get_num_fields (const DatabaseInfo database) { DatabaseFieldInfo dinfo = getDatabaseFieldInfo (database); if (dinfo == NULL) { return -1; } return dinfo->lastFieldEnt; } static ComplexFieldIndex emptyEnt = NULL; void freeComplexFieldIndex (ComplexFieldIndex i) { if (i != NULL) { if (i->name != NULL) { free (i->name); } if (i->admSubfield != NULL) { free (i->admSubfield); } if (emptyEnt == NULL) { emptyEnt = i; } else { free (i); } } } static ComplexFieldIndex allocComplexFieldIndex (void) { ComplexFieldIndex res; if (emptyEnt != NULL) { res = emptyEnt; emptyEnt = NULL; } else { res = (ComplexFieldIndex) xmalloc (sizeof (struct complex_field_index)); } return res; } void freeFieldList (FieldList list) { FieldList n; while (list != NULL) { n = list->next; freeComplexFieldIndex (list->ent); free (list); list = n; } } void freeFieldEdit (FieldEdit *edit) { FieldEdit *n; while (edit != NULL) { n = edit->next; if (edit->fieldToEditName != NULL) { free (edit->fieldToEditName); } if (edit->textFormat != NULL) { free (edit->textFormat); } freeFieldList (edit->fieldsForFormat); free (edit); edit = n; } } void clearFieldList (DatabaseInfo database) { DatabaseFieldInfo *dinfoPtr = getDatabaseFieldInfoWrite (database); if (dinfoPtr != NULL && *dinfoPtr != NULL) { DatabaseFieldInfo dinfo = *dinfoPtr; int x; for (x = 0; x < dinfo->lastFieldEnt; x++) { freeFieldDef (dinfo->fieldList[x]); } free (dinfo->fieldList); dinfo->fieldList = NULL; dinfo->fieldListSize = 0; dinfo->lastFieldEnt = 0; if (dinfo->namePosition != NULL) { free (dinfo->namePosition); dinfo->namePosition = NULL; } free (dinfo); *dinfoPtr = NULL; } } FieldList newFieldListEnt (const DatabaseInfo database, const char *name, FieldList next) { FieldList res = (FieldList) xmalloc (sizeof (struct field_list)); res->ent = newComplexFieldIndex (database, name); res->next = next; return res; } ComplexFieldIndex newComplexFieldIndex (const DatabaseInfo database, const char *name) { ComplexFieldIndex res = allocComplexFieldIndex (); res->database = database; res->name = xstrdup (name); res->dtype = InvalidComplexFieldIndexDatatype; res->admSubfield = NULL; res->isReason = 0; res->isOldPr = 0; res->isRaw = 0; return res; } ComplexFieldIndex newComplexFieldLiteralString (const char *string) { ComplexFieldIndex res = allocComplexFieldIndex (); res->database = NULL; res->name = xstrdup (string); res->dtype = StringValue; res->admSubfield = NULL; res->isReason = 0; res->isOldPr = 0; res->isRaw = 0; return res; } ComplexFieldIndex simpleComplexFieldIndex (FieldIndex index) { ComplexFieldIndex res = allocComplexFieldIndex (); res->database = index->database; res->name = NULL; res->datum.index = index; res->dtype = FieldIndexValue; res->admSubfield = NULL; res->isReason = 0; res->isOldPr = 0; res->isRaw = 0; return res; } /* Fill in the missing fields of ENT. */ int parseComplexFieldIndex (ComplexFieldIndex ent) { if (ent->dtype == StringValue) { return 0; } else if (ent->name != NULL) { size_t nlen = strlen (ent->name); char *name = ent->name; if (name[0] == '$') { return 0; } ent->admSubfield = NULL; ent->dtype = InvalidComplexFieldIndexDatatype; ent->isReason = 0; ent->isRaw = 0; ent->isOldPr = 0; if (name[nlen - 1] == ']') { char *ptr = strchr (name, '['); if (ptr != NULL && name[nlen - 1]) { name[nlen - 1] = '\0'; ent->admSubfield = xstrdup (ptr + 1); ptr[0] = '\0'; nlen = ptr - name; } } if (nlen > 12 && strcmp (name + nlen - 12, "-Changed-Why") == 0) { name[nlen - 12] = '\0'; ent->isReason = 1; } else { ent->isReason = 0; } if (strncasecmp (name, "raw:", 4) == 0) { ent->isRaw = 1; name += 4; } if (strncasecmp (name, "oldpr:", 6) == 0) { ent->isOldPr = 1; name += 6; } if (strncasecmp (name, "fieldtype:", 10) == 0) { ent->datum.fieldType = stringToFieldType (name + 10); if (ent->datum.fieldType != InvalidFieldType) { ent->dtype = FieldTypeValue; } } else if (strncasecmp (name, "builtinfield:", 13) == 0) { ent->dtype = FieldIndexValue; ent->datum.index = findBuiltinField (ent->database, name + 13); } else { ent->datum.index = find_field_index (ent->database, name); if (ent->datum.index == InvalidFieldIndex && ! ent->isReason) { ent->datum.headerIndex = find_header_index (name); if (ent->datum.headerIndex != InvalidHeaderName) { ent->dtype = HeaderNameValue; } } else { ent->dtype = FieldIndexValue; } } free (ent->name); ent->name = NULL; } if (ent->dtype == InvalidComplexFieldIndexDatatype) { return -1; } else { return 0; } } const char * get_field_value (PR *newPR, PR *oldPR, ComplexFieldIndex ent, FormatNamedParameter *params, int *mustBeFreed) { PR *pr = newPR; if (mustBeFreed != NULL) { *mustBeFreed = 0; } if (ent->isOldPr && oldPR != NULL) { pr = oldPR; } if (ent->dtype == StringValue) { return ent->name; } if (ent->name != NULL && ent->name[0] == '$') { return getNamedParameterValue (params, ent->name); } if (pr == NULL) { return ""; } if (ent->name == NULL || parseComplexFieldIndex (ent) == 0) { const char *value; if (ent->dtype == HeaderNameValue) { value = header_value (pr, ent->datum.headerIndex); } else if (ent->dtype == FieldTypeValue) { value = xstrdup ("invalid"); } else if (ent->admSubfield != NULL) { value = getAdmSubfieldValue (pr, ent->datum.index, ent->admSubfield); } else if (ent->isReason) { value = field_change_reason (pr, ent->datum.index); } else if (ent->datum.index != InvalidFieldIndex) { if (ent->isRaw || (mustBeFreed == NULL) || (fieldDefForIndex (ent->datum.index)->virtualFormat == NULL)) { value = field_value (pr, ent->datum.index); } else { char *res = NULL; FieldIndex indx = ent->datum.index; process_format (NULL, &res, pr, oldPR, fieldDefForIndex (indx)->virtualFormat, "\n", params); value = res; *mustBeFreed = 1; } } else { value = NULL; } return value; } else { return NULL; } } int isConstantFieldValue (ComplexFieldIndex ent) { if (ent->dtype == StringValue) { return 1; } return 0; } FieldIndex simpleFieldIndexValue (ComplexFieldIndex field) { if (field->name != NULL) { parseComplexFieldIndex (field); } if (field->dtype != FieldIndexValue) { return InvalidFieldIndex; } else { return field->datum.index; } } /* Return the string name equivalent of FIELD. */ char * complexFieldIndexToString (ComplexFieldIndex field) { switch (field->dtype) { case FieldTypeValue: { const char *name = fieldTypeAsString (field->datum.fieldType); char *res; asprintf (&res, "fieldtype:%s", name); return res; } break; case StringValue: { char *res; asprintf (&res, "\"%s\"", field->name); return res; } break; case HeaderNameValue: { return xstrdup (header_name (field->datum.headerIndex)); } case FieldIndexValue: { char *res; if (field->datum.index == InvalidFieldIndex) { res = xstrdup ("invalid"); } else { const char *changedWhy = (field->isReason ? "-Changed-Why" : ""); if (field->admSubfield != NULL) { asprintf (&res, "%s%s[%s]", fieldDefForIndex (field->datum.index)->name, changedWhy, field->admSubfield); } else { asprintf (&res, "%s%s", fieldDefForIndex (field->datum.index)->name, changedWhy); } } return res; } break; default: { if (field->name != NULL) { return xstrdup (field->name); } else { return xstrdup ("invalid"); } } break; } } FieldIndex find_field_index_with_len (const DatabaseInfo database, const char *name, size_t len) { int pr_fields = get_num_fields (database); int start = 0; int end = pr_fields - 1; DatabaseFieldInfo dinfo = getDatabaseFieldInfo (database); if (dinfo == NULL) { return InvalidFieldIndex; } while (start <= end) { int pos = (start + end) / 2; int val = strncasecmp (dinfo->fieldList[dinfo->namePosition[pos]]->name, name, len); if (val == 0 && dinfo->fieldList[dinfo->namePosition[pos]]->name[len] != '\0') { val = 1; } if (val == 0) { return getNthField (database, dinfo->namePosition[pos]); } else if (val < 0) { start = pos + 1; } else { end = pos - 1; } } return InvalidFieldIndex; } FieldIndex find_field_index (const DatabaseInfo database, const char *name) { return find_field_index_with_len (database, name, strlen (name)); } FieldType complexFieldType (ComplexFieldIndex field) { if (field->dtype == FieldTypeValue) { return field->datum.fieldType; } else { return InvalidFieldType; } } struct FieldTypeInfo { const char *name; FieldType type; } fieldTypeInfo[] = { { "Text", Text }, { "MultiText", MultiText }, { "Enum", Enum }, { "MultiEnum", MultiEnum }, { "Integer", Integer }, { "Date", Date }, { "TextWithRegex", TextWithRegex } , { NULL, InvalidFieldType } }; FieldType stringToFieldType (const char *string) { int x; for (x = 0; fieldTypeInfo[x].name != NULL; x++) { if (strcasecmp (fieldTypeInfo[x].name, string) == 0) { return fieldTypeInfo[x].type; } } return InvalidFieldType; } const char * fieldTypeAsString (FieldType type) { int x; for (x = 0; fieldTypeInfo[x].name != NULL; x++) { if (fieldTypeInfo[x].type == type) { return fieldTypeInfo[x].name; } } return "InvalidFieldType"; } gnats-4.1.0/gnats/field.h0000644000175000017500000001501207111405574015735 0ustar chewiechewie00000000000000/* Interface to describing fields. Copyright (C) 1999, 2000 Free Software Foundation, Inc. Contributed by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef FIELD_H #define FIELD_H typedef const struct field_def *FieldIndex; #define InvalidFieldIndex NULL typedef struct field_def * FieldDef; typedef struct complex_field_index *ComplexFieldIndex; typedef struct field_list *FieldList; typedef struct field_edit FieldEdit; typedef struct input_template_fields InputTemplate; typedef struct change_actions *ChangeActions; typedef struct databaseFieldInfo *DatabaseFieldInfo; typedef enum { InvalidFieldType = -1, Text = 0, MultiText, Enum, MultiEnum, Integer, Date, TextWithRegex, PRListType } FieldType; typedef enum { InvalidSearchType = -1, NilSearch = 0, RegCmp, RegFind, LessThan, GreaterThan, StringMatch, Equals, NotEquals, DefaultSearchType } SearchType; #include "pr.h" #include "adm.h" #include "query.h" #include "database.h" struct change_actions { QueryExpr expr; FieldList requiredFields; FieldEdit *edits; int addAuditTrail; QueryFormat *auditTrailFormat; int requireChangeReason; struct change_actions *next; }; struct field_edit { QueryExpr expr; char *fieldToEditName; FieldIndex fieldToEdit; int append; char *textFormat; FieldList fieldsForFormat; struct field_edit *next; }; struct input_template_fields { FieldIndex index; struct input_template_fields *next; }; struct field_def { /* The database that this entry is associated with. */ DatabaseInfo database; /* This field's index number. */ int number; /* The name of this field. */ char *name; /* One-line description of this field in human-readable form. */ char *description; /* Default value for the field, if no value is supplied. */ char *default_value; /* The suggested value when a PR is initially input. */ char *input_default_value; /* If variant is enum, this is the set of possible values. */ StringList *enumValues; /* Type of data that will be accepted in this field. */ FieldType datatype; /* List of characters that can be separators between enums in a MultiEnum field. */ char *multiEnumSeparator; /* The default type of search to do on this field. */ SearchType defaultSearchType; /* If non-zero, this field should be searched when doing text searches. */ int textsearch; /* A non-zero value if this is a restricted field. */ int restricted; /* Spaces are not permitted to appear in the index file for this field. */ int nospaces; /* This field has an administrative database associated with it; this is the pathanme to it. */ char *adm_db_name; /* The descriptor for the administrative database, if the field has one. */ AdmFieldDesc *adm_field_des; /* Chain of contents of the administrative database. */ AdmEntry *adm_contents; /* Number of fields in each record of the ADM database. */ int adm_db_fields; /* Which adm field is the key. */ int key_field; /* If the field value is required to match a regexp, this is it. */ StringList *regex; /* If this is an enum field and if allow_any_value is non-zero, we don't require the value to match one of the listed enum values. (This is mainly used for the Responsible field.) */ int allow_any_value; /* Set to a non-zero value if this field may not be edited. */ int readonly; /* The actions to perform when this field is edited. */ ChangeActions changeActions; /* Auxiliary undefined flags. */ StringList *auxFlags; /* Maximum number of PRs permitted per field entry. 0 means "any number". Usually 0 or 1.. */ unsigned int maxPrsPerLine; /* Set to 1 if the field should not be displayed. */ int editonly; QueryFormat *virtualFormat; }; struct field_list { ComplexFieldIndex ent; struct field_list *next; }; extern void freeFieldList (FieldList list); extern void freeStringList (StringList *list); extern void freeAdmFieldDesc (AdmFieldDesc *desc); extern void freeFieldEdit (FieldEdit *edit); extern void clearFieldList (DatabaseInfo database); extern FieldList newFieldListEnt (const DatabaseInfo database, const char *name, FieldList next); extern FieldIndex getNthField (const DatabaseInfo database, int n); extern ComplexFieldIndex newComplexFieldIndex (const DatabaseInfo database, const char *name); extern ComplexFieldIndex simpleComplexFieldIndex (FieldIndex index); extern ComplexFieldIndex newComplexFieldLiteralString (const char *string); extern void freeComplexFieldIndex (ComplexFieldIndex ent); extern int parseComplexFieldIndex (ComplexFieldIndex ent); extern FieldIndex simpleFieldIndexValue (ComplexFieldIndex field); extern const char * get_field_value (PR *pr, PR *oldPR, ComplexFieldIndex ent, FormatNamedParameter *params, int *mustBeFreed); int isConstantFieldValue (ComplexFieldIndex field); extern char *complexFieldIndexToString (ComplexFieldIndex field); extern char *getFieldFlags (const FieldIndex field); /* A bit cheezy, but it makes sense now. */ #define fieldDefForIndex(FIELD) ((FieldDef)FIELD) #define fieldNumber(FIELD) (fieldDefForIndex ((FIELD))->number) extern FieldDef newFieldDef (DatabaseInfo database, char *name); extern FieldIndex find_field_index (const DatabaseInfo database, const char *name); extern FieldIndex find_field_index_with_len (DatabaseInfo database, const char *name, size_t len); /* If the ComplexFieldIndex represents a field type, return it; otherwise, InvalidFieldType is returned. */ extern FieldType complexFieldType (ComplexFieldIndex field); extern const char *fieldTypeAsString (FieldType field); extern FieldType stringToFieldType (const char *string); extern ChangeActions newChangeAction (const DatabaseInfo database, const char *optExpr); extern void freeChangeActions (ChangeActions actions); extern int requiresChangeReason (FieldDef field); #endif gnats-4.1.0/gnats/file-pr.c0000644000175000017500000005725010207433626016214 0ustar chewiechewie00000000000000/* Main handling routines for GNATS. Copyright (C) 2001 Milan Zamazal Copyright (C) 1993, 1994, 1995, 1999, 2000 Free Software Foundation, Inc. Contributed by Tim Wicinski (wicinski@barn.com) and by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "query.h" #include "pcodes.h" #include "mail.h" static int needs_analysis (PR *pr); static int run_atpr(PR *pr, AdmEntry *submitter, int submitter_rtime, struct tm *expired, char *bug_name, ErrorDesc *err); static int getBugNumber (const DatabaseInfo database, ErrorDesc *err); static char* derive_submitter (PR *pr); static int missing_required_fields (const DatabaseInfo database, PR *pr, ErrorDesc *err); /* Creates a PR file using the contents of PR. If an error occurs, a negative value will be returned an an appropriate error code will be set in ERR. The new PR number will be returned on success. FLAG_AUTOCREATE indicates that a PR with a non-existent category should cause the category to be automatically created. */ static int createNewPRFile (PR *pr, int flag_autocreate, ErrorDesc *err) { const DatabaseInfo database = pr->database; int bug_number = 0; int errnum = 0; AdmEntry *submitter = NULL; AdmEntry *category = NULL; AdmEntry *responsible = NULL; char *path = NULL; char *prPath = NULL; char *bug_name = NULL; char number[14]; /* No more than 13 digits in a PR #, ha ha. */ struct tm *expired = NULL; int submitter_rtime; const char *site, *bug_group; BadFields bad_fields = NULL; char *def_subm = NULL; if (! databaseValid (database)) { setError (err, CODE_FILE_ERROR, "Invalid database %s.", databaseName (database)); return -1; } if (missing_required_fields (database, pr, err) > 0) { return -1; } /* If we don't have a valid submitter ID, try to get it from the "From:" header. If that doesn't work, use the default from the config file. */ site = field_value (pr, SUBMITTER (database)); if (site != NULL) { submitter = get_adm_record (SUBMITTER (database), site); } else { submitter = NULL; } def_subm = defaultSubmitter (database); if (submitter == NULL || (strcmp (site, def_subm) == 0)) { site = derive_submitter (pr); set_field (pr, SUBMITTER (database), site, err); submitter = get_adm_record (SUBMITTER (database), site); } if (submitter == NULL) { log_msg (LOG_INFO, 1, "resetting to default submitter from:", site); site = def_subm; /* If it's still an error, punt because this should not happen. Actually, it can't happen unless the submitter file is empty. */ submitter = get_adm_record (SUBMITTER (database), site); if (submitter == NULL) { setError (err, CODE_INVALID_ENUM, newBadFieldEntry (SUBMITTER (database), def_subm, NULL), "Can't find default submitter %s", def_subm); free (def_subm); return -1; } else { set_field (pr, SUBMITTER (database), def_subm, err); } } if (submitter->admFields[SubmitterAdmRtime] == NULL || submitter->admFields[SubmitterAdmRtime][0] == '\0') { submitter_rtime = -1; } else { submitter_rtime = atoi (submitter->admFields[SubmitterAdmRtime]); } /* If originator wasn't set, try to get the value from the From mail header. This is what users usually expect. */ { FieldIndex idx_origin = ORIGINATOR (database); const char *value_origin = (idx_origin == InvalidFieldIndex ? NULL : field_value (pr, idx_origin)); if (value_is_empty (value_origin)) { const char *value_from; ErrorDesc err; value_from = header_value (pr, REPLY_TO); if (value_is_empty (value_from)) value_from = header_value (pr, FROM); if (! value_is_empty (value_from)) set_field (pr, idx_origin, xstrdup (value_from), &err); } } bug_group = field_value (pr, CATEGORY (database)); if (bug_group != NULL) { category = get_adm_record (CATEGORY (database), bug_group); } else { category = NULL; } if (category == NULL) { bad_fields = newBadFieldEntry (CATEGORY (database), bug_group, bad_fields); { char *message; asprintf (&message, "%s from: %s\n", defaultCategory(database), bug_group); log_msg (LOG_INFO, 1, "resetting bug category to ", message); free (message); } bug_group = defaultCategory(database); set_field (pr, CATEGORY (database), defaultCategory(database), err); /* Again, but with default now. If it's not there, kick this to the GNATS_ADMIN. */ category = get_adm_record (CATEGORY (database), bug_group); if (category == NULL) { setError (err, CODE_FILE_ERROR, "No `%s' directory under %s.", defaultCategory(database), databaseDir (database)); return -1; } } /* Set responsible field, adding full name as well (if found). If it's coming in with a Responsible: field already, don't wipe it out. */ { const char *p = field_value (pr, RESPONSIBLE (database)); if (p != NULL && p[0] != '\0') { const char *person, *tmp; char *pcpy = NULL; if ((tmp = strchr (p, ' ')) != NULL) { pcpy = xstrdup (p); pcpy[tmp - p] = '\0'; person = pcpy; } else { person = p; } responsible = get_responsible_address (database, person); if (pcpy != NULL) { free (pcpy); } } } if (responsible == NULL) { responsible = get_responsible_address (database, category->admFields[CategoryAdmPerson]); if (responsible != NULL) { set_field (pr, RESPONSIBLE (database), responsible->admFields[ResponsibleAdmKey], err); log_msg (LOG_INFO, 1, "responsible person is:", field_value (pr, RESPONSIBLE (database))); } } { /* Check the subject and the synopsis lines. If both of these are null, then forget it. Currently it seems that values are set to '\0' when there is nothing there. */ const char *synopsis = field_value (pr, SYNOPSIS (database)); const char *subject = header_value (pr, SUBJECT); if ((subject == NULL || *subject == '\0') && (synopsis != NULL && *synopsis != '\0')) { set_header (pr, SUBJECT, xstrdup (synopsis)); } if ((synopsis == NULL || *synopsis == '\0') && (subject != NULL && *subject != '\0')) { set_field (pr, SYNOPSIS (database), subject, err); } } /* Set arrival date and time of response. */ { time_t seconds = time ((time_t) 0); char arrival_time[GNATS_TIME_LENGTH]; gnats_strftime (arrival_time, GNATS_TIME_LENGTH, "%a %b %d %H:%M:%S %z %Y", localtime (&seconds)); set_field (pr, ARRIVAL_DATE (database), arrival_time, err); } /* If the submitter isn't supposed to have a response time, don't bother trying to get it. */ if (submitter_rtime >= 0) { expired = get_response_time (database, submitter_rtime); } /* Put together the path to where the bug will be stored. If the dir is not there, and the category is the default, auto-create that one, if we want to. If not, make the bug pending, and store in there. */ asprintf (&path, "%s/%s", databaseDir (database), bug_group); errnum = fileExists (path) ? 0 : -1; if (errnum != 0 && ! flag_autocreate) { /* XXX ??? !!! Should append a message to the email being sent out. */ bug_group = defaultCategory(database); set_field (pr, CATEGORY (database), defaultCategory(database), err); log_msg (LOG_INFO, 1, "directory does not exist, changing to default:", path); free (path); asprintf (&path, "%s/%s", databaseDir (database), bug_group); errnum = fileExists (path) ? 0 : -1; } /* Check ERR again, to see if default category was there. */ if (errnum != 0) { mode_t mode = categoryDirPerms (database); if (strcmp (bug_group, defaultCategory(database)) == 0) { log_msg (LOG_INFO, 1, defaultCategory(database), " does not exist, creating..."); if (mkdir (path, mode) != 0) { setError (err, CODE_FILE_ERROR, "Can't create `%s' directory under %s.", defaultCategory(database), databaseDir (database)); return -1; } } else if (flag_autocreate) { if (mkdir (path, mode) != 0) { setError (err, CODE_FILE_ERROR, "Cannot create group: %s", path); return -1; } else { log_msg (LOG_INFO, 1, "creating directory:", path); } } } { /* Ensure the PR has a valid STATE. We set the default state on any of these cases: 1. field_value() returns NULL. 2. if field_value returns the default value. (field_value in 4.0beta1 returns the default, even if it is not really set.) 3. if set_field with the existing value fails. If something used set_field() previously, it was already validated, but we call set_field to validate again to be sure. */ char *val = (char *)field_value (pr, STATE (database)); char *default_val = fieldDefForIndex (STATE (database))->default_value; if (val != NULL) { val = xstrdup (val); } if (val == NULL || ! strcmp (val, default_val) || ! set_field (pr, STATE (database), val, err)) { set_field (pr, STATE (database), default_val, err); } if (val != NULL) { free (val); } } /* Retrieve a unique bug number. */ bug_number = getBugNumber (database, err); if (bug_number > 0) { sprintf (number, "%d", bug_number); set_field (pr, NUMBER (database), number, err); bad_fields = checkEnumTypes (pr, bad_fields, 1); /* Write the file out. */ asprintf (&bug_name, "%s/%d", bug_group, bug_number); asprintf (&prPath, "%s/%s", databaseDir (database), bug_name); if (createPrFile (pr, prPath, 1, err) != 0) { bug_number = -1; } else { log_msg (LOG_INFO, 1, "PR written out:", prPath); /* Add a line into the index for use by query-pr. */ /* This should be done regardless of whether the bug is default or not. */ if (addToIndex (pr, err) != 0) { bug_number = -1; } } } if (bug_number > 0) { /* If it isn't in the default category [pending], send all of the mail for it, create an index entry, and run at_pr. Otherwise, just notify gnats-admin. */ if (strcmp (category->admFields[CategoryAdmKey], defaultCategory (database)) != 0) { /* Acknowledge the person's problem report. */ if (submitterAck (database)) { composeMailMessage (pr, NULL, "initial-response-to-submitter", NULL, bad_fields, err); } composeMailMessage (pr, NULL, "initial-pr-notification", NULL, bad_fields, err); if (submitter_rtime != -1 && notifyExpire (database) && needs_analysis (pr)) { if (run_atpr (pr, submitter, submitter_rtime, expired, bug_name, err) != 0) { bug_number = -1; } } } else { composeMailMessage (pr, NULL, "initial-pr-notification-pending", NULL, bad_fields, err); } } free_adm_entry (category); free_adm_entry (submitter); free_adm_entry (responsible); if (path != NULL) { free (path); } if (prPath != NULL) { free (prPath); } if (bug_name != NULL) { free (bug_name); } if (def_subm != NULL) { free (def_subm); } return bug_number; } static int missing_required_fields (const DatabaseInfo database, PR *pr, ErrorDesc *err) { int cnt = 0; FieldList fields = getRequiredInputFields(database); while (fields != NULL) { const char *fldval = get_field_value (pr, NULL, fields->ent, NULL, NULL); if (value_is_empty (fldval)) { setError (err, CODE_INVALID_PR_CONTENTS, "Required field %s missing from new PR - cannot submit.", complexFieldIndexToString (fields->ent), field_value (pr, NUMBER (pr->database))); cnt++; } fields = fields->next; } return cnt; } /* XXX ??? !!! FIXME Shouldn't be hardcoded. */ static int needs_analysis (PR *pr) { const char *severity = field_value (pr, SEVERITY (pr->database)); const char *priority = field_value (pr, PRIORITY (pr->database)); if (severity != NULL && priority != NULL) { return strcmp (severity, "critical") == 0 || (strcmp (severity, "serious") == 0 && strcmp (priority, "high") == 0); } else { return 0; } } static char * arg_quote (const char *s) { char *buf; char *p; size_t finalLen = 0; const char *argPtr; if (s == NULL) { return xstrdup ("''"); } for (argPtr = s; *argPtr != '\0'; argPtr++) { if (*argPtr == '\'') { finalLen += 4; } else { finalLen++; } } buf = xmalloc (finalLen + 2); p = buf; for (; *s != '\0'; s++) { if (*s == '\'') { *p++ = '\''; *p++ = '\\'; *p++ = '\''; *p++ = '\''; } else { *p++ = *s; } } if (p == buf) { *p++ = ' '; } *p = '\0'; return buf; } static int run_atpr (PR *pr, AdmEntry *submitter, int submitter_rtime, struct tm *expired, char *bug_name, ErrorDesc *err) { char *at_pr; char *command = NULL; char buf[GNATS_TIME_LENGTH]; FILE *p; int i; static const char *ats[] = { "/usr/bin/at", "/bin/at", NULL }; asprintf (&at_pr, "%s/at-pr", binDir (pr->database)); strftime (buf, GNATS_TIME_LENGTH, "%H:%M %b %d", expired); for (i = 0; ats[i] != NULL; i++) { if (access (ats[i], X_OK) == 0) { asprintf (&command, "%s %s &> /dev/null", ats[i], buf); break; } } if (command != NULL) { p = popen (command, "w"); if (p == (FILE *)NULL) { setError (err, CODE_FILE_ERROR, "Couldn't open the pipe for at-pr."); log_msg (LOG_INFO, 0, "popen failed:"); return 1; } else { char *orig = arg_quote (field_value (pr, ORIGINATOR (pr->database))); char *cont = arg_quote (submitter->admFields[SubmitterAdmContact]); char *pa = arg_quote (gnatsAdminMailAddr (pr->database)); fprintf (p, "%s --database %s %d %s %s '%s' '%s' '%s'\n", at_pr, databaseName (pr->database), submitter_rtime, bug_name, submitter->admFields[SubmitterAdmKey], orig, cont, pa); pclose (p); free (orig); free (cont); free (pa); return 0; } } else { setError (err, CODE_FILE_ERROR, "couldn't find `at'"); return 1; } } /* Check to see if PR is a reply to an existing PR. If so, return the PR ID of the PR. */ static char * checkIfReply (PR *pr, ErrorDesc *err) { char *prID; char *prCat; AdmEntry *cat; const char *headerValue; struct re_pattern_buffer regex; struct re_registers regs; int i, len; reg_syntax_t old_syntax; headerValue = header_value (pr, SUBJECT); if (headerValue == NULL || *headerValue == '\0') { return NULL; } old_syntax = re_set_syntax (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CHAR_CLASSES); memset ((void *) ®ex, 0, sizeof (regex)); { const char *const PAT = "\\<(PR[ \t#/]?|([-[:alnum:]_+.]+)/)([0-9]+)"; re_compile_pattern (PAT, strlen (PAT), ®ex); } i = re_search (®ex, headerValue, strlen (headerValue), 0, strlen (headerValue), ®s); regfree (®ex); re_set_syntax (old_syntax); if (i < 0) { return NULL; } /* Check the category if there is one. */ if (regs.start[2] > -1) { len = regs.end[2] - regs.start[2]; prCat = xmalloc (len + 1); memcpy (prCat, headerValue + regs.start[2], len); prCat[len] = '\0'; /* See if the category exists: */ cat = get_adm_record (CATEGORY (pr->database), prCat); free_adm_entry(cat); free (prCat); if (cat == NULL) { free (regs.start); free (regs.end); return NULL; } } /* Check the PR number. */ len = regs.end[3] - regs.start[3]; prID = xmalloc (len + 1); memcpy (prID, headerValue + regs.start[3], len); prID[len] = '\0'; free (regs.start); free (regs.end); if (! prExists (pr->database, prID, err)) { free (prID); prID = NULL; } return prID; } /* This function compares the e-mail address in the "From:" header of a new PR with entries in the "addresses" file. If there is a match, we return the submitter ID from "addresses", otherwise we return the default submitter. */ static char * derive_submitter (PR *pr) { const char *from_address; char *from_string; char *from_copy = NULL; char *line; char *res = NULL; char *s; FILE *fp; from_address = header_value (pr, FROM); if (from_address == NULL || *from_address == '\0') { return defaultSubmitter (pr->database); } from_copy = xstrdup (from_address); s = from_copy + strlen(from_copy) - 1; /* Grab the address from out between the <>. */ if (*s == '>') { *s = '\0'; from_string = strrchr (from_copy, '<'); if (from_string != NULL) { from_string++; } else { from_string = from_copy; } } else { char *t = strchr (from_copy, ' '); if (t != NULL) { *t = '\0'; } from_string = from_copy; } { char *path = gnats_adm_dir (pr->database, "addresses"); fp = fopen (path, "r"); free (path); } if (fp != NULL) { while (res == NULL && (line = read_line (fp, NULL)) != NULL) { if (*line != '#') { AdmEntry *ent = build_adm_entry (line, InvalidFieldIndex); if (ent->fieldcount == 2) { if (strcasecmp (ent->admFields[1], from_string) == 0) { res = xstrdup (ent->admFields[0]); } } free_adm_entry (ent); } free (line); } fclose (fp); } free (from_copy); if (res != NULL) { return res; } else { return defaultSubmitter (pr->database); } } /* Append an email reply in NEW_PR to an existing PR with PR number NUMBER. The headers of the email mesage are included in NEW_PR, while the contents of the PR have not yet been read from INFILE. The entire body of the message is appended, while just the To:, From:, Date:, and Subject: lines from the header are included. */ static int append_report (FILE *infile, PR *new_pr, const char *number, ErrorDesc *err) { char line[1024]; /* This size doesn't matter here */ char *buf; size_t buf_size, len; const char *from, *to, *subject, *date, *cc; PR *pr; from = header_value (new_pr, FROM); to = header_value (new_pr, TO); cc = header_value (new_pr, CC); subject = header_value (new_pr, SUBJECT); date = header_value (new_pr, DATE); if (*date == '\0') { date = get_curr_date (); } if (! prExists (new_pr->database, number, err)) { return 1; } /* Now, add some header information before we get the rest of their message. */ /* XXX ??? !!! The format of this should be in the config file... the only issue is handling the indentation of the message text. */ asprintf (&buf, "\ From: %s\n\ To: %s\n\ Cc: %s\n\ Subject: %s\n\ Date: %s\n\ \n", from, to, cc, subject, date); /* Copy the message from infile, indenting each line by one character */ len = buf_size = strlen (buf); while ((fgets (line, sizeof (line) - 1, infile)) != NULL) { const size_t line_len = strlen (line); const size_t req_len = len + line_len + 2; if (buf_size < req_len) { buf_size = ((2*buf_size <= req_len) ? req_len : 2*buf_size); buf = xrealloc (buf, buf_size); } if (buf[len-1] == '\n') { buf[len++] = ' '; } memcpy (buf + len, line, line_len + 1); len += line_len; } fclose (infile); pr = readPRWithNum (new_pr->database, number, 0, err); if (pr == NULL) { return 1; } else { if (edit_field (pr->database, number, AUDIT_TRAIL (pr->database), 1, xstrdup (buf), NULL, header_value (pr, FROM), err) == 0) { return 1; } } /* * This could be a silent update to the PR, in which case, don't tell * the world about it (e.g. automatic build/source control messages). */ if (raw_header_value (new_pr, X_GNATS_NONOTIFY) == NULL) { FormatNamedParameter *params = NULL; params = allocateNamedParameter ("$MailFrom", from, params); params = allocateNamedParameter ("$MailTo", to, params); params = allocateNamedParameter ("$MailSubject", subject, params); params = allocateNamedParameter ("$MailCC", cc, params); params = allocateNamedParameter ("$NewAuditTrail", buf, params); composeMailMessage (pr, NULL, "appended-email-response", params, NULL, err); freeFormatParameterList (params); } free (buf); unblock_signals (); return 0; } /* Return the next available unique GNATS id. */ static int getBugNumber (const DatabaseInfo database, ErrorDesc *err) { char *sbuf; int bug_number; FILE *bug_file; /* First try to find and lock the gnats lock file. We need this since they want every bug to have a unique number. If lock doesn't exist, make it, if possible. */ sbuf = gnats_adm_dir (database, "current"); block_signals (); bug_file = fopen (sbuf, "r+"); if (bug_file == (FILE *) NULL) { log_msg (LOG_INFO, 1, "file 'current' not found, creating", sbuf); bug_file = fopen (sbuf, "w+"); if (bug_file != (FILE *) NULL) { bug_number = 1; } else { setError (err, CODE_FILE_ERROR, "Can't create the GNATS 'current' file (%s).", sbuf); return -1; } } else { if (fscanf (bug_file, "%d", &bug_number) != 1) { setError (err, CODE_FILE_ERROR, "Can't read from the global PR number counter (%s).", sbuf); return -1; } bug_number++; rewind (bug_file); } fprintf (bug_file, "%d", bug_number); fclose (bug_file); unblock_signals (); free (sbuf); return bug_number; } /* Submit the PR whose contents are referred to by FP. * Return the new PR number if it's a new PR, or return the PR number of * the PR which was appended to if it's an existing PR. */ int submit_pr (const DatabaseInfo database, FILE *fp, ErrorDesc *err) { int result, retval; PR *pr = allocPR (database); result = (read_header (pr, fp) >= 0); if (result != 0) { /* Check if the message is a reply to an existing PR; if it is, then just append this message to the end of that PR. Otherwise, process it normally. */ char *prID = checkIfReply (pr, err); if (prID != NULL) { /* Before inserting the reply, see if someone's got the PR locked; if they do, then try it at the next run of the queue. */ if (isPrLocked (database, prID)) { result = 0; setError (err, CODE_LOCKED_PR, "PR already locked"); } else { retval = append_report (fp, pr, prID, err); result = (retval == 0) ? atoi (prID) : 0; free_pr (pr); } free (prID); } else { read_pr (pr, fp, 0); retval = createNewPRFile (pr, createCategoryDirs (database), err); result = (retval < 0) ? 0 : retval; } } else { setError (err, CODE_UNREADABLE_PR, "Failure reading header"); } return result; } gnats-4.1.0/gnats/file-pr.sh0000644000175000017500000000526707264066451016414 0ustar chewiechewie00000000000000#!/bin/sh # Program to submit problem reports for GNATS. # Copyright (C) 1999 Free Software Foundation, Inc. # Contributed by Bob Manson (manson@juniper.net). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. debug_print=false # or echo to get output. LIBEXECDIR=xLIBEXECDIRx EDIT_USER= EDIT_PASSWD= version=xVERSIONx usage=" Usage: file-pr [-V|--version] [-h|--help] [-d|--database database_name] [-H|--host hostname] [-P|--port port_number] [-v|--user userid] [-w|--passwd password] [-f|--filename inputfile] " # Parse command line. We don't really need to do this, but that's ok. while [ $# -gt 0 ]; do case "$1" in -V|--version|--ve*) echo "$version"; exit 0 ;; -d | --database) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; GNATS_DB="--database=$1" ;; -d=* | --database=*) GNATS_DB="$1" ;; -D | --debug) shift ;; -H | --host) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; GNATS_HOST="--host=$1" ;; -H=* | --host=*) GNATS_HOST="$1" ;; -P | --port) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; GNATS_PORT="--port=$1" ;; -P=* | --port=*) GNATS_PORT="$1" ;; -v | --user) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; EDIT_USER="--user=$1" ;; -v=* | --user=*) EDIT_USER="$1" ;; -w | --passwd) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; EDIT_PASSWD="--passwd=$1" ;; -w=* | --passwd=*) EDIT_PASSWD="$1" ;; -f|--filename*) if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi shift ; FILENAME="$1" ;; -h|--help*) echo "$usage"; exit 0 ;; *) echo "$usage"; exit 1 ;; esac shift done # set command here to always pass host and port, and directory if supplied PR_EDIT="$LIBEXECDIR/gnats/pr-edit ${GNATS_HOST} ${GNATS_PORT} ${EDIT_USER} ${EDIT_PASSWD} ${GNATS_DB}" if [ "$FILENAME" != "" ]; then PR_EDIT="$PR_EDIT -f $FILENAME" fi $PR_EDIT --submit gnats-4.1.0/gnats/gen-closed-date.c0000644000175000017500000002201107570426211017575 0ustar chewiechewie00000000000000/* Generate the Closed-Date field for an existing GNATS database. Copyright (C) 1993, 1995, 2001, 2002 Free Software Foundation, Inc. Contributed by Rick Macdonald (rickm@vsl.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnats-dirs.h" #include /* The name this program was run with. */ const char *program_name; /* If 1, we're running in test mode and PR files are _not_ actually updated. */ int test_mode = 0; struct option long_options[] = { {"database", 1, NULL, 'd'}, {"outfile", 1, NULL, 'o'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {"test", 0, NULL, 't'}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "gen-closed-date" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]...\n\ Generate the Closed-Date field for an existing GNATS database.\n\ \n" "\ -d --database=DATABASE use DATABASE\n\ -o --outfile=FILENAME output the date to FILENAME\n\ -t --test report changes to be made, but don't change the files\n\ \n\ -h --help display this help and exit\n\ -V --version output version information and exit\n", NULL}; typedef struct entry { unsigned int number; char *string; } Entry; static int get_closed (PR *pr, ErrorDesc *err) { const char *final1, *final2, *from_start, *to_start; char from[32], to[32]; const char *p, *c, *when_start; char when[133]; char *new_audit; const char *copy_ptr; int len, from_len, to_len, closed_date_set = 0, changed_separator; p = field_value (pr, AUDIT_TRAIL (pr->database)); if (p == NULL || strlen (p) == 0) { /* No Audit-Trail at all; initialize Closed-Date */ set_field (pr, CLOSED_DATE (pr->database), "", err); return 1; } new_audit = xmalloc (strlen (p) * 2); new_audit[0] = '\0'; copy_ptr = p; /* Skip ahead to the last time it was closed. */ final2 = p; do { final1 = strstr (final2, "State-Changed-From-To:"); if (final1 != NULL) { final1 += 22; while (final1[0] != '\0' && isspace ((int)(unsigned char) final1[0])) { final1++; } from_start = final1; while (final1[0] != '\0' && final1[0] != '-') { final1++; } from_len = final1 - from_start; changed_separator = 0; if (final1[0] != '\0' && final1[1] == '>') { final1 += 2; } else { /* Change - to -> here */ final1++; strncat (new_audit, copy_ptr, final1 - copy_ptr); strcat (new_audit, ">"); copy_ptr = final1; changed_separator = 1; } to_start = final1; while (final1[0] != '\0' && !isspace ((int)(unsigned char) final1[0])) { final1++; } to_len = final1 - to_start; strncpy (from, from_start, from_len); from[from_len] = '\0'; strncpy (to, to_start, to_len); to[to_len] = '\0'; final2 = final1; if (test_mode && changed_separator) { printf ("\t%s->%s\n", from, to); } if (check_state_type (pr->database, from, "closed") != check_state_type (pr->database, to, "closed")) { if (check_state_type (pr->database, from, "closed")) { /* No longer closed; clear the Closed-Date field */ set_field (pr, CLOSED_DATE (pr->database), "", err); } else { /* Now closed; set the Closed-Date field */ /* Grab the When date str */ final1 = strstr (final2, "State-Changed-When:"); if (final1 != NULL) { final1 += 19; while (final1[0] != '\0' && isspace ((int)(unsigned char) final1[0])) { final1++; } when_start = final1; c = strchr (final1, '\n'); final2 = c; while (c >= final1 && isspace ((int)(unsigned char) c[0])) { c--; } c++; len = c - when_start; (void) strncpy (when, when_start, len); when[len] = '\0'; set_field (pr, CLOSED_DATE (pr->database), when, err); } final1 = final2; /* Just to keep the while loop going */ } if (test_mode) { printf("\t%s/%s Closed-Date: %s\n", field_value (pr, NUMBER (pr->database)), field_value (pr, CATEGORY (pr->database)), field_value (pr, CLOSED_DATE (pr->database))); } closed_date_set = 1; } } } while (final1 != NULL); strcat (new_audit, copy_ptr); set_field (pr, AUDIT_TRAIL (pr->database), new_audit, err); free (new_audit); if (! closed_date_set) { /* No state changes at all; initialize Closed-Date */ set_field (pr, CLOSED_DATE (pr->database), "", err); } return 1; } /* For a given category C, go into its directory and either emit an index entry for each file in it, or swallow its index entry so we can sort it later. */ static void do_category (DatabaseInfo database, const char *c) { DIR *d; struct dirent *next; struct stat stbuf; struct utimbuf utbuf; FILE *fp; size_t len = strlen (databaseDir (database)) + 1 + strlen (c) + 2; /* Allocate for a PR with 20 digits. */ char *path = (char *) xmalloc (len + 21); char *p; ErrorDesc err; errno = 0; if (chdir (databaseDir (database)) < 0) { fprintf (stderr, "%s: can't read the database directory %s: %s\n", program_name, databaseDir (database), strerror (errno)); exit (3); } if (c == NULL || *c == '\0') { free (path); return; } errno = 0; d = opendir (c); if (d == 0) { fprintf (stderr, "%s: can't open the category directory %s/%s: %s\n", program_name, databaseDir (database), c, strerror (errno)); free (path); return; } sprintf (path, "%s/%s/", databaseDir (database), c); /* Process each file in the directory; ignore files that have periods in their names; either they're the . and .. dirs, or they're a lock file (1234.lock). */ while ((next = readdir (d))) { if (strchr (next->d_name, '.') == NULL) { PR *pr; p = path + len - 1; strcat (p, next->d_name); fp = fopen (path, "r"); if (fp == (FILE *) NULL) { fprintf (stderr, "%s: couldn't read pr %s: %s\n", program_name, path, strerror (errno)); *p = '\0'; continue; } pr = allocPR (database); if (read_header (pr, fp) < 0) { fprintf (stderr, "%s: error reading pr %s\n", program_name, path); *p = '\0'; free_pr (pr); continue; } read_pr (pr, fp, 0); fclose (fp); get_closed (pr, &err); printf("%s/%s Closed-Date: %s\n", field_value (pr, NUMBER (pr->database)), field_value (pr, CATEGORY (pr->database)), field_value (pr, CLOSED_DATE (pr->database))); if (!test_mode) { /* Reset the file mtime after writing it out */ stat (path, &stbuf); if (createPrFile (pr, path, 1, &err) != 0) { client_print_errors (pr->database, err); } utbuf.actime = utbuf.modtime = stbuf.st_mtime; utime (path, &utbuf); } *p = '\0'; free_pr (pr); } } closedir (d); free (path); } int main (int argc, char **argv) { int optc; AdmEntry *clist, *c; FILE *output = NULL; /* ??? */ char *database_name = NULL; ErrorDesc err; DatabaseInfo database = NULL; program_name = (char *) basename (argv[0]); while ((optc = getopt_long (argc, argv, "o:htd:V", long_options, (int *) 0)) != EOF) { switch (optc) { case 'd': database_name = optarg; break; case 'o': output = fopen (optarg, "w+"); if (output == (FILE *) NULL) { fprintf (stderr, "%s: can't write to %s: %s\n", program_name, optarg, strerror (errno)); exit (3); } break; case 'V': version (PROGRAM_NAME); break; case 'h': usage (USAGE, 0); break; case 't': test_mode = 1; break; default: usage (USAGE, 1); } } database = init_gnats (program_name, database_name, &err); if (! databaseValid (database)) { client_print_errors (database, err); exit (1); } umask (022); /* lock the whole thing. */ if (client_lock_gnats (database, &err) != 0) { client_print_errors (database, err); exit (1); } clist = build_chain (CATEGORY (database)); for (c = clist ; c ; c = c->next) { do_category (database, c->admFields[CategoryAdmKey]); } if (output != NULL) { fclose (output); } /* unlock the whole thing. */ client_unlock_gnats (); exit (0); } gnats-4.1.0/gnats/gen-index.c0000644000175000017500000001731407521042047016527 0ustar chewiechewie00000000000000/* Generate an index file for an existing GNATS database. Copyright (C) 1993, 1995, 1999, 2001, 2002 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnats-dirs.h" /* The name this program was run with. */ const char *program_name; /* Where the index file should be output. */ FILE *output = NULL; /* If TRUE, we should sort the index list by number. */ int numeric_sorting = FALSE; #define PROGRAM_NAME "gen-index" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]...\n\ Generate new database index.\n\ \n", "\ -d --database=DATABASE use DATABASE\n\ -o --outfile=FILENAME output the index to FILENAME\n\ -n --numerical perform numerical sort\n\ -i --import read in the existing index instead of PRs\n\ -e --export force outputting the index in the text form\n\ \n\ -h --help display this help and exit\n\ -V --version output version information and exit\n", NULL}; typedef struct entry { unsigned int number; char *string; size_t length; } Entry; #define ENTRYNUMINCREMENT 1024 Entry *entries = NULL; int entryArraySize = 0; int num_entries = 0; static int entry_cmp (const void *e1a, const void *e2a) { const Entry *e1 = e1a; const Entry *e2 = e2a; return e1->number - e2->number; } static void add_pr (const DatabaseInfo database, PR *pr) { char *line = NULL; size_t lineLen; if (indexIsBinary (database)) { line = createIndexEntryBinary (pr, &lineLen); } else { line = createIndexEntry (pr, &lineLen); } if (line != NULL) { if (numeric_sorting) { if (num_entries >= entryArraySize) { entryArraySize += ENTRYNUMINCREMENT; entries = (Entry *) xrealloc ((char *) entries, entryArraySize * sizeof (Entry)); } entries[num_entries].number = atoi (field_value (pr, NUMBER (pr->database))); entries[num_entries].string = line; entries[num_entries].length = lineLen; num_entries++; } else { fwrite (line, 1, lineLen, output); free (line); } } } /* For a given category C, go into its directory and either emit an index entry for each file in it, or swallow its index entry so we can sort it later. */ static void do_category (DatabaseInfo database, const char *c) { DIR *d; struct dirent *next; FILE *fp; int len = strlen (databaseDir (database)) + 1 + strlen (c) + 2; /* Allocate for a PR with 20 digits. */ char *path = (char *) xmalloc (len + 21); errno = 0; if (chdir (databaseDir (database)) < 0) { fprintf (stderr, "%s: can't read the database directory %s: %s\n", program_name, databaseDir (database), strerror (errno)); exit (3); } if (c == NULL || *c == '\0') { free (path); return; } errno = 0; d = opendir (c); if (d == NULL) { if (! createCategoryDirs (database)) { fprintf (stderr, "%s: can't open the category directory %s/%s: %s\n", program_name, databaseDir (database), c, strerror (errno)); } free (path); return; } sprintf (path, "%s/%s/", databaseDir (database), c); /* Process each file in the directory; ignore files that have periods in their names; either they're the . and .. dirs, or they're a lock file (1234.lock). */ while ((next = readdir (d))) if (strchr (next->d_name, '.') == NULL && strlen (next->d_name) < 20) { PR *pr; char *p = path + len - 1; strcat (p, next->d_name); fp = fopen (path, "r"); if (fp == (FILE *) NULL) { fprintf (stderr, "%s: couldn't read pr %s: %s\n", program_name, path, strerror (errno)); *p = '\0'; continue; } pr = allocPR (database); if (read_header (pr, fp) < 0) { fprintf (stderr, "%s: error reading pr %s\n", program_name, path); *p = '\0'; free_pr (pr); continue; } read_pr (pr, fp, 1); fclose (fp); { const char *n = field_value (pr, NUMBER (pr->database)); if (n == NULL || n[0] == '-') { fprintf (stderr, "%s: defective pr %s\n", program_name, path); *p = '\0'; free_pr (pr); continue; } } *p = '\0'; add_pr (database, pr); free_pr (pr); } closedir (d); free (path); } static void do_prs (const DatabaseInfo database, PR *pr) { while (pr) { add_pr (database, pr); pr = getNextPR (pr); } } int main (int argc, char **argv) { int optc, i; AdmEntry *clist, *c; const char *database_name = NULL; const char *file_name = NULL; ErrorDesc err = NULL; DatabaseInfo database; static int importp = FALSE; static int exportp = FALSE; PR *pr = NULL; struct option long_options[] = { {"database", required_argument, NULL, 'd'}, {"outfile", required_argument, NULL, 'o'}, {"numerical", no_argument, NULL, 'n'}, {"import", no_argument, NULL, 'i'}, {"export", no_argument, NULL, 'e'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; program_name = basename (argv[0]); output = stdout; while ((optc = getopt_long (argc, argv, "o:hd:nVie", long_options, (int *) 0)) != EOF) { switch (optc) { case 0: /* automatically handled flag */ break; case 'd': database_name = optarg; break; case 'o': file_name = optarg; break; case 'n': numeric_sorting = TRUE; break; case 'i': importp = TRUE; break; case 'e': exportp = TRUE; break; case 'V': version (PROGRAM_NAME); break; case 'h': usage (USAGE, 0); break; default: usage (USAGE, 1); } } database = init_gnats (program_name, database_name, &err); if (database == NULL) { client_print_errors (database, err); exit (1); } umask (022); clist = fieldDefForIndex (CATEGORY (database))->adm_contents; if (importp) { pr = getFirstPR (database, &err); if (err) { client_print_errors (database, err); exit (1); } } if (exportp && indexIsBinary (database)) { IndexDesc desc = getIndexDesc (database); setIndexDescBinary (desc, FALSE); } if (file_name) output = fopen (file_name, "w+"); if (output == (FILE *) NULL) { fprintf (stderr, "%s: can't write to %s: %s\n", program_name, optarg, strerror (errno)); exit (3); } if (indexIsBinary (database)) { char numFields = indexFieldCount (database); fwrite (&numFields, 1, 1, output); } if (importp) do_prs (database, pr); else for (c = clist ; c ; c = c->next) do_category (database, c->admFields[CategoryAdmKey]); if (numeric_sorting && num_entries > 0) { qsort (entries, num_entries, sizeof (Entry), entry_cmp); for (i = 0; i < num_entries; i++) { fwrite (entries[i].string, 1, entries[i].length, output); } } fclose (output); freeDatabaseInfo (database); database = NULL; exit (0); } gnats-4.1.0/gnats/getclose.c0000644000175000017500000002067007560340040016452 0ustar chewiechewie00000000000000/* List PRs that were closed between certain dates. Copyright (C) 2001 Milan Zamazal Copyright (C) 1996, 1997 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ /* Initial version. To use this to find the PRs fixed in a particular release, run it as getclose migration freeze lastfreeze where the options are migration -- date of the migration for the current release freeze -- date of the freeze for the current release lastfreeze -- date of the freeze for the *previous* release The results will be in the form FIXED:foo:1234:the synopsis MAYBE:bar:1236:the synopsis Those marked as FIXED were closed before the migration into the new release. Those marked as MAYBE were closed after migration, but before freeze; thus, the fix may or may not have made it into the current release. These need to be researched to find out if the changes, if any, were included. */ #include "gnats.h" #include "query.h" /* The name this program was run with. */ const char *program_name; /* If 1, print the name of each PR that we look at. */ int verbose; /* When we migrated, froze the migrated code, and finally, when we froze the last release. */ time_t migration, freeze, lastfreeze; struct option long_options[] = { {"database", 1, NULL, 'd'}, {"verbose", 0, NULL, 'v'}, {"version", 0, NULL, 'V'}, {"host", 1, NULL, 'H'}, {"port", 1, NULL, 'P'}, {"user", 1, NULL, 'u'}, {"passwd", 1, NULL, 'w'}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "getclose" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]... MIGRATION FREEZE LASTFREEZE\n", "Find PRs fixed in a particular release.\n\ MIGRATION -- date of the migration for the current release\n\ FREEZE -- date of the freeze for the current release\n\ LASTFREEZE -- date of the freeze for the previous release\n\ \n", "The results will be in the form\n\ FIXED:foo:1234:the synopsis\n\ MAYBE:bar:1236:the synopsis\n\ Those marked as FIXED were closed before the migration into the current\n\ release.\n\ Those marked as MAYBE were closed after migration, but before freeze; thus,\n\ the fix may or may not have made it into the current release. These need\n\ to be researched to find out if the changes, if any, were included.\n\ \n", "Connection options:\n\ -d --database=DATABASE use DATABASE\n\ -H --host=SERVER connect to SERVER\n\ -P --port=PORT connect to the port PORT\n\ -v --user=NETID use NETID as the username on the remote server\n\ -w --passwd=PASSWORD user's password\n\ \n", "Other options:\n\ -v --verbose print the name of each PR as it is checked\n\ -h --help display this help and exit\n\ -V --version output version information and exit\n", NULL}; static time_t got_closed (const char *p) { if (p != NULL) { const char *final1, *final2; char *c; /* Skip ahead to the last time it was closed. */ final1 = p; do { final2 = final1; final1 = strstr (final2, "-closed\n"); if (final1) final1 += 8; } while (final1); if (! final2) return (time_t)0; /* Grab the date, and return the time it represents. */ final1 = strstr (final2, "When: "); if (! final1) return (time_t)0; c = strchr (final1 + 6, '\n'); if (c) *c = '\0'; return get_date ((char *)(final1 + 6), NULL); } else { return 0; } } static void do_stat (PR *pr) { /* XXX ??? Check the final argument */ time_t closed = got_closed (field_value (pr, AUDIT_TRAIL (pr->database))); if (verbose) { fprintf (stderr, "Checking PR %s\n", field_value (pr, NUMBER (pr->database))); } /* We don't care about ones that had no closed status in its audit trail. */ if (!closed) return; if (verbose) { fprintf (stderr, "PR closed on date %d\n", (int)closed); } /* fixed in this release */ if ((closed > lastfreeze) && (closed < migration)) { printf ("FIXED:%s:%s:%s\n", field_value (pr, CATEGORY (pr->database)), field_value (pr, NUMBER (pr->database)), field_value (pr, SYNOPSIS (pr->database))); } /* maybe, maybe not */ else if ((closed >= migration) && (closed <= freeze)) { printf ("MAYBE:%s:%s:%s\n", field_value (pr, CATEGORY (pr->database)), field_value (pr, NUMBER (pr->database)), field_value (pr, SYNOPSIS (pr->database))); } } static void do_prlist (const DatabaseInfo database) { ErrorDesc err; PR *pr = getFirstPR (database, &err); if (pr == NULL) { client_print_errors (database, err); exit (1); } while (pr != NULL) { if (check_state_type (database, field_value (pr, STATE (pr->database)), "closed") && gnats_regcmp ("no", field_value (pr, CONFIDENTIAL (pr->database)), NULL) == 0) { if (fillInPR (pr, &err) == 0) { do_stat (pr); free_pr_contents (pr); } else { client_print_errors (database, err); fprintf (stderr, "Unable to read PR %s\n", field_value (pr, NUMBER (pr->database))); } } pr = getNextPR (pr); } } static void do_netprlist (void) { StringList *prs; const char *expr = "(! builtinfield:State[type] ~ \"closed\") & ([builtinfield:Confidential ~ \"no\")"; for (prs = clientGetPRList (expr); prs != NULL ; prs = prs->next) { PR *pr = clientReadPR (prs->name); if (pr != NULL) { do_stat (pr); free_pr (pr); } else { fprintf (stderr, "Unable to read PR %s\n", prs->name); } } } int failed_dates = 0; static time_t procdate (char *d) { time_t t; t = get_date (d, NULL); if (!t || t == -1) { fprintf (stderr, "%s: invalid date `%s'\n", program_name, d); failed_dates = 1; } return t; } int main (int argc, char **argv) { int optc; char *database_name = NULL; int networkmode = 0; char *hostname = NULL; int port = -1; char *user = NULL; char *passwd = NULL; program_name = basename (argv[0]); verbose = 0; while ((optc = getopt_long (argc, argv, "hvVd:H:P:u:w:", long_options, (int *) 0)) != EOF) { switch (optc) { case 'd': database_name = optarg; break; case 'V': version (PROGRAM_NAME); exit (0); break; case 'v': verbose = 1; break; case 'h': usage (USAGE, 0); break; case 'H': hostname = optarg; networkmode = 1; break; case 'P': port = atoi (optarg); networkmode = 1; break; case 'u': user = optarg; networkmode = 1; break; case 'w': passwd = optarg; networkmode = 1; break; default: usage (USAGE, 1); } } if (optind == argc || optind > 3) usage (USAGE, 1); migration = procdate (argv[optind++]); freeze = procdate (argv[optind++]); lastfreeze = procdate (argv[optind++]); if (failed_dates) exit (1); if (verbose) { fprintf (stderr, "Migration date: %d\n", (int) migration); fprintf (stderr, "Freeze date: %d\n", (int) freeze); fprintf (stderr, "Last freeze: %d\n", (int) lastfreeze); } if (! networkmode) { networkmode = gnatsdbHasNetconn (database_name); } if (! networkmode) { ErrorDesc err; DatabaseInfo database; database = init_gnats (program_name, database_name, &err); if (database == NULL) { client_print_errors (database, err); exit (1); } do_prlist (database); } else { ErrorDesc err; if (client_init_gnats (&err, user, passwd, hostname, port, database_name) != 0) { client_print_errors (NULL, err); exit (1); } do_netprlist (); } exit (0); } gnats-4.1.0/gnats/getdate.h0000644000175000017500000000242507005261441016266 0ustar chewiechewie00000000000000/* Copyright (C) 1995, 1997, 1998 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if HAVE_CONFIG_H # include #endif #ifndef PARAMS # if defined PROTOTYPES || (defined __STDC__ && __STDC__) # define PARAMS(Args) Args # else # define PARAMS(Args) () # endif #endif #ifdef vms # include # include #else # include # if TIME_WITH_SYS_TIME # include # include # else # if HAVE_SYS_TIME_H # include # else # include # endif # endif #endif /* defined (vms) */ time_t get_date PARAMS ((const char *p, const time_t *now)); gnats-4.1.0/gnats/getdate.y0000644000175000017500000006730607275333676016343 0ustar chewiechewie00000000000000%{ /* Parse a string into an internal time stamp. Copyright 1999, 2000 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Originally written by Steven M. Bellovin while at the University of North Carolina at Chapel Hill. Later tweaked by a couple of people on Usenet. Completely overhauled by Rich $alz and Jim Berets in August, 1990. Modified by Paul Eggert in August 1999 to do the right thing about local DST. Unlike previous versions, this version is reentrant. */ #ifdef HAVE_CONFIG_H # include # ifdef HAVE_ALLOCA_H # include # endif #endif /* Since the code of getdate.y is not included in the Emacs executable itself, there is no need to #define static in this file. Even if the code were included in the Emacs executable, it probably wouldn't do any harm to #undef it here; this will only cause problems if we try to write to a static variable, which I don't think this code needs to do. */ #ifdef emacs # undef static #endif #include #if HAVE_STDLIB_H # include /* for `free'; used by Bison 1.27 */ #endif #if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII) # define IN_CTYPE_DOMAIN(c) 1 #else # define IN_CTYPE_DOMAIN(c) isascii (c) #endif #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) #define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) #define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) /* ISDIGIT differs from ISDIGIT_LOCALE, as follows: - Its arg may be any int or unsigned int; it need not be an unsigned char. - It's guaranteed to evaluate its argument exactly once. - It's typically faster. Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless it's important to use the locale's definition of `digit' even when the host does not conform to Posix. */ #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) #if STDC_HEADERS || HAVE_STRING_H # include #endif #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ # define __attribute__(x) #endif #ifndef ATTRIBUTE_UNUSED # define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) #endif #define EPOCH_YEAR 1970 #define TM_YEAR_BASE 1900 #define HOUR(x) ((x) * 60) /* An integer value, and the number of digits in its textual representation. */ typedef struct { int value; int digits; } textint; /* An entry in the lexical lookup table. */ typedef struct { char const *name; int type; int value; } table; /* Meridian: am, pm, or 24-hour style. */ enum { MERam, MERpm, MER24 }; /* Information passed to and from the parser. */ typedef struct { /* The input string remaining to be parsed. */ const char *input; /* N, if this is the Nth Tuesday. */ int day_ordinal; /* Day of week; Sunday is 0. */ int day_number; /* tm_isdst flag for the local zone. */ int local_isdst; /* Time zone, in minutes east of UTC. */ int time_zone; /* Style used for time. */ int meridian; /* Gregorian year, month, day, hour, minutes, and seconds. */ textint year; int month; int day; int hour; int minutes; int seconds; /* Relative year, month, day, hour, minutes, and seconds. */ int rel_year; int rel_month; int rel_day; int rel_hour; int rel_minutes; int rel_seconds; /* Counts of nonterminals of various flavors parsed so far. */ int dates_seen; int days_seen; int local_zones_seen; int rels_seen; int times_seen; int zones_seen; /* Table of local time zone abbrevations, terminated by a null entry. */ table local_time_zone_table[3]; } parser_control; #define PC (* (parser_control *) parm) #define YYLEX_PARAM parm #define YYPARSE_PARAM parm static int yyerror (); static int yylex (); %} /* We want a reentrant parser. */ %pure_parser /* This grammar has 13 shift/reduce conflicts. */ %expect 13 %union { int intval; textint textintval; } %token tAGO tDST %token tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tLOCAL_ZONE tMERIDIAN %token tMINUTE_UNIT tMONTH tMONTH_UNIT tSEC_UNIT tYEAR_UNIT tZONE %token tSNUMBER tUNUMBER %type o_merid %% spec: /* empty */ | spec item ; item: time { PC.times_seen++; } | local_zone { PC.local_zones_seen++; } | zone { PC.zones_seen++; } | date { PC.dates_seen++; } | day { PC.days_seen++; } | rel { PC.rels_seen++; } | number ; time: tUNUMBER tMERIDIAN { PC.hour = $1.value; PC.minutes = 0; PC.seconds = 0; PC.meridian = $2; } | tUNUMBER ':' tUNUMBER o_merid { PC.hour = $1.value; PC.minutes = $3.value; PC.seconds = 0; PC.meridian = $4; } | tUNUMBER ':' tUNUMBER tSNUMBER { PC.hour = $1.value; PC.minutes = $3.value; PC.meridian = MER24; PC.zones_seen++; PC.time_zone = $4.value % 100 + ($4.value / 100) * 60; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { PC.hour = $1.value; PC.minutes = $3.value; PC.seconds = $5.value; PC.meridian = $6; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { PC.hour = $1.value; PC.minutes = $3.value; PC.seconds = $5.value; PC.meridian = MER24; PC.zones_seen++; PC.time_zone = $6.value % 100 + ($6.value / 100) * 60; } ; local_zone: tLOCAL_ZONE { PC.local_isdst = $1; } | tLOCAL_ZONE tDST { PC.local_isdst = $1 < 0 ? 1 : $1 + 1; } ; zone: tZONE { PC.time_zone = $1; } | tDAYZONE { PC.time_zone = $1 + 60; } | tZONE tDST { PC.time_zone = $1 + 60; } ; day: tDAY { PC.day_ordinal = 1; PC.day_number = $1; } | tDAY ',' { PC.day_ordinal = 1; PC.day_number = $1; } | tUNUMBER tDAY { PC.day_ordinal = $1.value; PC.day_number = $2; } ; date: tUNUMBER '/' tUNUMBER { PC.month = $1.value; PC.day = $3.value; } | tUNUMBER '/' tUNUMBER '/' tUNUMBER { /* Interpret as YYYY/MM/DD if the first value has 4 or more digits, otherwise as MM/DD/YY. The goal in recognizing YYYY/MM/DD is solely to support legacy machine-generated dates like those in an RCS log listing. If you want portability, use the ISO 8601 format. */ if (4 <= $1.digits) { PC.year = $1; PC.month = $3.value; PC.day = $5.value; } else { PC.month = $1.value; PC.day = $3.value; PC.year = $5; } } | tUNUMBER tSNUMBER tSNUMBER { /* ISO 8601 format. YYYY-MM-DD. */ PC.year = $1; PC.month = -$2.value; PC.day = -$3.value; } | tUNUMBER tMONTH tSNUMBER { /* e.g. 17-JUN-1992. */ PC.day = $1.value; PC.month = $2; PC.year.value = -$3.value; PC.year.digits = $3.digits; } | tMONTH tUNUMBER { PC.month = $1; PC.day = $2.value; } | tMONTH tUNUMBER ',' tUNUMBER { PC.month = $1; PC.day = $2.value; PC.year = $4; } | tUNUMBER tMONTH { PC.day = $1.value; PC.month = $2; } | tUNUMBER tMONTH tUNUMBER { PC.day = $1.value; PC.month = $2; PC.year = $3; } ; rel: relunit tAGO { PC.rel_seconds = -PC.rel_seconds; PC.rel_minutes = -PC.rel_minutes; PC.rel_hour = -PC.rel_hour; PC.rel_day = -PC.rel_day; PC.rel_month = -PC.rel_month; PC.rel_year = -PC.rel_year; } | relunit ; relunit: tUNUMBER tYEAR_UNIT { PC.rel_year += $1.value * $2; } | tSNUMBER tYEAR_UNIT { PC.rel_year += $1.value * $2; } | tYEAR_UNIT { PC.rel_year += $1; } | tUNUMBER tMONTH_UNIT { PC.rel_month += $1.value * $2; } | tSNUMBER tMONTH_UNIT { PC.rel_month += $1.value * $2; } | tMONTH_UNIT { PC.rel_month += $1; } | tUNUMBER tDAY_UNIT { PC.rel_day += $1.value * $2; } | tSNUMBER tDAY_UNIT { PC.rel_day += $1.value * $2; } | tDAY_UNIT { PC.rel_day += $1 } | tUNUMBER tHOUR_UNIT { PC.rel_hour += $1.value * $2; } | tSNUMBER tHOUR_UNIT { PC.rel_hour += $1.value * $2; } | tHOUR_UNIT { PC.rel_hour += $1 } | tUNUMBER tMINUTE_UNIT { PC.rel_minutes += $1.value * $2; } | tSNUMBER tMINUTE_UNIT { PC.rel_minutes += $1.value * $2; } | tMINUTE_UNIT { PC.rel_minutes += $1 } | tUNUMBER tSEC_UNIT { PC.rel_seconds += $1.value * $2; } | tSNUMBER tSEC_UNIT { PC.rel_seconds += $1.value * $2; } | tSEC_UNIT { PC.rel_seconds += $1; } ; number: tUNUMBER { if (PC.dates_seen && ! PC.rels_seen && (PC.times_seen || 2 < $1.digits)) PC.year = $1; else { if (4 < $1.digits) { PC.dates_seen++; PC.day = $1.value % 100; PC.month = ($1.value / 100) % 100; PC.year.value = $1.value / 10000; PC.year.digits = $1.digits - 4; } else { PC.times_seen++; if ($1.digits <= 2) { PC.hour = $1.value; PC.minutes = 0; } else { PC.hour = $1.value / 100; PC.minutes = $1.value % 100; } PC.seconds = 0; PC.meridian = MER24; } } } ; o_merid: /* empty */ { $$ = MER24; } | tMERIDIAN { $$ = $1; } ; %% /* Include this file down here because bison inserts code above which may define-away `const'. We want the prototype for get_date to have the same signature as the function definition. */ #include "getdate.h" #ifndef gmtime struct tm *gmtime (); #endif #ifndef localtime struct tm *localtime (); #endif #ifndef mktime time_t mktime (); #endif static table const meridian_table[] = { { "AM", tMERIDIAN, MERam }, { "A.M.", tMERIDIAN, MERam }, { "PM", tMERIDIAN, MERpm }, { "P.M.", tMERIDIAN, MERpm }, { 0, 0, 0 } }; static table const dst_table[] = { { "DST", tDST, 0 } }; static table const month_and_day_table[] = { { "JANUARY", tMONTH, 1 }, { "FEBRUARY", tMONTH, 2 }, { "MARCH", tMONTH, 3 }, { "APRIL", tMONTH, 4 }, { "MAY", tMONTH, 5 }, { "JUNE", tMONTH, 6 }, { "JULY", tMONTH, 7 }, { "AUGUST", tMONTH, 8 }, { "SEPTEMBER",tMONTH, 9 }, { "SEPT", tMONTH, 9 }, { "OCTOBER", tMONTH, 10 }, { "NOVEMBER", tMONTH, 11 }, { "DECEMBER", tMONTH, 12 }, { "SUNDAY", tDAY, 0 }, { "MONDAY", tDAY, 1 }, { "TUESDAY", tDAY, 2 }, { "TUES", tDAY, 2 }, { "WEDNESDAY",tDAY, 3 }, { "WEDNES", tDAY, 3 }, { "THURSDAY", tDAY, 4 }, { "THUR", tDAY, 4 }, { "THURS", tDAY, 4 }, { "FRIDAY", tDAY, 5 }, { "SATURDAY", tDAY, 6 }, { 0, 0, 0 } }; static table const time_units_table[] = { { "YEAR", tYEAR_UNIT, 1 }, { "MONTH", tMONTH_UNIT, 1 }, { "FORTNIGHT",tDAY_UNIT, 14 }, { "WEEK", tDAY_UNIT, 7 }, { "DAY", tDAY_UNIT, 1 }, { "HOUR", tHOUR_UNIT, 1 }, { "MINUTE", tMINUTE_UNIT, 1 }, { "MIN", tMINUTE_UNIT, 1 }, { "SECOND", tSEC_UNIT, 1 }, { "SEC", tSEC_UNIT, 1 }, { 0, 0, 0 } }; /* Assorted relative-time words. */ static table const relative_time_table[] = { { "TOMORROW", tMINUTE_UNIT, 24 * 60 }, { "YESTERDAY",tMINUTE_UNIT, - (24 * 60) }, { "TODAY", tMINUTE_UNIT, 0 }, { "NOW", tMINUTE_UNIT, 0 }, { "LAST", tUNUMBER, -1 }, { "THIS", tUNUMBER, 0 }, { "NEXT", tUNUMBER, 1 }, { "FIRST", tUNUMBER, 1 }, /*{ "SECOND", tUNUMBER, 2 }, */ { "THIRD", tUNUMBER, 3 }, { "FOURTH", tUNUMBER, 4 }, { "FIFTH", tUNUMBER, 5 }, { "SIXTH", tUNUMBER, 6 }, { "SEVENTH", tUNUMBER, 7 }, { "EIGHTH", tUNUMBER, 8 }, { "NINTH", tUNUMBER, 9 }, { "TENTH", tUNUMBER, 10 }, { "ELEVENTH", tUNUMBER, 11 }, { "TWELFTH", tUNUMBER, 12 }, { "AGO", tAGO, 1 }, { 0, 0, 0 } }; /* The time zone table. This table is necessarily incomplete, as time zone abbreviations are ambiguous; e.g. Australians interpret "EST" as Eastern time in Australia, not as US Eastern Standard Time. You cannot rely on getdate to handle arbitrary time zone abbreviations; use numeric abbreviations like `-0500' instead. */ static table const time_zone_table[] = { { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ { "UTC", tZONE, HOUR ( 0) }, { "WET", tZONE, HOUR ( 0) }, /* Western European */ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */ { "CET", tZONE, HOUR ( 1) }, /* Central European */ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */ { "MET", tZONE, HOUR ( 1) }, /* Middle European */ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */ { "GST", tZONE, HOUR (10) }, /* Guam Standard */ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */ { 0, 0, 0 } }; /* Military time zone table. */ static table const military_table[] = { { "A", tZONE, -HOUR ( 1) }, { "B", tZONE, -HOUR ( 2) }, { "C", tZONE, -HOUR ( 3) }, { "D", tZONE, -HOUR ( 4) }, { "E", tZONE, -HOUR ( 5) }, { "F", tZONE, -HOUR ( 6) }, { "G", tZONE, -HOUR ( 7) }, { "H", tZONE, -HOUR ( 8) }, { "I", tZONE, -HOUR ( 9) }, { "K", tZONE, -HOUR (10) }, { "L", tZONE, -HOUR (11) }, { "M", tZONE, -HOUR (12) }, { "N", tZONE, HOUR ( 1) }, { "O", tZONE, HOUR ( 2) }, { "P", tZONE, HOUR ( 3) }, { "Q", tZONE, HOUR ( 4) }, { "R", tZONE, HOUR ( 5) }, { "S", tZONE, HOUR ( 6) }, { "T", tZONE, HOUR ( 7) }, { "U", tZONE, HOUR ( 8) }, { "V", tZONE, HOUR ( 9) }, { "W", tZONE, HOUR (10) }, { "X", tZONE, HOUR (11) }, { "Y", tZONE, HOUR (12) }, { "Z", tZONE, HOUR ( 0) }, { 0, 0, 0 } }; static int to_hour (int hours, int meridian) { switch (meridian) { case MER24: return 0 <= hours && hours < 24 ? hours : -1; case MERam: return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1; case MERpm: return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1; default: abort (); } /* NOTREACHED */ } static int to_year (textint textyear) { int year = textyear.value; if (year < 0) year = -year; /* XPG4 suggests that years 00-68 map to 2000-2068, and years 69-99 map to 1969-1999. */ if (textyear.digits == 2) year += year < 69 ? 2000 : 1900; return year; } static table const * lookup_zone (parser_control const *pc, char const *name) { table const *tp; /* Try local zone abbreviations first; they're more likely to be right. */ for (tp = pc->local_time_zone_table; tp->name; tp++) if (strcmp (name, tp->name) == 0) return tp; for (tp = time_zone_table; tp->name; tp++) if (strcmp (name, tp->name) == 0) return tp; return 0; } #if ! HAVE_TM_GMTOFF /* Yield the difference between *A and *B, measured in seconds, ignoring leap seconds. The body of this function is taken directly from the GNU C Library; see src/strftime.c. */ static int tm_diff (struct tm const *a, struct tm const *b) { /* Compute intervening leap days correctly even if year is negative. Take care to avoid int overflow in leap day calculations, but it's OK to assume that A and B are close to each other. */ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3); int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3); int a100 = a4 / 25 - (a4 % 25 < 0); int b100 = b4 / 25 - (b4 % 25 < 0); int a400 = a100 >> 2; int b400 = b100 >> 2; int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); int years = a->tm_year - b->tm_year; int days = (365 * years + intervening_leap_days + (a->tm_yday - b->tm_yday)); return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec)); } #endif /* ! HAVE_TM_GMTOFF */ static table const * lookup_word (parser_control const *pc, char *word) { char *p; char *q; size_t wordlen; table const *tp; int i; int abbrev; /* Make it uppercase. */ for (p = word; *p; p++) if (ISLOWER ((unsigned char) *p)) *p = toupper ((unsigned char) *p); for (tp = meridian_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* See if we have an abbreviation for a month. */ wordlen = strlen (word); abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.'); for (tp = month_and_day_table; tp->name; tp++) if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0) return tp; if ((tp = lookup_zone (pc, word))) return tp; if (strcmp (word, dst_table[0].name) == 0) return dst_table; for (tp = time_units_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* Strip off any plural and try the units table again. */ if (word[wordlen - 1] == 'S') { word[wordlen - 1] = '\0'; for (tp = time_units_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */ } for (tp = relative_time_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* Military time zones. */ if (wordlen == 1) for (tp = military_table; tp->name; tp++) if (word[0] == tp->name[0]) return tp; /* Drop out any periods and try the time zone table again. */ for (i = 0, p = q = word; (*p = *q); q++) if (*q == '.') i = 1; else p++; if (i && (tp = lookup_zone (pc, word))) return tp; return 0; } static int yylex (YYSTYPE *lvalp, parser_control *pc) { unsigned char c; int count; for (;;) { while (c = *pc->input, ISSPACE (c)) pc->input++; if (ISDIGIT (c) || c == '-' || c == '+') { char const *p; int sign; int value; if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; c = *++pc->input; if (! ISDIGIT (c)) /* skip the '-' sign */ continue; } else sign = 0; p = pc->input; value = 0; do { value = 10 * value + c - '0'; c = *++p; } while (ISDIGIT (c)); lvalp->textintval.value = sign < 0 ? -value : value; lvalp->textintval.digits = p - pc->input; pc->input = p; return sign ? tSNUMBER : tUNUMBER; } if (ISALPHA (c)) { char buff[20]; char *p = buff; table const *tp; do { if (p < buff + sizeof buff - 1) *p++ = c; c = *++pc->input; } while (ISALPHA (c) || c == '.'); *p = '\0'; tp = lookup_word (pc, buff); if (! tp) return '?'; lvalp->intval = tp->value; return tp->type; } if (c != '(') return *pc->input++; count = 0; do { c = *pc->input++; if (c == '\0') return c; if (c == '(') count++; else if (c == ')') count--; } while (count > 0); } } /* Do nothing if the parser reports an error. */ static int yyerror (char *s ATTRIBUTE_UNUSED) { return 0; } /* Parse a date/time string P. Return the corresponding time_t value, or (time_t) -1 if there is an error. P can be an incomplete or relative time specification; if so, use *NOW as the basis for the returned time. */ time_t get_date (const char *p, const time_t *now) { time_t Start = now ? *now : time (0); struct tm *tmp = localtime (&Start); struct tm tm; struct tm tm0; parser_control pc; if (! tmp) return -1; pc.input = p; pc.year.value = tmp->tm_year + TM_YEAR_BASE; pc.year.digits = 4; pc.month = tmp->tm_mon + 1; pc.day = tmp->tm_mday; pc.hour = tmp->tm_hour; pc.minutes = tmp->tm_min; pc.seconds = tmp->tm_sec; tm.tm_isdst = tmp->tm_isdst; pc.meridian = MER24; pc.rel_seconds = 0; pc.rel_minutes = 0; pc.rel_hour = 0; pc.rel_day = 0; pc.rel_month = 0; pc.rel_year = 0; pc.dates_seen = 0; pc.days_seen = 0; pc.rels_seen = 0; pc.times_seen = 0; pc.local_zones_seen = 0; pc.zones_seen = 0; #if HAVE_TM_ZONE pc.local_time_zone_table[0].name = tmp->tm_zone; pc.local_time_zone_table[0].type = tLOCAL_ZONE; pc.local_time_zone_table[0].value = tmp->tm_isdst; pc.local_time_zone_table[1].name = 0; /* Probe the names used in the next three calendar quarters, looking for a tm_isdst different from the one we already have. */ { int quarter; for (quarter = 1; quarter <= 3; quarter++) { time_t probe = Start + quarter * (90 * 24 * 60 * 60); struct tm *probe_tm = localtime (&probe); if (probe_tm && probe_tm->tm_zone && probe_tm->tm_isdst != pc.local_time_zone_table[0].value) { { pc.local_time_zone_table[1].name = probe_tm->tm_zone; pc.local_time_zone_table[1].type = tLOCAL_ZONE; pc.local_time_zone_table[1].value = probe_tm->tm_isdst; pc.local_time_zone_table[2].name = 0; } break; } } } #else #if HAVE_TZNAME { # ifndef tzname extern char *tzname[]; # endif int i; for (i = 0; i < 2; i++) { pc.local_time_zone_table[i].name = tzname[i]; pc.local_time_zone_table[i].type = tLOCAL_ZONE; pc.local_time_zone_table[i].value = i; } pc.local_time_zone_table[i].name = 0; } #else pc.local_time_zone_table[0].name = 0; #endif #endif if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name && ! strcmp (pc.local_time_zone_table[0].name, pc.local_time_zone_table[1].name)) { /* This locale uses the same abbrevation for standard and daylight times. So if we see that abbreviation, we don't know whether it's daylight time. */ pc.local_time_zone_table[0].value = -1; pc.local_time_zone_table[1].name = 0; } if (yyparse (&pc) != 0 || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen || 1 < (pc.local_zones_seen + pc.zones_seen) || (pc.local_zones_seen && 1 < pc.local_isdst)) return -1; tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year; tm.tm_mon = pc.month - 1 + pc.rel_month; tm.tm_mday = pc.day + pc.rel_day; if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen)) { tm.tm_hour = to_hour (pc.hour, pc.meridian); if (tm.tm_hour < 0) return -1; tm.tm_min = pc.minutes; tm.tm_sec = pc.seconds; } else { tm.tm_hour = tm.tm_min = tm.tm_sec = 0; } /* Let mktime deduce tm_isdst if we have an absolute time stamp, or if the relative time stamp mentions days, months, or years. */ if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day | pc.rel_month | pc.rel_year) tm.tm_isdst = -1; /* But if the input explicitly specifies local time with or without DST, give mktime that information. */ if (pc.local_zones_seen) tm.tm_isdst = pc.local_isdst; tm0 = tm; Start = mktime (&tm); if (Start == (time_t) -1) { /* Guard against falsely reporting errors near the time_t boundaries when parsing times in other time zones. For example, if the min time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead of UTC, then the min localtime value is 1970-01-01 08:00:00; if we apply mktime to 1970-01-01 00:00:00 we will get an error, so we apply mktime to 1970-01-02 08:00:00 instead and adjust the time zone by 24 hours to compensate. This algorithm assumes that there is no DST transition within a day of the time_t boundaries. */ if (pc.zones_seen) { tm = tm0; if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE) { tm.tm_mday++; pc.time_zone += 24 * 60; } else { tm.tm_mday--; pc.time_zone -= 24 * 60; } Start = mktime (&tm); } if (Start == (time_t) -1) return Start; } if (pc.days_seen && ! pc.dates_seen) { tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7 + 7 * (pc.day_ordinal - (0 < pc.day_ordinal))); Start = mktime (&tm); if (Start == (time_t) -1) return Start; } if (pc.zones_seen) { int delta = pc.time_zone * 60; #ifdef HAVE_TM_GMTOFF delta -= tm.tm_gmtoff; #else struct tm *gmt = gmtime (&Start); if (! gmt) return -1; delta -= tm_diff (&tm, gmt); #endif if ((Start < Start - delta) != (delta < 0)) return -1; /* time_t overflow */ Start -= delta; } /* Add relative hours, minutes, and seconds. Ignore leap seconds; i.e. "+ 10 minutes" means 600 seconds, even if one of them is a leap second. Typically this is not what the user wants, but it's too hard to do it the other way, because the time zone indicator must be applied before relative times, and if mktime is applied again the time zone will be lost. */ { time_t t0 = Start; long d1 = 60 * 60 * (long) pc.rel_hour; time_t t1 = t0 + d1; long d2 = 60 * (long) pc.rel_minutes; time_t t2 = t1 + d2; int d3 = pc.rel_seconds; time_t t3 = t2 + d3; if ((d1 / (60 * 60) ^ pc.rel_hour) | (d2 / 60 ^ pc.rel_minutes) | ((t0 + d1 < t0) ^ (d1 < 0)) | ((t1 + d2 < t1) ^ (d2 < 0)) | ((t2 + d3 < t2) ^ (d3 < 0))) return -1; Start = t3; } return Start; } #if TEST #include int main (int ac, char **av) { char buff[BUFSIZ]; time_t d; printf ("Enter date, or blank line to exit.\n\t> "); fflush (stdout); buff[BUFSIZ - 1] = 0; while (fgets (buff, BUFSIZ - 1, stdin) && buff[0]) { d = get_date (buff, 0); if (d == (time_t) -1) printf ("Bad format - couldn't convert.\n"); else printf ("%s", ctime (&d)); printf ("\t> "); fflush (stdout); } return 0; } #endif /* defined TEST */ gnats-4.1.0/gnats/gnats-databases.in0000644000175000017500000000125707034727321020101 0ustar chewiechewie00000000000000# This file contains a list of databases in the form # name:description:topleveldir # # NAME is the name used to access the database. # # DESCRIPTION is an (optional) human-readable description of the contents. # # TOPLEVELDIR is the top-level directory where the database is located. # It must contain a gnats-adm directory with the database configuration # file, and one or more directories containing PRs. # # The clients use the GNATSDB environment variable to determine the default # name of the database to use; for most clients this may be overridden with # a "-d databasename" command-line option. # # default is the default database. default:Bug database:xGNATS_DEFAULT_DB_DIRx gnats-4.1.0/gnats/gnats-dirs.h0000644000175000017500000000215306620401142016716 0ustar chewiechewie00000000000000/* Things needed to read and use directories. Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #if HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif #endif gnats-4.1.0/gnats/gnats-pwconv.c0000644000175000017500000001631510153112451017267 0ustar chewiechewie00000000000000/* GNATS password conversion tool. Copyright (C) 2001, 2002 Free Software Foundation, Inc. This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #ifdef HAVE_LIBCRYPT #ifdef HAVE_CRYPT_H /* some systems declare `crypt' in unistd.h */ #include #endif #endif enum _Crypt_Type { NONE, PLAIN, CRYPT, MD5 }; typedef enum _Crypt_Type Crypt_Type; #define PROGRAM_NAME "gnats-pwconv" const char *program_name = PROGRAM_NAME; /* static const int MAXLINE = 1024; */ static const char* const VERSION = "1.0"; static const char* USAGE[] = { "Usage: " PROGRAM_NAME, #ifdef HAVE_LIBCRYPT " {-c | -m | -p} INFILE [OUTFILE]\n", #else " -p INFILE [OUTFILE]\n", #endif "Convert GNATS v3 gnatsd*.access passwords to version 4 format.\n", #ifdef HAVE_LIBCRYPT "Supports plaintext, DES crypt and MD5 output.\n", #else "Supports only unencrypted plaintext (compiled without `libcrypt').\n", #endif "\n", #ifdef HAVE_LIBCRYPT " -c --crypt Use crypt() encryption of passwords.\n\ -m --md5 Use MD5 encryption.\n", #endif " -p --plaintext Do not encrypt the passwords (plaintext).\n\ -h --help\n\ -V --version\n", NULL }; /* Print perror MESSAGE, processed through printf with a single argument ARG. */ static void perrorf (const char *message, char *arg) { char *formatted; if (asprintf (&formatted, message, arg) < 0) { perror ("System error"); exit (1); } perror (formatted); free (formatted); } /* Split LINE into its fields. Return true iff the operation was successful. Note: LINE is modified during the operation. */ static bool parse_entry (char *line, char **username, char **password, char **level, char **dbs) { int i; int length = strlen (line); char *separator; char **fields[4]; fields[0] = username; fields[1] = password; fields[2] = level; fields[3] = dbs; if (length && line[length-1] == '\n') { line[length-1] = '\0'; } *dbs = (char *)""; for (i = 0; (i < 4) && (separator = (char *)strchr (line, ':')) != NULL; i++) { *(fields[i]) = line; *separator = '\0'; line = separator + 1; } return i >= 3; } /* Encrypt CLEARPWSTRING by the encryption type CRYPTTYPE and store the result into NEWPWENTRY. Return 0 on success, 1 if MD5 encryption is requested and it is not supported by the system. */ static int encrypt_ (char *clearpwstring, Crypt_Type crypttype, char **newpwentry) { int result; #ifdef HAVE_LIBCRYPT unsigned long seed = random(); char salt[12]; char rawsalt[9]; const char *SEEDCHARS = "./0123456789ABCDEFGHIJKLMNOPQRST" "UVWXYZabcdefghijklmnopqrstuvwxyz"; const int SEEDCHARS_LEN = strlen (SEEDCHARS); int i; for (i = 0; i < 8; i++) { rawsalt[i] = SEEDCHARS[(seed/(i+1)) % SEEDCHARS_LEN]; } rawsalt[i] = '\0'; #endif switch (crypttype) { case PLAIN: result = asprintf (newpwentry, "$0$%s", clearpwstring); break; #ifdef HAVE_LIBCRYPT case CRYPT: strncpy (salt, rawsalt, 2); salt[2] = '\0'; result = asprintf (newpwentry, "%s", crypt (clearpwstring, salt)); break; case MD5: sprintf (salt, "$1$%s", rawsalt); result = asprintf (newpwentry, "%s", crypt (clearpwstring, salt)); break; #endif default: fprintf (stderr, "Program error\n"); exit (1); } if (result < 0) { fprintf (stderr, "Memory allocation error\n"); exit (1); } /* Are we on a system that supports MD5? */ return (crypttype == MD5 && strncmp ("$1$", *newpwentry, 3)) ? 1 : 0; } /* Convert password data in the file INFILE to the file OUTFILE. OUTFILE can be NULL, in which case the data is output to stdout. CRYPTTYPE is passed through to `encrypt_'. Return 0 on success, anything else otherwise. */ static int process_file (char *infile, char *outfile, int crypttype) { FILE *input; FILE *output; char *line; int i; if ((input = fopen (infile, "r")) == NULL) { perrorf ("Can't open the file `%s' for input", infile); return 1; } if (outfile == NULL) { output = stdout; } else if ((output = fopen (outfile, "w")) == NULL) { perrorf ("Can't open the file `%s' for output", outfile); return 1; } for (i = 1; (line = read_line (input, NULL)) != NULL; i++) { if (strncmp (line, "#", 1) == 0 || (strspn (line, " \t\r\n") == strlen (line))) { fprintf (output, "%s", line); } else { char *username, *password, *level, *dbs; char *newpwentry; if (parse_entry (line, &username, &password, &level, &dbs)) { if (encrypt_ (password, crypttype, &newpwentry) == 1) { fprintf (stderr, "Error: " "MD5 encryption not supported on this system.\n"); free (line); free (newpwentry); return 1; } fprintf (output, "%s:%s:%s:%s\n", username, newpwentry, level, dbs); free (newpwentry); } else { fprintf (stderr, "Error: Unable to decode line %d of the file `%s'.\n", i, infile); free (line); return 1; } free (line); } } fclose(input); fclose(output); return 0; } int main (int argc, char **argv) { #ifdef HAVE_LIBCRYPT static const char* const OPTSTRING = "pcmVh"; #else static const char* const OPTSTRING = "pVh"; #endif int optc = 0; int opt_index = 0; Crypt_Type crypttype = NONE; char *infile = NULL; char *outfile = NULL; struct option LONG_OPTIONS[] = { {"plaintext", no_argument, NULL, 'p'}, #ifdef HAVE_LIBCRYPT {"crypt", no_argument, NULL, 'c'}, {"md5", no_argument, NULL, 'm'}, #endif {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; while ((optc = getopt_long (argc, argv, OPTSTRING, LONG_OPTIONS, &opt_index)) != -1) { switch (optc) { case 'p': if (crypttype != NONE) usage (USAGE, 1); crypttype = PLAIN; break; case 'c': if (crypttype != NONE) usage (USAGE, 1); crypttype = CRYPT; break; case 'm': if (crypttype != NONE) usage (USAGE, 1); crypttype = MD5; break; case 'V': printf ("%s %s\n", PROGRAM_NAME, VERSION); exit (0); break; case 'h': usage (USAGE, 0); break; default: usage (USAGE, 1); } } if ((crypttype == NONE) || (optind >= argc)) usage (USAGE, 1); infile = argv[optind++]; if (optind < argc) { outfile = argv[optind]; } srandom (time (NULL)); return process_file (infile, outfile, crypttype); } gnats-4.1.0/gnats/gnats.el0000644000175000017500000017247107523260555016161 0ustar chewiechewie00000000000000;;; gnats.el --- Emacs interface for GNATS. ;; Copyright (C) 2000, 2001, 2002 Milan Zamazal ;; Copyright (C) 2000 Bob Manson ;; ;; Contributed by Bob Manson (manson@juniper.net) ;; entirely written from scratch. ;; Further improved by Milan Zamazal . ;; ;; This file is part of GNU GNATS. ;; ;; GNU GNATS 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. ;; ;; GNU GNATS is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU GNATS; see the file COPYING. If not, write to ;; the Free Software Foundation, 59 Temple Place - Suite 330, ;; Boston, MA 02111, USA. ;;; Commentary: ;; ;; This file is still woefully incomplete; it seems to work for me, ;; however. ;;; Code: (defgroup gnats nil "The GNU GNATS bug tracking system frontend.") (defcustom gnats-server nil "*Server name or address to connect to. If it is nil, the value from the GNATSDB environment variable is used. If the environment variable is unset, \"localhost\" is used." :group 'gnats :type '(choice (const nil) string)) (defcustom gnats-port nil "*Server port to connect to as an integer or nil. If it is nil, the value from the GNATSDB environment variable is used. If the environment variable is unset, 1529 is used." :group 'gnats :type '(choice (const nil) integer)) (defcustom gnats-database nil "*Name of the database to work with. If it is nil, the value from the GNATSDB environment variable is used. If the environment variable is unset, \"default\" is used." :group 'gnats :type '(choice (const nil) string)) (defcustom gnats-user nil "*User name to use when connecting to the server. If it is nil, the value from the GNATSDB environment variable is used. If the environment variable is unset, (user-login-name) is used." :group 'gnats :type '(choice (const nil) string)) (defcustom gnats-password nil "*Password to use when connecting to the server. If it is nil, the value from the GNATSDB environment variable is used. If the environment variable is unset, \"*\" is used." :group 'gnats :type '(choice (const nil) string)) (defcustom gnats-default-organization "" "*Default value of the `Organization' field when sending new PRs." :group 'gnats :type 'string) (defcustom gnats-default-submitter "" "*Default value of the `Submitter-Id' field when sending new PRs." :group 'gnats :type 'string) (defcustom gnats-query-reverse-listing nil "*If non-nil, list query results from the highest PR number to the lowest." :group 'gnats :type 'boolean) (defvar gnats-server-conn nil "The per-buffer connection descriptor for gnats edit mode.") (make-variable-buffer-local 'gnats-server-conn) (put 'gnats-server-conn 'permanent-local t) (defvar gnats-edit-mode-map '() "Keymap for GNATS edit mode. Most keys are rebound; the buffer is read-only so that only gnats-specific; functions can modify it.") (unless gnats-edit-mode-map (setq gnats-edit-mode-map (make-keymap)) (substitute-key-definition 'newline 'gnats-end-line gnats-edit-mode-map global-map) (substitute-key-definition 'newline-and-indent 'gnats-end-line gnats-edit-mode-map global-map) (substitute-key-definition 'delete-backward-char 'gnats-delete-backward-char gnats-edit-mode-map global-map) (substitute-key-definition 'delete-char 'gnats-delete-char gnats-edit-mode-map global-map) (substitute-key-definition 'open-line 'gnats-open-line gnats-edit-mode-map global-map) (substitute-key-definition 'kill-line 'gnats-kill-line gnats-edit-mode-map global-map) (substitute-key-definition 'advertised-undo 'gnats-advertised-undo gnats-edit-mode-map global-map) (substitute-key-definition 'indent-for-tab-command 'gnats-insert-char gnats-edit-mode-map global-map) (substitute-key-definition 'self-insert-command 'gnats-insert-char gnats-edit-mode-map global-map) (define-key gnats-edit-mode-map "\C-c\C-c" 'gnats-apply-or-submit) (define-key gnats-edit-mode-map "\t" 'gnats-next-field) (define-key gnats-edit-mode-map "\e\t" 'gnats-previous-field)) (easy-menu-define gnats-edit-mode-menu gnats-edit-mode-map "Menu for editing GNATS problem reports." '("Gnats" ["Submit changes" gnats-apply-or-submit :active (let ((field-list (get gnats-server-conn 'field-list)) (foundp nil)) (while (and (not foundp) field-list) (when (gnats-field-edited-p (car field-list)) (setq foundp t)) (setq field-list (cdr field-list))) foundp) :help "Submit changes to edited fields"] ["Next field" gnats-next-field :help "Go to the next field"] ["Previous field" gnats-previous-field :help "Go to the previous field"])) (defvar gnats-edit-button-map '() "Keymap for enumerated field editting buttons.") (unless gnats-edit-button-map (setq gnats-edit-button-map (copy-keymap gnats-edit-mode-map)) (define-key gnats-edit-button-map [down-mouse-2] 'gnats-mouse-request-enum) (define-key gnats-edit-button-map [mouse-2] (lambda () (interactive)))) (defun gnats-delete-process () (let ((process (get gnats-server-conn 'process)) (buffer (get gnats-server-conn 'server-buffer))) (when process (delete-process process)) (when buffer (kill-buffer buffer)))) (add-hook 'kill-buffer-hook 'gnats-delete-process) (defun gnats-gen-completion-list (field) "Generate a completion collection from the legal values for FIELD." (mapcar '(lambda (x) (list x x)) (get field 'valid-values))) (defun gnats-get-field-value (field) "Return the current value of FIELD from the buffer." (let* ((curr-point (gnats-find-field-text field)) (field-type (get field 'type)) (start (gnats-find-field-start field curr-point)) (end (next-single-property-change curr-point 'gnats-field-name))) ;; Don't want the trailing newline. (setq end (if end (- end 1) (point-max))) ;; Don't include the leading newline on a multitext field. (if (eq field-type 'multitext) (setq start (+ start 1))) (buffer-substring-no-properties start end))) (defun gnats-advertised-undo (&optional count) "Undo, but disabling motion-hooks and read-only attributes. Do the undo COUNT times." (interactive "P") (let ((inhibit-read-only t) (inhibit-point-motion-hooks t)) (advertised-undo count))) (defun gnats-mark-field-edited (field) "Mark FIELD as having been edited. Insert a Reason-Changed-Why field as needed." (put field 'was-edited t) (if (and (not (get field 'has-changed-why)) (get field 'requires-changed-why)) (let ((field-type (get field 'type)) (end-of-curr-field)) (if (eq (get-text-property (point) 'gnats-field-name) field) (setq end-of-curr-field (next-single-property-change (point) 'gnats-field-name)) (setq end-of-curr-field (point))) (gnats-run-modify-command (let ((field-changed (gnats-gen-changed-why field))) (goto-char end-of-curr-field) (gnats-insert-label field-changed nil nil) (gnats-insert-text field-changed "" nil) (put field 'has-changed-why t) (undo-boundary) ;; Wanna end up at the start of the to-be-entered text for ;; the foo-Changed-Why field. (goto-char (- (point) 1))))))) (defun gnats-find-field-start (field curr-point) "Find the start of the field contents for FIELD. CURR-POINT must be a point within the field contents." (or (if (eq (get-text-property (- curr-point 1) 'gnats-field-name) field) (previous-single-property-change curr-point 'gnats-field-name)) curr-point)) (defun gnats-replace-curr-text (field new-text) "Replace FIELD's text in the edit buffer with NEW-TEXT." (let* ((curr-point (point)) (start (gnats-find-field-start field curr-point)) (end (next-single-property-change curr-point 'gnats-field-name)) (inhibit-read-only t) (inhibit-point-motion-hooks t)) (delete-region start end) ;; Make the undo atomic. (if (and (listp buffer-undo-list) (null (car buffer-undo-list))) (setq buffer-undo-list (cdr buffer-undo-list))) (goto-char start) (gnats-insert-text field new-text t (list 'read-only t 'mouse-face 'highlight 'local-map gnats-edit-button-map)))) (defun gnats-delete-field (field) "Remove FIELD entirely from the PR. Point is assumed to be somewhere before the start of the field." (let ((field-data-start (gnats-find-field-text field))) ;; Did we find the field contents? (if field-data-start (let* ((start (or (previous-single-property-change (- field-data-start 1) 'gnats-field-name) (point-min))) (end (or (next-single-property-change field-data-start 'gnats-field-name) (point-max)))) (gnats-run-modify-command (delete-region start end)) (gnats-clear-field-contents field))))) (defun gnats-reset-value (field) "Reset FIELD to its original value. Also deletes an associated -Changed-Why field, if one was added." (when (get field 'has-changed-why) (gnats-delete-field (gnats-gen-changed-why field)) (put field 'has-changed-why nil)) (gnats-replace-curr-text field (get field 'value)) (put field 'was-edited nil)) (defun gnats-cycle-enum-value (field) "Replace the current enum FIELD's value in the buffer with the next value." (let* ((old-value (gnats-get-field-value field)) (valid-values (get field 'valid-values)) (values valid-values) v new-value) (while values (when (and (string= (car values) old-value) (cdr values)) (setq new-value (cadr values)) (setq values nil)) (setq values (cdr values))) (unless new-value (setq new-value (car valid-values))) (unless (string= new-value old-value) (undo-boundary) (if (and (get field 'has-changed-why) (string= (get field 'value) old-value)) (put field 'has-changed-why nil)) (save-excursion (if (string= (get field 'value) new-value) (gnats-reset-value field) (gnats-replace-curr-text field new-value) (gnats-mark-field-edited field)))))) (defun gnats-mouse-request-enum (e) "Ask the user for an enumerated value for FIELD and change the field value. Use an X menu for the value selection." (interactive "e") (mouse-set-point e) (sit-for 0) (gnats-request-enum (get-text-property (point) 'gnats-field-name) e)) (defun gnats-request-enum (field &optional menup no-default) "Ask the user for an enumerated value for FIELD and change the field value. If MENUP is non-nil, use an X menu for the selection. If NO-DEFAULT is non-nil, do not insert a suggested default value into minibuffer." (let* ((completions (gnats-gen-completion-list field)) (old-value (gnats-get-field-value field)) (new-value (if menup (x-popup-menu t (list (concat "New value for " (get field 'field-name) ":") (cons "" (mapcar (lambda (x) (cons (car x) (cadr x))) completions)))) (completing-read (concat "New value for " (get field 'field-name) ": ") completions nil t (cond (no-default "") ((integerp last-nonmenu-event) (let ((c completions) (default nil)) (while (and (not default) c) (if (eq (string-to-char (caar c)) last-nonmenu-event) (setq default (caar c)) (setq c (cdr c)))) (or default old-value))) (t old-value)))))) (when (and new-value (not (string= new-value old-value))) (undo-boundary) (if (and (get field 'has-changed-why) (string= (get field 'value) old-value)) (put field 'has-changed-why nil)) (if (string= (get field 'value) new-value) (gnats-reset-value field) (gnats-replace-curr-text field new-value) (or (gnats-mark-field-edited field) (goto-char (gnats-find-next-field))))))) (defun gnats-find-next-field () "Return the position of the next field, or (point-max)." (let ((pos (text-property-any (point) (point-max) 'gnats-field-name nil))) (if pos (setq pos (next-single-property-change pos 'gnats-field-name))) (or (gnats-find-field-adjust pos) (point-max)))) (defun gnats-find-previous-field () "Return the position of the previous field, or (point-min)." (let ((pos (let ((field-name (get-text-property (point) 'gnats-field-name))) (if field-name (previous-single-property-change (gnats-find-field-start field-name (point)) 'gnats-field-name) (point))))) (if pos (setq pos (previous-single-property-change pos 'gnats-field-name))) (or (gnats-find-field-adjust pos) (point-min)))) (defun gnats-find-field-adjust (pos) "Return the first editing position of the field at POS. If POS is nil, return nil." (when pos (save-excursion (goto-char pos) (let ((field-name (get-text-property (point) 'gnats-field-name))) (and field-name (eq (get field-name 'type) 'multitext) (eolp) (beginning-of-line 2))) (point)))) (defmacro gnats-run-modify-command (&rest body) "Execute BODY after inhibiting read-only attributes. The read-only attributes are restored to their previous state afterwards." `(let ((inhibit-read-only t)) ,@body)) (defun gnats-delete-char (count) "Delete COUNT chars under the cursor from the current buffer." (interactive "p") (let* ((char-attrs (text-properties-at (point))) (field-name (plist-get char-attrs 'gnats-field-name)) (field-type (and field-name (get field-name 'type)))) (cond ((or (eq 'enum field-type) (eq 'enum-in-file field-type)) (gnats-request-enum field-name)) ((and (eolp) (not (eq field-type 'multitext))) (error "Read-only text may not be edited")) ((and (eolp) (not (and (eq count 1) (bolp) (not (and (get-text-property (+ (point) 1) 'read-only) (get-text-property (- (point) 1) 'read-only))))) (or (get-text-property (+ (point) 1) 'read-only) (get-text-property (- (point) 1) 'read-only))) (error "Read-only text may not be edited")) ((or (null field-name) (text-property-any (point) (+ (point) count) 'read-only t)) (error "Read-only text may not be edited")) (t (gnats-run-modify-command (delete-char count)) (gnats-mark-field-edited field-name))))) (defun gnats-delete-backward-char (count) "Delete COUNT chars under the cursor from the edit buffer." (interactive "p") (let* ((edit-point (if (< 1 (point)) (- (point) 1) 1)) (char-attrs (text-properties-at edit-point)) (field-name (plist-get char-attrs 'gnats-field-name)) (field-type (and field-name (get field-name 'type)))) (cond ((or (eq 'enum field-type) (eq 'enum-in-file field-type)) (gnats-request-enum field-name)) ((and (bolp) (not (eq field-type 'multitext))) (error "Read-only text may not be edited")) ((and (bolp) (or (get-text-property (- edit-point 1) 'read-only) (get-text-property (+ edit-point 1) 'read-only))) (error "Read-only text may not be edited")) ((or (null field-name) (text-property-any (- (point) count) edit-point 'read-only t)) (error "Read-only text may not be edited")) (t (gnats-run-modify-command (delete-backward-char count)) (gnats-mark-field-edited field-name))))) (defun gnats-find-field-text (field) "Return the location of the field text in the buffer for FIELD. If the text is not found, nil is returned." ;; We assume that (point) is within the field contents, tho this ;; will work even if it isn't. (or (text-property-any (point) (point-max) 'gnats-field-name field) (text-property-any (point-min) (point) 'gnats-field-name field))) (defun gnats-server-response-ok (resp) "Examine the server response line RESP. Return either the error message from the server, or nil if the response indicates that the operation was successful." (if (and (>= (car (car resp)) 200) (< (car (car resp)) 300)) nil (concat (nth 1 (car resp)) "\n"))) (defun gnats-field-edited-p (field) "Return T if the FIELD has been edited." (and (get field 'was-edited) (not (string= (gnats-get-field-value field) (get field 'value))))) (defun gnats-validate-field (field) "Verify that the contents of FIELD are valid. Return either nil, indicating that the contents are valid, or the server error message." (if (gnats-field-edited-p field) (let* ((field-text (gnats-get-field-value field)) (server-resp (gnats-send-command-and-text (concat "VFLD " (get field 'field-name)) field-text))) (gnats-server-response-ok server-resp)))) (defun gnats-apply-edit (field) "Send the contents of FIELD to the server as an edit. The result is either nil (indicating that the edit was successful) or a string containing the error message from the server." (let* ((curr-value (gnats-get-field-value field)) (changed-why-field (gnats-gen-changed-why field)) (change-reason (and (get field 'has-changed-why) (not (string= (get field 'value) curr-value)) (gnats-get-field-value changed-why-field))) (server-resp (gnats-server-response-ok (gnats-send-command-and-text (concat "REPL " (get gnats-server-conn 'pr-number) " " (get field 'field-name)) curr-value change-reason)))) server-resp)) (defun gnats-apply-edits () "Verify the current set of edits with the server. If all edits are acceptable, the outstanding edits are applied and any resulting error messages are displayed. If there are no errors after the edits are applied, the PR contents are reloaded." (let ((field-list (get gnats-server-conn 'field-list)) (validate-res (mapconcat 'gnats-validate-field (get gnats-server-conn 'field-list) ""))) (if (not (string= validate-res "")) (error validate-res)) (while field-list (let ((field (car field-list))) (if (gnats-field-edited-p field) (let ((field-res (gnats-apply-edit field))) (if field-res (error field-res) (put field 'was-edited nil) (put field 'value (gnats-get-field-value field))))) (setq field-list (cdr field-list)))) (gnats-clear-edit-buffer) (gnats-get-pr (get gnats-server-conn 'pr-number)) (gnats-edit-mode t))) (defun gnats-apply-or-submit () "If in edit mode apply the current set of changes, or submit the new PR." (interactive) (save-excursion (if (eq (get gnats-server-conn 'mode) 'submit) (gnats-submit-pr) (gnats-apply-edits)))) (defun gnats-get-pr-contents () "Collect the current PR contents as a standard-formatted PR." (save-excursion (goto-char (point-min)) (let ((field-list (get gnats-server-conn 'input-fields)) (res "")) (while field-list (let* ((field (car field-list)) (field-value (gnats-get-field-value field)) (field-type (get field 'type)) (field-name (concat ">" (get field 'field-name) ":"))) (setq res (concat res (if (eq 'multitext field-type) (concat field-name "\n" field-value) (concat field-name " " field-value)) "\n"))) (setq field-list (cdr field-list))) res))) (defun gnats-submit-pr () "Submit the current PR; if successful, the buffer is killed." (let* ((pr-contents (gnats-get-pr-contents)) (server-resp (gnats-server-response-ok (gnats-send-command-and-text "SUBM" pr-contents)))) (if server-resp (error server-resp) ;(kill-buffer (get gnats-server-conn 'server-buffer)) (message "PR successfully submitted.")))) (defun gnats-insert-char (count) "Insert COUNT chars of the `last-command-char' into the current buffer." (interactive "p") (let* ((char-attrs (text-properties-at (point))) (ch last-command-char) (field-name (plist-get char-attrs 'gnats-field-name)) (field-type (and field-name (get field-name 'type)))) (cond ((or (eq ch ?\r) (eq ch ?\n)) (gnats-end-line)) ((or (eq 'enum field-type) (eq 'enum-in-file field-type)) (if (eq ch ?\ ) (gnats-cycle-enum-value field-name) (gnats-request-enum field-name))) ((and (eq 'multitext field-type) (eolp) (get-text-property (- (point) 1) 'read-only)) (error "Read-only text may not be edited")) ((or (plist-get char-attrs 'read-only) (null field-name)) (error "Read-only text may not be edited")) (t (let ((curr-point (point))) (gnats-run-modify-command (self-insert-command count)) (add-text-properties curr-point (point) (list 'gnats-field-name field-name)) (gnats-mark-field-edited field-name)))))) (defun gnats-end-line () "Handle an EOL character from the user." (interactive) (let* ((char-attrs (text-properties-at (point))) (field-name (plist-get char-attrs 'gnats-field-name)) (field-type (and field-name (get field-name 'type)))) (cond ((or (eq 'enum field-type) (eq 'enum-in-file field-type)) (gnats-request-enum field-name nil t)) ((or (plist-get char-attrs 'read-only) (null field-name)) (error "Read-only text may not be edited")) ((gnats-multitext-field-p field-name) (gnats-run-modify-command (newline)) (gnats-mark-field-edited field-name)) (t (error "Newlines not permitted in this field"))))) (defun gnats-open-line (count) "Open a line. Argument COUNT specifies how many lines are opened." (interactive "p") (let* ((char-attrs (text-properties-at (point))) (field-name (plist-get char-attrs 'gnats-field-name)) (field-type (and field-name (get field-name 'type)))) (cond ((or (eq 'enum field-type) (eq 'enum-in-file field-type)) (gnats-request-enum field-name)) ((or (plist-get char-attrs 'read-only) (null field-name)) (error "Read-only text may not be edited")) ((gnats-multitext-field-p field-name) (gnats-run-modify-command (open-line count)) (gnats-mark-field-edited field-name)) (t (error "This field may only contain one line of text"))))) (defun gnats-kill-line (&optional count) "Delete to the end of the line. If the optional argument COUNT is given, delete that many lines." (interactive "P") (let* ((edit-point (point)) (end-point (save-excursion (if count (forward-line count) (end-of-line)) (point))) (start-point (min edit-point end-point)) (char-attrs (text-properties-at edit-point)) (field-name (plist-get char-attrs 'gnats-field-name)) (field-type (and field-name (get field-name 'type)))) (setq end-point (1+ (max end-point edit-point))) (if (and (null count) (eolp)) (setq end-point (1+ end-point))) (cond ((null field-name) (error "Read-only text may not be edited")) ((or (eq 'enum field-type) (eq 'enum-in-file field-type)) (gnats-request-enum field-name)) ((and (text-property-any start-point end-point 'read-only t) (or (not (bolp)) (not (eq count nil)) (get-text-property (- start-point 2) 'read-only))) (error "Read-only text may not be edited")) (t (gnats-run-modify-command (kill-line count)) (gnats-mark-field-edited field-name))))) (defun gnats-next-field () "Move to the next input field." (interactive) (goto-char (gnats-find-next-field)) (when (eobp) (goto-char (point-min)) (goto-char (gnats-find-next-field)))) (defun gnats-previous-field () "Move to the previous input field." (interactive) (goto-char (gnats-find-previous-field)) (when (bobp) (goto-char (point-max)) (goto-char (gnats-find-previous-field)))) (defvar gnats-edit-font-lock-keywords '(("^>\\S-+:" . font-lock-keyword-face) ("^>Synopsis:\\s-*\\(.*\\)$" 1 font-lock-variable-name-face))) (defun gnats-update-font-lock-keywords () "Update the value of `gnats-edit-font-lock-keywords-1'. The value is set to fontify the values of the enum fields." (let ((fields (get gnats-server-conn 'field-list)) (highlight-fields nil)) (while fields (when (eq (get (car fields) 'type) 'enum) (setq highlight-fields (cons (regexp-quote (get (car fields) 'field-name)) highlight-fields))) (setq fields (cdr fields))) (when highlight-fields (setq gnats-edit-font-lock-keywords (cons (let ((regexp (regexp-opt highlight-fields))) (list (concat "^>\\(" regexp "\\):\\s-*\\(.*\\)$") (+ (regexp-opt-depth regexp) 2) 'font-lock-builtin-face)) gnats-edit-font-lock-keywords))))) (defvar gnats-edit-mode-hook nil "Hook run by `gnats-edit-mode'.") (defun gnats-edit-mode (&optional quietp) "Major mode for editing PRs. Press \\[gnats-apply-or-submit] to submit your changes." ;; Should we be doing this here? By the time the mode is specified ;; we've already diddled with several local variables. (kill-all-local-variables) (setq major-mode 'gnats-edit-mode) (setq mode-name "gnats-edit") (use-local-map gnats-edit-mode-map) (setq buffer-undo-list nil) (set-buffer-modified-p nil) (make-local-variable 'paragraph-separate) (make-local-variable 'paragraph-start) (setq paragraph-separate ">\\|[ \t\f]*$" paragraph-start paragraph-separate) (make-local-variable 'gnats-edit-font-lock-keywords) (gnats-update-font-lock-keywords) (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(gnats-edit-font-lock-keywords t t)) (make-local-variable 'after-change-functions) (setq after-change-functions (cons 'gnats-extend-properties after-change-functions)) (unless quietp (message "Press `C-c C-c' to submit your changes.")) (run-hooks 'gnats-edit-mode-hook)) (put 'gnats-edit-mode 'mode-class 'special) (defun gnats-edit-server (&optional pr) "Connect to the GNATS server and return its connection as a process. Optional argument PR specifies the problem report from which the server information should be retrieved." (setq gnats-server-conn (intern (buffer-name))) (gnats-init-response) (put gnats-server-conn 'server-buffer (generate-new-buffer " *gnats-net*")) (gnats-get-addr-info pr) (let ((first-char (string-to-char (get gnats-server-conn 'server-host))) (success nil)) (unwind-protect (progn (if (or (eq first-char ?/) (eq first-char ?.)) (progn (put gnats-server-conn 'process (start-process "gnatsd" (get gnats-server-conn 'server-buffer) (get gnats-server-conn 'server-host) "--database" "default" "--not-inetd")) (put gnats-server-conn 'eol-chars "\n")) (put gnats-server-conn 'process (open-network-stream "gnats-edit-server" (get gnats-server-conn 'server-buffer) (get gnats-server-conn 'server-host) (get gnats-server-conn 'server-port))) (put gnats-server-conn 'eol-chars "\r\n")) (setq success t)) (if success (progn (set-process-filter (get gnats-server-conn 'process) 'gnats-process-filter) (gnats-get-response)) (kill-buffer (get gnats-server-conn 'server-buffer)))))) (defun gnats-debug-string (string) "Display STRING in the associated server buffer." (let ((old-buffer (current-buffer)) (process-buffer (process-buffer (get gnats-server-conn 'process)))) (unwind-protect (when process-buffer (set-buffer process-buffer) (goto-char (point-max)) (insert string)) (set-buffer old-buffer)))) (defun gnats-insert-label (field single-line first-char-attr) "Add a label for FIELD at point. If SINGLE-LINE is true, the field is assumed to only allow one line of text. The first character of the label text will have FIRST-CHAR-ATTR set." (let* ((curr-pos (point)) (field-name (get field 'field-name)) (field-spacing (1+ (- (get gnats-server-conn 'max-field-name-width) (length field-name))))) (insert ">" field-name ":") (if single-line (insert (make-string field-spacing ?\ )) (insert "\n")) (if first-char-attr (add-text-properties curr-pos (1+ curr-pos) (append first-char-attr '(intangible t)))) (if single-line (set-text-properties (- (point) 1) (point) '(intangible t read-only t rear-nonsticky t)) (add-text-properties (- (point) 2) (- (point) 1) '(rear-nonsticky t))) (add-text-properties curr-pos (- (point) 1) '(intangible t read-only t)))) (defun gnats-insert-text (field text single-line &optional props) "Insert FIELD TEXT into the edit buffer. If SINGLE-LINE is set, then the field is assumed to only hold one line of text. The optional property list PROPS will be set on the inserted text, if it is supplied." (let ((curr-pos (point))) (insert text "\n") (if (not single-line) (setq curr-pos (- curr-pos 1))) (add-text-properties curr-pos (1+ curr-pos) '(front-sticky t)) (add-text-properties (- (point) 1) (point) '(rear-nonsticky t)) (add-text-properties curr-pos (point) (append (list 'gnats-field-name field) props)))) (defun gnats-extend-properties (beg end len) "Set GNATS mode properties of the insert text between BEG and END. Moreover, mark the current field as edited. Intended to be used in the `insert-behind-hooks' property." (let ((field-name (get-text-property end 'gnats-field-name))) (when field-name (set-text-properties beg end `(gnats-field-name ,field-name front-sticky t)) (gnats-mark-field-edited field-name)))) (defun gnats-format-field (prev-field field &optional input) ;; checkdoc-order: nil "If FIELD is a valid edit field, format it into the edit buffer. PREV-FIELD is the previously-inserted field, or nil if this is the first field. FIELD is returned if it was formatted, PREV-FIELD otherwise. If the optional argument INPUT is nil and the field is read only, don't format the field." (let* ((field-type (get field 'type)) (field-flags (downcase (get field 'flags))) (field-value (or (get field 'value) "")) (curr-pos (point)) (prev-field-type (and prev-field (get prev-field 'type))) (first-label-attr nil)) ;; skip readonly fields (if (or input (not (string-match "readonly" field-flags))) (progn (if (or (null prev-field-type) (not (eq prev-field-type 'multitext))) (setq first-label-attr '(front-sticky t))) (cond ((eq field-type 'multitext) (gnats-insert-label field nil first-label-attr) (gnats-insert-text field field-value nil)) ;; enum fields can't be directly edited ((or (eq field-type 'enum) (eq field-type 'enum-in-file)) (gnats-insert-label field t first-label-attr) (gnats-insert-text field field-value t (append '(read-only t) (unless input (list 'mouse-face 'highlight 'local-map gnats-edit-button-map))))) (t (gnats-insert-label field t first-label-attr) (gnats-insert-text field field-value t))) field) prev-field))) (defun gnats-format-pr (&optional input) "Format the currently-loaded PR into the edit buffer. If the optional argument INPUT is nil, don't format read-only fields." (let ((prev-field nil)) (mapcar '(lambda (field) (setq prev-field (gnats-format-field prev-field field input))) (get gnats-server-conn 'field-list)))) (defun gnats-gen-input-template () "Generate an initial input template." (let ((prev-field nil)) (mapcar '(lambda (field) (setq prev-field (gnats-format-field prev-field field))) (get gnats-server-conn 'input-fields)))) (defun gnats-gen-field-symbol (field) "Return the symbol for FIELD." (intern (concat "gnats-field-name-" (downcase field)))) (defun gnats-gen-changed-why (field) "Return the symbol of the change-reason field associated with FIELD." (make-variable-buffer-local (gnats-gen-field-symbol (concat (get field 'field-name) "-Changed-Why")))) (defun gnats-add-field-name (element) "Add ELEMENT as a valid field name in the current database. ELEMENT must be a string." (if (eq (car element) 0) (let ((namelen (length (nth 1 element))) (field-sym (make-variable-buffer-local (gnats-gen-field-symbol (nth 1 element))))) (if (> namelen (get gnats-server-conn 'max-field-name-width)) (put gnats-server-conn 'max-field-name-width namelen)) (put gnats-server-conn 'field-list (append (get gnats-server-conn 'field-list) (list field-sym))) (put field-sym 'field-name (nth 1 element))))) (defun gnats-field-list-as-string () "Return the list of field names as a space-separated string." (mapconcat '(lambda (x) (get x 'field-name)) (get gnats-server-conn 'field-list) " ")) (defun gnats-iterate-info (fields result-list func) ;; checkdoc-order: nil "Iterate the set of server responses in RESULT-LIST. FIELDS is the list of corresponding field names. For each valid server response, FUNC is invoked with the field name and server response text." (while result-list (let ((elem (car result-list)) (field (car fields))) (if (or (eq (car elem) 0) (eq (car elem) 350)) (funcall func field (nth 1 elem)))) (setq result-list (cdr result-list)) (setq fields (cdr fields)))) (defun gnats-get-field-values (field) "Get the set of legal field values for FIELD from the server. Store them as the valid-values property in FIELD." (let ((values (gnats-send-command "FVLD" (get field 'field-name))) (res nil)) (while values (let ((elem (car values))) (if (eq (car elem) 0) (setq res (append res (list (nth 1 elem))))) (setq values (cdr values)))) (put field 'valid-values res))) (defun gnats-add-changed-why (field) "Add a change-reason field for FIELD, if FIELD requires a change reason." (if (string-match "requirechangereason" (downcase (get field 'flags))) (let ((newf (gnats-gen-changed-why field))) ;; Add a property for it, to make things a bit easier. (put field 'requires-changed-why t) (put newf 'field-name (concat (get field 'field-name) "-Changed-Why")) (put newf 'type 'multitext)))) (defun gnats-get-field-info () "Get the field metadata from the server. Write it into the appropriate field properties." (put gnats-server-conn 'field-list nil) (put gnats-server-conn 'max-field-name-width 0) (put gnats-server-conn 'input-fields nil) (let ((our-field-list (gnats-send-command "list" "fieldnames"))) (mapcar 'gnats-add-field-name our-field-list) (setq our-field-list (gnats-send-command "FTYP" (gnats-field-list-as-string))) (gnats-iterate-info (get gnats-server-conn 'field-list) our-field-list '(lambda (field val) (put field 'type (intern (downcase val))))) (setq our-field-list (gnats-send-command "FIELDFLAGS" (gnats-field-list-as-string))) (gnats-iterate-info (get gnats-server-conn 'field-list) our-field-list '(lambda (field val) (put field 'flags val))) (setq our-field-list (gnats-send-command "INPUTDEFAULT" (gnats-field-list-as-string))) (gnats-iterate-info (get gnats-server-conn 'field-list) our-field-list '(lambda (field val) (when val (while (string-match "\\\\n" val) (setq val (replace-match "\n" nil nil val))) (when (and (gnats-multitext-field-p field) (string-match "\\`\n" val)) (setq val (replace-match "" nil nil val)))) (put field 'input-default val))) (setq our-field-list (gnats-send-command "LIST INITIALINPUTFIELDS")) (mapcar '(lambda (field) (if (eq (car field) 0) (put gnats-server-conn 'input-fields (append (get gnats-server-conn 'input-fields) (list (gnats-gen-field-symbol (nth 1 field))))))) our-field-list) (mapcar 'gnats-get-field-values (get gnats-server-conn 'field-list)) (mapcar 'gnats-add-changed-why (get gnats-server-conn 'field-list)))) (defun gnats-field-name (string) "Return a list composed of the field name and text is returned. STRING is a single line from a PR retrieved from the server. If STRING does not begin with a GNATS field header, the field name will be nil instead, and the text will be the entire value of STRING." (let ((data (match-data))) (unwind-protect (if (string-match "^>\\([^:]+\\):[ \t]*" string) (list (gnats-gen-field-symbol (match-string 1 string)) (substring string (match-end 0))) (list nil string)) (set-match-data data)))) (defun gnats-multitext-field-p (field) "Return t if FIELD is a multitext field, nil otherwise." (eq 'multitext (get field 'type))) (defun gnats-parse-pr (state server-response) ;; checkdoc-order: nil "Parse one line of a PR retrieved from the server in SERVER-RESPONSE. STATE is the current parse state. The PR text is stored in the appropriate field's value property, and the next parse state is returned." (if (and server-response (eq 0 (nth 0 server-response))) (let* ((field-info (gnats-field-name (nth 1 server-response))) (field-name (nth 0 field-info)) (text (nth 1 field-info)) (field-type)) (if (null field-name) (setq field-name (nth 1 state)) ;; Clear the current field value; we're just seeing this field for ;; the first time. (put field-name 'value nil)) (when field-name (setq state (list (nth 0 state) field-name)) (setq field-type (get field-name 'type)) ;; If the current line has a field header, then we go back to ;; state 0. (if (nth 0 field-info) (setq state '(0 nil))) (if (eq 0 (nth 0 state)) (if (eq field-type 'multitext) (setq state (list 1 field-name)) (put field-name 'value text)) (let ((oldtext (get field-name 'value))) (put field-name 'value (concat oldtext (cond (oldtext "\n")) text))))))) state) (defun gnats-fetch-pr (pr &optional input) "Lock and parse PR from the server. If the optional argument INPUT is non-nil, get the problem report without locking the database." (let ((our-pr-text (if input (progn ;; TODO: Handle gnatsd errors. (gnats-send-command "QFMT" "full") (gnats-send-command "RSET") (gnats-send-command "QUER" pr)) (gnats-send-command "LOCK" (prin1-to-string pr t) "emacs"))) (parse-pr-state '(0 nil))) ;; We unlock it (for now). (unless input (unlock-pr pr)) (put gnats-server-conn 'pr-number pr) ;; We must reset all input fields here, otherwise an input field from the ;; previous PR not present in this PR might survive. (mapc (lambda (field-name) (put field-name 'value nil)) (get gnats-server-conn 'field-list)) (if (> (car (car our-pr-text)) 399) (progn (error (nth 1 (car our-pr-text))) nil) (mapcar '(lambda (x) (setq parse-pr-state (gnats-parse-pr parse-pr-state x))) our-pr-text) t))) (defun gnats-add-dot (string) "If STRING begins with a period (.), prepend a second period to it. The resulting string is returned." (if (eq (string-to-char string) ?.) (concat "." string) string)) (defun gnats-nl-to-crnl (string) "Convert the linefeeds in STRING to CRLF pairs. Additionally a single CRLF is appended if the text does not end in one. The resulting string is returned." (let ((res "") (eol-chars (get gnats-server-conn 'eol-chars))) (while (string-match "\n" string) (setq res (concat res (gnats-add-dot (substring string 0 (match-beginning 0))) eol-chars) string (substring string (match-end 0)))) (if string (concat res (gnats-add-dot string) eol-chars) res))) (defun gnats-send-command (&rest comm) "Send the command COMM to the server, and wait for the server's response." (let ((cstr (concat (mapconcat 'concat comm " ") (get gnats-server-conn 'eol-chars)))) (gnats-init-response) (gnats-debug-string cstr) (process-send-string (get gnats-server-conn 'process) cstr) (gnats-get-response))) (defun gnats-send-command-and-text (comm first-text &optional second-text) "Send the command COMM, followed by FIRST-TEXT. If the optional argument SECOND-TEXT is given and the server requests it, it will be sent. If COMM is successful nil is returned; otherwise, the server error message is returned." (let* ((server-resp (gnats-send-command comm)) (server-code (car (car server-resp)))) (if (and (> server-code 210) (< server-code 300)) (progn (setq server-resp (gnats-send-command (concat (gnats-nl-to-crnl first-text) "."))) (setq server-code (car (car server-resp))) (if (and second-text (> server-code 210) (< server-code 300)) (setq server-resp (gnats-send-command (concat (gnats-nl-to-crnl second-text) ".")))))) server-resp)) (defun gnats-parse-server-line (string) "Parse the server response line in STRING and return it as a list of lists. Each sublist consists of two elements; a response code and the associated text. PR text has a response code of 0. The `gnats-server-conn' property `output-complete' will be set when the final server response line has been reached." (let ((data (match-data)) (status 0) (cont t) (res nil)) (unwind-protect (progn (while (string-match "^\\([^\r\n]*\\)\r?\n" string) (let ((text (match-string 1 string))) (setq string (substring string (match-end 0))) ;; If in mode 1, the server's sending ;; us the standard response lines. ;; Mode 2 has output ending with a ;; single . at the end. (if (eq (get gnats-server-conn 'read-mode) 1) (progn ;; Should check result of string-match to see if it worked. (string-match "^\\([0-9][0-9][0-9]\\)\\(.\\)\\(.*\\)$" text) (setq status (string-to-number (match-string 1 text))) (setq cont (string= "-" (match-string 2 text))) (setq text (match-string 3 text))) ; Mode 2. (progn (setq status 0) ;; If the line contains just a period, then we're done. (setq cont (not (string= "." text))) ;; Strip leading periods. (string-match "^[.]?\\(.*\\)$" text) ;; Don't add a line for the final . (if cont (setq text (match-string 1 text)) (setq text nil)))) (if text (setq res (append res (list (list status text))))) (if (and (eq (get gnats-server-conn 'read-mode) 1) (>= status 300) (< status 350)) (progn (put gnats-server-conn 'read-mode 2) (setq cont t))))) (put gnats-server-conn 'output-complete (not cont)) (put gnats-server-conn 'parsed-output (append (get gnats-server-conn 'parsed-output) res))) (set-match-data data)))) (defun gnats-init-response () "Prepare to parse a server response. This function should be invoked just before a server command is sent." (put gnats-server-conn 'curr-output "") (put gnats-server-conn 'parsed-output nil) (put gnats-server-conn 'read-mode 1) (put gnats-server-conn 'output-complete nil)) (defun gnats-get-response () "Wait up to 10 seconds for a complete response from the server. The response is a value returned from `gnats-parse-server-line'." ;;; TODO: Make the timeout configurable. (let ((no-timeout t)) (while (and no-timeout (eq (get gnats-server-conn 'output-complete) nil)) (setq no-timeout (accept-process-output (get gnats-server-conn 'process) 10 0))) (if no-timeout (let ((res (get gnats-server-conn 'parsed-output))) (put gnats-server-conn 'parsed-output nil) res) (error "Input timeout from the server")))) (defun gnats-process-filter (process output) "Process a response from the GNATS server connection in PROCESS. OUTPUT is the text from the server. The resulting parsed response is placed in gnats-server-conn's `parsed-output' property. If a complete response has been parsed, the `output-complete' property is set." (put gnats-server-conn 'curr-output (concat (get gnats-server-conn 'curr-output) output)) (if (eq 10 (string-to-char (substring output -1))) (progn (gnats-debug-string (get gnats-server-conn 'curr-output)) (let ((our-output (get gnats-server-conn 'curr-output))) (put gnats-server-conn 'curr-output "") (gnats-parse-server-line our-output))))) (defun gnats-server-login () "Login to the server." (gnats-send-command "USER" (get gnats-server-conn 'server-username) (get gnats-server-conn 'server-password))) (defun gnats-edit-chdb () "Do a CHDB command as needed." (gnats-send-command "CHDB" (get gnats-server-conn 'server-database))) (defun gnats-get-mail-alias () "Return the mail alias for the current user. The alias is taken from the database's responsible adm file. If it cannot be retrieved `user-mail-address' is used. The alias is then set as the editting e-mail address." (let* ((resp (gnats-send-command "ADMV" "builtinfield:responsible" (user-login-name) "alias")) (alias (if (and (>= (car (car resp)) 350) (< (car (car resp)) 400)) (nth 1 (car resp)) user-mail-address))) (put gnats-server-conn 'mail-alias alias) (when alias (gnats-send-command "EDITADDR" alias)) alias)) (defun gnats-get-pr (pr &optional input) "Read in PR from the server and display it. If the optional argument INPUT is non-nil, get the problem report without locking the database." (when (gnats-fetch-pr pr input) (gnats-format-pr input) t)) (defun gnats-clear-field-contents (field) "Clear the field value properties for FIELD." (put field 'value nil) (put field 'was-edited nil) (put field 'has-chagned-why nil)) (defun gnats-set-initial-values () "Set the initial values for PR fields." (mapcar '(lambda (field) (put field 'value (get field 'input-default))) (get gnats-server-conn 'field-list)) (if gnats-default-organization (put 'gnats-field-name-organization 'value gnats-default-organization)) (if gnats-default-submitter (put 'gnats-field-name-submitter-id 'value gnats-default-submitter)) (put 'gnats-field-name-originator 'value (concat (get gnats-server-conn 'mail-alias) " (" (user-full-name) ")"))) (defun gnats-clear-all-field-contents () "Clear all the field contents." (mapcar 'gnats-clear-field-contents (get gnats-server-conn 'field-list))) (defun gnats-clear-edit-buffer () "Clear the contents of the field buffer, and any associated data structures." (toggle-read-only -1) (gnats-run-modify-command (erase-buffer)) (gnats-clear-all-field-contents)) (defun gnats-get-addr-info (pr) "Determine the username, passwd, database server, etc. to use for PR." (save-excursion (let* ((database (or (and pr (string-match "^\\([^:]+\\):" (prin1-to-string pr t)) (match-string 1 (prin1-to-string pr t))) gnats-database (and (not (getenv "GNATSDB")) "default"))) (server (or gnats-server (and (not (getenv "GNATSDB")) "localhost"))) (port (or (and gnats-port (prin1-to-string gnats-port t)) (and (not (getenv "GNATSDB")) "1529"))) (user (or gnats-user (and (not (getenv "GNATSDB")) (user-login-name)))) (password (or gnats-password (unless (getenv "GNATSDB") (setq gnats-password (read-passwd (format "Password for %s@%s:%s/%s: " user server port database) nil "*"))))) (query-args (append (when database (list "--database" database)) (when database (list "--host" server)) (when database (list "--port" port)) (when database (list "--user" user)) (when database (list "--passwd" password)))) (query-pr-buffer (generate-new-buffer " *gnats-query-pr*")) (query-pr-res (if (and server (not (string-match "^/" server))) (apply 'call-process "query-pr" nil query-pr-buffer nil "--print-server-addr" query-args) (getenv "GNATSDB")))) (if query-pr-res (let ((buffer-contents (save-excursion (set-buffer query-pr-buffer) (buffer-string)))) (if (string-match "^\\([^:]+\\):\\([^:]+\\):\\([^:]+\\):\\([^:]+\\):\\([^\r\n]+\\)" buffer-contents) (progn (put gnats-server-conn 'server-host (match-string 1 buffer-contents)) (put gnats-server-conn 'server-port (let ((x (string-to-int (match-string 2 buffer-contents)))) (if (< 0 x) x (match-string 2 buffer-contents)))) (put gnats-server-conn 'server-database (match-string 3 buffer-contents)) (put gnats-server-conn 'server-username (match-string 4 buffer-contents)) (put gnats-server-conn 'server-password (match-string 5 buffer-contents))) (switch-to-buffer query-pr-buffer) (error "Couldn't retrieve server info"))) (error "Couldn't retrieve server info from query-pr")) (kill-buffer query-pr-buffer)))) ;;;###autoload (defun send-pr (&optional arg) "Generate a new initial PR template for the user. If a prefix argument is given, run `gnats-change-database' first." (interactive "P") (when arg (call-interactively 'gnats-change-database)) (let ((edit-buffer (generate-new-buffer "*gnats-send*")) (success nil)) (unwind-protect (save-excursion (set-buffer edit-buffer) (gnats-clear-edit-buffer) (gnats-edit-server) (gnats-server-login) (gnats-edit-chdb) (gnats-get-mail-alias) (gnats-get-field-info) (gnats-set-initial-values) (gnats-gen-input-template) (put gnats-server-conn 'mode 'submit) (gnats-edit-mode) (setq success t)) (if (not success) (progn (kill-buffer edit-buffer) (kill-buffer (get gnats-server-conn 'server-buffer))) (switch-to-buffer edit-buffer) (goto-char (point-min)))))) ;;;###autoload (defun edit-pr (pr) "Edit the specified PR; prompts for a PR number if one was not given." (interactive "nPR Number: ") ;; Should whine if a gnats-edit-PR buffer for the PR already exists. (setq pr (prin1-to-string pr t)) (let ((edit-buffer (generate-new-buffer (concat "*gnats-edit-" pr "*"))) (success nil)) (unwind-protect (save-excursion (set-buffer edit-buffer) (gnats-clear-edit-buffer) (gnats-edit-server pr) (gnats-server-login) (gnats-edit-chdb) (gnats-get-mail-alias) (gnats-get-field-info) (if (gnats-get-pr pr) (progn (put gnats-server-conn 'mode 'edit) (gnats-edit-mode) (setq success t)))) (if (not success) (progn (kill-buffer edit-buffer) (kill-buffer (get gnats-server-conn 'server-buffer))) (switch-to-buffer edit-buffer) (goto-char (point-min)))))) (defvar gnats-query-buffer-name "*gnats-query*" "Name of the buffer presenting the summary of PRs returned by a query.") (defvar gnats-query-mode-map '() "Keymap for GNATS query mode.") (when (null gnats-query-mode-map) (setq gnats-query-mode-map (make-keymap)) (define-key gnats-query-mode-map "\r" 'gnats-query-view-pr) (define-key gnats-query-mode-map "v" 'gnats-query-view-pr) (define-key gnats-query-mode-map [mouse-2] 'gnats-query-view-pr) (define-key gnats-query-mode-map "D" 'gnats-change-database) (define-key gnats-query-mode-map "e" 'gnats-query-edit-pr) (define-key gnats-query-mode-map "g" 'gnats-query-reread) (define-key gnats-query-mode-map "G" 'query-pr) (define-key gnats-query-mode-map "q" 'bury-buffer) (define-key gnats-query-mode-map "s" 'send-pr)) (defvar gnats-query-mode-hook nil "Hook run by `gnats-query-mode'.") (defvar gnats-query-font-lock-keywords '(("^\\s-*[0-9]+\\s-+\\S-+\\s-+\\S-+\\s-+\\(feedback\\|closed\\).*$" . font-lock-comment-face) ("^.*\\.*$" . font-lock-warning-face))) (defun gnats-query-mode () "Major mode for browsing GNATS reports. Use \\[gnats-query-view-pr] to view the problem report under the cursor and \\[gnats-query-edit-pr] to edit it. \\{gnats-query-mode-map}" (kill-all-local-variables) (setq major-mode 'gnats-query-mode) (setq mode-name "gnats-query") (use-local-map gnats-query-mode-map) (setq buffer-read-only t) (set-buffer-modified-p nil) (make-local-variable 'truncate-lines) (setq truncate-lines t) (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(gnats-query-font-lock-keywords t)) (view-mode) (setq minor-mode-overriding-map-alist (list (cons 'view-mode (let ((keymap (copy-keymap view-mode-map))) (define-key keymap "e" nil) (define-key keymap "g" nil) (define-key keymap "s" nil) (define-key keymap "\r" nil) keymap)))) (run-hooks 'gnats-query-mode-hook)) (put 'gnats-query-mode 'mode-class 'special) (defun gnats-query-current-pr () "Return the id of the problem report on the current line, as a string. If there is no problem report on the current line, signal an error. The function works in the query buffers." (let ((pr (save-excursion (beginning-of-line) (when (re-search-forward "\\=[ ]*\\([0-9]+\\)" nil t) (match-string-no-properties 1))))) (or pr (error "No problem on the current line")))) (defvar gnats-view-mode-map nil "Keymap for GNATS view mode.") (when (null gnats-view-mode-map) (setq gnats-view-mode-map (make-keymap)) (define-key gnats-view-mode-map "e" 'gnats-view-edit-pr)) (defvar gnats-view-mode-hook nil "Hook run by `gnats-view-mode'.") (defun gnats-view-edit-pr () "Turn the current viewer of a problem report into the edit mode." (interactive) (unless (eq major-mode 'gnats-view-mode) (error "Not in the gnats-view mode")) (rename-buffer (generate-new-buffer-name (concat "*gnats-edit-" (prin1-to-string (get gnats-server-conn 'pr-number) t) "*"))) ;; We have to reformat the buffer to discard read-only fields (setq buffer-read-only nil) (let ((inhibit-read-only t)) (erase-buffer) (gnats-format-pr)) (put gnats-server-conn 'mode 'edit) (gnats-edit-mode) (goto-char (point-min))) (defun gnats-view-mode () "Major mode for viewing GNATS problem reports. \\{gnats-view-mode-map}" (kill-all-local-variables) (setq major-mode 'gnats-view-mode) (setq mode-name "gnats-view") (use-local-map gnats-view-mode-map) (setq buffer-read-only t) (set-buffer-modified-p nil) (make-local-variable 'gnats-edit-font-lock-keywords) (gnats-update-font-lock-keywords) (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(gnats-edit-font-lock-keywords t t)) (view-mode) (setq minor-mode-overriding-map-alist (list (cons 'view-mode (let ((keymap (copy-keymap view-mode-map))) (define-key keymap "e" nil) keymap)))) (run-hooks 'gnats-view-mode-hook)) (put 'gnats-view-mode 'mode-class 'special) (defun gnats-query-view-pr () "View the problem report listed on the current line." (interactive) (when (memq 'down (event-modifiers last-command-event)) (mouse-set-point last-command-event)) (view-pr (string-to-int (gnats-query-current-pr)))) ;;;###autoload (defun view-pr (pr) "View the problem report PR." (interactive "nPR Number: ") (let* ((edit-buffer (generate-new-buffer (concat "*gnats-view-" (prin1-to-string pr t) "*"))) (success nil)) (unwind-protect (save-excursion (set-buffer edit-buffer) (gnats-clear-edit-buffer) (gnats-edit-server) (gnats-server-login) (gnats-edit-chdb) (gnats-get-mail-alias) (gnats-get-field-info) (if (gnats-get-pr (format "%d" pr) t) (progn (put gnats-server-conn 'mode 'view) (gnats-view-mode) (setq success t)))) (if (not success) (progn (kill-buffer edit-buffer) (kill-buffer (get gnats-server-conn 'server-buffer))) (switch-to-buffer edit-buffer) (goto-char (point-min)))))) (defun gnats-query-edit-pr () "Edit the problem report listed on the current line." (interactive) (edit-pr (string-to-int (gnats-query-current-pr)))) (defun gnats-do-query (query) "Perform QUERY and insert the result to the current buffer." ;; TODO: Handle gnatsd errors. (gnats-send-command "QFMT" "summary") (gnats-send-command "RSET") (unless (string= query "") (gnats-send-command "EXPR" query)) (let ((result (gnats-send-command "QUER"))) (unless (= (caar result) 300) (error "Query error (%d %s)" (car (car result)) (cadr (car result)))) (setq result (cdr result)) (while result (let ((line (car result))) (unless (= (car line) 0) (error "Error during receiving the answer")) (let ((point (point))) (insert (cadr line) "\n") (put-text-property point (1- (point)) 'mouse-face 'highlight))) (setq result (cdr result))))) (defvar query-pr-history nil "History of the `query-pr' command.") (defun gnats-query-reread () "Redo last query." (interactive) (if query-pr-history (query-pr (car query-pr-history)) (call-interactively 'query-pr))) ;;;###autoload (defun query-pr (query) "Create query buffer resulting from QUERY. QUERY is a string representing a query in the gnatsd format." ;; TODO: Maybe the description of the format should be here? (interactive (list (read-string "Query: " nil 'query-pr-history))) (let ((query-buffer (get-buffer-create gnats-query-buffer-name)) (success nil)) (unwind-protect (save-excursion (set-buffer query-buffer) (gnats-clear-edit-buffer) (gnats-delete-process) (gnats-edit-server) (gnats-server-login) (gnats-edit-chdb) (gnats-get-mail-alias) (gnats-get-field-info) (gnats-do-query query) (sort-lines gnats-query-reverse-listing (point-min) (point-max)) (put gnats-server-conn 'mode 'query) (gnats-query-mode) (setq success t)) (if (not success) (progn (kill-buffer query-buffer) (kill-buffer (get gnats-server-conn 'server-buffer))) (switch-to-buffer query-buffer) (message "%d matching PRs." (count-lines (point-min) (point-max))) (goto-char (point-min)))))) ;;;###autoload (defun unlock-database () "Unlock the whole database." (interactive) (gnats-send-command "UNDB")) ;;;###autoload (defun unlock-pr (pr) "Unlock the problem report PR." (interactive "sPR Number: ") (gnats-send-command "UNLK" pr)) (defun gnats-change-database (database host port user) "Set new database parameters." (interactive (list (read-from-minibuffer "Database: " gnats-database) (read-from-minibuffer "Host: " (or gnats-server "localhost")) (string-to-number (read-from-minibuffer "Port: " (if gnats-port (format "%d" gnats-port) 1529))) (read-from-minibuffer "User: " (or gnats-user (user-login-name))))) (setq gnats-database database gnats-server host gnats-port port gnats-user user gnats-password nil) (setq-default gnats-database database gnats-server host gnats-port port gnats-user user)) (defun gnats-show-connection () "Show the server connection buffer associated with the current buffer. You can use this function to view the communication with gnatsd in case of problems." (interactive) (let ((buffer (get gnats-server-conn 'server-buffer))) (if buffer (switch-to-buffer buffer) (error "No connection associated with this buffer")))) (defvar gnats-dbconfig-mode-map nil "Keymap for `gnats-dbconfig-mode'.") (unless gnats-dbconfig-mode-map (setq gnats-dbconfig-mode-map (make-sparse-keymap))) (defvar gnats-dbconfig-mode-syntax-table nil "Syntax table for `gnats-dbconfig-mode'.") (unless gnats-dbconfig-mode-syntax-table (setq gnats-dbconfig-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?\( "(" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?\) ")" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?{ "(" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?} ")" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?\" "\"" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?\\ "\\" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?$ "_" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?# "<" gnats-dbconfig-mode-syntax-table) (modify-syntax-entry ?\n ">" gnats-dbconfig-mode-syntax-table)) (defvar gnats-dbconfig-mode-abbrev-table nil "Abbrev table for `gnats-dbconfig-mode'.") (defvar gnats-dbconfig-font-lock-keywords `(,(regexp-opt '("add-audit-trail" "all" "allow-any-value" "append-to-field" "audit-trail-format" "aux-flags" "binary-index" "body" "builtin-name" "business-day-hours" "business-week-days" "category-dir-perms" "create-category-dirs" "database-info" "debug-mode" "default" "description" "edit-only" "exact-regexp" "field" "fields" "fixed-address" "format" "from-address" "header" "index" "inexact-regexp" "initial-entry" "input-default" "keep-all-received-headers" "key" "libexecdir" "mail-format" "matching" "max-prs-in-field" "nospaces-in-index" "notify-about-expired-prs" "on-change" "path" "pr-list" "query" "query-default" "raw" "read-only" "reply-to" "require" "require-change-reason" "restricted" "send-submitter-ack" "separator" "separators" "set-field" "textsearch" "to-addresses" "values" "virtual-format") 'words) (,(regexp-opt '("date" "enum" "enumerated-in-file" "integer" "multi-enumerated-in-file" "multienum" "multitext" "text") 'words) . font-lock-type-face) ("false\\|true" . font-lock-constant-face) (,(concat "\"\\(\\$" (regexp-opt '("ChangeReason" "CurrentDate" "EditUserEmailAddr" "FieldName" "MailCC" "MailFrom" "MailSubject" "MailTo" "NewAuditTrail" "NewValue" "OldResponsible" "OldValue" "PRNum") 'words) "\\)\"") . (1 font-lock-variable-name-face t nil))) "Font lock keywords for `gnats-dbconfig-mode'.") (defvar gnats-dbconfig-mode-hook nil "Hook run `gnats-dbconfig-mode'.") ;;;###autoload (defun gnats-dbconfig-mode () "Major mode for editing the `dbconfig' GNATS configuration file." (interactive) (kill-all-local-variables) (setq major-mode 'gnats-dbconfig-mode) (setq mode-name "dbconfig") (use-local-map gnats-dbconfig-mode-map) (set-syntax-table gnats-dbconfig-mode-syntax-table) (make-local-variable 'comment-start) (make-local-variable 'comment-start-skip) (setq comment-start "# " comment-start-skip "# *") (setq local-abbrev-table gnats-dbconfig-mode-abbrev-table) (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(gnats-dbconfig-font-lock-keywords nil t)) (setq imenu-generic-expression '((nil "^\\(database-info\\|on-change\\|index\\|initial-entry\\)" 1) ("Mail formats" "^mail-format +\"\\([^\"\n]+\\)\"" 1) ("Queries" "^query +\"\\([^\"\n]+\\)\"" 1) ("Fields" "^field +\"\\([^\"\n]+\\)\"" 1))) (run-hooks 'gnats-dbconfig-mode-hook)) (add-to-list 'auto-mode-alist '("\\ #include /* On FreeBSD this ends up defining RE_DUP_MAX. We need to make sure it's included before our regex.h. */ #include /* Use some miscelaneous functions; should be included after stdio.h */ #include "ansidecl.h" /* If system have getopt_long() it seems GNU compliant and likely use GNU-compatible getopt() as well. Otherwise, we will use getopt*() from libiberty. */ #ifdef HAVE_GETOPT #define HAVE_DECL_GETOPT 1 #else #define HAVE_DECL_GETOPT 0 #endif /* HAVE_GETOPT */ #ifdef HAVE_GETOPT_LONG #include #else #include "gnugetopt.h" #endif /* HAVE_GETOPT_LONG */ #include #include #ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */ #define mode_t unsigned short #endif #if !defined(S_ISREG) && defined(S_IFREG) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif #ifndef S_ISLNK #define lstat stat #endif #ifdef HAVE_MEMORY_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYSLOG_H #include #endif #if defined(HAVE_STRING_H) || defined(STDC_HEADERS) #include #else #include #endif #include #ifdef STDC_HEADERS #define getopt system_getopt #include #undef getopt #else /* not STDC_HEADERS */ char *getenv (); extern int errno; #endif /* STDC_HEADERS */ #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION) #include #else #include #endif #if defined(HAVE_LIBGEN_H) # if defined(HAVE_BASENAME) || defined(HAVE_DIRNAME) #include # endif #endif /* HAVE_LIBGEN_H */ #ifndef alloca /* Make alloca work the best possible way. */ #ifdef __GNUC__ #define alloca __builtin_alloca #else /* not __GNUC__ */ #if HAVE_ALLOCA_H #include #else /* not __GNUC__ or HAVE_ALLOCA_H */ #ifndef _AIX /* Already did AIX, up at the top. */ char *alloca (); #endif /* not _AIX */ #endif /* not HAVE_ALLOCA_H */ #endif /* not __GNUC__ */ #endif /* not alloca */ #if defined(__STDC__) || defined(_AIX) #include #else #include #endif #include #include #include #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) # define __attribute__(x) #endif #ifndef ATTRIBUTE_UNUSED # define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) #endif extern int asprintf (char **buf, const char *fmt, ...); extern int vasprintf (char **buf, const char *fmt, va_list args); #if ! HAVE_DECL_UNSETENV extern void unsetenv (const char *name); #endif #if defined (__svr4__) && defined (__sun__) extern int gethostname (char *name, int namelen); #endif /* Types */ /* A generic boolean type. */ typedef short bool; #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #ifndef RETSIGTYPE #define RETSIGTYPE void #endif /* A cons whose car is a string. */ typedef struct string_list { char *name; struct string_list *next; } StringList; typedef struct error_desc *ErrorDesc; typedef struct bad_fields *BadFields; /* Possible values for the logging mode. Note "syslog" will only be used if the system supports it---otherwise it will relegate to "mail". TODO: Fix this comment. */ typedef enum { SYSLOG, MAIL, LOGFILE, STDERR, NOLOG } Logging_Methods; /* XXX ??? !!! What is this stuff for? */ #ifndef LOGGING # ifdef HAVE_SYSLOG_H # define LOGGING SYSLOG # ifndef LOG_LEVEL # ifdef LOG_USER # define LOG_LEVEL LOG_USER extern int log_level; # endif # endif # else /* !HAVE_SYSLOG_H */ /* FIXME */ # define LOGGING MAIL # define LOG_ERR 0 # define LOG_INFO 1 # endif /* HAVE_SYSLOG_H */ #endif /* LOGGING */ #define LOG_NONE -1 /* Constants */ /* This used to be 30, but we upped it to 50 to make sure that int'l timezones will fit. */ /* FIXME: This introduces an arbitrary limit on a buffer size. It should be removed. */ #define GNATS_TIME_LENGTH 50 /* Exit codes. */ extern const int EXIT_OK; extern const int EXIT_PROGRAM_ERROR; /* Files that controls access to the database. */ #define DB_ACCESS_FILE "gnatsd.user_access" #define DB_HOST_ACCESS_FILE "gnatsd.host_access" /* Default values of field properties. */ #define DEFAULT_MULTIENUM_SEPARATOR ": " /* Global variables */ /* Current version of GNATS. */ extern char *version_string; /* The name this program was run with. */ extern const char *program_name; /* Local includes. */ #include "field.h" #include "database.h" #include "index.h" #include "pr.h" #include "query.h" #include "regex.h" #include "adm.h" /* Functions */ /* in btime.c */ extern struct tm *get_response_time (const DatabaseInfo database, unsigned int responseTimeInDays); /* in client.c */ extern int get_reply (FILE *); extern void client_exit (void); extern void safe_exit (void); extern void client_chdb (const char *database); extern int client_lock_gnats (const DatabaseInfo database, ErrorDesc *err); extern void client_unlock_gnats (void); extern void sendRemoteQuery (const char *queryExpr, const char **args, const char *queryFormatName, FILE *outfile); extern void sendRemoteListQuery (ListTypes whichList, FILE *outfile); extern void scanEnv (char **user, char **passwd, char **hostname, int *port, char **database); extern int client_init_gnats (ErrorDesc *err, const char *user, const char *password, const char *hostname, int port, const char *database); extern void client_print_errors (const DatabaseInfo database, ErrorDesc errDesc); extern void tohex (char *ptr, char *buf, int sz); extern int hexdigit (char c); extern void fromhex (char *ptr, char *buf, int sz); extern void clientGetAdmField (FILE *outfile, const char *admField, const char *admSubfield, const char *admKey); extern PR *clientReadPR (const char *prNum); /* Returns a list of PRs that match EXPR. */ extern StringList *clientGetPRList (const char *expr); extern void netCheckPR (FILE *file, int initialPR); extern void netEditField (FILE *fieldData, const char *prNum, const char *fieldName, const char *editUserEmailAddr, int appendToField, char *reason); extern void netSubmitNewPR (FILE *file, int show_prnum); extern void netModifyPR (FILE *file, const char *prNum, const char *editUserEmailAddr); extern void netLockDB (void); extern void netUnlockDB (void); extern void netLockPR (const char *prNum, const char *username, const char *processID); extern void netUnlockPR (const char *prNum); extern void netDeletePR (const char *prNum, const char *editUserEmailAddr); extern void netSetEditEmailAddr (const char *address); extern void netFieldFlags (const char *fieldname); extern void netValidValues (const char *fieldname); extern void netFieldDescription (const char *fieldname); extern void netFieldType (const char *fieldname); /* in edit.c */ extern int check_pr_file (const DatabaseInfo database, FILE *infile, ErrorDesc *err, int initial_entry); extern int check_pr (PR *pr, ErrorDesc *err, int initial_entry); extern int replace_pr (const DatabaseInfo database, FILE *infile, const char *editUserEmailAddr, ErrorDesc *err); extern int lock_pr (const DatabaseInfo database, const char *filename, const char *username, const char *processid, ErrorDesc *error); extern int unlock_pr (const DatabaseInfo database, const char *filename, ErrorDesc *error); extern int validateFieldValue (FieldIndex field, const char *text, ErrorDesc *err, int dontCheckEnums); extern int edit_field (const DatabaseInfo database, const char *prnum, FieldIndex fieldIndex, int append, char *newcontents, char *changeReason, const char *editUserEmailAddr, ErrorDesc *err); extern int applyFieldEdit (PR *pr, FieldEdit *edit, ErrorDesc *err, FormatNamedParameter *params); extern int deletePR (const DatabaseInfo database, const char *prNum, const char *editUserEmailAddr, ErrorDesc *err); /* in fconfigl.l and fconfig.y */ extern void fconferror (const char *string); extern int fconflex (void); extern int yylex (void); /* in file-pr.c */ extern int submit_pr (const DatabaseInfo database, FILE *, ErrorDesc *err); /* in getdate.c */ extern time_t get_date (char *, ...); /* in internal.c */ extern void block_signals (void); extern void unblock_signals (void); extern int is_gnats_locked (const DatabaseInfo database); extern int lock_gnats (const DatabaseInfo database, ErrorDesc *); extern int unlock_gnats (const DatabaseInfo database, ErrorDesc *); extern void punt (const DatabaseInfo database, int, ...); extern int copy_file (const char *, const char *); extern const char *get_prid_from_path (const char*); extern const char *get_cat_prid_from_path (const char*); extern char *get_lock_path (const DatabaseInfo database, const char *prID); extern char *get_curr_date (void); extern int gnatsdbHasNetconn (const char *database_name); extern int isPrLocked (const DatabaseInfo database, const char *prNum); extern int fileExists (const char *filename); extern void setError (ErrorDesc *errorDesc, int errorCode, ...); extern BadFields newBadFieldEntry (FieldIndex field, const char *badValue, BadFields next); extern void freeBadFieldList (BadFields list); extern void freeErrorDesc (ErrorDesc desc); extern int getErrorCode (ErrorDesc errorDesc); extern const char *getErrorMessage (ErrorDesc errorDesc); extern BadFields getBadFieldList (ErrorDesc errorDesc); extern const char *badFieldValue (BadFields ent); extern FieldIndex badFieldIndex (BadFields ent); extern BadFields nextBadField (BadFields ent); extern int check_state_type (const DatabaseInfo database, const char *state, const char *type); /* in lists.c */ extern ListTypes stringToListType (const char *string); extern const char *listTypeToString (ListTypes which); extern int getGnatsFile (const DatabaseInfo database, ListTypes which, const char *file, const char *eolTerminator); /* in misc.c */ extern DatabaseInfo init_gnats (const char *program_name, const char *database_name, ErrorDesc *err); extern void log_msg (int, int, ...); extern void init_logging (const char *filename); extern void enable_debugging (void); extern char *read_line (FILE *input_des, size_t *max_len); extern char *get_next_field (const char **line, int delim); extern char *get_token (char *, char *); extern FILE *open_mail_file (const DatabaseInfo database); extern void close_mail_file (FILE *); extern char *quote_string (const char *string); extern StringList *new_string_list_ent (char *string, StringList *next); extern PTR xmalloc (size_t size); extern PTR xrealloc (PTR ptr, size_t size); extern char *xstrdup (const char *string); extern char *xstrndup (const char *string, size_t length); extern const char *temporary_directory (void); extern int open_temporary_file (char *template, int mode); extern FILE *fopen_temporary_file (char *template, const char *fopen_mode, const int mode); extern size_t gnats_strftime (char *s, size_t size, const char *template, const struct tm *brokentime); extern void usage (const char *const texts[], int exit_code); extern void version (const char *const program_name); extern bool value_is_empty (const char *string); #ifndef HAVE_ASPRINTF extern int asprintf (char **ret, const char *format, ...) ATTRIBUTE_PRINTF_2; #endif #ifndef HAVE_VASPRINTF extern int vasprintf (char **ret, const char *format, va_list) ATTRIBUTE_PRINTF(2,0); #endif #ifndef HAVE_BASENAME extern char *basename (char *path); #endif #endif /* !_gnats_h_ */ gnats-4.1.0/gnats/gnatsd.c0000644000175000017500000005707210207433626016140 0ustar chewiechewie00000000000000/* Remote GNATS server. Copyright (C) 1994, 95, 96, 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnatsd.h" #include "query.h" #ifdef HAVE_LIBCRYPT #ifdef HAVE_CRYPT_H /* some systems declare `crypt' in unistd.h */ #include #endif #endif #if defined (__svr4__) && defined (__sun__) #undef SIG_IGN #define SIG_IGN (void (*)(int))1 #endif /* ??? */ static char myname[MAXHOSTNAMELEN]; /* The base name of the program binary. */ const char *program_name; /* The name and IP address of the host talking with us and their access level. */ const char *current_host; const char *current_addr; Access_Level user_access; /* Whether or not they need to execute CHDB; reset to 0 when they do */ int require_db = 0; /* Maximum available access level. */ static Access_Level max_access_level = ACCESS_ADMIN; struct option long_options[] = { {"database", 1, NULL, 'd'}, {"not-inetd", 0, NULL, 'n'}, {"maximum-access-level", 1, NULL, 'm'}, {"version", 0, NULL, 'V'}, {"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "gnatsd" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]...\n\ Communication interface to GNATS databases.\n\ \n", "\ -d --database=DATABASE use DATABASE\n\ -n --not-inetd no need to authorize when using Kerberos\n\ -m --maximum-access-level=LEVEL do not allow exceeding access LEVEL\n\ \n\ -h --help display this help and exit\n\ -V --version output version information and exit\n", NULL}; #ifdef HAVE_KERBEROS /* Non-zero if the client has used Kerberos authentication. */ int client_authorized; #endif /* Non-zero if the host has to use Kerberos. */ int kerberos_host; /* gnatsd command definition */ typedef struct _command { const char *s; /* command string */ void (*fn)(int ac, char **av); /* the function to be invoked */ Access_Level access; /* the minimum required access level */ bool onearg; /* ??? */ } Command; static Command cmds[] = { /* Various unrestricted commands */ { "QUIT", GNATS_quit, ACCESS_NONE, FALSE }, { "AUTH", GNATS_auth, ACCESS_NONE, FALSE }, { "USER", GNATS_user, ACCESS_NONE, FALSE }, { "HELP", GNATS_help, ACCESS_NONE, FALSE }, /* Switch the database being viewed. */ { "CHDB", GNATS_chdb, ACCESS_NONE, FALSE }, /* Check that the supplied PR text is valid. */ { "CHEK", GNATS_chek, ACCESS_VIEW, FALSE }, /* Submit a new PR. */ { "SUBM", GNATS_subm, ACCESS_SUBMIT, FALSE }, /* Append text to a field in the specified PR. */ { "APPN", GNATS_appn, ACCESS_EDIT, FALSE }, /* Replace the contents of a field in the specified PR. */ { "REPL", GNATS_repl, ACCESS_EDIT, FALSE }, /* Return the list of available databases. */ { "DBLS", GNATS_dbls, ACCESS_LISTDB, FALSE}, /* Return the description of the specified database. */ { "DBDESC", GNATS_dbdesc, ACCESS_VIEW, TRUE }, /* Validate that the specified data is valid for the field. */ { "VFLD", GNATS_vfld, ACCESS_VIEW, TRUE }, /* Set query constraints (no need to restrict) */ { "RSET", GNATS_rset, ACCESS_VIEW, FALSE }, /* The format used when returning query results. */ { "QFMT", GNATS_qfmt, ACCESS_VIEW, TRUE }, /* Specify a query expression to use. */ { "EXPR", GNATS_expr, ACCESS_VIEW, TRUE }, /* Query a PR. */ { "QUER", GNATS_quer, ACCESS_VIEW, FALSE }, /* List GNATS internals */ { "LIST", GNATS_list, ACCESS_VIEW, FALSE }, /* Lock the specified PR, using the specified username and (optional) PID */ { "LOCK", GNATS_lock, ACCESS_EDIT, FALSE }, /* Set the email address of the user editing PRs. */ { "EDITADDR", GNATS_editaddr, ACCESS_EDIT, TRUE }, /* Edit a PR; the PR contents are sent and used to replace an existing PR. */ { "EDIT", GNATS_edit, ACCESS_EDIT, FALSE }, /* Unlock the specified PR. */ { "UNLK", GNATS_unlk, ACCESS_EDIT, FALSE }, /* Stop and start the database. */ { "LKDB", GNATS_lkdb, ACCESS_EDIT, FALSE }, { "UNDB", GNATS_undb, ACCESS_EDIT, FALSE }, /* Return the type of data stored in the field. */ { "FTYP", GNATS_ftyp, ACCESS_VIEW, FALSE }, /* Return the field property value specified by the arguments. */ { "FTYPINFO", GNATS_ftypinfo, ACCESS_VIEW, FALSE}, /* Return a human-readable description of the field. */ { "FDSC", GNATS_fdsc, ACCESS_VIEW, FALSE }, /* Return either a regexp that describes the valid values for the specified field, or a list of valid values (for an enum field). */ { "FVLD", GNATS_fvld, ACCESS_VIEW, TRUE }, /* List the flags set on this the specified field(s). */ { "FIELDFLAGS", GNATS_fieldflags, ACCESS_VIEW, FALSE }, /* List the default values suggested when an initial PR is input. */ { "INPUTDEFAULT", GNATS_inputdefault, ACCESS_VIEW, FALSE }, /* Deletes the specified PR from the database. */ { "DELETE", GNATS_delete, ACCESS_ADMIN, FALSE }, /* Returns an entry from the adm data associated with the specified field that matches the specified key. If a subfield is also specified, only the data in that subfield is returned. */ { "ADMV", GNATS_admv, ACCESS_VIEW, FALSE }, { NULL, NULL, -1, FALSE }, }; /* Return true iff `line' matches the shell `pattern'. Iff `matchcase' is false, the matching is case insensitive.*/ static bool match (const char *line, const char *pattern, bool matchcase) { /* If p is a null string, this is a match (downward compatibility) */ if (*pattern == '\0') { return TRUE; } while (*pattern != '\0') { if (*line == '\0' && *pattern != '*') { return FALSE; } switch (*pattern) { case '\\': /* Literal match with following character. */ pattern++; /* FALLTHROUGH */ default: if (matchcase) { if (*line != *pattern) { return FALSE; } } else { if (tolower ((int)(*line)) != tolower ((int)(*pattern))) { return FALSE; } } break; case '?': /* Match anything. */ break; case '*': { while (*pattern == '*') { /* Consecutive stars act just like one. */ pattern++; } if (*pattern == '\0') { /* Trailing star matches everything. */ return TRUE; } /* This is very inefficient. */ while (*line != '\0') { int matched = match (line, pattern, matchcase); if (matched) { return matched; } line++; } /* Didn't find a match for the trailing pattern, so it failed. */ return FALSE; } break; } line++; pattern++; } /* We've run out of chars in pattern. If there are more line chars, there is no match. */ if (*line != '\0') { return FALSE; } else { return TRUE; } } /* Return true iff `password' matches `hash'. `hash' is a possibly encrypted password, according to the $?$ convention. */ static int password_match (const char *password, const char *hash) { if (strlen(password) && strlen(hash)) { if (! strncmp (hash, "$0$", 3)) { /* explicit plain-text password */ return match (password, hash+3, TRUE); } else { #ifdef HAVE_LIBCRYPT /* DES crypt or MD5 hash of the password */ char *encrypted = crypt (password, hash); return encrypted && ! strcmp (encrypted, hash); #else /* TODO: log some warning */ return FALSE; #endif } } else { if (strlen(password)) { return FALSE; } else { return ! strlen(hash) ; } } } /* */ static char * get_name (struct in_addr *host) { char *buf; int i; struct hostent *hp; #ifdef h_addr char **pp; #endif hp = gethostbyaddr ((char *) host, sizeof (*host), AF_INET); if (hp == NULL) { return NULL; } i = strlen (hp->h_name); buf = (char *) xmalloc (i + 1); strcpy (buf, hp->h_name); hp = gethostbyname (buf); if (hp == NULL) return NULL; /* XXX ??? !!! This is for def sure not the right way to do this; it should be done with an autoconf test instead. */ #ifdef h_addr for (pp = hp->h_addr_list; *pp; pp++) { if (memcmp ((char *) &host->s_addr, (char *) *pp, hp->h_length) == 0) { break; } } if (*pp == NULL) { return NULL; } #else if (memcmp ((char *) &host->s_addr, (char *) hp->h_addr, hp->h_length) != 0) { return NULL; } #endif return buf; } /* Assignment of symbolic values to strings of access levels. */ typedef struct _Access_String { const Access_Level access; const char *string; } Access_String; static Access_String ACCESS_STRINGS[] = { {ACCESS_UNKNOWN, "unknown"}, {ACCESS_DENY, "deny"}, {ACCESS_NONE, "none"}, {ACCESS_LISTDB, "listdb"}, {ACCESS_SUBMIT, "submit"}, {ACCESS_VIEW, "view"}, {ACCESS_VIEWCONF, "viewconf"}, {ACCESS_EDIT, "edit"}, {ACCESS_ADMIN, "admin"}, {NO_LEVEL, "none"} }; /* Return the numeric code of string representation of the access level `key'. */ static Access_Level access_level (char *key) { unsigned int i; for (i = 0; ACCESS_STRINGS[i].access != NO_LEVEL; i++) { if (strcasecmp (key, ACCESS_STRINGS[i].string) == 0) return ACCESS_STRINGS[i].access; } return ACCESS_NONE; } /* Return the string representation of the access level `access'. */ const char * access_level_str (Access_Level access) { int i; for (i = 0; ACCESS_STRINGS[i].access != NO_LEVEL; i++) { if (access == ACCESS_STRINGS[i].access) break; } return ACCESS_STRINGS[i].string; } /* Return a non-zero value if the host was found; ACCESS will contain the access level. */ static int validateHost (AdmEntry *hostList, const char *host, const char *ipaddr, Access_Level *access) { int found = 0; /* The format of the file is: sitename:access: where `sitename' is the hostname allowed; `access' is the access level, and the third field is undefined for now, but may be the field to control what PRs, categories, or submitter-id PRs are allowed, or whatever. */ while (hostList != NULL) { /* check hostname and IP */ if (match (host, hostList->admFields[HostListKey], FALSE) || (ipaddr != NULL && match (ipaddr, hostList->admFields[HostListKey], FALSE))) { found = 1; *access = access_level (hostList->admFields[HostListAccessLevel]); break; } hostList = hostList->next; } #ifdef HAVE_KERBEROS /* ??? */ if (! found) { *access = ACCESS_EDIT; found = kerberos_host = 1; } #endif return found; } /* Returns a non-zero value if an entry was found for the user; the access level will be contained in ACCESS. */ static int findUserAccessLevel (const char *file, const char *user, const char *passwd, Access_Level *access, const DatabaseInfo database) { FILE *acc; int found = 0; const char *dName; /* The format of the file is: userid:passwd:access:database */ acc = fopen (file, "r"); if (acc == NULL) { return 0; } if (databaseValid (database)) { dName = databaseName (database); } else { dName = ""; } while (! found) { char *buffer = read_line (acc, NULL); if (buffer != NULL) { AdmEntry *ent = build_adm_entry (buffer, InvalidFieldIndex); free (buffer); /* Is there a mistake on the setup of this line? (must have 3 or 4 fields) */ if ((ent->fieldcount == 3 || ent->fieldcount == 4) && match (user, ent->admFields[0], TRUE)) { if (! password_match (passwd, ent->admFields[1])) { /* Username matched but password didn't. */ if (strlen(ent->admFields[1]) && strlen(passwd)) { *access = ACCESS_NONE; found = 1; } } else { if (ent->fieldcount == 4) { /* Compare all given names against the name of the requested database. */ const char *l2 = ent->admFields[3]; if (l2 == NULL || ! strlen(l2)) found = 1; while (l2 != NULL && ! found) { char *token = get_next_field (&l2, ','); if (match (dName, token, TRUE)) { found = 1; } free (token); } } else { found = 1; } if (found) { *access = access_level (ent->admFields[2]); } } } } else { /* Ran out of entries. */ break; } } fclose (acc); if (found && *access > max_access_level) { *access = max_access_level; } return found; } /* Get the access level for this user. */ static int get_user_access (const DatabaseInfo database, const char *user, const char *passwd, Access_Level *access) { int found = 0; if (databaseValid (database)) { char *path = gnats_adm_dir (database, DB_ACCESS_FILE); if (path != NULL) { found = findUserAccessLevel (path, user, passwd, access, database); free (path); } } if (! found) { found = findUserAccessLevel (GNATSD_USER_ACCESS_FILE, user, passwd, access, database); } return found; } /* See if we know about this host. If we don't, then run with it. */ int verifyHostAndUser (const DatabaseInfo database, const char *host, const char *ipaddr, const char *username, const char *passwd, Access_Level *access) { int hostFound = 0; int userFound = 0; Access_Level hostAccess = ACCESS_NONE; Access_Level userAccess = ACCESS_NONE; if (databaseValid (database)) { AdmEntry *hostList = getHostList (database); hostFound = validateHost (hostList, host, ipaddr, &hostAccess); } if (! hostFound) { AdmEntry *hostList = getGlobalHostList (); hostFound = validateHost (hostList, host, ipaddr, &hostAccess); } if (! hostFound) { *access = ACCESS_NONE; } else { userFound = get_user_access (database, username, passwd, &userAccess); if (userFound) { *access = (userAccess >= hostAccess ? userAccess : hostAccess); } else { *access = hostAccess; } } return hostFound; } static void startConnection (void) { struct sockaddr_in s; #if HAVE_SOCKLEN_T socklen_t len; #else int len; #endif int access = ACCESS_UNKNOWN; len = sizeof (s); if (getpeername (0, (struct sockaddr *)&s, &len) < 0) { if (! isatty (0)) { log_msg (LOG_ERR, FALSE, "can't get peername %m", "?"); printf ("%d Why can't I figure out your name? Later.\r\n", CODE_NO_ACCESS); access = ACCESS_DENY; } else { current_host = "stdin"; current_addr = current_host; } } else { if (s.sin_family != AF_INET) { syslog (LOG_ERR, "%s: bad address family %ld", "?", (long) s.sin_family); printf ("%d You're a member of a bad address family. Later.\r\n", CODE_NO_ACCESS); access = ACCESS_DENY; } else { current_addr = (char *) inet_ntoa (s.sin_addr); current_host = get_name (&s.sin_addr); if (current_host == NULL) { current_host = current_addr; } } } } MsgType get_line (char **dest, int timeout) { static int count = 0; static char buffer[BUFSIZ]; /* The size doesn't matter here */ static char *bp = NULL; struct timeval t; fd_set rmask; int done = 0; int errorCode = PR_ok; size_t resultLen = 0; char *result = NULL; while ((! done) && errorCode == PR_ok) { if (count == 0) { int i; /* Fill the buffer. */ FD_ZERO(&rmask); FD_SET(0, &rmask); t.tv_sec = timeout; t.tv_usec = 0; i = select (0 + 1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &t); if (i < 0) { if (errno == EINTR) { continue; } else { errorCode = PR_timeout; } } else if (i == 0 || !FD_ISSET(0, &rmask)) { errorCode = PR_timeout; } else { count = read (0, buffer, sizeof buffer); if (count < 0) { /* "This isn't the correct error code, but we'll pass that." -- paraphrased Philip Marlowe */ errorCode = PR_timeout; } else if (count == 0) { errorCode = PR_eof; } else { bp = buffer; } } } if (errorCode == PR_ok) { char *eol = memchr (bp, '\n', count); size_t amtRead; size_t amtToCopy; if (eol != NULL) { /* We don't want to copy the '\n' out. */ amtToCopy = eol - bp; /* Gobble the '\n'. */ amtRead = amtToCopy + 1; } else { amtRead = count; amtToCopy = amtRead; } result = xrealloc (result, resultLen + amtToCopy + 1); memcpy (result + resultLen, bp, amtToCopy); resultLen += amtToCopy; count -= amtRead; bp += amtRead; if (eol != NULL) { done = 1; } } } if (errorCode == PR_ok) { /* If last two characters are \r\n, kill the \r as well as the \n. */ if (resultLen > 0 && result[resultLen - 1] == '\r') { resultLen--; } result[resultLen] = '\0'; } else { if (result != NULL) { free (result); result = NULL; } /* Whatever's in the buffer is garbage. */ bp = buffer; count = 0; } *dest = result; return errorCode; } static int gnatsd_argify(char *line, char ***argvp, Command **cp) { char **argv; char *lineCopy; char *argStart; int argc = 1; /* Copy the line, which we will split up. (Tho why we're counting \n and ' ' as separators but not other space characters is a mystery, especially as \n should never appear here as a separator.) */ while (*line == ' ' || *line == '\n') { line++; } lineCopy = xstrdup (line); argv = (char **) xmalloc (sizeof (char **) * 2); argv[0] = lineCopy; argStart = strpbrk(lineCopy, " \n"); if (argStart != NULL) { *(argStart++) = '\0'; while (*argStart == ' ' || *argStart == '\n') { argStart++; } } for (*cp = cmds; (*cp)->s != NULL; (*cp)++) { if (strcasecmp ((*cp)->s, argv[0]) == 0) { break; } } if ((*cp)->s == NULL) { *cp = NULL; } if (*cp != NULL && (*cp)->onearg) { if (argStart != NULL) { argv = (char **) xrealloc (argv, sizeof (char **) * (argc + 2)); argv[argc++] = argStart; } } else { while (argStart != NULL && *argStart != '\0') { char *nextWord = strpbrk (argStart, " \n"); argv = (char **) xrealloc (argv, sizeof (char **) * (argc + 2)); argv[argc++] = argStart; if (nextWord != NULL) { *(nextWord++) = '\0'; while (*nextWord == ' ' || *nextWord == '\n') { nextWord++; } } argStart = nextWord; } } argv[argc] = NULL; *argvp = argv; return argc; } static void freeArgs (int ac ATTRIBUTE_UNUSED, char **av) { if (av != NULL) { if (av[0] != NULL) { free (av[0]); } free (av); } } static void serverMainLoop (void) { char **av; int ac = 0; Command *cp; MsgType r; int done = 0; while (! done) { char *buff; fflush (stdout); r = get_line (&buff, 2 * 60 * 60); av = NULL; cp = NULL; ac = 0; if (r == PR_ok) { if (buff[0] == '\0') { printf ("%d Unrecognized command.\r\n", CODE_ERROR); } else { ac = gnatsd_argify (buff, &av, &cp); } } else { if (r == PR_timeout) { printf ("%d Read timed out.\r\n", CODE_TIMEOUT); } done = 1; } if (buff != NULL) { free (buff); buff = NULL; } /* Ignore blank/invalid lines. */ if (av != NULL) { if (strcasecmp (av[0], "quit") == 0) { freeArgs (ac, av); av = NULL; done = 1; } else if (cp != NULL) { /* Check access level */ Access_Level access_required = cp->access; #ifdef HAVE_KERBEROS /* Did they send AUTH? */ if (kerberos_host && (access_required > user_access) && !client_authorized) { syslog (LOG_ERR, "GNATS command `%s' without authentication for %s", cp->s, current_host); } #endif /* require_db means the first command must be CHDB and it must succeed. */ if (require_db && (strcasecmp (av[0], "chdb") != 0)) { printf ("%d CHDB command required (database invalid).\r\n", CODE_NO_ACCESS); } else if (access_required > user_access) { printf ("%d You are not authorized to perform this operation (%s).\r\n", CODE_NO_ACCESS, cp->s); } else { /* Call the function. We skip the command itself in the arg list. */ (*cp->fn) (ac - 1, av + 1); if (require_db) { printf ("%d Required CHDB command failed.\r\n", CODE_NO_ACCESS); } } } else { printf ("%d Unrecognized command.\r\n", CODE_ERROR); } freeArgs (ac, av); av = NULL; } } } int main (int argc, char **argv) { struct hostent *hp; int optc; int not_inetd = 0; char *database = NULL; ErrorDesc err; program_name = basename (argv[0]); while ((optc = getopt_long (argc, argv, "d:nm:Vh", long_options, (int *) 0)) != EOF) { switch (optc) { case 'd': database = optarg; break; case 'n': not_inetd = 1; break; case 'm': max_access_level = access_level(optarg); break; case 'V': version (PROGRAM_NAME); exit (0); break; case 'h': usage (USAGE, 0); break; default: usage (USAGE, 1); } } umask (022); #ifdef HAVE_KERBEROS kerberos_host = client_authorized = 0; if (not_inetd) { client_authorized = 1; } #endif /* close file descriptors */ fflush (stderr); fflush (stdout); init_logging (NULL); if (gethostname (myname, MAXHOSTNAMELEN) != 0) { fprintf (stderr, "%s: cannot find out the name of this host\n", program_name); exit (1); } /* Now see if we can get a FQDN for this host. */ hp = (struct hostent *) gethostbyname (myname); if (hp != NULL && (strlen (hp->h_name) > strlen (myname))) { strncpy (myname, hp->h_name, MAXHOSTNAMELEN); } /* Don't pay attention to SIGPIPE; read will give us the problem if it happens. */ signal (SIGPIPE, SIG_IGN); if (! not_inetd) { startConnection (); } else { current_host = myname; if (hp != NULL) { current_addr = (char *) inet_ntoa (*(struct in_addr *) hp->h_addr); } else { current_addr = myname; } } /* Change to the default database. */ if (gnatsdChdb (database, "", "", 1, &err) != 0) { fprintf (stderr, "%d GNATS initialization of database failed: %s\n", getErrorCode (err), getErrorMessage (err)); /* XXX ??? !!! Not sure what to do here exactly. Badness, really. */ if (getErrorCode (err) >= 600) { /* Fatal error. */ exit (1); } else { require_db = 1; } } if (user_access > ACCESS_DENY) { printf ("%d%c%s GNATS server %s ready.\r\n", CODE_GREETING, kerberos_host ? '-' : ' ', myname, version_string); if (kerberos_host) { printf ("%d Hi %s; you must use Kerberos authentication.\r\n", CODE_GREETING, current_host); } serverMainLoop (); printf ("%d Later.\r\n", CODE_CLOSING); } exit (0); } gnats-4.1.0/gnats/gnatsd.h0000644000175000017500000001002507370347042016133 0ustar chewiechewie00000000000000/* Codes returned by the GNATS server. Copyright (C) 2001 Milan Zamazal Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include /* for sockaddr_in */ #include /* for inet_ntoa decl */ #include #ifdef HAVE_NETDB_H #include /* for hostent and MAXHOSTNAMELEN */ #endif #include /* for AF_INET */ #include /* for timeval */ #ifdef HAVE_SYS_SELECT_H #include /* for fd_set */ #endif /* The information we need for a reply from the server. */ typedef struct _reply { int state; char *text; int type; } Reply; typedef enum _msg_type { PR_eof, PR_ok, PR_timeout } MsgType; #include "query.h" /* gnatsd access levels */ typedef enum _Access_Level { ACCESS_UNKNOWN, ACCESS_DENY, ACCESS_NONE, ACCESS_LISTDB, ACCESS_SUBMIT, ACCESS_VIEW, ACCESS_VIEWCONF, ACCESS_EDIT, ACCESS_ADMIN, NO_LEVEL /* for internal auxiliary use only */ } Access_Level; /* The name and IP address of the host talking with us and their access level. */ extern const char *current_host; extern const char *current_addr; extern Access_Level user_access; /* in gnatsd.c */ extern MsgType get_line (char **text, int timeout); extern int verifyHostAndUser (const DatabaseInfo database, const char *host, const char *ipaddr, const char *username, const char *passwd, Access_Level *access); extern const char *access_level_str (Access_Level); extern int gnatsdChdb (const char *database, const char *user, const char *password, int quiet, ErrorDesc *err); /* cmds.c */ extern void GNATS_quit (int ac, char **av); extern void GNATS_qfmt (int ac, char **av); extern void GNATS_quer (int ac, char **av); extern void GNATS_lock (int ac, char **av); extern void GNATS_unlk (int ac, char **av); extern void GNATS_lkdb (int ac, char **av); extern void GNATS_undb (int ac, char **av); extern void GNATS_dbls (int ac, char **av); extern void GNATS_dbdesc (int ac, char **av); extern void GNATS_chdb (int ac, char **av); extern void GNATS_chek (int ac, char **av); extern void GNATS_subm (int ac, char **av); extern void GNATS_appn (int ac, char **av); extern void GNATS_repl (int ac, char **av); extern void GNATS_edit (int ac, char **av); extern void GNATS_vfld (int ac, char **av); extern void GNATS_rset (int ac, char **av); extern void GNATS_auth (int ac, char **av); extern void GNATS_user (int ac, char **av); extern void GNATS_list (int ac, char **av); extern void GNATS_help (int ac, char **av); extern void GNATS_expr (int ac, char **av); extern void GNATS_ftyp (int ac, char **av); extern void GNATS_fdsc (int ac, char **av); extern void GNATS_fvld (int ac, char **av); extern void GNATS_admv (int ac, char **av); extern void GNATS_ftypinfo (int ac, char **av); extern void GNATS_editaddr (int ac, char **av); extern void GNATS_fieldflags (int ac, char **av); extern void GNATS_inputdefault (int ac, char **av); extern void GNATS_delete (int ac, char **av); /* Whether we received `STATE-' or `STATE '. */ #define REPLY_CONT 1 #define REPLY_END 2 /* Used if Kerberos version 4 authentication is enabled. */ #define GNATS_KRB4_VERSIONID "GnatsK1.0" #define GNATS_KRB4_PRINCIPAL_NAME gnatsAdminMailAddr () #include "pcodes.h" gnats-4.1.0/gnats/gnatsd.host_access0000644000175000017500000000341007654204443020204 0ustar chewiechewie00000000000000# # Hosts that can do lookups with the GNATS daemon. # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # host:access-level:whatever # # * host: the hostname or IP address of the host contacting gnatsd. # Wildcard characters are supported in the host field. # "*" matches anything; "?" matches any single character. # NOTE: When authenticating, GNATS reads the entries in this file in # sequence until a match is found. This means that wildcard entries # must be placed near the end of the file, otherwise, they will # override non-wildcard entries appearing after the wildcard ones. # # * access-level: (default = edit) # deny - gnatsd closes the connection # none - no further access until userid and password given # listdb - same as 'none', except that the host is allowed to # list the available databases on the server # view - query and view PRs with Confidential=no only # viewconf - query and view PRs with Confidential=yes # edit - full edit access # admin - full admin access (required for operations such as # deleting PRs) # This is just the default access level for the user's host. Normally, # this will get overridden (increased) with the USER command. See the # gnatsd.user_access file. # # We currently don't make use of the third field. Ideas include # listing the categories, the PRs matching a given submitter-id, and # the PRs of a certain category to a particular site. # #192.168.*:view: #software.free.com:edit: *:listdb: gnats-4.1.0/gnats/gnatsd.user_access0000644000175000017500000000426307675541213020216 0ustar chewiechewie00000000000000# # User access levels with the GNATS daemon. # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # userid:password:access-level:database-alias # # Wildcard characters are supported for userid, password and database. # "*" matches anything; "?" matches any single character. # NOTE: When authenticating, GNATS reads the entries in this file in # sequence until a match is found. This means that wildcard entries # must be placed near the end of the file, otherwise, they will # override non-wildcard entries appearing after the wildcard ones. # # * userid: a user id to gain access to gnatsd # * password: a password for the user. Passwords prefixed by # $0$ are assumed to be plain-text. Passwords without a $0$ # prefix are assumed to be encrypted with standard # crypt(). For example, on FreeBSD systems, no prefix implies DES # encryption, a prefix of $1$ implies MD5 encryption, while # $2$ prefix implies Blowfish encryption. GNATS will support all the # encryption methods supported by your system's crypt() routine. An # empty field value means that the user should not supply any # password. # * access-level: (default = listdb) # deny - gnatsd closes the connection # none - no further access until userid and password given # listdb - same as 'none', except that the user is allowed to # list the available databases on the server # view - query and view PRs with Confidential=no only # viewconf - query and view PRs with Confidential=yes # edit - full edit access # admin - full admin access (required for operations such as # deleting PRs) # This overrides (increases but never lowers) the access level given # as the default for the user's host in the gnatsd.host_access file. # * database-alias: a comma-separated list of database names. # It's ignored in gnatsd-adm/gnatsd.user_access since this file is # already database specific. # #*::view: gnats-4.1.0/gnats/index.c0000644000175000017500000006332310207433626015763 0ustar chewiechewie00000000000000/* Miscellaneous index routines for use with GNATS. Copyright (C) 1993, 1995, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com) and by Tim Wicinski (wicinski@barn.com). Heavily revised by Bob Manson (manson@juniper.net); also added binary index support. This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ /* Binary format (all values are in MSB-first order): * 1 byte: number of fields in each index entry * For each record: * 2 bytes: total length of record, including this 2 byte length * For each field: * 2 bytes: length of field, not including this 2 byte length or NUL * terminator * N bytes: data in field, NUL-terminated */ #include "gnats.h" #include "gnatsd.h" struct index_desc { DatabaseInfo database; char *path; FieldList fields; char *separator; int isBinary; int numberOfFields; int *fieldInIndex; time_t mtime; int indexRead; PR *prChain; }; typedef struct index_file_desc { IndexDesc desc; FILE *fileDes; } *IndexFileDesc; struct indexEntry { char *buf; char **fields; PR *nextPR; PR *prevPR; }; static PR *nextIndexEntryBinary (IndexFileDesc fp); static int format_field (FieldIndex field, const char *value, const char *separator, char **dest, size_t *length) { char datebuf[30]; size_t valLen; size_t destLen; size_t sepLen; if (value == NULL) { value = ""; } if (fieldDefForIndex (field)->nospaces) { char *r = strchr (value, ' '); if (r != NULL) { valLen = r - value; } } if (fieldDefForIndex (field)->datatype == Date) { time_t d = 0; if (value != NULL && *value != '\0') { /* We used to fail here if the date was invalid, but that's a mistake. */ d = get_any_date (value); } sprintf (datebuf, "%d", (int) d); value = datebuf; } if (value == NULL) { value = ""; } destLen = *length; valLen = strlen (value); sepLen = strlen (separator); *dest = xrealloc (*dest, destLen + valLen + sepLen + 1); memcpy (*dest + destLen, separator, sepLen); memcpy (*dest + destLen + sepLen, value, valLen); (*dest)[destLen + sepLen + valLen] = '\0'; *length = destLen + sepLen + valLen; return sepLen + valLen; } char * createIndexEntry (PR *pr, size_t *reclen) { FieldList f; char *res; IndexDesc indexDesc = getIndexDesc (pr->database); if (indexIsBinary (pr->database)) { return createIndexEntryBinary (pr, reclen); } /* XXX ??? !!! For now. We need a way to refer to "PRID". */ asprintf (&res, "%s/%s", field_value (pr, CATEGORY (pr->database)), field_value (pr, NUMBER (pr->database))); *reclen = strlen (res); for (f = indexDesc->fields; f != NULL; f = f->next) { FieldIndex i = simpleFieldIndexValue (f->ent); if (format_field (i, field_value (pr, i), indexDesc->separator, &res, reclen) < 0) { free (res); res = NULL; break; } } append_string (&res, "\n"); (*reclen)++; return res; } static char * find_sep (IndexDesc indexDesc, char *start) { char *end; int seplen = strlen (indexDesc->separator); do { end = strchr (start, indexDesc->separator[0]); if (end != NULL) { if (seplen == 1 || strncmp (start, indexDesc->separator, seplen) == 0) { return end; } end++; } } while (end != NULL); return end; } static char * readBinaryRecord (IndexFileDesc fp, size_t *length) { char *res; unsigned char entlen[2]; if (fread (entlen, 1, 2, fp->fileDes) != 2) { return NULL; } *length = entlen[0] * 256 + entlen[1] - 2; res = xmalloc (*length); if (fread (res, 1, *length, fp->fileDes) == *length) { return res; } else { free (res); return NULL; } } static char * extractBinaryField (char **record, size_t *lengthPtr) { size_t length = *lengthPtr; if (length > 0) { char *recLen = *record; size_t fieldLen = (recLen[0] & 255) * 256 + (recLen[1] & 255); if ((fieldLen + 3) <= length) { char *recptr = *record + 2; *lengthPtr = length - (fieldLen + 3); (*record) = recLen + fieldLen + 3; return recptr; } } return NULL; } /* Return the next index entry from FP. */ static PR * nextIndexEntry (IndexFileDesc fp) { char *start, *end; char *buf; PR *res; int x; int seplen; FieldList f; Index *p; if (fp->desc->isBinary) { return nextIndexEntryBinary (fp); } res = allocPR (fp->desc->database); p = res->index; seplen = strlen (fp->desc->separator); p->prevPR = NULL; p->nextPR = NULL; p->fields = (char **) xmalloc (sizeof (char *) * get_num_fields (fp->desc->database)); memset (p->fields, 0, sizeof (char *) * get_num_fields (fp->desc->database)); while ((buf = read_line (fp->fileDes, NULL)) != NULL) { if (buf[0] != '#') { break; } else { free (buf); } } if (buf == NULL) { goto no_entry; } p->buf = buf; x = strlen (buf) - 1; if (buf[x] == '\n') { buf[x] = '\0'; } start = buf; end = strchr (start, '/'); if (end == NULL) { goto no_entry; } *end = '\0'; p->fields[fieldDefForIndex (CATEGORY (fp->desc->database))->number] = start; start = end + 1; end = find_sep (fp->desc, start); if (end == NULL) { goto no_entry; } *end = '\0'; p->fields[fieldDefForIndex (NUMBER (fp->desc->database))->number] = start; for (f = fp->desc->fields; f != NULL && end != NULL; f = f->next) { FieldIndex i = simpleFieldIndexValue (f->ent); if (i != InvalidFieldIndex) { start = end + seplen; p->fields[fieldNumber (i)] = start; } if (f->next != NULL) { end = find_sep (fp->desc, start); if (end != NULL) { *end = '\0'; } } } if (f == NULL) { return res; } no_entry: free_pr (res); return NULL; } static PR * nextIndexEntryBinary (IndexFileDesc fp) { char *record; PR *res = NULL; size_t length; record = readBinaryRecord (fp, &length); if (record != NULL) { FieldList f; Index *indexEnt; res = allocPR (fp->desc->database); indexEnt = res->index; indexEnt->prevPR = NULL; indexEnt->nextPR = NULL; indexEnt->fields = (char **) xmalloc (sizeof (char *) * get_num_fields (fp->desc->database)); indexEnt->buf = record; memset (indexEnt->fields, 0, sizeof (char *) * get_num_fields (fp->desc->database)); indexEnt->fields[fieldDefForIndex (NUMBER (fp->desc->database))->number] = extractBinaryField (&record, &length); indexEnt->fields[fieldDefForIndex (CATEGORY (fp->desc->database))->number] = extractBinaryField (&record, &length); for (f = fp->desc->fields; res != NULL && f != NULL; f = f->next) { FieldIndex i = simpleFieldIndexValue (f->ent); if (i != InvalidFieldIndex) { indexEnt->fields[fieldNumber (i)] = extractBinaryField (&record, &length); if (indexEnt->fields[fieldNumber (i)] == NULL) { free_pr (res); res = NULL; } } else { free_pr (res); res = NULL; } } } return res; } static void appendBinaryFieldContents (char **dest, const char *value, size_t *recLenPtr) { size_t valLen; size_t recLen = *recLenPtr; if (value == NULL) { value = ""; valLen = 0; } else { valLen = strlen (value); } *dest = xrealloc (*dest, recLen + valLen + 3); memcpy (*dest + recLen + 2, value, valLen + 1); (*dest)[recLen + 0] = valLen / 256; (*dest)[recLen + 1] = valLen % 256; *recLenPtr += valLen + 3; } char * createIndexEntryBinary (PR *pr, size_t *recLen) { const DatabaseInfo database = pr->database; const IndexDesc indexDesc = getIndexDesc (database); FieldList f; char *res; *recLen = 2; res = xmalloc (2); appendBinaryFieldContents (&res, field_value (pr, NUMBER (pr->database)), recLen); appendBinaryFieldContents (&res, field_value (pr, CATEGORY (pr->database)), recLen); for (f = indexDesc->fields; f != NULL; f = f->next) { FieldIndex i = simpleFieldIndexValue (f->ent); size_t fieldLenOffset = *recLen; int valLen; /* Two bytes for the field length. */ *recLen += 2; valLen = format_field (i, field_value (pr, i), "", &res, recLen); res[fieldLenOffset + 0] = valLen / 256; res[fieldLenOffset + 1] = valLen & 255; /* One for the NUL character; format_field() always appends one, but doesn't include it in the length. */ (*recLen)++; } res[0] = *recLen / 256; res[1] = *recLen % 256; return res; } static char * findPrCategoryBinary (IndexFileDesc fp, const char *number) { unsigned char fieldcount; char *record; size_t recLen; if (fread (&fieldcount, 1, 1, fp->fileDes) != 1) { return NULL; } while ((record = readBinaryRecord (fp, &recLen)) != NULL) { char *recPos = record; char *prNum = extractBinaryField (&recPos, &recLen); if (prNum != NULL && strcmp (prNum, number) == 0) { char *category = extractBinaryField (&recPos, &recLen); free (record); return category; } free (record); } return NULL; } /* Find problem report NUMBER in the index file, returning its category. */ static char * findPrCategory (IndexFileDesc fp, const char *number) { char *buf; char *res = NULL; while ((res == NULL) && (buf = read_line (fp->fileDes, NULL)) != NULL) { if (buf[0] != '#') { char *start = buf; char *end = strchr (start, '/'); if (end != NULL) { char *numStart = end + 1; char *category = start; *end = '\0'; end = find_sep (fp->desc, numStart); if (end != NULL) { *end = '\0'; if (strcmp (numStart, number) == 0) { res = xstrdup (category); } } } } free (buf); } return res; } static time_t statIndex (char *name) { struct stat buf; int i; i = stat (name, &buf); if (i < 0) { return (time_t)-1; } return buf.st_mtime; } static IndexFileDesc openIndex (IndexDesc indexDesc, ErrorDesc *err) { FILE *fp; time_t t; char *index_filename = gnats_adm_dir (indexDesc->database, indexDesc->path); IndexFileDesc res = (IndexFileDesc) xmalloc (sizeof (struct index_file_desc)); res->desc = indexDesc; fp = fopen (index_filename, "r"); if (fp != NULL) { t = statIndex (index_filename); /* ??? XXX !!! Do we want to do something here? */ if (t != (time_t)-1) { indexDesc->mtime = t; } res->fileDes = fp; if (indexDesc->isBinary) { unsigned char fieldCount; if ((fread (&fieldCount, 1, 1, res->fileDes) != 1) || (fieldCount != indexDesc->numberOfFields)) { setError (err, CODE_INVALID_INDEX, "Index file %s contains incorrect number of fields", index_filename); fclose (res->fileDes); free (res); res = NULL; } } } else { setError (err, CODE_FILE_ERROR, "Unable to open index file %s", index_filename); free (res); res = NULL; } free (index_filename); return res; } static void closeIndex (IndexFileDesc desc) { fclose (desc->fileDes); free (desc); } /* getIndex - reads in the entire set of PRs with index entries. */ static PR * getIndex (IndexDesc indexDesc, ErrorDesc *err) { IndexFileDesc fp = openIndex (indexDesc, err); PR *new_chain = NULL; PR *end_chain = NULL; if (fp != NULL) { PR *i; while ((i = nextIndexEntry (fp))) { if (new_chain == NULL) { new_chain = i; end_chain = i; } else { i->index->prevPR = end_chain; end_chain->index->nextPR = i; end_chain = i; } } closeIndex (fp); } indexDesc->indexRead = 1; return new_chain; } static PR * getNewIndexIfChanged (DatabaseInfo database, ErrorDesc *err) { int rereadIndex; IndexDesc indexDesc = getIndexDesc (database); if (indexDesc->indexRead) { time_t t; char *index_filename = gnats_adm_dir (database, indexDesc->path); t = statIndex (index_filename); free (index_filename); if (t == (time_t)-1) { setError (err, CODE_FILE_ERROR, "GNATS cannot stat the index: %s.", strerror (errno)); return 0; } if (t > indexDesc->mtime) { rereadIndex = 1; } else { rereadIndex = 0; } } else { rereadIndex = 1; } if (rereadIndex) { return getIndex (indexDesc, err); } else { return NULL; } } void freePRIndex (PR *pr) { if (pr->index != NULL && pr->index->fields != NULL) { if (pr->index->buf != NULL) { free (pr->index->buf); pr->index->buf = NULL; } else { int x; for (x = get_num_fields (pr->database) - 1; x >= 0; x--) { if (pr->index->fields[x] != NULL) { free (pr->index->fields[x]); pr->index->fields[x] = NULL; } } } free (pr->index->fields); pr->index->fields = NULL; } } void allocIndex (PR *pr) { pr->index = (Index *) xmalloc (sizeof (Index)); pr->index->buf = NULL; pr->index->fields = NULL; pr->index->prevPR = NULL; pr->index->nextPR = NULL; } void buildIndexEntry (PR *pr) { int x; int num_fields = get_num_fields (pr->database); Index *newIndex; freePRIndex (pr); newIndex = pr->index; newIndex->fields = (char **) xmalloc (sizeof (char *) * num_fields); memset (newIndex->fields, 0, sizeof (char *) * num_fields); newIndex->buf = NULL; for (x = 0; x < num_fields; x++) { FieldIndex field = getNthField (pr->database, x); if (isIndexedFieldIndex (field)) { const char *fc = field_value (pr, field); if (fieldDefForIndex (field)->datatype == Date) { if (fc == NULL || fc[0] == '\0' || (strcmp (fc, "-1") == 0)) { newIndex->fields[x] = xstrdup ("0"); } else { time_t t = get_any_date (fc); asprintf (&(newIndex->fields[x]), "%d", (int) t); } } else { char *fcCopy; if (fc == NULL) { fcCopy = xstrdup (""); } else { fcCopy = xstrdup (fc); } /* ??? XXX Should we do this here? It's already being done in the "write out the index" code. */ if (fieldDefForIndex (field)->nospaces) { /* Try to minimize the leakage. */ char *p = strchr (fcCopy, ' '); if (p != NULL) { *p = '\0'; } } newIndex->fields[x] = fcCopy; } } } } int isIndexedFieldIndex (FieldIndex index) { IndexDesc indexDesc; if (index == InvalidFieldIndex) { return 0; } else { indexDesc = getIndexDesc (fieldDefForIndex (index)->database); return indexDesc->fieldInIndex[fieldDefForIndex (index)->number]; } } void finishIndexDesc (DatabaseInfo database, IndexDesc new) { int numFields = get_num_fields (database); new->fieldInIndex = (int *) xmalloc (sizeof (int) * numFields); { int x; for (x = 0; x < numFields; x++) { new->fieldInIndex[x] = 0; } } { FieldList f; for (f = new->fields; f != NULL; f = f->next) { FieldIndex i = simpleFieldIndexValue (f->ent); if (i != InvalidFieldIndex) { new->fieldInIndex[fieldNumber (i)] = 1; } } } new->fieldInIndex[fieldNumber (NUMBER (database))] = 1; new->fieldInIndex[fieldNumber (CATEGORY (database))] = 1; } int isIndexedField (ComplexFieldIndex ent) { if (parseComplexFieldIndex (ent) != 0) { return 0; } return isIndexedFieldIndex (simpleFieldIndexValue (ent)); } /* Write out the index for DATABASE's PR chain. Returns 0 on success, a non-zero value otherwise (and ERR will be filled in). */ int writeIndex (const DatabaseInfo database, ErrorDesc *err) { FILE *fp; char *path, *workfile; PR *pr; IndexDesc indexDesc = getIndexDesc (database); struct stat buf; workfile = gnats_adm_dir (database, "indXXXXXX"); fp = fopen_temporary_file (workfile, "w", 0644); if (fp == NULL) { setError (err, CODE_FILE_ERROR, "writeIndex () can't open the temporary file %s", workfile); free (workfile); return -1; } if (indexIsBinary (database)) { unsigned char fieldCount = indexFieldCount (database); fwrite (&fieldCount, 1, 1, fp); } for (pr = getFirstPR (database, err); pr != NULL ; pr = getNextPR (pr)) { size_t length; char *line = createIndexEntry (pr, &length); if (line != NULL) { fwrite (line, 1, length, fp); free (line); } } fclose (fp); block_signals (); path = gnats_adm_dir (database, indexDesc->path); /* sanity check -- make sure nobody has changed the index since we last read it */ if (stat (path, &buf) < 0) { /* if the index ain't there, no problem. if it's there, but unstattable, we're going to declare it a serious problem. not sure if this is the right thing to do... */ if (errno != ENOENT) { setError (err, CODE_FILE_ERROR, "GNATS cannot stat the index: %s.", strerror (errno)); log_msg (LOG_ERR, 1, "error in writeIndex:", getErrorMessage (*err)); return -1; } } if (buf.st_mtime > indexDesc->mtime) { setError (err, CODE_INVALID_INDEX, "Index has been modified since last read"); log_msg (LOG_ERR, 1, "error in writeIndex:", getErrorMessage (*err)); /* the index is corrupt: alert the administrator */ punt (database, 0, "Attempting to write index file %s,\n\ but index has been modified since last read. A PR has been modified,\n\ but the change has not been recorded in the index. You must manually\n\ regenerate the index.", path); return -1; } if ((rename (workfile, path)) < 0) { if (errno != EXDEV) { free (path); setError (err, CODE_FILE_ERROR, "could not rename temporary index %s into gnats-adm: %s", workfile, strerror (errno)); return -1; } if (copy_file (workfile, path)) { setError (err, CODE_FILE_ERROR, "could not copy temporary index %s into %s: %s", workfile, path, strerror (errno)); return -1; } unlink (workfile); } free (path); free (workfile); unblock_signals (); return 0; } /* Add the PR to the GNATS index file. */ int addToIndex (PR *pr, ErrorDesc *err) { FILE *fp; char *path; IndexDesc indexDesc = getIndexDesc (pr->database); buildIndexEntry (pr); block_signals (); path = gnats_adm_dir (pr->database, indexDesc->path); if (indexIsBinary (pr->database) && ! fileExists (path)) { unsigned char fieldCount = indexFieldCount (pr->database); fp = fopen (path, "w"); if (fp != NULL) { fwrite (&fieldCount, 1, 1, fp); } } else { fp = fopen (path, "a+"); } if (fp == NULL) { setError (err, CODE_FILE_ERROR, "Can't append to the GNATS index file (%s).", path); unblock_signals (); return -1; } { size_t reclen; char *line = createIndexEntry (pr, &reclen); fwrite (line, 1, reclen, fp); free (line); } fclose (fp); free (path); unblock_signals (); return 0; } char * indexValue (PR *pr, FieldIndex field) { if (pr->index != NULL && pr->index->fields != NULL) { return pr->index->fields[field->number]; } else { return NULL; } } char * getCategoryFromIndex (const DatabaseInfo database, const char *prnum, ErrorDesc *err) { IndexDesc indexDesc = getIndexDesc (database); IndexFileDesc fp = openIndex (indexDesc, err); if (fp != NULL) { char *category; if (fp->desc->isBinary) { category = findPrCategoryBinary (fp, prnum); } else { category = findPrCategory (fp, prnum); } closeIndex (fp); if (category == NULL) { setError (err, CODE_NONEXISTENT_PR, "PR %s is not listed in the index.", prnum); } return category; } else { return NULL; } } void freeIndexDesc (IndexDesc p) { free (p->path); freeFieldList (p->fields); free (p->separator); if (p->fieldInIndex != NULL) { free (p->fieldInIndex); } free (p); } IndexDesc newIndexDesc (const DatabaseInfo database) { IndexDesc res = xmalloc (sizeof (struct index_desc)); res->database = database; res->prChain = NULL; res->path = NULL; res->fields = NULL; res->separator = xstrdup ("|"); res->isBinary = 0; res->numberOfFields = 0; res->fieldInIndex = NULL; res->mtime = 0; res->indexRead = 0; return res; } void addFieldToIndex (IndexDesc desc, FieldList ent) { if (desc->fields == NULL) { desc->fields = ent; } else { FieldList f = desc->fields; while (f->next != NULL) { f = f->next; } f->next = ent; } desc->numberOfFields++; } void setIndexDescPath (IndexDesc desc, const char *path) { desc->path = xstrdup (path); } void setIndexDescSeparator (IndexDesc desc, const char *separator) { free (desc->separator); desc->separator = xstrdup (separator); } void setIndexDescBinary (IndexDesc desc, int flag) { desc->isBinary = flag; } static void freePRChain (PR *start) { while (start != NULL) { PR *next = getNextPR (start); free_pr (start); start = next; } } int checkPRChain (const DatabaseInfo database, ErrorDesc *err) { IndexDesc desc = getIndexDesc (database); PR *new_chain = getNewIndexIfChanged (database, err); if (new_chain != NULL) { freePRChain (desc->prChain); desc->prChain = new_chain; return 1; } else { return 0; } } void initIndex (DatabaseInfo database) { clearPRChain (database); } PR * getFirstPR (const DatabaseInfo database, ErrorDesc *err) { IndexDesc desc = getIndexDesc (database); /* first check the PRChain to make sure that the index isn't stale */ checkPRChain (database, err); return desc->prChain; } void clearPRChain (const DatabaseInfo database) { IndexDesc desc = getIndexDesc (database); if (desc != NULL) { if (desc->prChain != NULL) { freePRChain (desc->prChain); desc->prChain = NULL; } desc->indexRead = 0; } } /* Replace a PR in the index with a copy of a new PR. By generating a copy of the new PR, we allow for the new PR to be free'd without harming the index pr chain. */ int replaceCurrentPRInIndex (PR *curr_pr, PR *new_pr, ErrorDesc *err) { PR *pr_replace, *pr_copy; const DatabaseInfo database = curr_pr->database; const char *new_pr_num = field_value (new_pr, NUMBER (database)); const char *curr_pr_num = field_value (curr_pr, NUMBER (database)); if (strcmp (curr_pr_num, new_pr_num) != 0) { return 0; } /* create a copy of the new pr to be put into the index pr chain */ pr_copy = allocPR (database); set_field (pr_copy, NUMBER (curr_pr->database), new_pr_num, err); set_field (pr_copy, CATEGORY (database), field_value (new_pr, CATEGORY (database)), err); setPrevPR (pr_copy, curr_pr->index->prevPR); setNextPR (pr_copy, curr_pr->index->nextPR); fillInPR (pr_copy, err); /* put the copy of new_pr into place in the index pr chain... */ if (curr_pr->index->prevPR == NULL) { /* the pr to be replaced is at the head of the pr chain */ IndexDesc indexDesc = getIndexDesc (database); free_pr (indexDesc->prChain); indexDesc->prChain = pr_copy; return 1; } /* save a pointer to the pr to be replaced so that it can later be free'd */ pr_replace = getNextPR (curr_pr->index->prevPR); setNextPR (curr_pr->index->prevPR, pr_copy); if (curr_pr->index->nextPR != NULL) { /* the pr to be replaced is not at the end of the pr chain */ setPrevPR (curr_pr->index->nextPR, pr_copy); } free_pr (pr_replace); return 1; } /* Remove PR PRNUM from the index for the current database, and rewrite the database file. The database must have been locked before calling this function. */ int removePRFromIndex (const DatabaseInfo database, const char *prNum, ErrorDesc *err) { PR *list; PR *prev = NULL; IndexDesc indexDesc = getIndexDesc (database); if (! is_gnats_locked (database)) { setError (err, CODE_GNATS_NOT_LOCKED, "Must lock the database before removing a PR from the index"); return -1; } list = getFirstPR (database, err); while (list != NULL && strcmp (field_value (list, NUMBER (database)), prNum) != 0) { prev = list; list = getNextPR (list); } if (list == NULL) { setError (err, CODE_NONEXISTENT_PR, "PR %s not in index", prNum); return -2; } if (prev != NULL) { prev->index->nextPR = list->index->nextPR; } else { indexDesc->prChain = list->index->nextPR; } return writeIndex (database, err); } PR * getNextPR (PR *pr) { return pr->index->nextPR; } void setNextPR (PR *pr, PR *next_pr) { pr->index->nextPR = next_pr; } PR * getPrevPR (PR *pr) { return pr->index->prevPR; } void setPrevPR (PR *pr, PR *prev_pr) { pr->index->prevPR = prev_pr; } int indexIsBinary (const DatabaseInfo database) { IndexDesc indexDesc = getIndexDesc (database); if (indexDesc != NULL) { return indexDesc->isBinary; } else { return 0; } } int indexFieldCount (const DatabaseInfo database) { IndexDesc indexDesc = getIndexDesc (database); if (indexDesc != NULL) { return indexDesc->numberOfFields; } else { return 0; } } gnats-4.1.0/gnats/index.h0000644000175000017500000000461410207433626015766 0ustar chewiechewie00000000000000#ifndef _INDEX_H_ #define _INDEX_H_ typedef struct indexEntry Index; typedef struct index_desc *IndexDesc; #include "gnats.h" #include "database.h" #include "field.h" #include "pr.h" extern void initIndex (DatabaseInfo database); extern IndexDesc newIndexDesc (const DatabaseInfo database); extern void addFieldToIndex (IndexDesc desc, FieldList ent); extern void setIndexDescPath (IndexDesc desc, const char *path); extern void setIndexDescSeparator (IndexDesc desc, const char *separator); extern void setIndexDescBinary (IndexDesc desc, int flag); extern void allocIndex (PR *pr); extern void clearPRChain (const DatabaseInfo database); extern int checkPRChain (const DatabaseInfo database, ErrorDesc *err); extern PR *getFirstPR (const DatabaseInfo database, ErrorDesc *err); extern PR *getPrevPR (PR *pr); extern PR *getNextPR (PR *pr); extern void setPrevPR (PR *pr, PR *prev_pr); extern void setNextPR (PR *pr, PR *next_pr); extern void freePRIndex (PR *pr); /* Construct an index entry for PR. */ extern void buildIndexEntry (PR *pr); /* Return a non-zero value if FIELD is part of the index for its database. */ extern int isIndexedFieldIndex (FieldIndex field); extern int isIndexedField (ComplexFieldIndex field); /* Write out the database's PR index from the copy in memory. Returns 0 on success, a non-zero value otherwise. */ extern int writeIndex (const DatabaseInfo database, ErrorDesc *err); /* Add the PR to the GNATS index file for its database. Returns 0 on success, a non-zero value otherwise. */ extern int addToIndex (PR *pr, ErrorDesc *err); /* Create a new string representing the index entry for PR in DEST. */ extern char *createIndexEntry (PR *pr, size_t *entLen); extern char *createIndexEntryBinary (PR *pr, size_t *entLen); extern int replaceCurrentPRInIndex (PR *curr_pr, PR *newPR, ErrorDesc *err); extern char *indexValue (PR *pr, FieldIndex field); extern char *getCategoryFromIndex (const DatabaseInfo database, const char *prnum, ErrorDesc *err); extern int removePRFromIndex (const DatabaseInfo database, const char *prNum, ErrorDesc *err); extern void finishIndexDesc (const DatabaseInfo database, IndexDesc new); extern void freeIndexDesc (IndexDesc desc); extern int indexIsBinary (const DatabaseInfo database); extern int indexFieldCount (const DatabaseInfo database); extern int verifyPRExists (const DatabaseInfo database, const char *prID); #endif gnats-4.1.0/gnats/internal.c0000644000175000017500000002556307560340040016467 0ustar chewiechewie00000000000000/* Miscellaneous utility routines for GNATS. Copyright (C) 1993, 1994, 1995, 2001 Free Software Foundation, Inc. Contributed by Tim Wicinski (wicinski@barn.com) and Brendan Kehoe (brendan@cygnus.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "gnatsd.h" /* Copy regular file SOURCE onto file DEST. Return 1 if an error occurred, 0 if successful. */ int copy_file (const char *source, const char *dest) { int ifd; int ofd; char buf[1024 * 8]; int len; /* Number of bytes read into `buf'. */ if (unlink (dest) && errno != ENOENT) { log_msg (LOG_INFO, 1, "cannot remove ", dest); return 1; } ifd = open (source, O_RDONLY, 0); if (ifd < 0) { log_msg (LOG_INFO, 1, "can not open: ", source); return 1; } ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (ofd < 0) { log_msg (LOG_INFO, 1, "can not open: ", dest); close (ifd); return 1; } while ((len = read (ifd, buf, sizeof (buf))) > 0) { int wrote = 0; char *bp = buf; do { wrote = write (ofd, bp, len); if (wrote < 0) { log_msg (LOG_INFO, 1, "error in writing:", dest); close (ifd); close (ofd); unlink (dest); return 1; } bp += wrote; len -= wrote; } while (len > 0); } if (len < 0) { log_msg (LOG_INFO, 1, source, strerror(errno)); close (ifd); close (ofd); unlink (dest); return 1; } if (close (ifd) < 0) { log_msg (LOG_INFO, 1, source, strerror(errno)); close (ofd); return 1; } if (close (ofd) < 0) { log_msg (LOG_INFO, 1, dest, strerror(errno)); return 1; } /* FIXME: This is fine for GNATS, but if there's anything we ever want to have special permissions, we must add the code to restore the permissions to what they were. */ chmod (dest, 0644); return 0; } /* Try to lock the file noted by FP. */ int is_gnats_locked (const DatabaseInfo database) { char *path = gnats_adm_dir (database, "gnats.lock"); int res = fileExists (path); free (path); return res; } int lock_gnats (const DatabaseInfo database, ErrorDesc *err) { char *path; int count, res; const int MAXWAIT = 10; const int GRANULARITY = 1; path = gnats_adm_dir (database, "gnats.lock"); /* try repeatedly to get the lock */ for (count = 0; count < MAXWAIT / GRANULARITY; count++) { errno = 0; /* use atomic create, to avoid races */ if (open (path, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0) != -1) { /* success */ break; } else { if (errno != EEXIST) { /* something went wrong, error out */ break; } } /* somebody else has the lock, sleep and try again */ sleep (GRANULARITY); } if (!errno) { /* success */ res = 0; } else if (errno == EEXIST) { setError (err, CODE_GNATS_LOCKED, "GNATS lock file exists %s", path); res = -1; } else { setError (err, CODE_FILE_ERROR, "GNATS cannot create lock file: %s", strerror (errno)); log_msg(LOG_ERR, 1, "error in lock_gnats:", getErrorMessage (*err)); res = 1; } free (path); return res; } int unlock_gnats (const DatabaseInfo database, ErrorDesc *err) { char *path = gnats_adm_dir (database, "gnats.lock"); if (path == NULL) { setError (err, CODE_FILE_ERROR, "Can't get adm directory for database"); return 1; } if (! fileExists (path)) { setError (err, CODE_GNATS_NOT_LOCKED, "GNATS database is already unlocked."); free (path); return 1; } if (unlink (path) != 0) { setError (err, CODE_FILE_ERROR, "Unable to unlock database: %s", strerror(errno)); free (path); return -1; } free (path); return 0; } int fileExists (const char *filename) { struct stat s; if (stat (filename, &s) == 0) { return 1; } else { return 0; } } /* VARARGS */ void punt (const DatabaseInfo database, int die, ...) { va_list args; char *fmt; FILE *fp; char hostname[MAXHOSTNAMELEN]; VA_START (args, die); fmt = va_arg (args, char *); if (database != NULL) { fp = open_mail_file (database); if (fp == NULL) { char *lastDitchTry; asprintf (&lastDitchTry, "mail %s", gnatsAdminMailAddr (database)); fp = popen (lastDitchTry, "w"); free (lastDitchTry); } if (fp == NULL) { fprintf (stderr, "%s: cannot open mail file for errors\n", program_name); client_unlock_gnats (); exit (3); } if (gethostname (hostname, MAXHOSTNAMELEN) != 0) { strcpy (hostname, "(hostname unavailable)"); } fprintf (fp, "From: %s (GNATS Management)\n", gnatsAdminMailAddr (database)); fprintf (fp, "To: %s\n", gnatsAdminMailAddr (database)); fprintf (fp, "Subject: problem with %s on host %s\n", program_name, hostname); fprintf (fp, "\n\n"); /* Two newlines to massage buggy sendmails */ vfprintf (fp, fmt, args); close_mail_file (fp); } else { /* didn't get a valid database, complain to stderr */ fprintf (stderr, "Problem with %s\n", program_name); vfprintf (stderr, fmt, args); fprintf (stderr, "\n"); } va_end (args); if (die) { client_unlock_gnats (); exit (2); } } static void unlock_quit (int sig ATTRIBUTE_UNUSED) { client_unlock_gnats (); unblock_signals (); exit (1); } void block_signals (void) { signal (SIGSEGV, unlock_quit); signal (SIGHUP, unlock_quit); signal (SIGTERM, unlock_quit); signal (SIGINT, unlock_quit); signal (SIGQUIT, unlock_quit); #ifdef SIGIOT signal (SIGIOT, unlock_quit); #endif #ifdef SIGILL signal (SIGILL, unlock_quit); #endif #ifdef SIGABRT signal (SIGABRT, unlock_quit); #endif } /* Gaaaah. Bastards. */ #if defined (__sun__) && defined (__svr4__) #undef SIG_DFL #define SIG_DFL (void(*)(int))0 #endif void unblock_signals (void) { signal (SIGSEGV, SIG_DFL); signal (SIGHUP, SIG_DFL); signal (SIGTERM, SIG_DFL); signal (SIGINT, SIG_DFL); signal (SIGQUIT, SIG_DFL); #ifdef SIGIOT signal (SIGIOT, SIG_DFL); #endif #ifdef SIGILL signal (SIGILL, SIG_DFL); #endif #ifdef SIGABRT signal (SIGABRT, SIG_DFL); #endif } const char* get_prid_from_path (const char *path) { if (strchr (path, '/') == NULL) { return (path); } return (strrchr (path, '/') + 1); } const char* get_cat_prid_from_path (const char *path) { int i = 0; const char *p = path + strlen (path); if (strchr (path, '/') == NULL) return (path); while (i < 2 && p > path) { p--; if (*p == '/') i++; } if (i == 2) { return (p + 1); } else { return path; } } char* get_lock_path (const DatabaseInfo database, const char *prID) { char *path = NULL; if (prID != NULL) { char *tempname; asprintf (&tempname, "locks/%s.lock", prID); path = gnats_adm_dir (database, tempname); free (tempname); } return path; } int isPrLocked (const DatabaseInfo database, const char *prNum) { char *path = get_lock_path (database, prNum); int res = fileExists (path); free (path); return res; } char * get_curr_date (void) { time_t t = time((time_t) 0); char *date = (char *) xmalloc (GNATS_TIME_LENGTH); gnats_strftime (date, GNATS_TIME_LENGTH, "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); return date; } int gnatsdbHasNetconn (const char *database_name) { const char *var = getenv ("GNATSDB"); if (database_name != NULL && database_name[0] != '\0') { return databaseSpecIsNetConn (database_name); } else if (var != NULL && var[0] != '\0') { if (strchr (var, ':') != NULL) { return 1; } else { return databaseSpecIsNetConn (var); } } else { return databaseSpecIsNetConn ("default"); } } /* check_state_type - return 1 if state is of type type, otherwise 0 */ int check_state_type (const DatabaseInfo database, const char *state, const char *type) { AdmEntry *state_chain = fieldDefForIndex (STATE (database))->adm_contents; AdmEntry *ent = find_chain_entry_nocopy (state_chain, state); if (ent != NULL) { return (strcmp (ent->admFields[StateAdmType], type) == 0); } return 0; } struct error_desc { int errorCode; BadFields badFieldList; char *errorMessage; }; struct bad_fields { FieldIndex field; char *value; struct bad_fields *next; }; void setError (ErrorDesc *errorDesc, int errorCode, ...) { va_list args; char *format; VA_START (args, errorCode); *errorDesc = (ErrorDesc) xmalloc (sizeof (struct error_desc)); (*errorDesc)->errorCode = errorCode; switch (errorCode) { case CODE_INVALID_FIELD_CONTENTS: case CODE_INVALID_ENUM: case CODE_READONLY_FIELD: (*errorDesc)->badFieldList = va_arg (args, BadFields); break; default: (*errorDesc)->badFieldList = NULL; break; } format = va_arg (args, char *); if (format != NULL) { vasprintf (&(*errorDesc)->errorMessage, format, args); } else { (*errorDesc)->errorMessage = NULL; } va_end (args); } BadFields newBadFieldEntry (FieldIndex field, const char *badValue, BadFields next) { BadFields res = (BadFields) xmalloc (sizeof (struct bad_fields)); res->field = field; if (badValue != NULL) { res->value = xstrdup (badValue); } else { res->value = NULL; } res->next = next; return res; } void freeBadFieldList (BadFields list) { while (list != NULL) { BadFields next = list->next; free (list->value); free (list); list = next; } } void freeErrorDesc (ErrorDesc desc) { if (desc != NULL) { freeBadFieldList (desc->badFieldList); if (desc->errorMessage != NULL) { free (desc->errorMessage); } free (desc); } } const char * getErrorMessage (ErrorDesc desc) { return desc->errorMessage; } int getErrorCode (ErrorDesc desc) { return desc->errorCode; } BadFields getBadFieldList (ErrorDesc errorDesc) { return errorDesc->badFieldList; } FieldIndex badFieldIndex (BadFields ent) { return ent->field; } const char * badFieldValue (BadFields ent) { return ent->value; } BadFields nextBadField (BadFields ent) { return ent->next; } gnats-4.1.0/gnats/lists.c0000644000175000017500000001127107557340356016020 0ustar chewiechewie00000000000000/* Routines to provide lists of the GNATS low-level files. Copyright (C) 1995, 1999, 2000 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Majorly reworked by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gnats.h" #include "query.h" /* The maximum length of a file suffix listed below. */ #define MAXSUFFIX 4 struct list_type_list { const char *name; ListTypes which; const char *fileSuffix; const char *builtinFieldName; } listTypeList[] = { { "Categories", ListCategories, ".cat", "category" }, { "Submitters", ListSubmitters, ".sub", "submitter-id" }, { "Responsible", ListResponsible, ".res", "responsible" }, { "States", ListStates, ".sta", "state" }, { "FieldNames", ListFieldNames, ".fns", NULL }, { "InitialInputFields", ListInitialInputFields, ".lfn", NULL }, { "InitialRequiredFields", ListInitialRequiredFields, ".lrn", NULL }, { "Databases", ListDatabases, ".dbl", NULL }, { NULL, InvalidListType, NULL, NULL } }; ListTypes stringToListType (const char *string) { int x; for (x = 0; listTypeList[x].name != NULL; x++) { if (strcasecmp (string, listTypeList[x].name) == 0) { return listTypeList[x].which; } } return -1; } const char * listTypeToString (ListTypes which) { int x; for (x = 0; listTypeList[x].which != which && listTypeList[x].name != NULL; x++) { /* Empty */ } return listTypeList[x].name; } int getGnatsFile (const DatabaseInfo database, ListTypes whichList, const char *file, const char *eolTerminator) { char *outf = NULL; FILE *fpout = NULL; struct list_type_list *list_desc; int x; AdmEntry *chain = NULL; int fieldCount = 0; ErrorDesc err; for (x = 0; listTypeList[x].which != whichList && listTypeList[x].name != NULL; x++) { /* Empty */ } if (listTypeList[x].name == NULL) { return -1; } else { list_desc = &(listTypeList[x]); } if (file != NULL) { outf = (char *) xmalloc (strlen (file) + MAXSUFFIX + 1); strcpy (outf, file); eolTerminator = "\n"; } else { fpout = stdout; } if (outf != NULL) { strcat (outf, list_desc->fileSuffix); } if (outf != NULL) { fpout = fopen (outf, "w"); if (fpout == (FILE *)NULL) return -1; /* XXX */ } switch (list_desc->which) { case ListFieldNames: { int x; FieldIndex f; for (x = 0; (f = getNthField (database, x)) != NULL; x++) { fprintf (fpout, "%s\n", fieldDefForIndex (f)->name); } break; } case ListInitialInputFields: { InputTemplate *t; for (t = getInputTemplate (database); t != NULL; t = t->next) { FieldDef field = fieldDefForIndex (t->index); fprintf (fpout, "%s\n", field->name); } break; } case ListInitialRequiredFields: { FieldList fields = getRequiredInputFields(database); while (fields != NULL) { fprintf (fpout, "%s\n", complexFieldIndexToString (fields->ent)); fields = fields->next; } break; } case ListDatabases: chain = getDatabaseList (&err); fieldCount = 3; break; case ListStates: case ListCategories: case ListSubmitters: case ListResponsible: { FieldIndex field = findBuiltinField (database, list_desc->builtinFieldName); if (field != NULL) { chain = fieldDefForIndex (field)->adm_contents; fieldCount = fieldDefForIndex (field)->adm_db_fields; } else { chain = NULL; fieldCount = 0; } } break; case InvalidListType: abort (); break; } while (chain != NULL) { int x; for (x = 0; x < fieldCount; x++) { fprintf (fpout, (x > 0) ? ":%s" : "%s", chain->admFields[x]); } fprintf (fpout, "%s", eolTerminator); chain = chain->next; } if (outf) { fclose (fpout); } return 0; } gnats-4.1.0/gnats/mail-agent.sh0000644000175000017500000000207607552125035017061 0ustar chewiechewie00000000000000#!/bin/sh # Program to send mail for GNATS. # Copyright (C) 1999 Free Software Foundation, Inc. # Contributed by Bob Manson (manson@juniper.net) # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # This is a rather pointless script, but at least it isolates the number # of programs that actually invoke the mail agent to 1, making it easy # to change. MAIL_AGENT="xDEFAULT_MAIL_AGENTx" exec $MAIL_AGENT $@ > /dev/null gnats-4.1.0/gnats/mail-query.sh0000644000175000017500000000604507404673535017141 0ustar chewiechewie00000000000000#!/bin/sh # Program to process GNATS queries via email. # Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. # Contributed by Jason Merrill (jason@cygnus.com). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. GNATS_ADMIN_ADDR="`query-pr --responsible-address gnats-admin`" LIBEXECDIR=xLIBEXECDIRx PATH=xBINDIRx:/bin:/sbin:/usr/bin:/usr/ucb:/usr/bsd:/usr/sbin export PATH # Don't expand globs for the arguments to query-pr. set -f if [ -n "$GNATSDB" ]; then DATABASE="--database=\"$GNATSDB\"" fi to= args= oldIFS="$IFS" while true; do IFS=: read header contents IFS="$oldIFS" [ -z "$header" ] && break; contents="`echo $contents | sed 's/^ *//'`" [ "$header" = "From" -a -z "$to" ] && to="$contents" [ "$header" = "Reply-To" ] && to="$contents" [ "$header" = "Subject" ] && args="$contents" done mail=/tmp/query$$ exec 3>&1 4>&2 > $mail 2>&1 if [ -n "$to" ]; then echo "To: $to" echo "Subject: query-pr output [$args]" echo case $args in "") cat << __EOF__ Your query specified no constraints. This is probably not what you wanted; unconstrained queries get very large very fast. If you really want to see every non-confidential, non-closed PR in the database, specify some dummy constraint like \`--category='. To use this mail server, just include arguments to query-pr in the Subject: line. The options for query-pr are outlined below. __EOF__ query-pr --help ;; *query-pr*) query-pr --restricted --state 'o|a|f|s' \ `echo $args | sed 's/^.*query-pr//'` $DATABASE $*;; *) query-pr --restricted --state 'o|a|f|s' $args $DATABASE $*;; esac else echo "To: $GNATS_ADMIN_ADDR" echo "Subject: query-pr request failed" echo echo "Subject line:$args" echo "Body of message:" cat fi exec >&- 1>&3 2>&4 if [ `wc $mail | awk '{print $1}'` -lt 4 ]; then cat >> $mail 2>&1 << __EOF__ Your query produced no output. Here are some of the possible causes: 1) There are no matching PRs. You may want to try different parameters. 2) All matching PRs are confidential. For security reasons, this mail server does not display confidential PRs. 3) All matching PRs are closed. By default, this mail server does not display closed PRs; to override this behavior, specify \`--state=' (i.e. match any state) in your query. __EOF__ query-pr --help >> $mail 2>&1 fi $LIBEXECDIR/gnats/mail-agent < $mail [ $? -eq 0 ] && rm -f $mail gnats-4.1.0/gnats/mail.c0000644000175000017500000003140210207433626015567 0ustar chewiechewie00000000000000/* Mail processing routines for GNATS. Copyright (C) 2000, 2002 Free Software Foundation, Inc. Contributed by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "query.h" #include "pcodes.h" #include "mail.h" void addMessageFormat (DatabaseInfo database, MailMessageFormat format) { format->next = getMailFormatList (database); setMailFormatList (database, format); } MailMessageFormat findMailFormat (const DatabaseInfo database, const char *name) { MailMessageFormat p; for (p = getMailFormatList (database); p != NULL; p = p->next) { if (strcmp (p->name, name) == 0) { break; } } return p; } /* get_responsible_address - dredges the responsible party out of the appropriate places. This routine should be NIS Correct, but it isn't. */ AdmEntry * get_responsible_address (const DatabaseInfo database, const char *person) { AdmEntry *res = NULL; AdmEntry *responsible_chain = NULL; if (fieldDefForIndex (RESPONSIBLE (database)) != NULL) { responsible_chain = fieldDefForIndex (RESPONSIBLE (database))->adm_contents; res = find_chain_entry (responsible_chain, person); } /* First check the responsible file; if there's no entry, try the passwd file. */ if (res != NULL) { if (res->admFields[ResponsibleAdmAlias] == NULL || res->admFields[ResponsibleAdmAlias] == '\0') { if (res->admFields[ResponsibleAdmAlias] != NULL) { free (res->admFields[ResponsibleAdmAlias]); } res->admFields[ResponsibleAdmAlias] = xstrdup (res->admFields[ResponsibleAdmKey]); } } else { struct passwd *passwd; char *p; res = alloc_adm_entry (3); res->field = RESPONSIBLE (database); /* We should always allow names to show up as responsible, even if they aren't listed in the passwd file---folks don't remember (or usually need) to change closed PRs if the listed person happens to leave the company. */ res->admFields[ResponsibleAdmKey] = (char *) xstrdup (person); res->admFields[ResponsibleAdmAlias] = (char *) xstrdup (person); if ((passwd = getpwnam (person)) != 0) { /* Some passwd entries have commas for finger programs that understand office phone numbers, etc. Chop 'em off. */ p = (char *) strchr (passwd->pw_gecos, ','); if (p != NULL) *p = '\0'; res->admFields[ResponsibleAdmFullname] = (char *) xstrdup (passwd->pw_gecos); } else { res->admFields[ResponsibleAdmFullname] = xstrdup(""); } } return res; } static char * get_one_responsible_addr (const DatabaseInfo database, int full, int strict, const char *name) { AdmEntry *r; char *p; char *address = NULL; /* If it already vaguely resembles a full email address, then just return it as is. */ if (strpbrk (name, "<(@") != NULL) { return xstrdup (name); } /* Strip off (Foo Bar) or anything after a space in the name. */ p = (char *) strchr (name, ' '); if (p != (char *) NULL) { *p = '\0'; } p = (char *) strchr (name, '('); if (p != (char *) NULL) { *p = '\0'; } r = get_responsible_address (database, name); if (r != NULL && ((! strict) || r->admFields[ResponsibleAdmFullname][0] != '\0')) { if (full) { asprintf (&address, "%s:%s:%s", r->admFields[ResponsibleAdmKey], r->admFields[ResponsibleAdmFullname], r->admFields[ResponsibleAdmAlias]); } else { /* Make sure if the person putting the entry in accidentally added spaces or such after the colon, we strip them off. XXX ??? !!! We shouldn't do this here; instead, make sure the entry we return from get_responsible_address () is clean, or better still, do it when we read entries from the adm files. */ char *addr = r->admFields[ResponsibleAdmAlias]; while (*addr != '\0' && ! isalpha ((int) *addr)) { addr++; } if (*addr != '\0') { address = xstrdup (addr); } else { address = xstrdup (r->admFields[ResponsibleAdmKey]); } } } free_adm_entry (r); return address; } static char * getOneAddress (const char **addrPtr) { const char *addr = *addrPtr; const char *addrStart, *addrEnd; char *res; if (addrPtr == NULL || *addrPtr == NULL) { return NULL; } /* skip over leading white space */ while (*addr && isspace((int)(unsigned char)*addr)) { addr++; } addrStart = addr; while (*addr != ',' && *addr != '\0') { char nextc = '\0'; switch (*addr) { case '"': nextc = '"'; break; case '(': nextc = ')'; break; case '<': nextc = '>'; break; } if (nextc != '\0') { /* XXX ??? !!! This probably isn't handling backquotes properly. */ char *naddr = strchr (addr + 1, nextc); if (naddr == NULL) { addr += strlen (addr); break; } addr = naddr; } addr++; } addrEnd = addr; /* ignore any ending white space */ while (addr > addrStart && isspace((int)(unsigned char)*(addr-sizeof(*addr)))) { addr--; } if (addr <= addrStart) res = NULL; else res = xstrndup (addrStart, addr - addrStart); *addrPtr = (*addrEnd == '\0') ? NULL : addrEnd+1; return res; } char * get_responsible_addr (const DatabaseInfo database, int full, int strict, const char *name) { const char *c = name; char *res = NULL; while (c != NULL) { char *respaddr; char *addr = getOneAddress (&c); if (addr == NULL || *addr == '\0') { break; } respaddr = get_one_responsible_addr (database, full, strict, addr); if (respaddr != NULL) { if (res != NULL) { append_string (&res, ","); } append_string (&res, respaddr); free (respaddr); } free (addr); } return res; } char * generateMailAddress (PR *pr, PR *oldPR, MailAddress *address, FormatNamedParameter *params) { FieldList addrList; if (address->fixedAddress != NULL) { return get_responsible_addr (pr->database, 0, 0, address->fixedAddress); } for (addrList = address->addresses; addrList != NULL; addrList = addrList->next) { int mustBeFreed = 0; const char *value = get_field_value (pr, oldPR, addrList->ent, params, &mustBeFreed); if (value != NULL && value[0] != '\0') { char *res = get_responsible_addr (pr->database, 0, 0, value); size_t len = strlen (res); /* Badness 10000. XXX ??? !!! */ if (res[len - 1] == '\n') { res[len - 1] = '\0'; } if (mustBeFreed) { free ((char *) value); } return res; } if (mustBeFreed && value != NULL) { free ((char *) value); } } return NULL; } static char * insertAddress (char *addressList, const char *addrToInsert) { if (addrToInsert == NULL) { return addressList; } else if (addressList == NULL) { return xstrdup (addrToInsert); } else { size_t oldlen = strlen (addressList); size_t addrToInsertLen = strlen (addrToInsert); size_t newlen = oldlen + addrToInsertLen + 2; char *p = addressList; char *res; while (*p != '\0') { char *prevp = p; char *lastCharInAddr; p = strchr (p, ','); if (p == NULL) { p = prevp + strlen (prevp); } lastCharInAddr = p - 1; while (lastCharInAddr > prevp && isspace ((int)(unsigned char) *lastCharInAddr)) { lastCharInAddr--; } if (((size_t) (lastCharInAddr - prevp + 1)) == addrToInsertLen && memcmp (prevp, addrToInsert, addrToInsertLen) == 0) { return addressList; } if (*p == ',') { p++; } } res = xrealloc (addressList, newlen); res[oldlen] = ','; strcpy (res + oldlen + 1, addrToInsert); return res; } } /* Composes a mail message using FORMAT as the mail message format. */ int composeMailMessage (PR *pr, PR *oldPR, const char *formatName, FormatNamedParameter *parameters, BadFields bad_fields, ErrorDesc *err ATTRIBUTE_UNUSED) { MailMessageFormat format = findMailFormat (pr->database, formatName); FILE *msg; char *fromAddr; char *toAddr = NULL; char *replyToAddr = NULL; MailAddressList *p; if (format == NULL) { return -1; } block_signals (); fromAddr = generateMailAddress (pr, oldPR, format->fromAddress, parameters); if (fromAddr == NULL) { fromAddr = (char *)gnatsAdminMailAddr (pr->database); } for (p = format->toAddresses; p != NULL; p = p->next) { char *theAddr = generateMailAddress (pr, oldPR, p->address, parameters); if (theAddr != NULL) { toAddr = insertAddress (toAddr, theAddr); free (theAddr); } } for (p = format->replyTo; p != NULL; p = p->next) { char *theAddr = generateMailAddress (pr, oldPR, p->address, parameters); if (theAddr != NULL) { replyToAddr = insertAddress (replyToAddr, theAddr); free (theAddr); } } msg = open_mail_file (pr->database); if (msg == NULL) { return -1; } fprintf (msg, "From: %s\n", fromAddr); fprintf (msg, "To: %s\n", toAddr); if (replyToAddr != NULL) { fprintf (msg, "Reply-To: %s\n", replyToAddr); } process_format (msg, NULL, pr, oldPR, format->header, "\n", parameters); fprintf (msg, "\n"); /* XXX ??? !!! This should be handled as a format parameter. */ if (bad_fields != NULL) { /* Report the fields that were bad, separating them by an empty line. */ BadFields t; for (t = bad_fields; t != NULL ; t = nextBadField (t)) { FieldIndex field = badFieldIndex (t); const char *value = badFieldValue (t); if (value != NULL) { fprintf (msg, "\tNote: There was a bad value `%s' for the field `%s'.\n\tIt was set to the default value of `%s'.\n\n", value, fieldDefForIndex (field)->name, fieldDefForIndex (field)->default_value); } else { fprintf (msg, "\tNote: There was a missing value for the field `%s'.\n\tIt was set to the default value of `%s'.\n\n", fieldDefForIndex (field)->name, fieldDefForIndex (field)->default_value); } } } process_format (msg, NULL, pr, oldPR, format->body, "\n", parameters); close_mail_file (msg); free (fromAddr); free (toAddr); if (replyToAddr != NULL) { free (replyToAddr); } unblock_signals (); return 0; } FormatNamedParameter * allocateNamedParameter (const char *name, const char *value, FormatNamedParameter *next) { FormatNamedParameter *res = (FormatNamedParameter *) xmalloc (sizeof (FormatNamedParameter)); res->name = xstrdup (name); if (value != NULL) { res->value = xstrdup (value); } else { res->value = NULL; } res->next = next; return res; } const char * getNamedParameterValue (FormatNamedParameter *list, const char *name) { while (list != NULL) { if (strcmp (list->name, name) == 0) { return list->value; } list = list->next; } return NULL; } void freeFormatParameterList (FormatNamedParameter *list) { while (list != NULL) { FormatNamedParameter *next = list->next; free (list->name); free (list->value); free (list); list = next; } } void freeMailAddress (MailAddress *p) { if (p != NULL) { if (p->fixedAddress != NULL) { free (p->fixedAddress); } if (p->addresses != NULL) { freeFieldList (p->addresses); } free (p); } } void freeMailAddressList (MailAddressList *p) { while (p != NULL) { MailAddressList *next = p->next; freeMailAddress (p->address); free (p); p = next; } } void freeMessageFormat (MailMessageFormat p) { if (p->name != NULL) { free (p->name); } freeMailAddressList (p->toAddresses); freeMailAddress (p->fromAddress); freeMailAddressList (p->replyTo); freeQueryFormat (p->header); freeQueryFormat (p->body); free (p); } void freeMessageFormatList (MailMessageFormat formatList) { while (formatList != NULL) { MailMessageFormat next = formatList->next; freeMessageFormat (formatList); formatList = next; } } gnats-4.1.0/gnats/mail.h0000644000175000017500000000575307111405574015607 0ustar chewiechewie00000000000000/* Interface for sending mail and processing mail formats. Copyright (C) 2000 Free Software Foundation, Inc. Written by Bob Manson . This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef _MAIL_H #define _MAIL_H typedef struct mail_address MailAddress; typedef struct mail_address_list MailAddressList; typedef struct mail_message_format *MailMessageFormat; typedef struct format_named_parameter { char *name; char *value; struct format_named_parameter *next; } FormatNamedParameter; #include "query.h" #include "adm.h" /* These addresses are always mapped through the responsible adm file. */ struct mail_address { /* A fixed name. */ char *fixedAddress; /* A list of addresses to try--each one is tried in turn until a non-empty one is found. */ FieldList addresses; }; struct mail_address_list { MailAddress *address; struct mail_address_list *next; }; struct mail_message_format { /* The name of this message format. */ char *name; MailAddressList *toAddresses; MailAddress *fromAddress; MailAddressList *replyTo; QueryFormat *header; QueryFormat *body; struct mail_message_format *next; }; extern char *get_responsible_addr (const DatabaseInfo database, int full, int strict, const char *name); extern AdmEntry *get_responsible_address (const DatabaseInfo database, const char *); extern void addMessageFormat (DatabaseInfo database, MailMessageFormat format); extern MailMessageFormat findMailFormat (const DatabaseInfo database, const char *name); extern char *generateMailAddress (PR *pr, PR *oldPR, MailAddress *address, FormatNamedParameter *parameters); extern int composeMailMessage (PR *pr, PR *oldPR, const char *formatName, FormatNamedParameter *parameters, BadFields bad_fields, ErrorDesc *err); extern FormatNamedParameter * allocateNamedParameter (const char *name, const char *value, FormatNamedParameter *next); extern const char *getNamedParameterValue (FormatNamedParameter *list, const char *name); extern void freeFormatParameterList (FormatNamedParameter *list); extern void freeMailAddress (MailAddress *addr); extern void freeMailAddressList (MailAddressList *list); extern void freeMessageFormat (MailMessageFormat format); extern void freeMessageFormatList (MailMessageFormat formatList); #endif gnats-4.1.0/gnats/misc.c0000644000175000017500000005513010207435253015602 0ustar chewiechewie00000000000000/* Miscellaneous utility routines for GNATS. Copyright (C) 2000, 2001 Milan Zamazal Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. Contributed by Tim Wicinski (wicinski@barn.com) and Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" /* Exit constants. All GNATS C sources should use only the symbolic names defined here as exit codes. */ const int EXIT_OK = 0; const int EXIT_PROGRAM_ERROR = 127; void program_error (const char *file, int line); /* Logging */ /* TODO: The current logging facilities are quite primitive. They should be improved in the future. However the primary goal now is to unify logging in all the GNATS components. For that purpose the current logging facility is sufficient. */ /* Debugging level. */ static int debug_level = LOG_ERR; /* File to log all messages to. */ static FILE *gnats_logfile = NULL; /* Current logging method. */ static Logging_Methods log_method = NOLOG; /* Set logging level to LOG_INFO. Currently we support only two levels of debugging, thus it makes sense. */ void enable_debugging (void) { debug_level = LOG_INFO; } /* Log NUM_ARG messages given in `...' with logging SEVERITY. Actually at most two messages in `...' are supported. */ void #if defined(__STDC__) || defined(_AIX) log_msg (int severity, int num_arg, ...) #else log_msg (int severity, int num_arg, va_dcl va_alist) #endif { va_list args; VA_START (args, num_arg); if (debug_level >= severity) { char *message; char *buf; message = va_arg (args, char *); /* The following is incredibly stupid and broken, but I don't know how to do it better in C. */ if (num_arg > 0) { char *message2 = va_arg (args, char *); asprintf (&buf, "%s: %s %s\n", program_name, message, message2); } else { asprintf (&buf, "%s: %s\n", program_name, message); } switch (log_method) { #ifdef HAVE_SYSLOG_H case SYSLOG: syslog (severity, "%s", buf); break; #endif case MAIL: /* This is currently not used, because it could send a lot of mails to someone. */ program_error (__FILE__, __LINE__); break; case LOGFILE: if (gnats_logfile != (FILE *)NULL) { fprintf (gnats_logfile, "%s", buf); break; } /* No log file, log to stderr. */ case STDERR: fprintf (stderr, "%s", buf); break; case NOLOG: /* Do nothing. */ break; default: program_error (__FILE__, __LINE__); } free (buf); } va_end (args); } /* Set log_method appropriately. `logfile' is the file to log to. If it is NULL, we use another logging destination by guessing, considering various criteria. TODO: This method is very rudimentary and should be improved. */ void init_logging (const char *logfile) { if (logfile) { /* A log file explicitly requested. Let's try to open it. */ gnats_logfile = fopen (logfile, "at"); if (gnats_logfile != NULL) { log_method = LOGFILE; return; } } if (isatty (fileno (stderr))) /* If the program is invoked from a terminal, it is good to present the messages directly to the user. */ log_method = STDERR; else { /* Maybe this is a daemon. */ #ifdef HAVE_SYSLOG_H closelog (); #ifdef LOG_DAEMON openlog ("gnatsd", (LOG_PID|LOG_CONS), LOG_DAEMON); #else openlog ("gnatsd", LOG_PID); #endif log_method = SYSLOG; #else /* This should be MAIL, but I don't know how to use it well. */ log_method = NOLOG; #endif } if (logfile) /* Log file requested, but couldn't be open. Now we can report this fact. */ log_msg (LOG_ERR, 1, "Log file couldn't be open:", logfile); } /* Open the file (actually the pipe) to which the mail message will be written. */ FILE * open_mail_file (const DatabaseInfo database) { FILE *fp = NULL; char *mailAgentPath = mailAgent (database); if (mailAgentPath != NULL) { /* Can't use log_msg here, since gnats_logfile is being set by this first thing. */ fp = popen (mailAgentPath, "w"); free (mailAgentPath); if (debugMode (database)) { fprintf (fp, "From: %s (GNATS Management)\n", gnatsAdminMailAddr (database)); fprintf (fp, "To: %s\n", gnatsAdminMailAddr (database)); fprintf (fp, "Subject: mail output from %s\n", program_name); fprintf (fp, "\n\n"); } } return fp; } void close_mail_file (fp) FILE *fp; { if (fp) { fflush (fp); pclose (fp); } } /* Report a program error at `line' in `file' and exit with an error code. */ void program_error (const char *filename, int line) { char *message; asprintf (&message, "Program error at %s:%d", filename, line); log_msg (LOG_ERR, 0, message); free (message); exit (EXIT_PROGRAM_ERROR); } /* Initialize the system and load the database DATABASE_NAME. Return the basic database access structure. PROGRAM_NAME is the name of the calling program. If any error occurs, NULL is returned and `err' is set appropriately. */ DatabaseInfo init_gnats (const char *program_name, const char *database_name, ErrorDesc *err) { init_logging (NULL); re_set_syntax ((RE_SYNTAX_POSIX_EXTENDED | RE_BK_PLUS_QM) & ~RE_DOT_NEWLINE); if (initDatabaseList (err) != 0) { return NULL; } return findOrLoadDatabase (program_name, database_name, err); } StringList * new_string_list_ent (char *name, StringList *next) { StringList *res = (StringList *) xmalloc (sizeof (StringList)); res->name = name; res->next = next; return res; } /* Scan down LINE, returning the next token. We can't use strtok, since we often deal with constant strings like "foo | bar" for the default values for a PR. Returns the returned token as a malloc()ed string, and changes *LINE to point to the next place to begin parsing for the next token, or sets it to NULL if the token being returned is the last one. */ char * get_next_field (const char **line_ptr, int delim) { const char *line = *line_ptr; const char *end_line = line; const char *next_token; char *res; while (*end_line != delim && *end_line != '\0') { end_line++; } next_token = end_line; /* skip whitespace at the end of the token */ while (end_line > line && isspace ((int)(unsigned char) end_line[-1])) { end_line--; } res = xstrndup (line, end_line - line); if (*next_token == delim) { *line_ptr = next_token + 1; } else { *line_ptr = NULL; } return res; } /* Adds quote-marks (") around the string, and escapes any quotes that appear within the string with '\'. */ char * quote_string (const char *string) { const char *p = string; char *rp; char *res; int len = strlen (string) + 2; for (p = string; *p != '\0'; p++) { if (*p == '"') { len++; } } res = xmalloc (len + 1); rp = res + 1; res[0] = '"'; res[len - 1] = '"'; res[len] = '\0'; for (p = string; *p != '\0'; p++) { if (*p == '"') { *(rp++) = '\\'; } *(rp++) = *p; } return res; } #define MYMIN(a,b) ((a) < (b) ? (a) : (b)) /* Read a newline-terminated line of text from INPUT. If MAXLENARG is non-NULL and has a value greater than zero, a maximum of *MAXLENARG characters will be read. (Since the string is terminated with a '\0', *MAXLENARG + 1 chars will be allocated.) The returned line is allocated with malloc (), and is the property of the caller. If MAXLENARG is non-NULL, the number of characters read is stored there. A NULL value is returned if no text was read. */ char * read_line (FILE *input, size_t *max_len_arg) { size_t len = 0; size_t max_len = (max_len_arg != NULL ? *max_len_arg : 0); const size_t default_len = 512; char *res = xmalloc (max_len>0 ? max_len+1 : default_len); while (fgets (res+len, (max_len>0 ? max_len : default_len), input) != NULL) { size_t slen = strlen (res + len); len += slen; if (res[len - 1] == '\n') break; if (max_len > 0) { max_len -= slen; if (max_len == 0) break; } else { res = xrealloc (res, len + default_len); } } if (len == 0) { free (res); res = NULL; } else if (max_len_arg == NULL || *max_len_arg == 0) { res = xrealloc (res, len + 1); } if (max_len_arg != NULL) { *max_len_arg = len; } return res; } /* @deftypefn Supplemental char * xstrndup(const char *@var{str}, size_t @var{len}) Convenience function to copy @var{len} bytes of @var{str} to a newly allocated string. Returns char pointer to new string, or returns NULL if @var{len} < 1 or @var{str} == NULL. @end deftypefn */ char * xstrndup (const char *str, size_t len) { if (str == NULL) { return NULL; } else { char *res; if (len < 1) { len = 0; } res = xmalloc (len + 1); memcpy (res, str, len); res[len] = '\0'; return res; } } /* Allocate a memory with internal error handling. */ PTR xmalloc(size_t size) { void *ptr; if (size == (size_t)NULL) size = 1; if ((ptr = malloc(size)) == NULL) { (void)fprintf(stderr, "xmalloc: unable to allocate memory"); program_error(__FILE__, __LINE__); } return (ptr); } /* Safely change the size of previously allocated memory area. */ PTR xrealloc(PTR ptr, size_t size) { PTR ptr2; if (size == (size_t)NULL) size = 1; if ((ptr2 = realloc(ptr, size)) == NULL) { if (ptr != (PTR)NULL) free(ptr); (void)fprintf(stderr, "xrealloc: unable to relocate memory"); program_error(__FILE__, __LINE__); } return(ptr2); } /* Save a copy of a string with internal error handling. */ char * xstrdup(const char *str) { char *strc; if ((strc = strdup(str)) == NULL) { (void)fprintf(stderr, "xstrdup: unable to duplicate a string"); program_error(__FILE__, __LINE__); } return(strc); } #ifndef HAVE_MKDIR /* mkdir adapted from GNU tar. */ /* Make directory DPATH, with permission mode DMODE. Written by Robert Rother, Mariah Corporation, August 1985 (sdcsvax!rmr or rmr@@uscd). If you want it, it's yours. Severely hacked over by John Gilmore to make a 4.2BSD compatible subroutine. 11Mar86; hoptoad!gnu Modified by rmtodd@@uokmax 6-28-87 -- when making an already existing dir, subroutine didn't return EEXIST. It does now. */ int mkdir (dpath, dmode) char *dpath; int dmode; { int cpid, status; struct stat statbuf; if (stat (dpath, &statbuf) == 0) { errno = EEXIST; /* stat worked, so it already exists. */ return -1; } /* If stat fails for a reason other than non-existence, return error. */ if (errno != ENOENT) return -1; cpid = fork (); switch (cpid) { case -1: /* Cannot fork. */ return -1; /* errno is set already. */ case 0: /* Child process. */ /* Cheap hack to set mode of new directory. Since this child process is going away anyway, we zap its umask. This won't suffice to set SUID, SGID, etc. on this directory, so the parent process calls chmod afterward. */ status = umask (0); /* Get current umask. */ umask (status | (0777 & ~dmode)); /* Set for mkdir. */ execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); _exit (1); default: /* Parent process. */ while (wait (&status) != cpid) /* Wait for kid to finish. */ /* Do nothing. */ ; if (status & 0xFFFF) { errno = EIO; /* /bin/mkdir failed. */ return -1; } return chmod (dpath, dmode); } } #endif /* HAVE_MKDIR */ /* Return open file descriptor of the file specified by `template' suitable to `mktemp'. The file is open for reading and writing. If the stream can't be opened, a negative value is returned. */ int open_temporary_file (char *template, int mode) { int fd = -1; #ifndef HAVE_MKSTEMP const int NUMBER_OF_TRIALS = 3; #endif #ifdef HAVE_MKSTEMP fd = mkstemp (template); chmod (template, mode); #else { int i; for (i = 0; i < NUMBER_OF_TRIALS && fd < 0; i++) { #ifdef HAVE_MKTEMP mktemp (template); #else mkstemps (template, 0); #endif fd = open (template, O_RDWR | O_CREAT | O_EXCL, mode); } } #endif return fd; } /* Return the name of the directory to use for general temporary files. */ const char * temporary_directory (void) { #ifdef P_tmpdir return P_tmpdir; #else char *tmpdir = getenv ("TMPDIR"); if (tmpdir == NULL) { tmpdir = "/tmp"; } return tmpdir; #endif } /* Return open temporary file specified by `template' suitable to `mktemp'. `fopen_mode' is the mode string to be given to fopen. If the file can't be opened, return NULL. */ FILE * fopen_temporary_file (char *template, const char *fopen_mode, const int mode) { int fd = open_temporary_file (template, mode); return (fd < 0 ? NULL : fdopen (fd, fopen_mode)); } /* Auxiliary for gnats_strftime. */ static int minutes_gmt_offset (const struct tm *local_time_pointer) { const int MINUTES_PER_DAY = 24*60; time_t unix_time; struct tm local; struct tm gmt; int offset; /* Make local copies of the return values */ local = *local_time_pointer; unix_time = mktime (&local); gmt = *gmtime (&unix_time); /* mktime() not portably reliable; calculate minutes offset ourselves */ offset = ((local.tm_hour - gmt.tm_hour) * 60 + (local.tm_min - gmt.tm_min)); /* Adjust backwards/forwards if the day is different */ if (local.tm_year < gmt.tm_year) offset -= MINUTES_PER_DAY; else if (local.tm_year > gmt.tm_year) offset += MINUTES_PER_DAY; else if (local.tm_yday < gmt.tm_yday) offset -= MINUTES_PER_DAY; else if (local.tm_yday > gmt.tm_yday) offset += MINUTES_PER_DAY; return offset; } /* The same as `strftime' except it handles the case when `%z' is unsupported by libc. */ size_t gnats_strftime (char *s, size_t size, const char *template, const struct tm *brokentime) { static short have_strftime_with_z = -1; if (have_strftime_with_z < 0) { char buf[16]; strftime (buf, 16, "%z", brokentime); /* jonm@alchemetrics.co.uk - added check for +/- at the start ** of the string to support SCO OpenServer. The undocumented ** %z does not have a '+' on for positive offsets, so the ** return from get_curr_date() cannot be parsed by get_date(). */ have_strftime_with_z = ((int)buf[0] == '+' || (int)buf[0] == '-') && isdigit ((int)(buf[1])); } if (have_strftime_with_z) return strftime (s, size, template, brokentime); else { int padding = 0; const char *in = template; char *fixed_template = 0; char *out = 0; /* Because brokentime points to static data (allocated * by localtime()), it cannot be passed to a subroutine * and then later be relied on to point to the same data. */ struct tm btime = *brokentime; int result; /* Count number of %z so we know how much characters to add to the * template. We actually count the number of additional characters. * As we are going to replace each "%z" by "+hhmm" (sign, hours, * minutes), this is 3 extra chars for each %z. */ while (*in) { if (*in == '%' && *(in+1) == 'z') { in += 2; padding += 3; /* 3 extra chars for each %z */ } else { in++; } } /* Now allocate enough space. */ fixed_template = (char*)xmalloc (strlen(template)+padding+1); in = template; /* Inspect it again, this time replacing all %z. */ out = fixed_template; while (*in != '\0') { char c = *in++; if (c != '%') { *out++ = c; } else if (*in != 'z') { *out++ = c; /* the '%' */ *out++ = *in++; } else { int offset = minutes_gmt_offset (brokentime); char offset_buf[6]; char sign = '+'; unsigned int i, hours, minutes; if (offset < 0) { sign = '-'; offset = -offset; } hours = offset / 60; minutes = offset % 60; sprintf (offset_buf, "%c%02d%02d", sign, hours, minutes); for (i = 0; i < strlen (offset_buf); i++) *out++ = offset_buf[i]; in++; /* skip over 'z' */ } } *out = '\0'; result = strftime (s, size, fixed_template, &btime); free (fixed_template); return result; } } /* Print usage information and exit with EXIT_CODE. `texts' contains the output strings to be concatenated and printed; its last element must be NULL. (This is not a single string, because ISO C guarantees string length only to about 509 bytes.) */ void usage (const char *const texts[], int exit_code) { FILE *output = (exit_code ? stderr : stdout); const char *const *t; for (t = texts; *t != NULL; t++) fprintf (output, "%s", *t); exit (exit_code); } /* Output the version information for PROGRAM_NAME and exit. */ void version (const char *const program_name) { printf ("%s %s\n", program_name, version_string); exit (EXIT_OK); } /* Return true iff STRING is either NULL or doesn't contain any non-whitespace character. */ bool value_is_empty (const char *string) { if (string == NULL) return TRUE; { unsigned int i; for (i = 0; i < strlen (string); i++) if (! isspace ((int)(unsigned char)(string[i]))) return FALSE; return TRUE; } } /* The following functions are stolen from libiberty library (-liberty) */ #ifndef HAVE_ASPRINTF /* @deftypefn Extension int asprintf (char **@var{resptr}, const char *@var{format}, ...) Like @code{sprintf}, but instead of passing a pointer to a buffer, you pass a pointer to a pointer. This function will compute the size of the buffer needed, allocate memory with @code{malloc}, and store a pointer to the allocated memory in @code{*@var{resptr}}. The value returned is the same as @code{sprintf} would return. If memory could not be allocated, minus one is returned and @code{NULL} is stored in @code{*@var{resptr}}. @end deftypefn */ int asprintf VPARAMS ((char **buf, const char *fmt, ...)) { int status; VA_OPEN (ap, fmt); VA_FIXEDARG (ap, char **, buf); VA_FIXEDARG (ap, const char *, fmt); status = vasprintf (buf, fmt, ap); VA_CLOSE (ap); return status; } #endif /* HAVE_ASPRINTF */ #ifndef HAVE_VASPRINTF /* @deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args}) Like @code{vsprintf}, but instead of passing a pointer to a buffer, you pass a pointer to a pointer. This function will compute the size of the buffer needed, allocate memory with @code{malloc}, and store a pointer to the allocated memory in @code{*@var{resptr}}. The value returned is the same as @code{vsprintf} would return. If memory could not be allocated, minus one is returned and @code{NULL} is stored in @code{*@var{resptr}}. @end deftypefn */ /* This is a vasprintf helper */ static int int_vasprintf PARAMS ((char **, const char *, va_list)); static int int_vasprintf (result, format, args) char **result; const char *format; va_list args; { const char *p = format; /* Add one to make sure that it is never zero, which might cause malloc to return NULL. */ int total_width = strlen (format) + 1; va_list ap; #ifdef va_copy va_copy (ap, args); #else memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); #endif while (*p != '\0') { if (*p++ == '%') { while (strchr ("-+ #0", *p)) ++p; if (*p == '*') { ++p; total_width += abs (va_arg (ap, int)); } else total_width += strtoul (p, (char **) &p, 10); if (*p == '.') { ++p; if (*p == '*') { ++p; total_width += abs (va_arg (ap, int)); } else total_width += strtoul (p, (char **) &p, 10); } while (strchr ("hlL", *p)) ++p; /* Should be big enough for any format specifier except %s and floats. */ total_width += 30; switch (*p) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': case 'c': (void) va_arg (ap, int); break; case 'f': case 'e': case 'E': case 'g': case 'G': (void) va_arg (ap, double); /* Since an ieee double can have an exponent of 307, we'll make the buffer wide enough to cover the gross case. */ total_width += 307; break; case 's': total_width += strlen (va_arg (ap, char *)); break; case 'p': case 'n': (void) va_arg (ap, char *); break; } p++; } } #ifdef va_copy va_end (ap); #endif *result = (char *) malloc (total_width); if (*result != NULL) return vsprintf (*result, format, args); else return -1; } int vasprintf (result, format, args) char **result; const char *format; #if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) _BSD_VA_LIST_ args; #else va_list args; #endif { return int_vasprintf (result, format, args); } #endif /* HAVE_VASPRINTF */ #ifndef HAVE_BASENAME /* @deftypefn Supplemental char* basename (const char *@var{name}) Returns a pointer to the last component of pathname @var{name}. Behavior is undefined if the pathname ends in a directory separator. @end deftypefn */ #ifndef DIR_SEPARATOR #define DIR_SEPARATOR '/' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) #define HAVE_DOS_BASED_FILE_SYSTEM #ifndef DIR_SEPARATOR_2 #define DIR_SEPARATOR_2 '\\' #endif #endif /* Define IS_DIR_SEPARATOR. */ #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ /* Note: to be POSIX-2 compliant "name" have a "char *" type. */ char * basename (name) char *name; { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (ISALPHA (name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) { if (IS_DIR_SEPARATOR (*name)) { base = name + 1; } } return (char *) base; } #endif /* HAVE_BASENAME */ gnats-4.1.0/gnats/mk_auth.c0000644000175000017500000001607706620401142016300 0ustar chewiechewie00000000000000/* * mk_auth.c * * Copyright 1987, 1988 by the Massachusetts Institute of Technology. * * For copying and distribution information, please see the file * . * * Derived from sendauth.c by John Gilmore, 10 October 1994. */ #include "mit-copyright.h" #define DEFINE_SOCKADDR /* Ask for sockets declarations from krb.h. */ #define INTERFACE #define KRB_INT32 long #include #include "krb.h" #include #include #include #define KRB_SENDAUTH_VERS "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN chars */ /* * If the protocol changes, you will need to change the version string * and make appropriate changes in recvauth.c and sendauth.c. */ /* * This file contains two routines: krb_mk_auth() and krb_check_auth(). * * krb_mk_auth() packages a ticket for transmission to an application * server. * * krb_krb_check_auth() validates a mutual-authentication response from * the application server. * * These routines are portable versions that implement a protocol * compatible with the original Unix "sendauth". */ /* * The first argument to krb_mk_auth() contains a bitfield of * options (the options are defined in "krb.h"): * * KOPT_DONT_CANON Don't canonicalize instance as a hostname. * (If this option is not chosen, krb_get_phost() * is called to canonicalize it.) * * KOPT_DONT_MK_REQ Don't request server ticket from Kerberos. * A ticket must be supplied in the "ticket" * argument. * (If this option is not chosen, and there * is no ticket for the given server in the * ticket cache, one will be fetched using * krb_mk_req() and returned in "ticket".) * * KOPT_DO_MUTUAL Do mutual authentication, requiring that the * receiving server return the checksum+1 encrypted * in the session key. The mutual authentication * is done using krb_mk_priv() on the other side * (see "recvauth.c") and krb_rd_priv() on this * side. * * The "ticket" argument is used to store the new ticket * from the krb_mk_req() call. If the KOPT_DONT_MK_REQ options is * chosen, the ticket must be supplied in the "ticket" argument. * The "service", "inst", and "realm" arguments identify the ticket. * If "realm" is null, the local realm is used. * * The following argument is only needed if the KOPT_DO_MUTUAL option * is chosen: * * The "checksum" argument is a number that the server will add 1 to * to authenticate itself back to the client. * * The application protocol version number (of up to KRB_SENDAUTH_VLEN * characters) is passed in "version". * * The ticket is packaged into a message in the buffer pointed to by * the argument "buf". * * If all goes well, KSUCCESS is returned, otherwise some error code. * * The format of the message packaged to send to the application server is: * * Size Variable Field * ---- -------- ----- * * KRB_SENDAUTH_VLEN KRB_SENDAUTH_VER sendauth protocol * bytes version number * * KRB_SENDAUTH_VLEN version application protocol * bytes version number * * 4 bytes ticket->length length of ticket * * ticket->length ticket->dat ticket itself */ /* * Build a "sendauth" packet compatible with Unix sendauth/recvauth. */ int INTERFACE krb_mk_auth(options, ticket, service, inst, realm, checksum, version, buf) long options; /* bit-pattern of options */ KTEXT ticket; /* where to put ticket (return); or supplied in case of KOPT_DONT_MK_REQ */ char *service; /* service name */ char *inst; /* instance (OUTPUT canonicalized) */ char *realm; /* realm */ unsigned KRB_INT32 checksum; /* checksum to include in request */ char *version; /* version string */ KTEXT buf; /* Output buffer to fill */ { int rem, i; char krb_realm[REALM_SZ]; KRB_INT32 tkt_len; rem=KSUCCESS; /* get current realm if not passed in */ if (!realm) { rem = krb_get_lrealm(krb_realm,1); if (rem != KSUCCESS) return(rem); realm = krb_realm; } if (!(options & KOPT_DONT_CANON)) (void) strncpy(inst, krb_get_phost(inst), INST_SZ); /* get the ticket if desired */ if (!(options & KOPT_DONT_MK_REQ)) { rem = krb_mk_req(ticket, service, inst, realm, checksum); if (rem != KSUCCESS) return(rem); } #ifdef ATHENA_COMPAT /* this is only for compatibility with old servers */ if (options & KOPT_DO_OLDSTYLE) { (void) sprintf(buf->dat,"%d ",ticket->length); (void) write(fd, buf, strlen(buf)); (void) write(fd, (char *) ticket->dat, ticket->length); return(rem); } #endif /* ATHENA_COMPAT */ /* zero the buffer */ (void) memset(buf->dat, 0, MAX_KTXT_LEN); /* insert version strings */ (void) strncpy((char *)buf->dat, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN); (void) strncpy((char *)buf->dat+KRB_SENDAUTH_VLEN, version, KRB_SENDAUTH_VLEN); /* increment past vers strings */ i = 2*KRB_SENDAUTH_VLEN; /* put ticket length into buffer */ tkt_len = htonl((unsigned KRB_INT32) ticket->length); (void) memcpy(buf->dat+i, (char *) &tkt_len, sizeof(tkt_len)); i += sizeof(tkt_len); /* put ticket into buffer */ (void) memcpy(buf->dat+i, (char *) ticket->dat, ticket->length); i += ticket->length; buf->length = i; return KSUCCESS; } /* * For mutual authentication using mk_auth, check the server's response * to validate that we're really talking to the server which holds the * key that we obtained from the Kerberos key server. * * The "buf" argument is the response we received from the app server. * The "checksum" argument is a number that the server has added 1 to * to authenticate itself back to the client (us); the "msg_data" argument * returns the returned mutual-authentication message from the server * (i.e., the checksum+1); "session" holds the * session key of the server, extracted from the ticket file, for use * in decrypting the mutual authentication message from the server; * and "schedule" returns the key schedule for that decryption. The * the local and server addresses are given in "laddr" and "faddr". */ int INTERFACE krb_check_auth (buf, checksum, msg_data, session, schedule, laddr, faddr) KTEXT buf; /* The response we read from app server */ unsigned KRB_INT32 checksum; /* checksum we included in request */ MSG_DAT *msg_data; /* mutual auth MSG_DAT (return) */ C_Block session; /* credentials (input) */ Key_schedule schedule; /* key schedule (return) */ struct sockaddr_in *laddr; /* local address */ struct sockaddr_in *faddr; /* address of foreign host on fd */ { int cc; unsigned KRB_INT32 cksum; /* decrypt it */ #ifndef NOENCRYPTION key_sched(session, schedule); #endif /* !NOENCRYPTION */ if (cc = krb_rd_priv(buf->dat, buf->length, schedule, (C_Block *)session, faddr, laddr, msg_data)) return(cc); /* fetch the (incremented) checksum that we supplied in the request */ (void) memcpy((char *)&cksum, (char *)msg_data->app_data, sizeof(cksum)); cksum = ntohl(cksum); /* if it doesn't match, fail -- reply wasn't from our real server. */ if (cksum != checksum + 1) return(KFAILURE); /* XXX */ return(KSUCCESS); } gnats-4.1.0/gnats/mkcat.sh0000644000175000017500000000331307331325174016136 0ustar chewiechewie00000000000000#!/bin/sh # Create directories for each category in a GNATS categories file. # Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. # Contributed by Brendan Kehoe (brendan@cygnus.com) and # Tim Wicinski (wicinski@barn.com). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. prog=mkcat USAGE="Usage: $prog [--help] [--database=databasename]" # process command line options while [ $# -gt 0 ]; do case "$1" in -d | --database) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi shift ; GNATSDB="$1" ; export GNATSDB ;; --database=*) GNATSDB="`echo $1 | sed 's/^[-a-z]*=//'`" ; export GNATSDB ;; -*) echo "$USAGE" ; exit 1 ;; esac shift done GNATS_DB_DIR="`query-pr --print-directory-for-database`" # verify gnats root if [ ! -d ${GNATS_DB_DIR} ] ; then echo "$prog: No directory $GNATS_DB_DIR" exit 1 fi query-pr --list-categories | awk -F: '{print $1}' | while read i do if test -d "$GNATS_DB_DIR/$i"; then true else mkdir "$GNATS_DB_DIR/$i" echo "Category \`$GNATS_DB_DIR/$i' created." fi done exit 0 gnats-4.1.0/gnats/mkdb.sh0000744000175000017500000000534207557041141015760 0ustar chewiechewie00000000000000#! /bin/sh # Create initial database structure. # Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. # Contributed by Bozo Bob (manson@juniper.net). # Further hacked by Milan Zamazal (pdm@zamazal.org). # # This file is part of GNU GNATS. # (GNNOUUUUUUUUU GNATS! GNOUUUUUUUUU GNATS! Doesn't that have a nice # sound? Especially if you say all the Gs?) # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. GNATS_USER=xGNATS_USERx DATABASES=xGLOBAL_DB_LIST_FILEx DATADIR=xSYSCONFDIRx/gnats/defaults LIBEXECDIR=xLIBEXECDIRx domkdir() { mkdir -p "$1" || { echo "Can't create directory $1, exiting"; exit 1 ; } chown "${GNATS_USER}" "$1" } docp() { cp $DATADIR/"$1" "$2" || { echo "Can't copy file $DATADIR/$1 to $2, exiting"; exit 1 ; } chown "${GNATS_USER}" "$2" } prog=mkdb USAGE="Usage: $prog [--help] DATABASE-NAME" while [ $# -gt 0 ]; do case "$1" in -*) echo "$USAGE" ; exit 1 ;; *) if [ -n "$database" ] ; then echo "$USAGE" 1>&2 ; exit 1 ; else database="$1" ; fi ;; esac shift done if [ -z "${database}" ] then echo "$USAGE" 1>&2 ; exit 1; fi dbdir=`grep "^${database}:" $DATABASES | sed -n 's/^'${database}':[^:]*:\([^:]*\)$/\1/p'` if [ -z "${dbdir}" ] then echo "$prog: No proper entry for \`${database}' in \`$DATABASES':\n"`grep "^${database}:" $DATABASES` exit 1 fi if [ -d "${dbdir}" ] then echo "$prog: There's already a directory ${dbdir}, exiting" !>&2 exit 1 fi domkdir "${dbdir}" domkdir "${dbdir}/gnats-adm" domkdir "${dbdir}/gnats-adm/locks" domkdir "${dbdir}/gnats-queue" domkdir "${dbdir}/pending" echo "Copying default files from ${DATADIR}" docp categories "${dbdir}/gnats-adm/categories" docp submitters "${dbdir}/gnats-adm/submitters" docp responsible "${dbdir}/gnats-adm/responsible" docp gnatsd.user_access "${dbdir}/gnats-adm/gnatsd.user_access" chmod 600 "${dbdir}/gnats-adm/gnatsd.user_access" docp addresses "${dbdir}/gnats-adm/addresses" docp states "${dbdir}/gnats-adm/states" docp classes "${dbdir}/gnats-adm/classes" docp dbconfig "${dbdir}/gnats-adm/dbconfig" $LIBEXECDIR/gnats/gen-index -d "${database}" -o "${dbdir}/gnats-adm/index" gnats-4.1.0/gnats/pcodes.h0000644000175000017500000000444207370347042016136 0ustar chewiechewie00000000000000/* Directives for the pseudo-protocol. Copyright (C) 1997 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef __PCODES_H #define __PCODES_H #define CODE_GREETING 200 #define CODE_CLOSING 201 #define CODE_OK 210 #define CODE_SEND_PR 211 #define CODE_SEND_TEXT 212 #define CODE_SEND_CHANGE_REASON 213 #define CODE_NO_PRS_MATCHED 220 #define CODE_NO_ADM_ENTRY 221 #define CODE_PR_READY 300 #define CODE_TEXT_READY 301 #define CODE_INFORMATION 350 #define CODE_INFORMATION_FILLER 351 #define CODE_NONEXISTENT_PR 400 #define CODE_EOF_PR 401 #define CODE_UNREADABLE_PR 402 #define CODE_INVALID_PR_CONTENTS 403 #define CODE_INVALID_FIELD_NAME 410 #define CODE_INVALID_ENUM 411 #define CODE_INVALID_DATE 412 #define CODE_INVALID_FIELD_CONTENTS 413 #define CODE_INVALID_SEARCH_TYPE 414 #define CODE_INVALID_EXPR 415 #define CODE_INVALID_LIST 416 #define CODE_INVALID_DATABASE 417 #define CODE_INVALID_QUERY_FORMAT 418 #define CODE_INVALID_FIELD_EDIT 419 #define CODE_NO_KERBEROS 420 #define CODE_AUTH_TYPE_UNSUP 421 #define CODE_NO_ACCESS 422 #define CODE_LOCKED_PR 430 #define CODE_GNATS_LOCKED 431 #define CODE_GNATS_NOT_LOCKED 432 #define CODE_PR_NOT_LOCKED 433 #define CODE_READONLY_FIELD 434 #define CODE_INVALID_FTYPE_PROPERTY 435 #define CODE_CMD_ERROR 440 #define CODE_WRITE_PR_FAILED 450 #define CODE_ERROR 600 #define CODE_TIMEOUT 610 #define CODE_NO_GLOBAL_CONFIG 620 #define CODE_INVALID_GLOBAL_CONFIG 621 #define CODE_INVALID_INDEX 622 #define CODE_NO_INDEX 630 #define CODE_FILE_ERROR 640 #endif /* __PCODES_H */ gnats-4.1.0/gnats/pr-age.c0000644000175000017500000001051207560340040016012 0ustar chewiechewie00000000000000/* Give the age of a PR. Copyright (C) 2001 Milan Zamazal Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "query.h" /* The name this program was run with. */ const char *program_name; typedef struct _times { int days; int hours; } Times; struct option long_options[] = { {"database", 1, NULL, 'd'}, {"host", 1, NULL, 'H'}, {"port", 1, NULL, 'P'}, {"user", 1, NULL, 'v'}, {"passwd", 1, NULL, 'w'}, {"version", 0, NULL, 'V'}, {"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "pr-age" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]... PR\n\ Print days and hours passed since arrival of PR.\n\ \n", "Connection options:\n\ -d --database=DATABASE use DATABASE\n\ -H --host=SERVER connect to SERVER\n\ -P --port=PORT connect to the port PORT\n\ -v --user=NETID use NETID as the username on the remote server\n\ -w --passwd=PASSWORD user's password\n\ \n", "Other options:\n\ -h --help display this help and exit\n\ -V --version output version information and exit\n", NULL}; static Times * time_diff (time_t then) { Times *t = (Times *) xmalloc (sizeof (Times)); time_t seconds = time (0); time_t diff = seconds - then; time_t days, hours; days = (diff / 3600) / 24; diff -= (days * 60 * 60 * 24); hours = diff / 3600; t->days = days; t->hours = hours; return t; } static void report_age (PR *pr) { const char *dateStr = field_value (pr, ARRIVAL_DATE (pr->database)); time_t then; Times *t; if (dateStr == NULL) { dateStr = ""; } then = get_date ((char *) dateStr, NULL); if (then == 0) { fprintf (stderr, "%s: don't know the time for %s\n", program_name, field_value (pr, NUMBER (pr->database))); exit (1); } t = time_diff (then); printf ("%3d %2d\n", t->days, t->hours); free ((char*)t); } int main (int argc, char **argv) { int optc; char *nameOfDatabase = NULL; char *user = NULL; char *passwd = NULL; char *hostname = NULL; int port = -1; int networkmode = 0; PR *pr; ErrorDesc err; program_name = basename (argv[0]); while ((optc = getopt_long (argc, argv, "hVd:H:P:v:w:", long_options, (int *) 0)) != EOF) { switch (optc) { case 'd': nameOfDatabase = optarg; break; case 'V': version (PROGRAM_NAME); exit (0); break; case 'h': usage (USAGE, 0); break; case 'H': hostname = optarg; networkmode = 1; break; case 'P': port = atoi (optarg); networkmode = 1; break; case 'v': user = optarg; networkmode = 1; break; case 'w': passwd = optarg; networkmode = 1; break; default: usage (USAGE, 1); } } if (optind == argc || optind >= argc) usage (USAGE, 1); if (! networkmode) { networkmode = gnatsdbHasNetconn (nameOfDatabase); } if (! networkmode) { DatabaseInfo database = init_gnats (program_name, nameOfDatabase, &err); if (database == NULL) { client_print_errors (NULL, err); exit (1); } pr = readPRWithNum (database, argv[optind], 0, &err); if (pr == NULL) { client_print_errors (database, err); exit (1); } } else { if (client_init_gnats (&err, user, passwd, hostname, port, nameOfDatabase) != 0) { client_print_errors (NULL, err); exit (1); } pr = clientReadPR (argv[optind]); } if (pr != NULL) { report_age (pr); } exit (0); } gnats-4.1.0/gnats/pr-edit.c0000644000175000017500000003075107724054426016226 0ustar chewiechewie00000000000000/* Entry for the GNATS system. Copyright (C) 2001 Milan Zamazal Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. Originally written by Tim Wicinski (wicinski@barn.com). Further work by Brendan Kehoe (brendan@cygnus.com). Further work by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "pcodes.h" /* Name of this program. */ const char *program_name; enum { NONE, LOCK, UNLOCK, LOCKDB, UNLOCKDB, CHECK, CHECK_INITIAL, MODIFY, SUBMIT, APPEND, REPLACE, DELETE } edit_options; #define DELETE_PR_OPT 256 #define SHOW_PRNUM_OPT 257 struct option long_options[] = { {"lock", 1, NULL, 'l'}, {"unlock", 0, NULL, 'u'}, {"lockdb", 0, NULL, 'L'}, {"unlockdb", 0, NULL, 'U'}, {"check", 0, NULL, 'c'}, {"check-initial", 0, NULL, 'C'}, {"submit", 0, NULL, 's'}, {"append", 1, NULL, 'a'}, {"replace", 1, NULL, 'r'}, {"reason", 1, NULL, 'R'}, {"process", 1, NULL, 'p'}, {"database", 1, NULL, 'd'}, {"filename", 1, NULL, 'f'}, {"version", 0, NULL, 'V'}, {"delete-pr", 0, NULL, DELETE_PR_OPT}, {"show-prnum", 0, NULL, SHOW_PRNUM_OPT}, {"help", 0, NULL, 'h'}, {"user", 1, NULL, 'v'}, {"passwd", 1, NULL, 'w'}, {"host", 1, NULL, 'H'}, {"port", 1, NULL, 'P'}, {"debug", 0, NULL, 'D'}, {"email-addr", 1, NULL, 'e'}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "pr-edit" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]... [PR]\n\ Modify database.\n\ \n", "Actions:\n\ -l --lock=USER lock the given PR\n\ -u --unlock unlock the given PR\n\ -L --lockdb lock the whole database\n\ -U --unlockdb unlock the database\n\ -c --check check input for editting, don't change PR\n\ -C --check-initial check input for submission, don't submit new PR\n\ -s --submit submit new PR\n", "\ --show-prnum display the newly created PR number (for --submit)\n\ -a --append=FIELDNAME append input to FIELDNAME\n\ -r --replace=FIELDNAME replace FIELDNAME with input\n\ --delete-pr delete PR from the database completely\n\ -R --reason=REASON change describing text required by some fields\n\ \n", "Connection options:\n\ -d --database=DATABASE use DATABASE\n\ -H --host=SERVER connect to SERVER\n\ -P --port=PORT connect to the port PORT\n\ -v --user=NETID use NETID as the username on the remote server\n\ -w --passwd=PASSWORD user's password\n\ -e --email-addr=ADDRESS send contingent e-mail reports to ADDRESS\n\ -p --process=PID PID of the connecting process\n\ -f --filename=FILENAME read input from FILENAME instead of stdin\n\ \n", "Other options:\n\ -h --help display this help and exit\n\ -V --version output version information and exit\n\ -D --debug enable some debugging\n", NULL }; /* Read the entire contents of the file referenced by INP into memory, and return it as a char* string allocated with malloc (). */ static char * read_file (FILE *inp) { char *res = xmalloc (512); /* 512 is just a number. It's not a limit of any sort. */ size_t reslen = 512; size_t totlen = 0, inplen; while ((inplen = fread (res + totlen, 1, reslen - totlen, inp)) != 0) { totlen += inplen; if (totlen == reslen) { reslen += 512; res = xrealloc (res, reslen); } } if (totlen == reslen) { reslen++; res = xrealloc (res, reslen); } if (inp != stdin) { fclose (inp); } res[totlen] = '\0'; return res; } static void handleNetworkEdit (int edit_options, FILE *fpin, char *prnum, char *username, char *editEmailAddr, char *processid, char *fieldname, char *reason, int show_prnum) { int exitcode = 0; switch (edit_options) { case LOCK: netLockPR (prnum, username, processid); break; case UNLOCK: netUnlockPR (prnum); break; case APPEND: netEditField (fpin, prnum, fieldname, editEmailAddr, 1, reason); break; case REPLACE: netEditField (fpin, prnum, fieldname, editEmailAddr, 0, reason); break; case SUBMIT: { netSubmitNewPR (fpin, show_prnum); break; } case CHECK: case CHECK_INITIAL: { netCheckPR (fpin, edit_options == CHECK_INITIAL ? 1 : 0); break; } case LOCKDB: netLockDB (); break; case UNLOCKDB: netUnlockDB (); break; case DELETE: netDeletePR (prnum, editEmailAddr); break; default: { netModifyPR (fpin, prnum, editEmailAddr); break; } } client_exit (); exit (exitcode); } extern int debug; int main (int argc, char **argv) { DatabaseInfo database = NULL; FILE *fp = stdin; int option; char *prnum = NULL; char *username = (char *)NULL, *processid = (char *)NULL; /* Default to 1, a passing value. */ int result = 1; ErrorDesc err; int db_locked = 0; char *fieldname = NULL; char *nameOfDatabase = NULL; char *netid = NULL; char *passwd = NULL; char *host = NULL; int port = -1; int networkmode = 0; char *editUserEmailAddr = NULL; char *reason = NULL; int show_prnum = 0; program_name = basename (argv[0]); edit_options = MODIFY; while ((option = getopt_long (argc, argv, "l:uLUDhcp:d:f:VFv:w:H:P:e:", long_options, (int *)0)) != EOF) { switch (option) { case 'd': nameOfDatabase = optarg; break; case 'D': debug = 1; break; case SHOW_PRNUM_OPT: show_prnum = 1; break; case 'f': fp = fopen (optarg, "r"); /* If they gave a bogus argument, then exit right away; we don't want to send mail to gnats-admin every time someone tries to edit a bogus PR number. */ if (fp == (FILE *)NULL) { fprintf (stderr, "%s: Bad PR file %s.\n", program_name, optarg); exit (2); } break; case 'p': processid = optarg; break; case 'l': edit_options = LOCK; username = optarg; break; case 'u': edit_options = UNLOCK; break; case 'L': edit_options = LOCKDB; break; case 'U': edit_options = UNLOCKDB; break; case 'c': edit_options = CHECK; break; case 'C': edit_options = CHECK_INITIAL; break; case 's': edit_options = SUBMIT; break; case 'a': edit_options = APPEND; fieldname = optarg; break; case 'r': edit_options = REPLACE; fieldname = optarg; break; case 'R': reason = optarg; break; case DELETE_PR_OPT: edit_options = DELETE; break; case 'V': version (PROGRAM_NAME); exit (0); break; case 'h': usage (USAGE, 0); break; case 'H': host = optarg; networkmode = 1; break; case 'P': port = atoi (optarg); networkmode = 1; break; case 'v': netid = optarg; networkmode = 1; break; case 'w': passwd = optarg; networkmode = 1; break; case 'e': editUserEmailAddr = xstrdup (optarg); break; default: usage (USAGE, 3); break; } } /* if there is another arg, then we take it to be a file name. */ if (optind < argc) { prnum = argv[optind]; } if (prnum == NULL && (edit_options == MODIFY || edit_options == APPEND || edit_options == REPLACE)) { fprintf (stderr, "%s: Must supply the PR number when modifying a PR\n", program_name); exit (1); } if (editUserEmailAddr == NULL) { struct passwd *myent = getpwuid (getuid ()); if (myent != NULL) { char hostname[256]; gethostname (hostname, sizeof (hostname)); asprintf (&editUserEmailAddr, "%s@%s", myent->pw_name, hostname); } else { fprintf (stderr, "%s: no username for uid %d\n", program_name, (int) getuid ()); exit (1); } } if ((edit_options == LOCK) && (prnum == NULL || ! username)) { fprintf (stderr, "%s: Must lock with PR number, username, and process locking it.\n", program_name); exit (2); } if ((edit_options == UNLOCK) && (prnum == NULL)) { fprintf (stderr, "%s: Must unlock with PR number.\n", program_name); exit (2); } if (! networkmode) { networkmode = gnatsdbHasNetconn (nameOfDatabase); } if (networkmode) { if (client_init_gnats (&err, netid, passwd, host, port, nameOfDatabase) != 0) { client_print_errors (database, err); exit (3); } handleNetworkEdit (edit_options, fp, prnum, username, editUserEmailAddr, processid, fieldname, reason, show_prnum); } database = init_gnats (program_name, nameOfDatabase, &err); if (database == NULL) { result = 0; } else { umask (022); block_signals (); if (edit_options == LOCKDB || edit_options == APPEND || edit_options == REPLACE || edit_options == MODIFY || edit_options == SUBMIT) { result = (client_lock_gnats (database, &err) == 0); if (result) { db_locked = 1; } } } if (result) { switch (edit_options) { case LOCK: if (prExists (database, prnum, &err)) { result = lock_pr (database, prnum, username, processid, &err); if (result != 0) { PR *pr = readPRWithNum (database, prnum, 0, &err); if (pr != NULL) { print_named_format_pr (stdout, pr, "edit", "\n", &err); free_pr (pr); } else { if (unlock_pr (database, prnum, &err) != 0) { /* ??? XXX !!! */ setError (&err, CODE_NONEXISTENT_PR, "Invalid PR %s.", prnum); } result = 0; } } } else { result = 0; } break; case UNLOCK: result = unlock_pr (database, prnum, &err); break; case SUBMIT: { result = submit_pr (database, fp, &err); if (show_prnum && result) { fprintf (stdout, "%d\n", result); } break; } case APPEND: { char *contents = read_file (fp); FieldIndex field = find_field_index (database, fieldname); if (field == InvalidFieldIndex) { setError (&err, CODE_INVALID_FIELD_NAME, "No such field as %s", fieldname); result = 0; } else { result = edit_field (database, prnum, field, 1, contents, reason, editUserEmailAddr, &err); } break; } case REPLACE: { char *contents = read_file (fp); FieldIndex field = find_field_index (database, fieldname); if (field == InvalidFieldIndex) { setError (&err, CODE_INVALID_FIELD_NAME, "No such field as %s", fieldname); result = 0; } else { result = edit_field (database, prnum, field, 0, contents, reason, editUserEmailAddr, &err); } break; } case DELETE: { struct passwd *pwent = getpwnam (GNATS_USER); if (pwent == NULL) { setError (&err, CODE_ERROR, "No such user as %s\n", GNATS_USER); result = 0; } else if ((int) pwent->pw_uid != (int) getuid ()) { setError (&err, CODE_FILE_ERROR, "Must be user %s to delete a PR\n", GNATS_USER); result = 0; } else { result = ! deletePR (database, prnum, editUserEmailAddr, &err); } break; } case CHECK: case CHECK_INITIAL: result = check_pr_file (database, fp, &err, edit_options == CHECK_INITIAL); break; case LOCKDB: case UNLOCKDB: result = 1; /* so that the program exits with 0 status */ break; default: result = replace_pr (database, fp, editUserEmailAddr, &err); break; } } if (db_locked || edit_options == UNLOCKDB) { client_unlock_gnats (); } if (! result) { client_print_errors (database, err); } unblock_signals (); if (editUserEmailAddr != NULL) { free (editUserEmailAddr); editUserEmailAddr = NULL; } exit (result ? 0 : 2); } gnats-4.1.0/gnats/pr-init.c0000644000175000017500000000664307266362147016252 0ustar chewiechewie00000000000000#include "gnats.h" #include "builtin-fields.h" #include "pcodes.h" /* The set of builtin fields. If you change these, you must change builtin-fields.h to match. */ struct pr_builtin_field { /* The header string of the field. */ const char *builtin_name; }; struct pr_builtin_field builtinFields[NUM_BUILTIN_FIELDS] = { { "Number" }, { "Category" }, { "Synopsis" }, { "Confidential" }, { "Severity" }, { "Priority" }, { "Responsible" }, { "State" }, { "Submitter-Id" }, { "Arrival-Date" }, { "Closed-Date" }, { "Last-Modified" }, { "Originator" }, { "Description" }, { "Audit-Trail" }, { "Unformatted" } }; /* Init all the fields in the PR. */ static FILE *inpfile = NULL; int (*yyinpfunc)(char *buf, int max) = NULL; static int getFconfigLine (char *buf, int max) { if (fgets (buf, max, inpfile) == NULL) { return 0; } return (strlen (buf)); } static int badConfig; static ErrorDesc *errForDbParse; static const char *fconfigFile; DatabaseInfo databaseBeingDefined; /* Read in the field configuration file, and configure DATABASE appropriately. If FILENAME is non-NULL, use it as the file to read from. If FUNC is specified, FUNC will be used to read the actual data from the file; this is used by the network client to read the configuration from the server, rather than from a local file. FUNC is passed in a buffer in which to store the data read from the configuration file, and the maximum amount of data that can be written to BUF. FUNC should return the number of characters read, or 0 on EOF or error. */ int fconfigParse (DatabaseInfo database, const char *filename, int (*func)(char *buf, int max), ErrorDesc *err) { extern int fconfig_lineno; extern void fconfparse (void); extern void cleanLexer (void); databaseBeingDefined = database; badConfig = 0; if (filename != NULL) { inpfile = fopen (filename, "r"); if (inpfile == NULL) { setError (err, CODE_INVALID_DATABASE, "Unable to read config file %s", filename); return 1; } fconfigFile = filename; } else { fconfigFile = "server-supplied configuration"; } if (func != NULL) { yyinpfunc = func; } else { yyinpfunc = getFconfigLine; } errForDbParse = err; fconfig_lineno = 1; fconfparse (); if (filename != NULL) { fclose (inpfile); } cleanLexer (); return badConfig; } /* Not terribly helpful. XXX ??? !!! */ void fconferror (const char *message) { extern int fconfig_lineno; if (! badConfig) { setError (errForDbParse, CODE_INVALID_DATABASE, "Error at line %d of %s:%s", fconfig_lineno, fconfigFile, message); } badConfig = 1; } int fconflex (void) { extern int yylex (void); return yylex (); } int setBuiltinField (FieldIndex field, const char *name) { int x; for (x = 0; x < NUM_BUILTIN_FIELDS; x++) { if (strcasecmp (name, builtinFields[x].builtin_name) == 0) { setBuiltinDBField (field->database, x, field); break; } } if (x == NUM_BUILTIN_FIELDS) { return -1; } else { return 0; } } FieldIndex findBuiltinField (const DatabaseInfo database, const char *name) { int x; for (x = 0; x < NUM_BUILTIN_FIELDS; x++) { if (strcasecmp (name, builtinFields[x].builtin_name) == 0) { return getBuiltinField (database, x); } } return find_field_index (database, name); } gnats-4.1.0/gnats/pr-stat.c0000644000175000017500000001121707521042071016234 0ustar chewiechewie00000000000000/* Give stats on PRs regarding their lifetime from open to closed state. Copyright (C) 1994, 1995, 2002 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ /* Initial version, when complete dissect it and put functionality into the server, and make this a bare client using that design to extend the possibilities of what we're adding. */ #include "gnats.h" #include "query.h" void usage (), version (); /* The name this program was run with. */ char *program_name; typedef struct _times { int days; int hours; } Times; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"database", 1, NULL, 'd'}, {"version", 0, NULL, 'V'}, {NULL, 0, NULL, 0} }; Times * time_diff_2 (start, stop) time_t start, stop; { Times *t = (Times *) xmalloc (sizeof (Times)); time_t diff = stop - start; time_t days, hours; days = (diff / 3600) / 24; diff -= (days * 86400); /* days * 60 * 60 * 24 */ hours = diff / 3600; t->days = days; t->hours = hours; return t; } time_t got_closed (p) char *p; { time_t t; char *final1, *final2; char *c; /* Skip ahead to the last time it was closed. */ final1 = p; do { final2 = final1; final1 = strstr (final2, "-closed\n"); if (final1) final1 += 8; } while (final1); if (! final2) return (time_t)0; /* Grab the date, and return the time it represents. */ final1 = strstr (final2, "When: "); if (! final1) return (time_t)0; c = strchr (final1 + 6, '\n'); if (c) *c = '\0'; return get_date (final1 + 6, NULL); } void do_stat (p) char *p; { char *path; ErrorDesc err; path = lookup_pr_path (p, &err); if (path != NULL) { /* XXX ??? Check the final argument */ if (get_pr (path, p, 0)) { time_t start = get_date (field_value (ARRIVAL_DATE), NULL); time_t stop = got_closed (field_value (AUDIT_TRAIL)); Times *t; /* We don't care about ones that had no closed status in its audit trail. */ if (!start || !stop) { free (path); return; } t = time_diff_2 (start, stop); /* XXX do real stuff here */ printf ("%d %2d\n", t->days, t->hours); free (t); } else { fprintf (stderr, "Unable to read PR %s\n", p); } free (path); } } void do_category (c) char *c; { PR *pr; for (pr = pr_chain; pr != NULL ; pr = pr->next) { if ((strcmp (field_value (pr, CATEGORY->index), c) == 0) && (check_state_type (field_value (pr, STATE->index), "closed"))) { char *path; asprintf (&path, "%s/%s", c, field_value (pr, NUMBER->index)); do_stat (path); free (path); } } } int main (argc, argv) int argc; char **argv; { int optc; program_name = basename (argv[0]); char *database = NULL; ErrorDesc err; while ((optc = getopt_long (argc, argv, "hVd:", long_options, (int *) 0)) != EOF) { switch (optc) { case 'd': database = optarg; break; case 'V': version (); exit (0); break; case 'h': usage (0); break; default: usage (1); } } if (optind == argc || optind >= argc) usage (1); if (init_gnats (program_name, database, &err) != 0) { client_print_errors (err); exit (1); } index_chain = get_pr_chain (&err); if (index_chain == NULL) { client_print_errors (err); exit (1); } if (optind == argc) /* nothing */ ; else while (optind < argc) do_category (argv[optind++]); #if 0 /* One approach: */ printf ("Category # bugs Avg Age Max Age Min Age\n"); printf (" dy hr dy hr dy hr\n\n"); printf ("%-16s %4d %4d %02d %4d %02d %4d %02d\n", c, cnt[c], avgd, avgh, maxd, maxh, mind, minh); #endif exit (0); } void usage (x) int x; { fprintf (stderr, "Usage: %s [-d database_name] category [category...]\n", program_name); exit (x); } void version (void) { printf ("pr-stat %s\n", version_string); } gnats-4.1.0/gnats/pr.c0000644000175000017500000010341610207433626015273 0ustar chewiechewie00000000000000/* Functions for manipulating a PR. Copyright (C) 2001 Milan Zamazal Copyright (C) 1993, 1994, 1995, 1999, 2000 Free Software Foundation, Inc. Originally contributed by Tim Wicinski (wicinski@barn.com) and Brendan Kehoe (brendan@cygnus.com). Completely rewritten by Bob Manson (manson@juniper.net). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "pcodes.h" /* These will eventually be properly configurable. */ #define PR_FIELD_TAG_START '>' #define PR_FIELD_TAG_END ':' static FieldIndex find_field_num (const char *header, size_t len, PR *pr); struct PRDataString { char *buffer; char *string; }; static void freePRDataString (struct PRDataString *ptr) { if (ptr->buffer != NULL) { free (ptr->buffer); ptr->buffer = NULL; ptr->string = NULL; } else if (ptr->string != NULL) { free (ptr->string); ptr->string = NULL; } } /* Used when reading in a PR. */ struct PR_private { /* Buffer used for current field contents. */ char *buffer; /* Values of the fields. */ struct PR_private_value { /* The actual line contents. */ struct PRDataString data; /* Reason for change, if one is needed. */ struct PRDataString reason; } *value; /* Values of the headers. */ char **header; /* The total size of the buffer. */ size_t bufferSize; /* Length of the current contents. */ size_t bufferLen; /* Buffer used for the Unformatted: field. */ char *unformatted; /* Total size of the unformatted buffer. */ size_t unformattedSize; /* Length of the current contents. */ size_t unformattedLen; /* Current read state. */ enum ReadState { NormalState, MultiTextState } readState; /* The index of the multitext field being read in, if any. */ FieldIndex multiFieldIndex; /* Flag indicating that the multitext field being filled in is the -Changed-Why: field. */ int multiFieldIsReason; /* Non-zero if this is the field indicating the reason for the change. */ int isReason; /* Set if any data has actually been stored in the PR. */ int non_zero; }; static const char *headerNames[NUM_HEADER_ITEMS] = { "From", "Return-Path:", "Received:", "Message-Id:", "Date:", "From:", "Sender:", "Reply-To:", "To:", "Apparently-To:", "Cc:", "In-Reply-To:", "Subject:", "References:", "X-Send-Pr-Version:", "X-GNATS-Notify:", "X-GNATS-NoNotify:" }; /* Allocate a PR struct. */ PR * allocPR (const DatabaseInfo database) { PR *res = (PR *) xmalloc (sizeof (PR)); int field_num = get_num_fields (database); res->database = database; allocIndex (res); res->private = (struct PR_private *) xmalloc (sizeof (struct PR_private)); res->private->value = (struct PR_private_value *) xmalloc (sizeof (struct PR_private_value) * field_num); memset (res->private->value, 0, sizeof (struct PR_private_value) * field_num); res->private->header = (char **) xmalloc (sizeof (char *) * NUM_HEADER_ITEMS); memset (res->private->header, 0, sizeof (char *) * NUM_HEADER_ITEMS); res->private->buffer = NULL; res->private->bufferLen = 0; res->private->unformatted = NULL; res->private->unformattedSize = 0; res->private->unformattedLen = 0; res->private->multiFieldIndex = 0; res->private->isReason = 0; res->private->multiFieldIsReason = 0; res->private->non_zero = 0; res->prune = 0; res->read_in = 0; return res; } /* Get the PR at PATH. PR is the PR entry to be filled in. If PRUNE is non-zero, don't read any multitext fields. */ static int get_pr (PR *pr, const char *path, int prune) { FILE *fp = fopen (path, "r"); if (fp == (FILE *)NULL) { return 0; } if (read_header (pr, fp) < 0) { return 0; } read_pr (pr, fp, prune); fclose (fp); return 1; } int fillInPR (PR *pr, ErrorDesc *err) { char *path = gen_pr_path (pr); const char *num = field_value (pr, NUMBER (pr->database)); int val; if (num == NULL || path == NULL) { setError (err, CODE_ERROR, "Invalid PR in fillInPR()"); if (path != NULL) { free (path); } return -1; } else { val = get_pr (pr, path, 0); free (path); if (val == 0) { setError (err, CODE_FILE_ERROR, "Unable to read PR %s", num); return -1; } else { return 0; } } } static PR * get_pr_from_index (const DatabaseInfo database, const char *prnum, ErrorDesc *err) { PR *pr = getFirstPR (database, err); /* If they gave it to us with the category, remove it. */ if (( strrchr (prnum, '/')) != NULL) { prnum = strrchr (prnum, '/') + 1; } while (pr != NULL && strcmp (prnum, field_value (pr, NUMBER (database))) != 0) { pr = getNextPR (pr); } if (pr == NULL) { setError (err, CODE_NONEXISTENT_PR, "No PR %s listed in the index.", prnum); return NULL; } return pr; } /* Initializes PR for reading. Each line of the PR should be passed in via addLineToPR (). */ void initReadPR (PR *pr) { free_pr_contents (pr); pr->private->multiFieldIndex = InvalidFieldIndex; pr->private->readState = NormalState; pr->private->bufferSize = BUFSIZ; pr->private->unformattedSize = BUFSIZ; pr->private->buffer = xmalloc (pr->private->bufferSize); pr->private->unformatted = xmalloc (pr->private->unformattedSize); pr->private->bufferLen = 0; pr->private->unformattedLen = 0; } /* Read the file pointed to by FP, and look for matching field names, trying to attach values to those names. If PRUNE is non-zero, multitext fields are not read in. */ void read_pr (PR *pr, FILE *fp, int prune) { if (fp != NULL && pr != NULL) { size_t linelen = 0; char *line; initReadPR (pr); pr->prune = prune; while ((line = read_line (fp, &linelen)) != NULL) { addLineToPR (pr, line, line, linelen, prune); linelen = 0; } finishReadPR (pr, prune); } } /* Grab a field header name. The name is returned as a pointer into the line (it's always the passed-in value of *LINEPTR). The length of the header is returned in HEADERLEN. *LINEPTR is adjusted to point to the rest of the line (any whitespace between the name and the rest of the line is skipped). */ static const char * getFieldHeader (char **linePtr, size_t *headerLen, size_t linelen) { char *line = *linePtr; char *lineEnd = line + linelen; char *res = *linePtr; /* Grab the first word ending in space or : */ while (line < lineEnd && (! isspace ((int)(unsigned char) *line)) && *line != ':') { line++; } /* We want to include the : in the result */ if (line < lineEnd && *line == ':') { line++; } *headerLen = line - res; while (line < lineEnd && isspace ((int)(unsigned char) *line)) { line++; } *linePtr = line; return res; } /* Add line LINE of length LINELEN to PR. If PRUNE is non-zero, multitext fields are not added. */ void addLineToPR (PR *pr, char *buffer, char *line, size_t linelen, int prune) { FieldIndex fieldIndex = InvalidFieldIndex; struct PR_private *prv = pr->private; if (linelen > 1 && line[0] == PR_FIELD_TAG_START) { char *temp = line; size_t headerLen; const char *header = getFieldHeader (&temp, &headerLen, linelen); if (header != NULL) { if (header[headerLen - 1] == ':') { FieldIndex newFieldIndex = find_field_num (header, headerLen, pr); if (newFieldIndex != InvalidFieldIndex) { fieldIndex = newFieldIndex; pr->private->readState = NormalState; linelen -= (temp - line); line = temp; } } } } /* Heuristic for finding included PR fields */ if (prv->readState == MultiTextState) { /* Glluuuugh. XXX ??? !!! So we're saying "if the field index is the same as the current multitext field being read, or if the field was already set, then we don't have a valid field number? MOMMYYYY!!!! I'm tellin... "heuristic" my butt. */ if (fieldIndex != InvalidFieldIndex && (fieldIndex == prv->multiFieldIndex || prv->value[fieldNumber (fieldIndex)].data.string != NULL)) { fieldIndex = InvalidFieldIndex; } } /* If we can't find the name and we are not in multi_text line mode, it goes into unformatted. */ if (fieldIndex != InvalidFieldIndex) { if (fieldDefForIndex (fieldIndex)->datatype == MultiText || prv->isReason) { prv->readState = MultiTextState; if (! prune) { if (prv->multiFieldIndex != InvalidFieldIndex) { struct PRDataString *dest; if (prv->multiFieldIsReason) { dest = &(prv->value[fieldNumber (prv->multiFieldIndex)].reason); } else { dest = &(prv->value[fieldNumber (prv->multiFieldIndex)].data); } prv->buffer[prv->bufferLen++] = '\0'; if (dest->string != NULL) { freePRDataString (dest); } /* Doing two memcpys here isn't so great. Could just shove the old buffer into the field, then allocate a new one. */ dest->string = xmalloc (prv->bufferLen); memcpy (dest->string, prv->buffer, prv->bufferLen); prv->non_zero = 1; } memcpy (prv->buffer, line, linelen); prv->bufferLen = linelen; } prv->multiFieldIndex = fieldIndex; prv->multiFieldIsReason = prv->isReason; } else { struct PRDataString *dest = &(prv->value[fieldNumber (fieldIndex)].data); /* Skip leading spaces; I don't think this is really needed anyway, since we've already done it in getFieldHeader (). */ while (linelen > 0 && isspace ((int)(unsigned char) *line)) { line++; linelen--; } /* Fields that aren't MultiText shouldn't have spaces at the end. */ while (linelen > 0 && isspace ((int)(unsigned char) line[linelen - 1])) { linelen--; } line[linelen] = '\0'; if (dest->string != NULL) { freePRDataString (dest); } dest->string = line; dest->buffer = buffer; prv->non_zero = 1; prv->readState = NormalState; buffer = NULL; } } else if (prv->readState == MultiTextState) { if (! prune) { if ((linelen + prv->bufferLen) >= prv->bufferSize) { while ((linelen + prv->bufferLen + 2) >= prv->bufferSize) { prv->bufferSize = (prv->bufferSize * 2) + 2; } prv->buffer = (char *) xrealloc (prv->buffer, prv->bufferSize); } /* Insert a space if there isn't one already. */ if (prv->multiFieldIndex == UNFORMATTED (pr->database) && line[0] != ' ') { prv->buffer[prv->bufferLen] = ' '; prv->bufferLen++; } memcpy (prv->buffer + prv->bufferLen, line, linelen); prv->bufferLen += linelen; } } else { /* It must be unformatted. This is done separately since an unformatted field can show up anywhere. */ prv->readState = NormalState; /* We skip unformatted text if we're pruning. */ if (! prune) { if ((linelen + prv->unformattedLen + 1) >= prv->unformattedSize) { while ((linelen + prv->unformattedLen + 1) >= prv->unformattedSize) { prv->unformattedSize = (prv->unformattedSize * 2) + 1; } prv->unformatted = (char *) xrealloc (prv->unformatted, prv->unformattedSize); } /* Put a space in front of each unformatted line, showing it as "quoted text" */ prv->unformatted[prv->unformattedLen] = ' '; prv->unformattedLen++; memcpy (prv->unformatted + prv->unformattedLen, line, linelen); prv->unformattedLen += linelen; } } if (buffer != NULL) { free (buffer); } } /* Finish reading PR; if PRUNE is non-zero, we're skipping multitext fields. */ void finishReadPR (PR *pr, int prune) { struct PR_private *prv = pr->private; /* Store the last multitext field, if it wasn't stored. */ if (prv->multiFieldIndex != InvalidFieldIndex && ! prune) { struct PRDataString *dest; if (prv->multiFieldIsReason) { dest = &(prv->value[fieldNumber (prv->multiFieldIndex)].reason); } else { dest = &(prv->value[fieldNumber (prv->multiFieldIndex)].data); } if (dest->string != NULL) { freePRDataString (dest); } prv->buffer[prv->bufferLen] = '\0'; dest->buffer = prv->buffer; dest->string = prv->buffer; prv->non_zero = 1; prv->multiFieldIndex = InvalidFieldIndex; } else { free (prv->buffer); } /* Check to see if the unformatted field was used. */ if (prv->unformattedLen != 0 && ! prune) { prv->unformatted[prv->unformattedLen] = '\0'; if (prv->value[fieldNumber (UNFORMATTED (pr->database))].data.string != NULL) { int len = strlen (prv->value[fieldNumber (UNFORMATTED (pr->database))].data.string) + 1; if ((prv->unformattedLen + len) > prv->unformattedSize) { prv->unformattedSize = prv->unformattedLen + len; prv->unformatted = (char *) xrealloc (prv->unformatted, prv->unformattedSize); } memcpy (prv->unformatted + prv->unformattedLen, prv->value[fieldNumber (UNFORMATTED (pr->database))].data.string, len); unsetField (pr, UNFORMATTED (pr->database)); } /* ??? XXX !!! WTF is this shit? */ if (prv->value[fieldNumber (DESCRIPTION (pr->database))].data.string != NULL) { prv->value[fieldNumber (UNFORMATTED (pr->database))].data.string = prv->unformatted; prv->value[fieldNumber (UNFORMATTED (pr->database))].data.buffer = NULL; } else { prv->value[fieldNumber (DESCRIPTION (pr->database))].data.string = prv->unformatted; prv->value[fieldNumber (DESCRIPTION (pr->database))].data.buffer = NULL; } prv->non_zero = 1; } else { free (prv->unformatted); } prv->buffer = NULL; prv->unformatted = NULL; pr->read_in = 1; } /* Escape leading dots and end each line with \r\n */ void write_multitext (fp, str, eolTerminator) FILE *fp; const char *str; const char *eolTerminator; { const char *s, *e, *end = str + strlen (str); if (eolTerminator == NULL || (eolTerminator[0] == '\n' && eolTerminator[1] == '\0')) { fputs (str, fp); return; } s = str; while (s != NULL && s < end) { if (*s == '.') { fputc ('.', fp); } e = strchr (s, '\n'); if (e != NULL) { fwrite (s, 1, e - s, fp); fputs (eolTerminator, fp); s = e + 1; } else { fputs (s, fp); s = NULL; } } } void write_pr_field (FILE *fp, FieldIndex field, const char *fieldText, const char *eolTerminator) { if (! fieldDefForIndex (field)->editonly && fieldText != NULL) { static const char *spaceList = " "; int flen = strlen (fieldDefForIndex (field)->name) + 2; if (flen > 15) { flen = 15; } switch (fieldDefForIndex (field)->datatype) { case MultiText: { size_t len; fputc (PR_FIELD_TAG_START, fp); fputs (fieldDefForIndex (field)->name, fp); fputc (PR_FIELD_TAG_END, fp); fputs (eolTerminator, fp); write_multitext (fp, fieldText, eolTerminator); len = strlen (fieldText); if (len > 0 && fieldText[len - 1] != '\n') { fputs (eolTerminator, fp); } break; } case Date: { char t[GNATS_TIME_LENGTH]; time_t timeVal = get_any_date (fieldText); if (timeVal == 0 || timeVal == -1) t[0] = '\0'; else gnats_strftime (t, GNATS_TIME_LENGTH, "%a %b %d %H:%M:%S %z %Y", localtime (&timeVal)); fprintf (fp, "%c%s%c%s %s%s", PR_FIELD_TAG_START, fieldDefForIndex (field)->name, PR_FIELD_TAG_END, spaceList + flen, t, eolTerminator); break; } default: { fputc (PR_FIELD_TAG_START, fp); fputs (fieldDefForIndex (field)->name, fp); fputc (PR_FIELD_TAG_END, fp); fputs (spaceList + flen, fp); fputc (' ', fp); fputs (fieldText, fp); fputs (eolTerminator, fp); break; } } } } /* Write the entire PR into the file passed in via FP. */ void write_entire_pr (FILE *fp, PR *pr, const char *eolTerminator) { int i; int num_fields = get_num_fields (pr->database); for (i = 0; i < num_fields; i++) { write_pr_field (fp, getNthField (pr->database, i), field_value (pr, getNthField (pr->database, i)), eolTerminator); } } int verify_enum (FieldIndex i, const char *v) { StringList *p; if (fieldDefForIndex (i)->datatype == MultiEnum) { return verifyMultiEnum (i, v); } if (fieldDefForIndex (i)->datatype != Enum) { return -1; } if (fieldDefForIndex (i)->allow_any_value) { return 1; } if (v != NULL) { for (p = fieldDefForIndex (i)->enumValues; p != NULL; p = p->next) { if (strcasecmp (v, p->name) == 0) { return 1; } } } else if (fieldDefForIndex (i)->default_value == NULL) { return 1; } return 0; } int verifyMultiEnum (FieldIndex i, const char *value) { const char *curp = value; const char *separators; if (fieldDefForIndex (i)->datatype != MultiEnum) { return -1; } if (value == NULL) { if (fieldDefForIndex (i)->default_value == NULL) { return 1; } else { return 0; } } separators = fieldDefForIndex (i)->multiEnumSeparator; while (1) { char *nextp = strpbrk (curp, separators); size_t len; StringList *p; if (nextp == NULL) { len = strlen (curp); } else { len = nextp - curp; } for (p = fieldDefForIndex (i)->enumValues; p != NULL; p = p->next) { if (p->name[len] == '\0' && strncasecmp (curp, p->name, len) == 0) { break; } } if (p == NULL) { return 0; } if (nextp == NULL) { return 1; } curp = nextp + 1; } } /* Check all the enumerated typed fields that are declared, and check to make sure they're all good values. Reset any null or invalid entries. */ BadFields checkEnumTypes (PR *pr, BadFields currBadFields, int isInitialPR) { int i; int pr_fields = get_num_fields (pr->database); BadFields badFields = currBadFields; for (i = 0; i < pr_fields; i++) { FieldIndex field = getNthField (pr->database, i); FieldType type = fieldDefForIndex (field)->datatype; if ((type == Enum || type == MultiEnum) && ! fieldDefForIndex (field)->allow_any_value) { if (! verify_enum (field, pr->private->value[i].data.string)) { if ((! isInitialPR) || (pr->private->value[i].data.string != NULL)) { badFields = newBadFieldEntry (field, pr->private->value[i].data.string, badFields); unsetField (pr, field); } if (fieldDefForIndex (field)->default_value != NULL) { pr->private->value[i].data.string = xstrdup (fieldDefForIndex (field)->default_value); pr->private->non_zero = 1; pr->private->value[i].data.buffer = NULL; } } } } return badFields; } /* Find the field number for STRING. It's assumed to have a PR_FIELD_TAG_END at string[len - 1] and begins with a PR_FIELD_TAG_START. */ static FieldIndex find_field_num (const char *string, size_t len, PR *pr) { FieldIndex i = InvalidFieldIndex; if (string == NULL || string[0] != PR_FIELD_TAG_START || string[len - 1] != PR_FIELD_TAG_END) { return InvalidFieldIndex; } string++; len--; if (len > 13 && (strncasecmp (string + len - 13, "-Changed-Why:", 13) == 0)) { len -= 12; pr->private->isReason = 1; } else { pr->private->isReason = 0; } i = find_field_index_with_len (pr->database, string, len - 1); return i; } const char * field_change_reason (PR *pr, FieldIndex field) { if (field == InvalidFieldIndex) { abort (); } if (pr->prune || pr->private->header == NULL || pr->private->value == NULL || pr->private->value[fieldNumber (field)].data.string == NULL) { return NULL; } else { return pr->private->value[fieldNumber (field)].reason.string; } } void setFieldChangeReason (PR *pr, FieldIndex field, const char *text) { if (field == InvalidFieldIndex) { abort (); } freePRDataString (&pr->private->value[fieldNumber (field)].reason); pr->private->value[fieldNumber (field)].reason.string = xstrdup (text); pr->private->value[fieldNumber (field)].reason.buffer = NULL; } /* Returns the value of field FIELD from PR. If the PR does not directly have a value, check the PR's associated index entry; if that's also empty, we return the field's default value. The policy about returning a default value is a bit broken--we should only do that if the PR's actually been read in from a file. */ const char * field_value (PR *pr, FieldIndex field) { char *result = NULL; if (field == InvalidFieldIndex) { abort (); } if (pr->private != NULL && pr->private->value != NULL) { result = pr->private->value[field->number].data.string; } if (result == NULL) { /* Houston, we have a problem. For dates, the value that's stored in the index is an integer, not the actual value of the field... \hbadness 10000. XXX ??? !!! FIXME */ result = indexValue (pr, field); if (result != NULL && fieldDefForIndex (field)->datatype == Date && strcmp (result, "0") == 0) { result = NULL; } } /* Doing this here doesn't *seem* right. */ if (result == NULL) { if (fieldDefForIndex (field)->default_value != NULL) { pr->private->value[fieldNumber (field)].data.string = xstrdup (fieldDefForIndex (field)->default_value); pr->private->value[fieldNumber (field)].data.buffer = NULL; result = pr->private->value[fieldNumber (field)].data.string; pr->private->non_zero = 1; } } return result; } int prFieldHasValue (PR *pr, FieldIndex field) { if (field == InvalidFieldIndex) { abort (); } return (pr->private != NULL && pr->private->value != NULL && pr->private->value[fieldNumber (field)].data.string != NULL); } /* Set the value of the PR field INDEX to STRING. Returns TRUE if the operation was successful, FALSE if not (e.g., if STRING was a bad value for an enumerated field). */ bool set_field (PR *pr, FieldIndex field, const char *string, ErrorDesc *err) { bool valid; if (field == InvalidFieldIndex) { abort (); } valid = validateFieldValue (field, string, err, 0); if (valid) { unsetField (pr, field); pr->private->value[fieldNumber (field)].data.string = (char *) xstrdup (string); pr->private->value[fieldNumber (field)].data.buffer = NULL; pr->private->non_zero = 1; } return valid; } void unsetField (PR *pr, FieldIndex field) { if (field == InvalidFieldIndex) { abort (); } freePRDataString (&pr->private->value[fieldNumber (field)].data); freePRDataString (&pr->private->value[fieldNumber (field)].reason); } void freeStringList (StringList *s) { StringList *n; while (s != NULL) { n = s->next; free (s->name); free (s); s = n; } } /* Look to see if STRING is a mail header we know about. */ static short lookup_header (const char *string, size_t len) { Header_Name i; for (i = (Header_Name) 0; i < NUM_HEADER_ITEMS; i++) if (headerNames[i] != NULL && (strncasecmp (headerNames[i], string, len) == 0)) { return i; } return InvalidHeaderName; } /* If there's more than one instance of a given header, keep the first one and ignore any future ones. There's one exception to this rule: the `Received:' header. We are likely to get many of them, so just drop them down into the "value" of the first received header. */ static void set_continued_header (PR *pr, Header_Name i, char *buf) { char *b; if (pr->private->header[i] != NULL) { if (keepReceivedHeaders (pr->database) && i == RECEIVED) { if (*buf == ' ') { asprintf (&b, "%s\nReceived:%s", pr->private->header[i], buf); } else { asprintf (&b, "%s\nReceived: %s", pr->private->header[i], buf); } free (pr->private->header[i]); free (buf); pr->private->header[i] = b; } } else { pr->private->header[i] = buf; } } int read_header (PR *pr, FILE *fp) { Header_Name currHeader = -1; bool processing = FALSE; bool headers_found = FALSE; char *buf = NULL; int c; #define PEEK(FP) (c = getc (FP), ungetc (c, FP)) while (PEEK (fp) != EOF) { if ((c == '\t' || c == ' ') && processing) { /* RFC-822 multi-line header. */ char *line = read_line (fp, NULL); append_string (&buf, line); free (line); line = NULL; } else { if (processing) { size_t buflen = strlen (buf); if (buflen > 0 && buf[buflen - 1] == '\n') { /* Strip that blasted newline off. */ buf [buflen - 1] = '\0'; } set_continued_header (pr, currHeader, buf); buf = NULL; processing = FALSE; } /* If there's a blank line or a PR field, get out quickly. We used to also jump out when we saw a `>', but some versions of Unix, including USL Unix, place a `>From:' in the header for remote mail. */ /* But not handling `>' at all is bad too! It rejects PRs that contain no mail headers and no newline. */ if (c == '\n') { while (c == '\n') { c = getc (fp); } ungetc (c, fp); break; } else { size_t lineLen = 0; char *line = read_line (fp, &lineLen); char *temp = line; size_t headerLen; const char delimiter = '>'; const char *header = getFieldHeader (&temp, &headerLen, lineLen); if (header != NULL) { currHeader = lookup_header (header, headerLen); if (currHeader != InvalidHeaderName) { headers_found = TRUE; processing = TRUE; buf = xstrdup (temp); } else { if (c == delimiter && strncasecmp (">From:", header, headerLen)) break; } } else { if (c == delimiter) break; currHeader = InvalidHeaderName; } free (line); line = NULL; } } } if (feof (fp)) { return -1; } /* If no headers found, then back up. XXX ??? !!! Very bad. What if we're on a stream we can't rewind? */ if (!headers_found) { rewind (fp); } return 0; } static void write_header_field (FILE *fp, PR *pr, Header_Name field, const char *eolTerminator) { fputs (headerNames[field], fp); if (pr->private->header[field][0] != '\0') { if (pr->private->header[field][0] != ' ') { fputc (' ', fp); } fputs (pr->private->header[field], fp); } fputs (eolTerminator, fp); } void write_entire_header (FILE *fp, PR *pr, const char *eolTerminator) { Header_Name i; for (i = (Header_Name) 0; i < NUM_HEADER_ITEMS; i++) { if (pr->private->header[i] != NULL) { write_header_field (fp, pr, i, eolTerminator); } } } const char * header_name (Header_Name name) { if (name >= (int) NUM_HEADER_ITEMS) return NULL; else return headerNames[name]; } Header_Name find_header_index (const char *name) { return lookup_header (name, strlen (name)); } const char * raw_header_value (PR *pr, Header_Name name) { if (name >= NUM_HEADER_ITEMS || name < 0) { return NULL; } return pr->private->header[name]; } const char * header_value (PR *pr, Header_Name name) { const char *s = raw_header_value (pr, name); if (s == NULL) { pr->private->header[name] = (char *) xstrdup (""); s = pr->private->header[name]; } return s; } void set_header (PR *pr, Header_Name name, const char *string) { if (name >= NUM_HEADER_ITEMS || string == NULL) return; if (pr->private->header[name] != NULL) { free (pr->private->header[name]); } pr->private->header[name] = (char *) xstrdup (string); } void free_pr_header (PR *pr) { int i; for (i = 0; i < NUM_HEADER_ITEMS; i++) { if (pr->private->header[i] != NULL) { free (pr->private->header[i]); pr->private->header[i] = NULL; } } } char * gen_pr_path (PR *pr) { char *buf; asprintf (&buf, "%s/%s/%s", databaseDir (pr->database), field_value (pr, CATEGORY (pr->database)), field_value (pr, NUMBER (pr->database))); return buf; } void free_pr_contents (PR *pr) { if (pr->private != NULL && pr->private->value != NULL) { int i; int pr_fields = get_num_fields (pr->database); if (pr->private->non_zero) { for (i = 0; i < pr_fields; i++) { if (pr->private->value[i].data.string != NULL) { freePRDataString (&pr->private->value[i].data); } if (pr->private->value[i].reason.string != NULL) { freePRDataString (&pr->private->value[i].reason); } } pr->private->non_zero = 0; } if (pr->private->buffer != NULL) { free (pr->private->buffer); pr->private->buffer = NULL; } } pr->read_in = 0; } /* Write a file out to FILENAME with PR in it. If FORCE is false, then make sure the file doesn't already exist. */ int createPrFile (PR *pr, const char *filename, int force, ErrorDesc *err) { FILE *output; /* Quick check - if file already exists, this is not a good sign. */ if (force == 0 && fileExists (filename)) { setError (err, CODE_FILE_ERROR, "File for PR %s already exists, filename is %s", field_value (pr, NUMBER (pr->database)), filename); return -1; } block_signals (); /* Now build the file. */ output = fopen (filename, "w+"); if (output == NULL) { setError (err, CODE_FILE_ERROR, "Error in createPrFile () creating file %s", filename); unblock_signals (); return -1; } write_entire_header (output, pr, "\n"); fputc ('\n', output); write_entire_pr (output, pr, "\n"); fclose (output); unblock_signals (); return 0; } void free_pr (PR *pr) { free_pr_header (pr); free_pr_contents (pr); freePRIndex (pr); free (pr->index); free (pr->private->header); free (pr->private->value); free (pr->private); free (pr); } static char * get_pr_path (const DatabaseInfo database, PR *pr, const char *prnum, ErrorDesc *err) { char *path = NULL; const char *category = NULL; char *categoryFromIndex = NULL; if (pr != NULL) { category = field_value (pr, CATEGORY (database)); } else { categoryFromIndex = getCategoryFromIndex (database, prnum, err); category = categoryFromIndex; } if (category != NULL) { asprintf (&path, "%s/%s/%s", databaseDir (database), category, prnum); if (categoryFromIndex != NULL) { free (categoryFromIndex); } } return path; } int prExists (const DatabaseInfo database, const char *prnum, ErrorDesc *err) { PR *pr = get_pr_from_index (database, prnum, err); char *path = get_pr_path (database, pr, prnum, err); int res = 0; if (path != NULL) { res = fileExists (path); free (path); if (res == 0) { setError (err, CODE_FILE_ERROR, "Can't open file `%s'", path); } } return res; } static bool pr_file_readable (const char *path, ErrorDesc *err) { FILE *fp; if (path == NULL) { return FALSE; } if ((fp = fopen (path, "r")) == NULL) { setError (err, CODE_FILE_ERROR, "Can't open file `%s'", path); return FALSE; } fclose (fp); return TRUE; } PR * readPRWithNum (const DatabaseInfo database, const char *prnum, int prune, ErrorDesc *err) { PR *pr = NULL; PR *index_pr = get_pr_from_index (database, prnum, err); char *path = get_pr_path (database, index_pr, prnum, err); if (path != NULL) { if (pr_file_readable (path, err)) { pr = allocPR (database); setPrevPR (pr, getPrevPR (index_pr)); setNextPR (pr, getNextPR (index_pr)); if (get_pr (pr, path, prune) == 0) { free_pr (pr); pr = NULL; } } free (path); } return pr; } int pr_delete (const DatabaseInfo database, const char *prnum, ErrorDesc *err) { PR *pr; char *path = NULL; pr = get_pr_from_index (database, prnum, err); path = get_pr_path (database, pr, prnum, err); if (path == NULL || !pr_file_readable (path, err)) { if (path != NULL) { free (path); } return -1; } if (removePRFromIndex (database, prnum, err)) { free (path); return -5; } if (unlink (path)) { setError (err, CODE_FILE_ERROR, "Unable to unlink file %s\n", path); free (path); return -6; } free (path); return 1; } void freeInputTemplate (InputTemplate *template) { while (template != NULL) { InputTemplate *n = template->next; free (template); template = n; } } void printValidValues (FILE *outfile, FieldIndex i, const char *eol) { switch (fieldDefForIndex (i)->datatype) { case Enum: case MultiEnum: { StringList *s = fieldDefForIndex (i)->enumValues; while (s != NULL) { write_multitext (outfile, s->name, eol); fputs (eol, outfile); s = s->next; } break; } case TextWithRegex: { StringList *s = fieldDefForIndex (i)->regex; while (s != NULL) { write_multitext (outfile, s->name, eol); fputs (eol, outfile); s = s->next; } break; } default: { write_multitext (outfile, ".*\n", eol); break; } } } gnats-4.1.0/gnats/pr.h0000644000175000017500000001176510207433626015305 0ustar chewiechewie00000000000000/* Pieces of the actual PR. Copyright (C) 1993 Free Software Foundation, Inc. Contributed by Tim Wicinski (wicinski@barn.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef _pr_h_ #define _pr_h_ struct PR_struct; typedef struct PR_struct PR; /* These better be in the same order as they appear in the headerNames declaration in pr.c. */ typedef enum { InvalidHeaderName = -1, SM_FROM = 0, /* Sendmail 'From', must come before 'From:' */ RETURN_PATH, RECEIVED, /* received, GNATS keeps only the first rcvd header */ MSG_ID, /* Message-Id */ DATE, FROM, /* the "From:" field, as opposed to unix 'From' */ SENDER, REPLY_TO, TO, APPAR_TO, /* Apparently-To */ CC, IN_REP_TO, /* In-Reply-To */ SUBJECT, REFERENCES, X_SEND_PR, X_GNATS_NOTIFY, X_GNATS_NONOTIFY, NUM_HEADER_ITEMS /* Last entry, don't put anything in after this. */ } Header_Name; #include #include "gnats.h" #include "field.h" #include "index.h" /* Describes one entire PR. */ struct PR_struct { /* The database this PR is associated with. */ DatabaseInfo database; /* Index entry for this PR. */ Index *index; /* Non-zero if the PR contents are pruned. */ int prune; /* Non-zero if the PR has been read in. */ int read_in; /* Private data used by pr.c. */ struct PR_private *private; }; /* This *might* be correct. */ #define PR_IS_FULL(PR) ((PR)->prune == 0 && (PR)->read_in != 0) extern void write_entire_pr (FILE *outfile, PR *pr, const char *eolTerminator); extern void write_entire_header (FILE *outputle, PR *pr, const char *eolTerminator); extern void write_pr_field (FILE *outfile, FieldIndex field, const char *fieldText, const char *eolTerminator); extern int get_num_fields (const DatabaseInfo database); extern int setBuiltinField (FieldIndex field, const char *builtinName); extern FieldIndex findBuiltinField (const DatabaseInfo database, const char *name); extern int fillInPR (PR *pr, ErrorDesc *err); extern void initReadPR (PR *pr); extern void addLineToPR (PR *pr, char *buffer, char *line, size_t linelen, int prune); extern void finishReadPR (PR *pr, int prune); extern void write_multitext (FILE *fp, const char *str, const char *eolTerminator); extern const char *header_name (Header_Name header); extern const char *header_value (PR *pr, Header_Name header); extern const char *raw_header_value (PR *PR, Header_Name header); extern void set_header (PR *pr, Header_Name header, const char *newValue); extern int read_header (PR *pr, FILE *infile); extern void write_header (PR *pr, FILE *outfile, Header_Name headerField); extern PR *allocPR (const DatabaseInfo database); extern void free_pr (PR *pr); extern void free_pr_header (PR *pr); extern void free_pr_contents (PR *pr); extern char *gen_pr_path (PR *pr); extern void read_pr (PR *pr, FILE *infile, int prune); extern int initDbInfo (ErrorDesc *err); extern void freeInputTemplate (InputTemplate *template); extern const char *field_value (PR *pr, FieldIndex field); extern int prFieldHasValue (PR *pr, FieldIndex field); extern const char *field_change_reason (PR *pr, FieldIndex field); extern int verifyMultiEnum (FieldIndex field, const char *value); extern int verify_enum (FieldIndex field, const char *value); extern bool set_field (PR *pr, FieldIndex field, const char *value, ErrorDesc *err); extern void setFieldChangeReason (PR *pr, FieldIndex field, const char *value); extern void unsetField (PR *pr, FieldIndex field); extern BadFields checkEnumTypes (PR *pr, BadFields currBadFields, int isInitialPR); extern int fconfigParse (DatabaseInfo database, const char *filename, int (*func)(char *, int), ErrorDesc *err); extern int createPrFile (PR *pr, const char *filename, int force, ErrorDesc *err); extern int pr_delete (const DatabaseInfo database, const char *prnum, ErrorDesc *err); extern int prExists (const DatabaseInfo database, const char *prID, ErrorDesc *err); extern void printValidValues (FILE *outfile, FieldIndex i, const char *eol); extern PR *readPRWithNum (const DatabaseInfo database, const char *prID, int prune, ErrorDesc *err); /* Given the name of a header NAME, return its Header_Name value, or InvalidHeaderName if NAME is not a valid header name. */ extern Header_Name find_header_index (const char *name); #endif /* _pr_h_ */ gnats-4.1.0/gnats/query-pr.c0000644000175000017500000005520407560340040016432 0ustar chewiechewie00000000000000/* Perform queries on the contents of a GNATS database. Copyright (C) 2001, 2002 Milan Zamazal Copyright (C) 1993, 94, 95, 96, 1997, 2000 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Further hacked by Milan Zamazal (pdm@zamazal.org). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "query.h" #include "mail.h" /* The name this program was run with. */ const char *program_name; #define PORT_OPTION 257 #define EXPR_OPTION 258 #define LISTFIELDNAMES_OPTION 259 #define FIELDTYPE_OPTION 260 #define VALIDVALUES_OPTION 261 #define FIELDDESC_OPTION 262 #define LISTINPUTFIELD_OPTION 263 #define LIST_DATABASES_OPTION 264 #define PRINT_DIRECTORY_OPTION 265 #define PRINTSHVARS_OPTION 266 #define ADMSUBFIELD_OPTION 267 #define ADMFIELD_OPTION 268 #define ADMKEYVALUE_OPTION 269 #define RESPONSIBLEADDRESS_OPTION 270 #define FIELDFLAGS_OPTION 271 #define PRINTSERVERADDR_OPTION 272 extern int debug; struct option long_options[] = { {"category", 1, NULL, 'c'}, {"synopsis", 1, NULL, 'y'}, {"confidential", 1, NULL, 'C'}, {"debug", 0, NULL, 'D'}, {"database", 1, NULL, 'd'}, {"format", 1, NULL, 'f'}, {"full", 0, NULL, 'F'}, {"help", 0, NULL, 'h'}, {"host", 1, NULL, 'H'}, {"port", 1, NULL, PORT_OPTION}, {"user", 1, NULL, 'v'}, {"passwd", 1, NULL, 'w'}, {"multitext", 1, NULL, 'm'}, {"originator", 1, NULL, 'O'}, {"release", 1, NULL, 'A'}, {"class", 1, NULL, 'L'}, {"cases", 1, NULL, 'E'}, {"quarter", 1, NULL, 'Q'}, {"keywords", 1, NULL, 'K'}, {"output", 1, NULL, 'o'}, {"priority", 1, NULL, 'p'}, {"responsible", 1, NULL, 'r'}, {"restricted", 0, NULL, 'R'}, {"severity", 1, NULL, 'e'}, {"skip-closed", 0, NULL, 'x'}, {"sql", 0, NULL, 'i'}, {"sql2", 0, NULL, 'I'}, {"state", 1, NULL, 's'}, {"summary", 0, NULL, 'q'}, {"submitter", 1, NULL, 'S'}, {"text", 1, NULL, 't'}, {"required-before", 1, NULL, 'u'}, {"required-after", 1, NULL, 'U'}, {"arrived-before", 1, NULL, 'b'}, {"arrived-after", 1, NULL, 'a'}, {"modified-before", 1, NULL, 'B'}, {"modified-after", 1, NULL, 'M'}, {"closed-before", 1, NULL, 'z'}, {"closed-after", 1, NULL, 'Z'}, {"list-categories", 0, NULL, 'j'}, {"list-responsible", 0, NULL, 'k'}, {"list-submitters", 0, NULL, 'l'}, {"list-states", 0, NULL, 'T'}, {"list-databases", 0, NULL, LIST_DATABASES_OPTION}, {"print-directory-for-database", 0, NULL, PRINT_DIRECTORY_OPTION}, {"version", 0, NULL, 'V'}, /* Expression-related options */ {"and", 0, NULL, '&'}, {"or", 0, NULL, '|'}, {"expr", 1, NULL, EXPR_OPTION}, /* New field info options */ {"list-fields", 0, NULL, LISTFIELDNAMES_OPTION }, {"list-input-fields", 0, NULL, LISTINPUTFIELD_OPTION }, {"field-type", 1, NULL, FIELDTYPE_OPTION }, {"field-description", 1, NULL, FIELDDESC_OPTION }, {"field-flags", 1, NULL, FIELDFLAGS_OPTION }, {"valid-values", 1, NULL, VALIDVALUES_OPTION }, {"adm-field", 1, NULL, ADMFIELD_OPTION }, {"adm-subfield", 1, NULL, ADMSUBFIELD_OPTION }, {"adm-key", 1, NULL, ADMKEYVALUE_OPTION }, {"responsible-address", 1, NULL, RESPONSIBLEADDRESS_OPTION }, /* New misc options */ {"print-sh-vars", 0, NULL, PRINTSHVARS_OPTION}, {"print-server-addr", 0, NULL, PRINTSERVERADDR_OPTION}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "query-pr" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]... [PR]...\n\ Query database.\n\ \n", "Options:\n\ [--output file | -o file]\n\ [--database database | -d database]\n\ [--responsible-address address]\n\ [--list-databases] [--list-fields] [--list-input-fields]\n\ [--field-type type] [--field-description description]\n\ [--field-flags field]\n\ [--adm-field field] [--adm-subfield subfield]\n\ [--adm-key key]\n", " [--valid-values values]\n\ [--format format | -f format] [--full | -F] [--summary | -q]\n\ [--and | -&] [--or | -|] [--expr expr]\n\ [--help | -h] [--version | -V] [--debug | -D]\n\ \n", "Non-network-mode options:\n\ [--print-sh-vars] [--print-directory-for-database]\n\ \n", "Network-mode-only options:\n\ [--host host | -H host] [--port port]\n\ [--user user | -v user] [--passwd passwd | -w passwd]\n\ [--print-server-addr]\n\ \n", "Deprecated options:\n\ [--list-categories | -j] [--list-states | -T]\n\ [--list-responsible | -k] [--list-submitters | -l]\n\ [--category category | -c category]\n\ [--synopsis synopsis | -y synopsis]\n", " [--confidential confidential | -C confidential]\n\ [--multitext multitext | -m multitext]\n\ [--originator originator | -O originator]\n\ [--release release | -A release]\n", " [--class class | -L class] [--cases cases | -E cases]\n\ [--quarter quarter | -Q quarter]\n\ [--keywords keywords | -K keywords]\n\ [--priority priority | -p priority]\n\ [--responsible responsible | -r responsible]\n\ [--restricted | -R] [--severity severity | -e severity]\n", " [--skip-closed | -x] [--sql | -i] [--sql2 | -I]\n\ [--state state | -s state]\n\ [--submitter submitter | -S submitter]\n\ [--text text | -t text]\n\ [--required-before date | -u date]\n", " [--required-after date | -U date]\n\ [--arrived-before date | -b date]\n\ [--arrived-after date | -a date]\n\ [--modified-before date | -B date]\n\ [--modified-after date | -M date]\n\ [--closed-before date | -z date]\n\ [--closed-after date | -Z date]\n\n", NULL}; /* Where the results of query-pr should go. */ static FILE *outfile = NULL; static int closeOutfile = 0; /* These are the old hard-coded query options. */ static struct query_opt { /* Which field to query. */ const char *fieldName; /* The set of options that specify the field. For date fields, there are two options, one for "before" and one for "after". */ const char *options; /* Which type of search to perform. */ SearchType searchType; } query_opts[] = { { "builtinfield:originator", "O", RegFind }, { "builtinfield:submitter-id", "S", RegCmp }, { "builtinfield:arrival-date", "ba", InvalidSearchType }, { "builtinfield:synopsis", "y", RegFind }, { "builtinfield:confidential", "C", RegCmp }, { "builtinfield:severity", "e", RegCmp }, { "builtinfield:priority", "p", RegCmp }, { "builtinfield:category", "c", RegCmp }, { "builtinfield:quarter", "Q", RegFind }, { "builtinfield:keywords", "K", RegFind }, { "builtinfield:date-required", "uU", InvalidSearchType }, { "builtinfield:cases", "E", RegCmp }, { "builtinfield:release", "A", RegFind }, { "builtinfield:last-modified", "BM", InvalidSearchType }, { "builtinfield:closed-date", "zZ", InvalidSearchType }, { "builtinfield:responsible", "r", RegCmp }, { "builtinfield:state", "s", RegCmp }, { "builtinfield:class", "L", RegFind }, { NULL, NULL, InvalidSearchType } }; static void queryPrExit (int code) { if (closeOutfile) { fclose (outfile); outfile = NULL; closeOutfile = 0; } client_exit (); exit (code); } /* Process OPTC as a possible old-style query option. If it's an old option, return a string representation of an expression that matches it; otherwise, return NULL. */ static char * oldQueryField (int optc, char *optarg) { int z; for (z = 0; query_opts[z].options != NULL; z++) { const char *opts = query_opts[z].options; if (strlen (opts) > 1) { int wopt; for (wopt = 0; wopt < 2; wopt++) { if (opts[wopt] == optc) { SearchType type = (wopt ? GreaterThan : LessThan); char *qarg = quote_string (optarg); char *res; asprintf (&res, "%s%s%s", query_opts[z].fieldName, getSearchOperatorForType (type), qarg); free (qarg); return res; } } } else { if (opts[0] == optc) { SearchType type = query_opts[z].searchType; char *qarg = quote_string (optarg); char *res; asprintf (&res, "%s%s%s", query_opts[z].fieldName, getSearchOperatorForType (type), qarg); free (qarg); return res; } } } return NULL; } static void addSearchEntry (char **buf, char boolop, const char *fieldName, const char *searchOp, const char *searchString, int lhs) { char *newsearch; char *qarg = NULL; if (searchString != NULL) { qarg = quote_string (searchString); } if (*buf != NULL && **buf != '\0') { if (lhs) { asprintf (&newsearch, "(%s%s%s)%c(%s)", fieldName, searchOp, (qarg != NULL) ? qarg : "", boolop, *buf); } else { asprintf (&newsearch, "(%s)%c(%s%s%s)", *buf, boolop, fieldName, searchOp, (qarg != NULL) ? qarg : ""); } } else { asprintf (&newsearch, "%s%s%s", fieldName, searchOp, (qarg != NULL) ? qarg : ""); } if (qarg != NULL) { free (qarg); } if (*buf != NULL) { free (*buf); } *buf = newsearch; } static void client_print_query (int which, PR *pr, QueryFormat *query_format) { if (pr != NULL) { if (which > 1) { printf ("\n"); } print_pr (outfile, pr, query_format, "\n"); } else { if (which > 0) { printf ("\n"); } } } /* XXX ??? !!! We call exit from too many places. */ int main (int argc, char **argv) { DatabaseInfo database = NULL; int optc; int errors = 0; int formats = 0, lists = 0; char *user = NULL; char *passwd = NULL; char *hostname = NULL; int port = -1; int is_network_client = 0; static const char *optstring = "a:A:b:B:c:C:Dd:e:f:K:L:m:M:n:o:O:p:PQ:s:S:r:t:u:U:v:w:y:z:Z:VFGiIxhqH:RjJklT|&"; /* If 1, don't allow redirection or viewing of confidential PRs. */ int restricted = 0; ListTypes whichList = 0; const char *query_format_name = "standard"; int skip_closed = 0; char *validValuesField = NULL; char *fieldTypeField = NULL; char *fieldDescriptionField = NULL; char *nameOfDatabase = NULL; int printDirectory = 0; int printShVars = 0; int printServerAddr = 0; char *admField = NULL; char *admSubfield = NULL; char *admKey = NULL; char *responsibleAddress = NULL; char *exprBuf = NULL; char danglingOp; char *fieldFlagsField = NULL; char *outfile_name = NULL; program_name = basename (argv[0]); outfile = stdout; danglingOp = '&'; if (argc == 1) usage (USAGE, 1); while ((optc = getopt_long (argc, argv, optstring, long_options, (int *) 0)) != EOF) { char *oldQuery = oldQueryField (optc, optarg); if (oldQuery != NULL) { addSearchEntry (&exprBuf, danglingOp, "", oldQuery, NULL, 0); danglingOp = '&'; free (oldQuery); continue; } switch (optc) { case EXPR_OPTION: addSearchEntry (&exprBuf, danglingOp, "", optarg, NULL, 0); danglingOp = '&'; break; case '&': case '|': { danglingOp = optc; break; } case 'd': nameOfDatabase = optarg; break; case 'f': query_format_name = optarg; formats++; break; case 'o': if (strcmp (optarg, "-") && !restricted) outfile_name = optarg; break; case 'R': restricted = 1; outfile = stdout; break; case 'D': debug = 1; break; case 'm': { addSearchEntry (&exprBuf, danglingOp, "fieldtype:MultiText", "~", optarg, 0); danglingOp = '&'; break; } case 't': { addSearchEntry (&exprBuf, danglingOp, "fieldtype:Text", "~", optarg, 0); danglingOp = '&'; break; } case 'V': version (PROGRAM_NAME); break; case 'F': query_format_name = "full"; formats++; break; case 'i': query_format_name = "sql"; formats++; break; case 'I': query_format_name = "sql2"; formats++; break; case 'q': query_format_name = "summary"; formats++; break; case 'x': skip_closed = 1; break; case 'j': whichList = ListCategories; lists++; break; case 'k': whichList = ListResponsible; lists++; break; case 'l': whichList = ListSubmitters; lists++; break; case 'T': whichList = ListStates; lists++; break; case 'H': hostname = optarg; is_network_client = 1; break; case PORT_OPTION: port = atoi (optarg); is_network_client = 1; break; case 'v': user = optarg; is_network_client = 1; break; case 'w': passwd = optarg; is_network_client = 1; break; case LISTFIELDNAMES_OPTION: whichList = ListFieldNames; lists++; break; case LISTINPUTFIELD_OPTION: whichList = ListInitialInputFields; lists++; break; case VALIDVALUES_OPTION: validValuesField = optarg; break; case FIELDTYPE_OPTION: fieldTypeField = optarg; break; case FIELDDESC_OPTION: fieldDescriptionField = optarg; break; case LIST_DATABASES_OPTION: whichList = ListDatabases; lists++; break; case PRINT_DIRECTORY_OPTION: printDirectory = 1; break; case PRINTSHVARS_OPTION: printShVars = 1; formats++; lists++; break; case PRINTSERVERADDR_OPTION: printServerAddr = 1; formats++; lists++; break; case ADMFIELD_OPTION: admField = optarg; formats++; lists++; break; case ADMSUBFIELD_OPTION: admSubfield = optarg; break; case ADMKEYVALUE_OPTION: admKey = optarg; break; case RESPONSIBLEADDRESS_OPTION: responsibleAddress = optarg; break; case FIELDFLAGS_OPTION: fieldFlagsField = optarg; break; case 'h': usage (USAGE, 0); break; default: usage (USAGE, 1); } } if (outfile_name != NULL) { outfile = fopen (optarg, "w+"); if (outfile == (FILE *) NULL) { fprintf (stderr, "%s: cannot open file %s for writing\n", program_name, optarg); queryPrExit (3); } closeOutfile = 1; } if (formats > 1) { fprintf (stderr, "%s: only one output format may be specified\n", program_name); queryPrExit (3); } if (lists > 1) { fprintf (stderr, "%s: only one list option may be specified\n", program_name); queryPrExit (4); } if (! is_network_client) { is_network_client = gnatsdbHasNetconn (nameOfDatabase); } if (printServerAddr) { if (! is_network_client) { fprintf (stderr, "%s: --print-server-addr only works with a network client\n", program_name); queryPrExit (1); } scanEnv (&user, &passwd, &hostname, &port, &nameOfDatabase); if (user == NULL || passwd == NULL || hostname == NULL || port < 0 || nameOfDatabase == NULL) { fprintf (stderr, "%s: Invalid remote database configuration\n", program_name); queryPrExit (1); } fprintf (outfile, "%s:%d:%s:%s:%s\n", hostname, port, nameOfDatabase, user, passwd); queryPrExit (0); } if (is_network_client) { ErrorDesc err; if (client_init_gnats (&err, user, passwd, hostname, port, nameOfDatabase) != 0) { client_print_errors (database, err); queryPrExit (1); } } else { ErrorDesc err; database = init_gnats (program_name, nameOfDatabase, &err); if (! databaseValid (database)) { client_print_errors (database, err); queryPrExit (1); } } if (responsibleAddress != NULL) { if (is_network_client) { fprintf (stderr, "%s: --responsible-address not supported in network mode\n", program_name); queryPrExit (1); } else { char *addr = get_responsible_addr (database, 0, 0, responsibleAddress); fprintf (outfile, "%s\n", addr); free (addr); } queryPrExit (0); } else if (admField != NULL || admKey != NULL || admSubfield != NULL) { if (admField == NULL || admKey == NULL) { fprintf (stderr, "%s: Need to specify both --adm-field and --adm-key\n", program_name); queryPrExit (1); } if (is_network_client) { clientGetAdmField (outfile, admField, admSubfield, admKey); queryPrExit (0); } else { ComplexFieldIndex ci = newComplexFieldIndex (database, admField); FieldIndex i = simpleFieldIndexValue (ci); AdmEntry *ent; if (i == InvalidFieldIndex) { fprintf (stderr, "Invalid field name %s\n", admField); queryPrExit (1); } ent = get_adm_record (i, admKey); if (ent == NULL) { fprintf (stderr, "%s: no entry matching %s in field %s\n", program_name, admKey, admField); queryPrExit (1); } else { printAdmSubfield (outfile, "\n", i, ent, admSubfield); free_adm_entry (ent); queryPrExit (0); } } } if (printShVars) { if (is_network_client) { fprintf (stderr, "--print-sh-vars is not supported in network mode\n"); queryPrExit (1); } fprintf (outfile, "GNATSDB=\"%s\"\n", databaseName (database)); fprintf (outfile, "GNATSDB_VALID=%d\n", databaseValid (database)); if (databaseValid (database)) { char *defaultCategoryName = defaultCategory (database); char *defaultStateName = defaultState (database); fprintf (outfile, "GNATSDBDIR=\"%s\"\n", databaseDir (database)); fprintf (outfile, "DEBUG_MODE=%d\n", debugMode (database)); fprintf (outfile, "DEFAULTCATEGORY=\"%s\"\n", defaultCategoryName); fprintf (outfile, "DEFAULTSTATE=\"%s\"\n", defaultStateName); free (defaultCategoryName); free (defaultStateName); } queryPrExit (0); } if (printDirectory) { if (is_network_client) { fprintf (stderr, "%s: --print-directory-for-database not supported in network mode\n", program_name); queryPrExit (1); } else if (databaseValid (database)) { fprintf (outfile, "%s\n", databaseDir (database)); queryPrExit (0); } else { fprintf (stderr, "%s: Invalid database name `%s'\n", program_name, nameOfDatabase); queryPrExit (1); } } if (fieldTypeField != NULL) { if (is_network_client) { netFieldType (fieldTypeField); } else { char *p; while (fieldTypeField != NULL) { FieldIndex i; p = strchr (fieldTypeField, ' '); if (p != NULL) { *(p++) = '\0'; } i = find_field_index (database, fieldTypeField); if (i != InvalidFieldIndex) { fprintf (outfile, "%s\n", fieldTypeAsString (i->datatype)); } else { fprintf (stderr, "%s: No such field as %s\n", program_name, fieldTypeField); queryPrExit (1); } fieldTypeField = p; } } queryPrExit (0); } if (fieldFlagsField != NULL) { if (is_network_client) { netFieldFlags (fieldFlagsField); } else { char *p; while (fieldFlagsField != NULL) { FieldIndex i; p = strchr (fieldFlagsField, ' '); if (p != NULL) { *(p++) = '\0'; } i = find_field_index (database, fieldFlagsField); if (i != InvalidFieldIndex) { char *flags = getFieldFlags (i); fprintf (outfile, "%s\n", flags); free (flags); } else { fprintf (stderr, "%s: No such field as %s\n", program_name, fieldFlagsField); queryPrExit (1); } fieldFlagsField = p; } } queryPrExit (0); } if (validValuesField != NULL) { if (is_network_client) { netValidValues (validValuesField); } else { FieldIndex i = find_field_index (database, validValuesField); if (i == InvalidFieldIndex) { fprintf (stderr, "%s: No such field as %s\n", program_name, validValuesField); queryPrExit (1); } printValidValues (outfile, i, "\n"); } queryPrExit (0); } if (fieldDescriptionField != NULL) { if (is_network_client) { netFieldDescription (fieldDescriptionField); } else { FieldIndex i = find_field_index (database, fieldDescriptionField); if (i == InvalidFieldIndex) { fprintf (stderr, "%s: No such field as %s\n", program_name, fieldDescriptionField); queryPrExit (1); } if (fieldDefForIndex (i)->description != NULL) { fprintf (outfile, "%s\n", fieldDefForIndex (i)->description); } else { fprintf (outfile, "\n"); } } queryPrExit (0); } if (skip_closed) { addSearchEntry (&exprBuf, '&', "(! builtinfield:State[type] = \"closed\")", "", NULL, 0); } if (restricted) { addSearchEntry (&exprBuf, '&', "builtinfield:Confidential", "^", "no", 1); } if (is_network_client) { if (lists > 0) { sendRemoteListQuery (whichList, outfile); } else { sendRemoteQuery (exprBuf, ((const char **)argv) + optind, query_format_name, outfile); } if (exprBuf != NULL) { free (exprBuf); } queryPrExit (0); } else { QueryFormat *query_format; QueryExpr expr = NULL; if (lists) { getGnatsFile (database, whichList, NULL, "\n"); queryPrExit (0); } if (exprBuf != NULL && exprBuf[0] != '\0') { expr = parseQueryExpression (database, exprBuf, exprBuf + strlen (exprBuf) - 1); if (expr == NULL) { fprintf (stderr, "query-pr: Cannot parse `%s'\n", exprBuf); free (exprBuf); exprBuf = NULL; queryPrExit (1); } } else { const char *emptyExpr = ""; expr = parseQueryExpression (database, emptyExpr, emptyExpr); } { ErrorDesc err; query_format = findQueryFormat (database, query_format_name, &err); if (query_format == NULL) { client_print_errors (database, err); queryPrExit (1); } } { ErrorDesc err; int res = iterate_prs (database, argc - optind, argv + optind, expr, query_format, client_print_query, &err); if (res < 0) { client_print_errors (database, err); } else if (res == 0) { /* ??? */ errors = 1; } } if (errors > 0) { fprintf (stderr, "%s: no PRs matched\n", program_name); } if (exprBuf != NULL) { free (exprBuf); exprBuf = NULL; } if (expr != NULL) { freeQueryExpr (expr); expr = NULL; } query_format = NULL; /* exit non-zero if there were any troubles. */ queryPrExit (errors != 0); } /* NOTREACHED */ return 0; } gnats-4.1.0/gnats/query.c0000644000175000017500000011717307570426211016025 0ustar chewiechewie00000000000000/* Query handling code. Copyright (C) 1994, 95, 96, 1997, 1999, 2000 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). Massively revised by Bob Manson (manson@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "gnats.h" #include "query.h" #include "pcodes.h" /* One item to search for. */ typedef struct query_item { ComplexFieldIndex fieldIndex; struct re_pattern_buffer *compRegexp; } *QueryItem; static QueryItem freeQueryItemEnt = NULL; static QueryItem newQueryItem (ComplexFieldIndex index) { QueryItem res; if (freeQueryItemEnt != NULL) { res = freeQueryItemEnt; freeQueryItemEnt = NULL; } else { res = (QueryItem) xmalloc (sizeof (struct query_item)); } res->fieldIndex = index; if (isConstantFieldValue (res->fieldIndex)) { res->compRegexp = (struct re_pattern_buffer *) xmalloc (sizeof (struct re_pattern_buffer)); memset (res->compRegexp, 0, sizeof (struct re_pattern_buffer)); } else { res->compRegexp = NULL; } return res; } static void freeQueryItem (QueryItem i) { if (i != NULL) { freeComplexFieldIndex (i->fieldIndex); if (i->compRegexp != NULL) { /* XXX ??? !!! Hack 'cause the translate buffer is a static array */ i->compRegexp->translate = NULL; regfree (i->compRegexp); free (i->compRegexp); } if (freeQueryItemEnt == NULL) { freeQueryItemEnt = i; } else { free (i); } } } typedef struct search_item { /* The type of search to perform, of course. */ SearchType searchType; /* The items on the left and right-hand-sides. */ QueryItem lhs; QueryItem rhs; } SearchItem; typedef struct queryTree { /* The operation to perform on this node. */ QueryOp op; /* The left and right sides of the expression; if this is a unary op, the left side contains the expression. */ struct queryTree *left, *right; /* If this is a QueryMatch expression, the actual query to perform. */ SearchItem ent; } *QueryTree; struct queryExpr { /* Database that this query is associated with. */ DatabaseInfo database; /* The actual query tree. */ QueryTree tree; }; struct SearchTypes { const char *name; const char *operator; SearchType searchType; } searchTypes[] = { /* Order here does matter--we need to have == before =. (Bleah, yeah). */ { "LessThan", "<", LessThan }, { "GreaterThan", ">", GreaterThan }, { "Equals", "==", Equals }, { "NotEquals", "!=", NotEquals }, { "RegCmp", "=", RegCmp }, { "RegFind", "~", RegFind }, { "DefaultSearchType", "^", DefaultSearchType }, { NULL, NULL, InvalidSearchType } }; /* Adds query format Q to the list of query formats. */ void addQueryFormat (DatabaseInfo database, QueryFormat *q) { QueryFormat *list = getQueryFormatList (database); q->next = list; setQueryFormatList (database, q); } static QueryFormat * parseQueryFormat (const DatabaseInfo database, const char *expr, ErrorDesc *err) { const char *sstart; char *fstring = NULL; QueryFormat *res; FieldList currEnt = NULL; while (expr[0] != '\0' && isspace ((int)(unsigned char) expr[0])) { expr++; } if (expr[0] == '\0') { return NULL; } if (expr[0] == '"') { expr++; sstart = expr; while (expr[0] != '\0' && expr[0] != '\"') { if (expr[0] == '\\' && expr[1] != '\0') { expr++; } expr++; } fstring = xmalloc (expr - sstart + 1); memcpy (fstring, sstart, expr - sstart); fstring[expr - sstart] = '\0'; if (expr[0] == '"') { expr++; } } res = (QueryFormat *) xmalloc (sizeof (QueryFormat)); res->name = NULL; res->printf = fstring; res->separator = xstrdup ("\n"); res->fields = NULL; while (expr[0] != '\0') { const char *nstart = expr; FieldList newEnt; if (isspace ((int)(unsigned char) expr[0])) { expr++; continue; } while ((! isspace ((int)(unsigned char) expr[0])) && expr[0] != '\0') { expr++; } fstring = xmalloc (expr - nstart + 1); memcpy (fstring, nstart, expr - nstart); fstring[expr - nstart] = '\0'; newEnt = newFieldListEnt (database, fstring, NULL); if (currEnt == NULL) { res->fields = newEnt; } else { currEnt->next = newEnt; } currEnt = newEnt; if (parseComplexFieldIndex (currEnt->ent) != 0) { setError (err, CODE_INVALID_FIELD_NAME, "Invalid field name or query format %s", fstring); freeQueryFormat (res); res = NULL; break; } } return res; } /* Find the first query format with name NAME; returns the query format, or NULL if one was not found. */ QueryFormat * findQueryFormat (const DatabaseInfo database, const char *name, ErrorDesc *err) { QueryFormat *q = getQueryFormatList (database); while (q != NULL) { if (strcmp (q->name, name) == 0) { return q; } q = q->next; } /* It might be a format expression. */ return parseQueryFormat (database, name, err); } /* Return a non-zero value if P is composed entirely of digits. */ static int numeric (const char *p) { while (*p != '\0') { if (!isdigit ((int) *p)) return 0; p++; } return 1; } /* Convert STRING into a time_t. It may either be a Unix time value (seconds since Jan 1, 1970) or one of the other standard date formats accepted by GNATS. */ time_t get_any_date (const char *string) { if (string == NULL) { return -1; } else if (numeric (string)) { return atoi (string); } else { return get_date ((char *) string, NULL); } } /* Return the numeric equivalent of this state; 0 if not available. */ int enum_numeric (const char *text, FieldIndex field) { if ((text != NULL) && (text[0] != '\0')) { StringList *values; int count = 1; for (values = fieldDefForIndex (field)->enumValues; values != NULL; values = values->next) { if (strcasecmp (values->name, text) == 0) { return count; } count++; } } return 0; } static char * sql_time (const char *s) { time_t t; struct tm *ar_time; /* Note: we deliberately use 21 here, since that is what the width of this time string will end up looking like. In the case where we use things relative to timezone and such, it'd grow---but not here. */ char *buf = (char *) xmalloc (21); t = get_any_date (s); ar_time = (struct tm *) localtime (&t); strftime (buf, 21, "%Y-%m-%d %H:%M:%S", ar_time); return buf; } static char case_fold[256]; /* Return 0 if VALUE matched the regexp in PAT, 1 otherwise. */ int gnats_regcmp (const char *pat, const char *value, struct re_pattern_buffer *barg) { struct re_pattern_buffer buf; struct re_pattern_buffer *bufPtr; union { const char *c; int i; } r; if (barg == NULL) { bufPtr = &buf; memset ((void *) &buf, 0, sizeof (buf)); } else { bufPtr = barg; } if (case_fold[1] == 0) { int i; for (i = 0; i < 256; i++) { case_fold[i] = tolower (i); } } if (bufPtr->translate == NULL) { bufPtr->translate = case_fold; bufPtr->fastmap = xmalloc (256); #ifdef USE_RX bufPtr->syntax_parens = (char *)1; #endif r.c = re_compile_pattern (pat, strlen (pat), bufPtr); if (r.c) { fprintf (stderr, "%s: re_compile_pattern: %s\n", program_name, r.c); /* XXX ??? !!! Wow. This makes real sense. :-( */ exit (2); } } r.i = strlen (value); r.i = re_match (bufPtr, value, strlen (value), 0, 0); if (barg == NULL) { buf.translate = NULL; regfree (&buf); } switch (r.i) { case -2: fprintf (stderr, "%s: warning: re_match died with pattern %s and string %s\n", program_name, pat, value); /*FALLTHRU*/ case -1: return 1; default: return 0; } } /* Return 0 if any portion of VALUE matches the regexp in PAT, 1 otherwise. */ int regfind (const char *pat, const char *value, struct re_pattern_buffer *barg) { struct re_pattern_buffer buf; struct re_pattern_buffer *bufPtr; union { const char *c; int i; } r; if (barg == NULL) { bufPtr = &buf; memset ((void *) &buf, 0, sizeof (buf)); } else { bufPtr = barg; } if (case_fold[1] == 0) { int i; for (i = 0; i < 256; i++) { case_fold[i] = tolower (i); } } if (bufPtr->translate == NULL) { bufPtr->translate = case_fold; bufPtr->fastmap = xmalloc (256); #ifdef USE_RX bufPtr->syntax_parens = (char *)1; #endif r.c = re_compile_pattern (pat, strlen (pat), bufPtr); if (r.c) { fprintf (stderr, "%s: re_compile_pattern: %s\n", program_name, r.c); /* XXX ??? !!! Wow. This makes real sense. :-( */ exit (2); } } r.i = strlen (value); r.i = re_search (bufPtr, value, r.i, 0, r.i, 0); if (barg == NULL) { buf.translate = NULL; regfree (&buf); } switch (r.i) { case -2: fprintf (stderr, "%s: warning: re_search died with pattern %s and string %s\n", program_name, pat, value); /*FALLTHRU*/ case -1: return 1; default: return 0; } } static int intFieldCompare (QueryItem *fields, const char *lhs, const char *rhs) { FieldType fieldType; FieldIndex fieldIndex = simpleFieldIndexValue (fields[0]->fieldIndex); if (fieldIndex != InvalidFieldIndex) { fieldType = fieldDefForIndex (fieldIndex)->datatype; } else { fieldType = Text; } switch (fieldType) { case Date: { time_t lv = (lhs[0] == '\0' ? 0 : get_any_date (lhs)); time_t rv = (rhs[0] == '\0' ? 0 : get_any_date (rhs)); if (lv == -1 || rv == -1) { return strcmp (lhs, rhs); } else if (lv < rv) { return -1; } else if (lv == rv) { return 0; } else { return 1; } } break; case Integer: { int lv = atoi (lhs); int rv = atoi (rhs); if (lv < rv) { return -1; } else if (lv == rv) { return 0; } else { return 1; } } break; case Enum: { int lv = enum_numeric (lhs, fieldIndex); int rv = enum_numeric (rhs, fieldIndex); if (lv == 0 || rv == 0) { return strcmp (lhs, rhs); } if (lv < rv) { return -1; } else if (lv == rv) { return 0; } else { return 1; } } break; default: { return strcmp (lhs, rhs); } break; } } static int fieldCompare (PR *pr, PR *oldPR, QueryItem *fields, SearchType searchType, FormatNamedParameter *params) { struct localFieldInfo { const char *value; FieldIndex index; int mustBeFreed; } vals[2]; int i; int res = 0; int x; for (i = 0; i < 2; i++) { /* Not sure what to do with this mess. XXX ??? !!! FIXME */ if (parseComplexFieldIndex (fields[i]->fieldIndex) != 0) { return 0; } } for (i = 0; i < 2; i++) { if (complexFieldType (fields[i]->fieldIndex) != InvalidFieldType) { int num_fields = get_num_fields (pr->database); FieldType fieldType = complexFieldType (fields[i]->fieldIndex); for (x = 0; x < num_fields; x++) { FieldIndex field = getNthField (pr->database, x); if ((fieldType == Text && fieldDefForIndex (field)->textsearch) || (fieldType != Text && fieldDefForIndex (field)->datatype == fieldType)) { ComplexFieldIndex ent = simpleComplexFieldIndex (field); QueryItem newFields[2]; int res; newFields[i] = newQueryItem (ent); newFields[1 - i] = fields [1 - i]; res = fieldCompare (pr, oldPR, newFields, searchType, params); freeQueryItem (newFields[i]); if (res) { return 1; } } } return 0; } } for (x = 0; x < 2; x++) { vals[x].index = simpleFieldIndexValue (fields[x]->fieldIndex); } if (searchType == DefaultSearchType) { if (vals[0].index != InvalidFieldIndex) { searchType = fieldDefForIndex (vals[0].index)->defaultSearchType; } else { searchType = RegCmp; } } if ((! PR_IS_FULL (pr)) && (! isIndexedField (fields[0]->fieldIndex))) { ErrorDesc err; if (fillInPR (pr, &err) != 0) { return 0; } } for (x = 0; x < 2; x++) { vals[x].value = get_field_value (pr, oldPR, fields[x]->fieldIndex, params, &(vals[x].mustBeFreed)); } if (vals[0].value == NULL || vals[1].value == NULL) { for (x = 0; x < 2; x++) { if (vals[x].mustBeFreed && vals[x].value != NULL) { free ((char *)vals[x].value); } } return 0; } switch (searchType) { case DefaultSearchType: /* Shouldn't get here */ abort (); break; case RegCmp: res = (gnats_regcmp (vals[1].value, vals[0].value, fields[1]->compRegexp) == 0); break; case RegFind: res = (regfind (vals[1].value, vals[0].value, fields[1]->compRegexp) == 0); break; case LessThan: res = (intFieldCompare (fields, vals[0].value, vals[1].value) < 0); break; case GreaterThan: res = (intFieldCompare (fields, vals[0].value, vals[1].value) > 0); break; case Equals: res = (intFieldCompare (fields, vals[0].value, vals[1].value) == 0); break; case NotEquals: res = (intFieldCompare (fields, vals[0].value, vals[1].value) != 0); break; case StringMatch: res = (strcmp (vals[0].value, vals[1].value) == 0); break; case NilSearch: /* ??? XXX !!! Hmmmm. Return 1? */ res = 0; break; case InvalidSearchType: abort (); break; } for (x = 0; x < 2; x++) { if (vals[x].mustBeFreed) { free ((char *) vals[x].value); } } return res; } static int pr_match_field (PR *pr, PR *oldPR, SearchItem *item, FormatNamedParameter *params) { QueryItem fields[2]; if (pr == NULL) { return 0; } fields[0] = item->lhs; fields[1] = item->rhs; return fieldCompare (pr, oldPR, fields, item->searchType, params); } /* Returns a non-zero value if the PR referenced by I matches the expression tree in QEXP. */ static int pr_matches_tree (PR *pr, PR *oldPR, QueryTree qexp, FormatNamedParameter *params) { if (qexp == NULL) { return 1; } switch (qexp->op) { case QueryMatch: return pr_match_field (pr, oldPR, &qexp->ent, params); break; case QueryNot: return ! pr_matches_tree (pr, oldPR, qexp->left, params); break; case QueryAnd: return pr_matches_tree (pr, oldPR, qexp->left, params) && pr_matches_tree (pr, oldPR, qexp->right, params); break; case QueryOr: return pr_matches_tree (pr, oldPR, qexp->left, params) || pr_matches_tree (pr, oldPR, qexp->right, params); break; default: abort (); } return 0; } int pr_matches_expr (PR *pr, PR *oldPR, QueryExpr qexp, FormatNamedParameter *params) { QueryTree tree = NULL; if (qexp != NULL) { tree = qexp->tree; } return pr_matches_tree (pr, oldPR, tree, params); } void append_string (char **res, const char *string) { if (*res != NULL) { size_t oldlen = strlen (*res); size_t newlen = strlen (string); *res = xrealloc (*res, oldlen + newlen + 1); memcpy (*res + oldlen, string, newlen + 1); } else { *res = xstrdup (string); } } /* mmmm, cheezy. */ static void append_char (char **res, char chr) { char buf[2]; buf[0] = chr; buf[1] = '\0'; append_string (res, buf); } /* Prints the string CONTENTS using the printf format FORMAT to either FP (if it is non-NULL), or appended to RES via append_string (). */ static void do_print (FILE *fp, char **res, const char *format, const char *contents) { size_t flen = strlen (format); if (format[flen - 1] == 'd') { int val = atoi (contents); if (fp != NULL) { fprintf (fp, format, val); } else { char *new; asprintf (&new, format, val); append_string (res, new); free (new); } } else { if (fp != NULL) { fprintf (fp, format, contents); } else { char *new; asprintf (&new, format, contents); append_string (res, new); free (new); } } } static void writeFullPR (FILE *fp, PR *pr, int rawQuery, const char *eolTerminator) { int i; int num_fields = get_num_fields (pr->database); for (i = 0; i < num_fields; i++) { int mustBeFreed = 0; const char *contents; FieldIndex field = getNthField (pr->database, i); if (! rawQuery) { ComplexFieldIndex fieldIndex = simpleComplexFieldIndex (field); contents = get_field_value (pr, NULL, fieldIndex, NULL, &mustBeFreed); freeComplexFieldIndex (fieldIndex); } else { contents = field_value (pr, field); } write_pr_field (fp, field, contents, eolTerminator); if (mustBeFreed) { free ((char *) contents); } } } static void format_pr_field (FILE *fp, char **res, PR *pr, PR *oldPR, FieldList *fieldPtr, const char *format, const char *eolTerminator, FormatNamedParameter *parameters, int rawQuery) { int flen = strlen (format); char *fdup = xstrdup (format); const char *p; ComplexFieldIndex field = (*fieldPtr)->ent; switch (format[flen - 1]) { case 's': { int mustBeFreed = 0; const char *contents = get_field_value (pr, oldPR, field, parameters, &mustBeFreed); if (contents == NULL) { contents = ""; } do_print (fp, res, fdup, contents); if (mustBeFreed) { free ((char *) contents); } *fieldPtr = (*fieldPtr)->next; } break; case 'S': { int mustBeFreed = 0; const char *contents = get_field_value (pr, oldPR, field, parameters, &mustBeFreed); char *temp; if (contents == NULL) { contents = ""; } for (p = contents; *p && *p != ' '; p++) { /* Empty */ } fdup[flen - 1] = 's'; if (*p == ' ') { temp = xmalloc (p - contents + 1); memcpy (temp, contents, p - contents); temp[p - contents] = '\0'; fprintf (fp, fdup, temp); free (temp); } else { fprintf (fp, fdup, contents); } if (mustBeFreed) { free ((char *) contents); } *fieldPtr = (*fieldPtr)->next; } break; case 'F': { int mustBeFreed = 0; const char *contents = get_field_value (pr, oldPR, field, parameters, &mustBeFreed); write_pr_field (fp, simpleFieldIndexValue (field), contents, eolTerminator); if (mustBeFreed) { free ((char *) contents); } *fieldPtr = (*fieldPtr)->next; break; } case 'd': { char buffer[21]; int mustBeFreed = 0; const char *contents = get_field_value (pr, oldPR, field, parameters, &mustBeFreed); FieldIndex fieldIndex = simpleFieldIndexValue (field); if (contents == NULL) { contents = ""; } switch (fieldDefForIndex (fieldIndex)->datatype) { case Enum: sprintf (buffer, "%d", enum_numeric (contents, fieldIndex)); do_print (fp, res, format, buffer); break; case Date: sprintf (buffer, "%d", (int) get_any_date (contents)); do_print (fp, res, format, buffer); break; case Integer: sprintf (buffer, "%d", atoi (contents)); do_print (fp, res, format, buffer); break; default: do_print (fp, res, format, "0"); break; } if (mustBeFreed) { free ((char *) contents); } *fieldPtr = (*fieldPtr)->next; } break; case 'D': { FieldIndex fieldIndex = simpleFieldIndexValue (field); if (fieldIndex != InvalidFieldIndex && fieldDefForIndex (fieldIndex)->datatype == Date) { int mustBeFreed = 0; const char *strftimeFormat = "%a %b %d %H:%M:%S %z %Y"; char *fend = NULL; const char *contents = get_field_value (pr, oldPR, field, parameters, &mustBeFreed); char *t = NULL; time_t time; if (contents == NULL) { contents = ""; } time = get_any_date (contents); if (fdup[1] == '{') { fend = strchr (fdup + 2, '}'); if (fend != NULL) { strftimeFormat = fdup + 2; *fend = '\0'; } } if (time == 0 || time == -1) { /* Silly, but I'm lazy. */ t = xstrdup (""); } else { size_t resLen; size_t tlen = 0; /* It isn't clear what strftime returns if there is a format error. So we're paranoid and limit the amount of data it can allocate. */ do { tlen += 512; t = xrealloc (t, tlen); t[0] = '\0'; resLen = gnats_strftime (t, tlen, strftimeFormat, localtime (&time)); } while (resLen == 0 && tlen < 4096); } fdup[flen - 1] = 's'; if (fend != NULL) { *fend = '%'; } do_print (fp, res, fend != NULL ? fend : fdup, t); free (t); if (mustBeFreed) { free ((char *) contents); } } *fieldPtr = (*fieldPtr)->next; } break; case 'Q': { FieldIndex fieldIndex = simpleFieldIndexValue (field); if (fieldIndex != InvalidFieldIndex && fieldDefForIndex (fieldIndex)->datatype == Date) { int mustBeFreed = 0; const char *contents = get_field_value (pr, oldPR, field, parameters, &mustBeFreed); long i; if (contents == NULL) { contents = ""; } i = get_any_date (contents); fdup[flen - 1] = 's'; if (i != 0 && i != -1) { char *qd = sql_time (contents); do_print (fp, res, fdup, qd); free (qd); } else { do_print (fp, res, fdup, ""); } if (mustBeFreed) { free ((char *) contents); } } *fieldPtr = (*fieldPtr)->next; } break; case 'P': { writeFullPR (fp, pr, rawQuery, eolTerminator); break; } } free (fdup); } static int process_printf_format (FILE *fp, char **res, PR *pr, PR *oldPR, const char *format, FieldList fields, const char *eolTerminator, FormatNamedParameter *parameters, int rawQuery) { static char fcopy[1024]; while (*format != '\0') { if (format[0] == '\\' && format[1] == 't') { if (fp != NULL) { fputc ('\t', fp); } else { append_char (res, '\t'); } format++; } else if (format[0] == '\\' && format[1] == 'n') { if (fp != NULL) { fputs (eolTerminator, fp); } else { append_string (res, eolTerminator); } format++; } else if (format[0] == '%') { char *fptr = fcopy + 1; fcopy[0] = *(format++); if (*format == '{') { while (*format != '}' && (fptr - fcopy) < 1022) { *(fptr++) = *format; format++; } if (*format == '}') { *(fptr++) = *format; format++; } } while ((isdigit ((int) *format) || *format == '-' || *format == '+' || *format == '.') && ((fptr - fcopy) < 1022)) { *(fptr++) = *format; format++; } *(fptr++) = *format; *fptr = '\0'; if (*format == '%') { fputs (format, fp); } else { if (fields == NULL) { return 0; } format_pr_field (fp, res, pr, oldPR, &fields, fcopy, eolTerminator, parameters, rawQuery); } } else { if (fp != NULL) { fputc (*format, fp); } else { append_char (res, *format); } } format++; } return 1; } int process_format (FILE *fp, char **res, PR *pr, PR *oldPR, QueryFormat *fmt, const char *eolTerminator, FormatNamedParameter *parameters) { int do_open_pr = 0; if (pr != NULL) { if (! PR_IS_FULL (pr)) { FieldList p = fmt->fields; if (p == NULL) { do_open_pr = 1; } else { while (p != NULL) { if (! isIndexedField (p->ent)) { do_open_pr = 1; break; } p = p->next; } } } if (do_open_pr) { ErrorDesc err; if (fillInPR (pr, &err)) { return 0; } } } if (fmt->printf != NULL) { return process_printf_format (fp, res, pr, oldPR, fmt->printf, fmt->fields, eolTerminator, parameters, fmt->rawQuery); } else if (pr != NULL) { if (fmt->fields == NULL) { write_entire_header (fp, pr, eolTerminator); fprintf (fp, eolTerminator); writeFullPR (fp, pr, fmt->rawQuery, eolTerminator); } else { FieldList flist = fmt->fields; while (flist != NULL) { if (fmt->separator == NULL) { const char *contents; int mustBeFreed = 0; FieldIndex fieldIndex = simpleFieldIndexValue (flist->ent); if (fmt->rawQuery) { contents = field_value (pr, fieldIndex); } else { contents = get_field_value (pr, oldPR, flist->ent, parameters, &mustBeFreed); } write_pr_field (fp, fieldIndex, contents, eolTerminator); if (mustBeFreed) { free ((char *) contents); } flist = flist->next; } else { format_pr_field (fp, res, pr, oldPR, &flist, "%s", eolTerminator, parameters, fmt->rawQuery); } } } return 1; } else { return 0; } } int print_named_format_pr (FILE *fp, PR *pr, const char *fmtName, const char *eolTerminator, ErrorDesc *err) { QueryFormat *fmt = findQueryFormat (pr->database, fmtName, err); if (fmt == NULL) { return 0; } else { return process_format (fp, NULL, pr, NULL, fmt, eolTerminator, NULL); } } int print_pr (FILE *dest, PR *pr, QueryFormat *query_format, const char *eolTerminator) { return process_format (dest, NULL, pr, NULL, query_format, eolTerminator, NULL); } /* Iterate through a set of PRs. For those PRs that match the expression in EXP, invoke FUNC with the count of PRs that have matched so far, the PR* entry for the PR, and the supplied QUERY_FORMAT. FUNC is invoked once more after all of the queries have been searched. The PR* pointer is NULL, and the count corresponds to the total # of PRs that matched. If AC is 0 or AV is NULL, we iterate through all of the PRs in the index for the current database. Otherwise, only those PRs that match the PRIDs in AV[0], AV[1]. AV[2]...AV[AC-1] are tested. */ int iterate_prs (const DatabaseInfo database, int ac, char **av, QueryExpr exp, QueryFormat *query_format, QueryFunc func, ErrorDesc *err) { int found = 0; QueryTree tree = NULL; if (exp != NULL) { if (exp->database != database) { abort (); } tree = exp->tree; } *err = NULL; if (ac == 0 || av == NULL) { PR *pr = getFirstPR (database, err); if (*err != NULL) { return -1; } /* We weren't given a list of PRs to check, so we do the whole shooting match. */ while (pr != NULL) { if (pr_matches_tree (pr, NULL, tree, NULL)) { found++; func (found, pr, query_format); } free_pr_header (pr); free_pr_contents (pr); pr = getNextPR (pr); } } else { int cpr; for (cpr = 0; cpr < ac; cpr++) { char *pat, *n; char *p = av[cpr]; int plen; PR *pr; struct re_pattern_buffer buf; memset (&buf, 0, sizeof (buf)); /* Remove the category */ if ((n = (char *) strrchr (p, '/')) != NULL) { p = n + 1; } plen = strlen (p); pat = (char *) xmalloc (plen + 3); strcpy (pat, p); strcpy (pat + plen, "\\'"); *err = NULL; pr = getFirstPR (database, err); if (*err != NULL) { return -1; } while (pr != NULL) { if (gnats_regcmp (pat, field_value (pr, NUMBER (pr->database)), &buf) == 0) { if (pr_matches_expr (pr, NULL, exp, NULL)) { found++; func (found, pr, query_format); } /* Only one PR will match this PR number, because it's not really a regexp */ break; } free_pr_header (pr); free_pr_contents (pr); pr = getNextPR (pr); } buf.translate = NULL; regfree (&buf); free (pat); } } func (found, NULL, 0); return found; } static QueryTree newQueryTree (void) { QueryTree ent = (QueryTree) xmalloc (sizeof (struct queryTree)); ent->left = NULL; ent->right = NULL; ent->ent.searchType = InvalidSearchType; ent->ent.lhs = NULL; ent->ent.rhs = NULL; ent->op = InvalidQueryOp; return ent; } static QueryExpr newQueryExpr (const DatabaseInfo database) { QueryExpr ent = (QueryExpr) xmalloc (sizeof (struct queryExpr)); ent->database = database; ent->tree = newQueryTree (); return ent; } static QueryExpr queryField (const DatabaseInfo database, ComplexFieldIndex lhs, SearchType stype, ComplexFieldIndex rhs) { QueryExpr ent = newQueryExpr (database); ent->tree->op = QueryMatch; ent->tree->ent.searchType = stype; ent->tree->ent.lhs = newQueryItem (lhs); ent->tree->ent.rhs = newQueryItem (rhs); return ent; } static void freeQueryTree (QueryTree tree) { if (tree != NULL) { freeQueryTree (tree->left); freeQueryTree (tree->right); freeQueryItem (tree->ent.lhs); freeQueryItem (tree->ent.rhs); free (tree); } } void freeQueryExpr (QueryExpr query) { if (query != NULL) { freeQueryTree (query->tree); free (query); } } /* Return the SearchType value for OPERATOR, which is a query expression operator. */ static SearchType getSearchTypeForOperator (const char *operator, size_t *len) { int x; for (x = 0; searchTypes[x].name != NULL; x++) { if (searchTypes[x].operator[0] == operator[0]) { *len = strlen (searchTypes[x].operator); if (*len == 1 || strncmp (searchTypes[x].operator, operator, *len) == 0) { break; } } } return searchTypes[x].searchType; } /* Return the search operator for SearchType TYPE. */ const char * getSearchOperatorForType (SearchType type) { int x; for (x = 0; searchTypes[x].name != NULL; x++) { if (searchTypes[x].searchType == type) { return searchTypes[x].operator; } } return NULL; } /* Find the matching parenthesis for the parenthesized expression between EXPR and EXPEND. Returns either a pointer to the matching parenthesis, or NULL on failure. */ static const char * findMatchingParen (const char *expr, const char *expend) { int pcnt = 0; if (*expr != '(') { abort (); } while (expr <= expend) { if (*expr == '(') { pcnt++; } else if (*expr == ')') { pcnt--; } if (pcnt == 0) { break; } expr++; } if (pcnt > 0) { /* Invalid expression. */ return NULL; } else { return expr; } } /* Find the ending quote for the quoted string between EXPR and EXPREND inclusive; EXPR must point to the leading quote. Returns a pointer to the ending quote on success, or NULL on failure. */ static const char * findMatchingQuote (const char *expr, const char *exprend) { if (*expr != '"') { abort (); } expr++; while (expr <= exprend) { if (*expr == '\\') { expr++; } else if (*expr == '"') { return expr; } expr++; } if (expr <= exprend) { return expr; } else { return NULL; } } /* Remove any leading and trailing white space in the string between *EXPR and *EXPEND inclusive. */ static void stripWhiteSpace (const char **expr, const char **expend) { while (expr <= expend && isspace ((int)(unsigned char) **expr)) { (*expr)++; } while (expr <= expend && isspace ((int)(unsigned char) **expend)) { (*expend)--; } } /* Parse the possibly-quoted string argument between EXPR and EXPEND inclusive. Returns a malloc()ed copy of the string, with all leading and trailing whitespace removed if the string was unquoted. */ static char * parseStringArgument (const char *expr, const char *expend) { char *res; stripWhiteSpace (&expr, &expend); if (*expr == '"' && *expend == '"') { expr++; expend--; } res = xmalloc (expend - expr + 2); memcpy (res, expr, expend - expr + 1); res[expend - expr + 1] = '\0'; return res; } static ComplexFieldIndex parseQueryArgument (const DatabaseInfo database, const char *start, const char *end) { stripWhiteSpace (&start, &end); if (start[0] == '"') { char *string = parseStringArgument (start, end); ComplexFieldIndex field = newComplexFieldLiteralString (string); free (string); return field; } else { char *name = parseStringArgument (start, end); ComplexFieldIndex field = newComplexFieldIndex (database, name); free (name); return field; } } /* Parse a "simple" query expression between EXPR and EXPEND inclusive. */ static QueryExpr parseSimpleQueryExpression (const DatabaseInfo database, const char *expr, const char *expend) { const char *exprstart; stripWhiteSpace (&expr, &expend); exprstart = expr; while (expr <= expend) { if (*expr == '\\') { expr++; } else if (*expr == '"') { expr = findMatchingQuote (expr, expend); if (expr == NULL) { return NULL; } } else if (*expr == '(') { const char *pend = findMatchingParen (expr, expend); if (pend == NULL || pend != expend) { return NULL; } else { return parseQueryExpression (database, expr + 1, expend - 1); } } else { size_t len; SearchType searchType = getSearchTypeForOperator (expr, &len); if (searchType != InvalidSearchType) { ComplexFieldIndex lhs, rhs; lhs = parseQueryArgument (database, exprstart, expr - 1); rhs = parseQueryArgument (database, expr + len, expend); return queryField (database, lhs, searchType, rhs); } } expr++; } return NULL; } /* Try to parse the string between EXPR and EXPREND inclusive as a query expression. The equivalent QueryExpr tree is returned on success, or a NULL value if the expression could not be parsed. We may not be handling a & b | c quite right--this gets parsed as a & (b | c) instead of (a & b) | c Also, ! a & b & c is parsed as ! (a & b & c) which may or may not be what is desired. Depending on order without using parenthesis to make things clear is just asking for trouble. */ QueryExpr parseQueryExpression (const DatabaseInfo database, const char *expr, const char *exprend) { const char *exprstart = expr; if (exprend == NULL) { exprend = expr + strlen (expr) - 1; } while (expr <= exprend) { if (*expr == '\\') { expr++; } else if (*expr == '"') { expr = findMatchingQuote (expr, exprend); if (expr == NULL) { return NULL; } } else if (*expr == '(') { const char *pend = findMatchingParen (expr, exprend); if (pend == NULL) { return NULL; } if (pend == exprend) { return parseQueryExpression (database, expr + 1, exprend - 1); } expr = pend; } else if (*expr == '!' && *(expr + 1) != '=') { QueryExpr exp; exp = parseQueryExpression (database, expr + 1, exprend); return booleanQuery (QueryNot, exp, NULL); } else if (*expr == '&' || *expr == '|') { QueryExpr left, right; QueryOp op = (*expr == '&' ? QueryAnd : QueryOr); left = parseQueryExpression (database, exprstart, expr - 1); if (left == NULL) { return NULL; } right = parseQueryExpression (database, expr + 1, exprend); if (right == NULL) { return NULL; } return booleanQuery (op, left, right); } expr++; } /* Didn't find any ANDs or ORs, so maybe it's a simple expression. */ return parseSimpleQueryExpression (database, exprstart, exprend); } /* Appends an expression searching for SearchItem ITEM to the string in STRING, and returns either a pointer to the new string, or NULL on failure. */ static char * appendSearchItem (char *string, SearchItem *item) { int oldlen = (string == NULL) ? 0 : strlen (string); SearchType searchType = item->searchType; size_t addlen; char *lhs = complexFieldIndexToString (item->lhs->fieldIndex); char *rhs = complexFieldIndexToString (item->rhs->fieldIndex); const char *oper; oper = getSearchOperatorForType (searchType); if (oper == NULL) { return NULL; } addlen = strlen (lhs) + strlen (oper) + strlen (rhs); string = xrealloc (string, oldlen + addlen + 1); strcpy (string + oldlen, lhs); strcat (string + oldlen, oper); strcat (string + oldlen, rhs); free (lhs); free (rhs); return string; } /* Converts the QueryExpr EXPR to a string, and appends it to STRING; STRING is reallocated dynamically with xrealloc () as needed. Returns either the newly-appended string, or NULL on failure. */ static char * queryTreeToString (char *string, QueryTree expr) { /* A little macro to append CH to the string STRING. Yes, this is sorta slow. No, I don't care. */ #define addCh(CH) {\ size_t len = (string == NULL) ? 0 : strlen (string);\ string = xrealloc (string, len + 2);\ string[len] = (CH);\ string[len + 1] = '\0';\ } addCh ('('); switch (expr->op) { case QueryAnd: case QueryOr: { string = queryTreeToString (string, expr->left); if (string != NULL) { addCh (expr->op == QueryAnd ? '&' : '|'); string = queryTreeToString (string, expr->right); } break; } case QueryNot: { /* A little tricky. We replace the '(' we added above with a '!', then add a '('. */ size_t len = strlen (string); string[len - 1] = '!'; addCh ('('); string = queryTreeToString (string, expr->left); break; } case QueryMatch: { string = appendSearchItem (string, &(expr->ent)); break; } default: { abort (); break; } } if (string != NULL) { addCh (')'); } return string; #undef addChar } char * queryExprToString (char *string, QueryExpr expr) { QueryTree tree = NULL; if (expr != NULL) { tree = expr->tree; } return queryTreeToString (string, tree); } QueryExpr booleanQuery (QueryOp op, QueryExpr left, QueryExpr right) { QueryExpr res; if (left == NULL && right == NULL) { return NULL; } if (op != QueryNot) { if (left == NULL) { return right; } else if (right == NULL) { return left; } } res = newQueryExpr (left->database); res->tree->op = op; switch (op) { case QueryOr: case QueryAnd: res->tree->left = left->tree; res->tree->right = right->tree; left->tree = NULL; right->tree = NULL; freeQueryExpr (left); freeQueryExpr (right); break; case QueryNot: res->tree->left = left->tree; res->tree->right = NULL; left->tree = NULL; freeQueryExpr (left); break; default: abort (); break; } return res; } void freeQueryFormat (QueryFormat *q) { if (q != NULL) { if (q->name != NULL) { free (q->name); } if (q->printf != NULL) { free (q->printf); } if (q->separator != NULL) { free (q->separator); } if (q->fields != NULL) { freeFieldList (q->fields); } free (q); } } void freeQueryFormatList (QueryFormat *q) { while (q != NULL) { QueryFormat *next = q->next; freeQueryFormat (q); q = next; } } gnats-4.1.0/gnats/query.h0000644000175000017500000001142707557340356016037 0ustar chewiechewie00000000000000/* All things that the query tools have in common. Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc. Contributed by Brendan Kehoe (brendan@cygnus.com). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef _QUERY_H_ #define _QUERY_H_ typedef struct queryFormat QueryFormat; typedef struct queryExpr *QueryExpr; struct re_pattern_buffer; typedef enum e_lists { InvalidListType = -1, ListCategories = 0, ListSubmitters, ListResponsible, ListStates, ListFieldNames, ListInitialInputFields, ListInitialRequiredFields, ListDatabases } ListTypes; /* The four operations to perform. */ typedef enum queryOp { InvalidQueryOp = -1, QueryMatch = 0, QueryAnd, QueryOr, QueryNot } QueryOp; #include "index.h" #include "builtin-fields.h" #include "field.h" #include "mail.h" struct queryFormat { /* The name of this query format. */ char *name; /* A printf-style format. If this is null, we just write the fields out as-is. */ char *printf; /* The separator to place between each field. If this is NULL, we print out the field header followed by the contents, and an EOL between each field. */ char *separator; /* The list of fields. */ FieldList fields; /* If 1, the query is "raw", and should not process virtual fields. */ int rawQuery; /* The next format in the list. */ struct queryFormat *next; }; /* The function that is invoked from iterate_prs () is of this type. First argument is the result # (1 for the first PR matched, 2 for the second, etc). The second argument is the PR entry for the PR, and the final argument is the QueryFormat supplied to iterate_prs. The function is invoked with a NULL PR entry when we run out of PRs to match; the result # is the total # of PRs that were matched. */ typedef void (*QueryFunc)(int, PR *, QueryFormat *); /* Return the numeric equivalent of enum entry TEXT for field FIELD; entries are numbered starting from 1. 0 is returned if TEXT is not a valid entry for FIELD. */ extern int enum_numeric (const char *text, FieldIndex field); extern int gnats_regcmp (const char *regexp, const char *string, struct re_pattern_buffer *compRegexp); extern int regfind (const char *regexp, const char *string, struct re_pattern_buffer *compRegexp); extern QueryExpr booleanQuery (QueryOp op, QueryExpr left, QueryExpr right); extern QueryExpr queryFieldType (FieldType fieldType, SearchType stype, ComplexFieldIndex rhs); extern QueryExpr queryBuiltinField (PR_BuiltinField builtinField, SearchType stype, const char *regex); extern QueryExpr *insertBooleanQuery (QueryExpr *lhs, QueryOp op); extern void freeQueryExpr (QueryExpr); extern int print_pr (FILE *, PR *pr, QueryFormat *query_format, const char *eolTerminator); extern int print_named_format_pr (FILE *, PR *pr, const char *format_name, const char *eolTerminator, ErrorDesc *err); extern int process_format (FILE *fp, char **res, PR *pr, PR *oldPR, QueryFormat *fmt, const char *eolTerminator, FormatNamedParameter *parameters); extern int pr_matches_expr (PR *pr, PR *oldPR, QueryExpr expr, FormatNamedParameter *params); extern int set_query_opt (QueryExpr *, int, const char *, int); extern int iterate_prs (const DatabaseInfo database, int ac, char **av, QueryExpr exp, QueryFormat *format, QueryFunc func, ErrorDesc *err); extern void addQueryFormat (DatabaseInfo database, QueryFormat *format); extern QueryFormat *findQueryFormat (const DatabaseInfo database, const char *name, ErrorDesc *err); extern void insert_not_closed (QueryExpr *); extern void insert_closed (QueryExpr *); extern SearchType getSearchTypeForName (const char *); extern const char *getSearchOperatorForType (SearchType type); extern QueryExpr parseQueryExpression (const DatabaseInfo database, const char *expr, const char *exprend); extern char *queryExprToString (char *string, QueryExpr expr); extern time_t get_any_date (const char *dateString); extern void append_string (char **res, const char *string); extern void freeQueryFormat (QueryFormat *format); extern void freeQueryFormatList (QueryFormat *q); #endif gnats-4.1.0/gnats/queue-pr.c0000644000175000017500000002756207521042103016413 0ustar chewiechewie00000000000000/* Handle getting a message from email into GNATS. Copyright (C) 2001 Free Software Foundation Copyright (C) 1993, 1994, 1995 (FIXME: Brendan Kehoe or Cygnus/Red Hat) Contributed by Brendan Kehoe (brendan@cygnus.com). Further work by Milan Zamazal (pdm@zamazal.org) and Dirk Bergstrom (dirk@juniper.net). This file is part of GNU GNATS. GNU GNATS 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. GNU GNATS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU GNATS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include #include /* FIXME */ #include /* FIXME: gets MAXBSIZE */ #include "gnats.h" #include "gnats-dirs.h" #ifndef MAXBSIZE /* FIXME - from params.h */ #define MAXBSIZE 8192 #endif /* The name this program was run with. */ const char *program_name; /* Iff TRUE, queue the incoming message. */ bool queue_msg = FALSE; /* Max size for messages. */ int max_size = 0; /* Iff TRUE, run pr-edit on each message in the queue. */ bool run_queue = FALSE; /* If TRUE, emit debugging information. */ bool flag_debug = FALSE; /* Which file (defaults to NULL, aka stdin) to use to read as the message to queue for GNATS. */ char *queue_file = NULL; struct option const long_options[] = { {"database", 1, NULL, 'd'}, {"file", 1, NULL, 'f'}, {"debug", 0, NULL, 'D'}, {"queue", 0, NULL, 'q'}, {"run", 0, NULL, 'r'}, {"max-size", 1, NULL, 'm'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {NULL, 0, NULL, 0} }; #define PROGRAM_NAME "queue-pr" static const char *const USAGE[] = { "Usage: " PROGRAM_NAME " [OPTION]...\n\ Handle messages submitted via e-mail.\n\ ", "\n\ -q, --queue queue the given message\n\ -r, --run process messages in the queue\n\ -f, --file=FILENAME read the message from FILENAME instead of stdin\n\ -m, --max-size=KBYTES don't process messages larger than KBYTES\n\ -d, --database=DATABASE use DATABASE instead of the default database\n\ -D, --debug enable some debugging\n\ -h, --help display this help and exit\n\ -V, --version display version information and exit\n\ ", "\n\ Usually you want to specify exactly one of the options `--queue' and `--run'.\ \n", NULL}; /* Run pr-edit on FILENAME and return its exit status. */ static int fork_gnats (DatabaseInfo database, const char *filename) { /* A safe environment for execle(). */ static const char *safe_env[] = { "", "PATH=/bin:/usr/bin", NULL }; char *ptr; int pid; /* pid_t */ int status; const char *gaddr = gnatsAdminMailAddr (database); asprintf (&ptr, "USER=%s", gaddr); safe_env[0] = ptr; errno = 0; pid = fork(); if (pid < 0) { punt (database, 1, "could not fork pr-edit: %s\n", strerror (errno)); } else if (pid == 0) { char *pr_edit_bin; int fd; asprintf (&pr_edit_bin, "%s/pr-edit", binDir (database)); if (! debugMode (database)) { /* Redirect stderr to /dev/null, since `at' will give you info about the job you've queued. If opening /dev/null fails, just ignore it and go on. */ fd = open ("/dev/null", O_RDWR); if (fd > 0) { close (2); fcntl (fd, F_DUPFD, 2); } } errno = 0; if (flag_debug) { if (execle (pr_edit_bin, "pr-edit", "--submit", "-f", filename, "--debug", "--database", databaseName (database), NULL, safe_env) < 0) { punt (database, 1, "execle of gnats failed: %s\n", strerror (errno)); } } else { if (execle (pr_edit_bin, "pr-edit", "--submit", "-f", filename, "--database", databaseName (database), NULL, safe_env) < 0) { punt (database, 1, "execle of gnats failed: %s\n", strerror (errno)); } } exit (-1); /* XXX */ } waitpid (pid, &status, 0); /* FIXME: not portable */ free (ptr); #ifndef WEXITSTATUS #define WEXITSTATUS(x) (((union wait*)&(x))->w_retcode) #endif return WEXITSTATUS (status); } /* Run a gnats process on each message in QUEUE_DIR. */ static void run_gnats (DatabaseInfo database, const char *queue_dir) { DIR *d; struct dirent *next; int i; int nfiles = 0; int maxfiles = 10; struct file { char *name; } *files = (struct file *) xmalloc (sizeof (struct file) * maxfiles); if (chdir (queue_dir) < 0) { punt (database, 1, "can't open queue directory: %s", queue_dir); } errno = 0; d = opendir ("."); if (! d) { log_msg (LOG_INFO, 1, "can't open: ", queue_dir); return; } while ((next = readdir (d))) if (next->d_name[0] != '.') { if (strcmp (next->d_name, "core") == 0) { log_msg (LOG_INFO, 0, "core file in queue directory"); continue; } /* skip files larger than max_size */ if (max_size) { struct stat buf; if (stat ((char*) next->d_name, &buf) == 0) { if ((int) buf.st_size > max_size) { char *max; char *name2 = xmalloc (strlen ((char*) next->d_name) + 2); strcpy (name2, "."); strcat (name2, (char*) next->d_name); rename ((char*) next->d_name, name2); asprintf (&max, "%d", max_size / 1024); punt (database, 0, ("file `%s' larger than max-size of %sK.\n" "renamed to `%s' pending human intervention.\n"), (char*) next->d_name, max, name2); log_msg (LOG_INFO, 1, "file larger than max-size:", name2); free (name2); free (max); continue; } } } if (nfiles == maxfiles) { maxfiles *= 2; files = (struct file *) xrealloc ((char *) files, sizeof (struct file) * maxfiles); } files[nfiles++].name = (char *) xstrdup (next->d_name); } closedir (d); /* Run a gnats process for each file in the directory. */ for (i = 0; i < nfiles; i++) { int child_status; if (flag_debug) fprintf (stderr, "%s: running %s\n", program_name, files[i].name); child_status = fork_gnats (database, files[i].name); /* If gnats ran okay, then we can unlink the queue file. Otherwise, keep it around so we can give it another try whenever the problems have been taken care of. Exit status of 1: Simple failure, try again 2: Unexpected failure, probably case-specific 3: Unexpected failure, probably general */ if (child_status == 0) { if (unlink (files[i].name)) log_msg (LOG_INFO, 1, "cannot remove: ", files[i].name); } else if (child_status == 2) { struct stat buf; if (stat ((char*) files[i].name, &buf) != 0 && errno == ENOENT) { /* the file is gone, perhaps another queue-pr took care of it? */ punt (database, 0, "file `%s' was gone when pr-edit tried to process it.\n", files[i].name); } else { /* something else bad has happened with this file, move it aside, and alert the admin */ char *name2 = xmalloc (strlen (files[i].name) + 2); strcpy (name2, "."); strcat (name2, files[i].name); rename (files[i].name, name2); punt (database, 0, "renamed `%s' to `%s' pending human intervention.\n", files[i].name, name2); free (name2); } if (is_gnats_locked (database)) { client_unlock_gnats (); } } else if (child_status == 3) { punt (database, 0, "pr-edit complained of a (probably) general problem.\n"); } } } /* Drop the message in QUEUE_FILE (or, failing that, stdin) into the QUEUE_DIR. */ static void drop_msg (DatabaseInfo database, const char *queue_dir) { int fd[2]; const char *tmpdir; char *bug_file; int r; /* XXX ssize_t */ char *buf = (char *) xmalloc (MAXBSIZE); char *base, *new_name; if (queue_file) { fd[0] = open (queue_file, O_RDONLY); if (fd[0] < 0) punt (database, 1, "can't open queue file %s for reading: %s\n", queue_file, strerror (errno)); } else fd[0] = 0; tmpdir = temporary_directory (); asprintf (&bug_file, "%s/gnatsXXXXXX", tmpdir); fd[1] = open_temporary_file (bug_file, 0664); if (fd[1] < 0) { punt (database, 1, "can't open queue file %s for writing: %s\n", bug_file, strerror (errno)); } while ((r = read (fd[0], buf, MAXBSIZE)) > 0) { if (write (fd[1], buf, r) < 0) { if (fd[0]) close (fd[0]); close (fd[1]); punt (database, 1, "error in writing %s: %s\n", bug_file, strerror (errno)); } } if (r < 0) { if (queue_file) punt (database, 1, "error reading queue file %s: %s\n", queue_file, strerror (errno)); } if (fd[0]) { close (fd[0]); } close (fd[1]); errno = 0; base = basename (bug_file); asprintf (&new_name, "%s/%s", queue_dir, base); /* FIXME: Is there any guarantee here that NEW_NAME doesn't already exist? */ if (rename (bug_file, new_name) < 0) { if (errno != EXDEV) { punt (database, 1, "could not rename %s into the queue dir: %s\n", bug_file, strerror (errno)); } { char *tmp_name; asprintf (&tmp_name, "%s/.%s", queue_dir, base); copy_file (bug_file, tmp_name); if (rename (tmp_name, new_name) < 0) { punt (database, 1, "could not rename %s to %s: %s\n", tmp_name, new_name, strerror (errno)); } } if (unlink (bug_file)) { punt (database, 1, "cannot remove `%s'", bug_file); } } } int main (int argc, char **argv) { int optc; char *database_name = NULL; ErrorDesc err; char *queue_dir; DatabaseInfo database = NULL; unsigned long max_size_scale; unsigned long max_size_range; program_name = basename (argv[0]); /* FIXME: handle signals */ while ((optc = getopt_long (argc, argv, "d:f:VmqrDh", long_options, (int *) 0)) != EOF) { switch (optc) { case 'd': if (optarg[0] == '\0') { punt (database, 1, "directory must be non-null\n"); } database_name = optarg; break; case 'f': if (optarg[0] == '\0') { punt (database, 1, "filename must be non-null\n"); } queue_file = optarg; break; case 'r': if (queue_msg) { punt (database, 1, "-q and -r can't be specified at the same time.\n"); } run_queue = TRUE; break; case 'm': max_size_range = LONG_MAX / 1024; max_size_scale = strtol (optarg, NULL, 10); if (max_size_scale <= 1 || max_size_scale > max_size_range || errno == ERANGE) { punt (database, 1, "max-size must be an integer between 1 and %li\n", max_size_range); } max_size = max_size * 1024; break; case 'q': if (run_queue) { punt (database, 1, "-q and -r can't be specified at the same time.\n"); } queue_msg = TRUE; break; case 'D': flag_debug = TRUE; break; case 'h': usage (USAGE, 0); break; case 'V': fprintf (stderr, "queue-pr version %s.\n", version_string); exit (0); break; default: fprintf (stderr, "%s", USAGE); exit (1); break; } } umask (022); database = init_gnats (program_name, database_name, &err); if (! databaseValid (database)) { client_print_errors (database, err); fprintf (stderr, "%s: invalid value for GNATS database\n", program_name); exit (1); } asprintf (&queue_dir, "%s/gnats-queue", databaseDir (database)); if (queue_msg) { drop_msg (database, queue_dir); } if (run_queue) { run_gnats (database, queue_dir); } free (queue_dir); exit (0); } gnats-4.1.0/gnats/regex.c0000644000175000017500000053255307405230165015773 0ustar chewiechewie00000000000000/* Extended regular expression matching and search library, version 0.12. (Implements POSIX draft P1003.2/D11.2, except for some of the internationalization features.) Copyright (C) 1993,94,95,96,97,98,99,2000 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* TODO: - structure the opcode space into opcode+flag. - merge with glibc's regex.[ch]. - replace (succeed_n + jump_n + set_number_at) with something that doesn't need to modify the compiled regexp so that re_match can be reentrant. - get rid of on_failure_jump_smart by doing the optimization in re_comp rather than at run-time, so that re_match can be reentrant. */ /* AIX requires this to be the first thing in the file. */ #if defined _AIX && !defined REGEX_MALLOC #pragma alloca #endif #undef _GNU_SOURCE #define _GNU_SOURCE #ifdef HAVE_CONFIG_H # include #endif #if defined STDC_HEADERS && !defined emacs # include #else /* We need this for `regex.h', and perhaps for the Emacs include files. */ # include #endif /* Whether to use ISO C Amendment 1 wide char functions. Those should not be used for Emacs since it uses its own. */ #if defined _LIBC #define WIDE_CHAR_SUPPORT 1 #else #define WIDE_CHAR_SUPPORT \ (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC && !emacs) #endif /* For platform which support the ISO C amendement 1 functionality we support user defined character classes. */ #if WIDE_CHAR_SUPPORT /* Solaris 2.5 has a bug: must be included before . */ # include # include #endif #ifdef _LIBC /* We have to keep the namespace clean. */ # define regfree(preg) __regfree (preg) # define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) # define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) # define regerror(errcode, preg, errbuf, errbuf_size) \ __regerror(errcode, preg, errbuf, errbuf_size) # define re_set_registers(bu, re, nu, st, en) \ __re_set_registers (bu, re, nu, st, en) # define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) # define re_match(bufp, string, size, pos, regs) \ __re_match (bufp, string, size, pos, regs) # define re_search(bufp, string, size, startpos, range, regs) \ __re_search (bufp, string, size, startpos, range, regs) # define re_compile_pattern(pattern, length, bufp) \ __re_compile_pattern (pattern, length, bufp) # define re_set_syntax(syntax) __re_set_syntax (syntax) # define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) # define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) /* Make sure we call libc's function even if the user overrides them. */ # define btowc __btowc # define iswctype __iswctype # define wctype __wctype # define WEAK_ALIAS(a,b) weak_alias (a, b) /* We are also using some library internals. */ # include # include # include #else # define WEAK_ALIAS(a,b) #endif /* This is for other GNU distributions with internationalized messages. */ #if HAVE_LIBINTL_H || defined _LIBC # include #else # define gettext(msgid) (msgid) #endif #ifndef gettext_noop /* This define is so xgettext can find the internationalizable strings. */ # define gettext_noop(String) String #endif /* The `emacs' switch turns on certain matching commands that make sense only in Emacs. */ #ifdef emacs # include "lisp.h" # include "buffer.h" /* Make syntax table lookup grant data in gl_state. */ # define SYNTAX_ENTRY_VIA_PROPERTY # include "syntax.h" # include "charset.h" # include "category.h" # ifdef malloc # undef malloc # endif # define malloc xmalloc # ifdef realloc # undef realloc # endif # define realloc xrealloc # ifdef free # undef free # endif # define free xfree /* Converts the pointer to the char to BEG-based offset from the start. */ # define PTR_TO_OFFSET(d) POS_AS_IN_BUFFER (POINTER_TO_OFFSET (d)) # define POS_AS_IN_BUFFER(p) ((p) + (NILP (re_match_object) || BUFFERP (re_match_object))) # define RE_MULTIBYTE_P(bufp) ((bufp)->multibyte) # define RE_STRING_CHAR(p, s) \ (multibyte ? (STRING_CHAR (p, s)) : (*(p))) # define RE_STRING_CHAR_AND_LENGTH(p, s, len) \ (multibyte ? (STRING_CHAR_AND_LENGTH (p, s, len)) : ((len) = 1, *(p))) /* Set C a (possibly multibyte) character before P. P points into a string which is the virtual concatenation of STR1 (which ends at END1) or STR2 (which ends at END2). */ # define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2) \ do { \ if (multibyte) \ { \ re_char *dtemp = (p) == (str2) ? (end1) : (p); \ re_char *dlimit = ((p) > (str2) && (p) <= (end2)) ? (str2) : (str1); \ while (dtemp-- > dlimit && !CHAR_HEAD_P (*dtemp)); \ c = STRING_CHAR (dtemp, (p) - dtemp); \ } \ else \ (c = ((p) == (str2) ? (end1) : (p))[-1]); \ } while (0) #else /* not emacs */ /* If we are not linking with Emacs proper, we can't use the relocating allocator even if config.h says that we can. */ # undef REL_ALLOC # if defined STDC_HEADERS || defined _LIBC # include # else char *malloc (); char *realloc (); # endif /* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. If nothing else has been done, use the method below. */ # ifdef INHIBIT_STRING_HEADER # if !(defined HAVE_BZERO && defined HAVE_BCOPY) # if !defined bzero && !defined bcopy # undef INHIBIT_STRING_HEADER # endif # endif # endif /* This is the normal way of making sure we have memcpy, memcmp and bzero. This is used in most programs--a few other programs avoid this by defining INHIBIT_STRING_HEADER. */ # ifndef INHIBIT_STRING_HEADER # if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC # include # ifndef bzero # ifndef _LIBC # define bzero(s, n) (memset (s, '\0', n), (s)) # else # define bzero(s, n) __bzero (s, n) # endif # endif # else # include # ifndef memcmp # define memcmp(s1, s2, n) bcmp (s1, s2, n) # endif # ifndef memcpy # define memcpy(d, s, n) (bcopy (s, d, n), (d)) # endif # endif # endif /* Define the syntax stuff for \<, \>, etc. */ /* Sword must be nonzero for the wordchar pattern commands in re_match_2. */ enum syntaxcode { Swhitespace = 0, Sword = 1 }; # ifdef SWITCH_ENUM_BUG # define SWITCH_ENUM_CAST(x) ((int)(x)) # else # define SWITCH_ENUM_CAST(x) (x) # endif /* Dummy macros for non-Emacs environments. */ # define BASE_LEADING_CODE_P(c) (0) # define CHAR_CHARSET(c) 0 # define CHARSET_LEADING_CODE_BASE(c) 0 # define MAX_MULTIBYTE_LENGTH 1 # define RE_MULTIBYTE_P(x) 0 # define WORD_BOUNDARY_P(c1, c2) (0) # define CHAR_HEAD_P(p) (1) # define SINGLE_BYTE_CHAR_P(c) (1) # define SAME_CHARSET_P(c1, c2) (1) # define MULTIBYTE_FORM_LENGTH(p, s) (1) # define STRING_CHAR(p, s) (*(p)) # define RE_STRING_CHAR STRING_CHAR # define CHAR_STRING(c, s) (*(s) = (c), 1) # define STRING_CHAR_AND_LENGTH(p, s, actual_len) ((actual_len) = 1, *(p)) # define RE_STRING_CHAR_AND_LENGTH STRING_CHAR_AND_LENGTH # define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2) \ (c = ((p) == (str2) ? *((end1) - 1) : *((p) - 1))) # define MAKE_CHAR(charset, c1, c2) (c1) #endif /* not emacs */ #ifndef RE_TRANSLATE # define RE_TRANSLATE(TBL, C) ((unsigned char)(TBL)[C]) # define RE_TRANSLATE_P(TBL) (TBL) #endif /* Get the interface, including the syntax bits. */ #include "regex.h" /* isalpha etc. are used for the character classes. */ #include #ifdef emacs /* 1 if C is an ASCII character. */ # define IS_REAL_ASCII(c) ((c) < 0200) /* 1 if C is a unibyte character. */ # define ISUNIBYTE(c) (SINGLE_BYTE_CHAR_P ((c))) /* The Emacs definitions should not be directly affected by locales. */ /* In Emacs, these are only used for single-byte characters. */ # define ISDIGIT(c) ((c) >= '0' && (c) <= '9') # define ISCNTRL(c) ((c) < ' ') # define ISXDIGIT(c) (((c) >= '0' && (c) <= '9') \ || ((c) >= 'a' && (c) <= 'f') \ || ((c) >= 'A' && (c) <= 'F')) /* This is only used for single-byte characters. */ # define ISBLANK(c) ((c) == ' ' || (c) == '\t') /* The rest must handle multibyte characters. */ # define ISGRAPH(c) (SINGLE_BYTE_CHAR_P (c) \ ? (c) > ' ' && !((c) >= 0177 && (c) <= 0237) \ : 1) # define ISPRINT(c) (SINGLE_BYTE_CHAR_P (c) \ ? (c) >= ' ' && !((c) >= 0177 && (c) <= 0237) \ : 1) # define ISALNUM(c) (IS_REAL_ASCII (c) \ ? (((c) >= 'a' && (c) <= 'z') \ || ((c) >= 'A' && (c) <= 'Z') \ || ((c) >= '0' && (c) <= '9')) \ : SYNTAX (c) == Sword) # define ISALPHA(c) (IS_REAL_ASCII (c) \ ? (((c) >= 'a' && (c) <= 'z') \ || ((c) >= 'A' && (c) <= 'Z')) \ : SYNTAX (c) == Sword) # define ISLOWER(c) (LOWERCASEP (c)) # define ISPUNCT(c) (IS_REAL_ASCII (c) \ ? ((c) > ' ' && (c) < 0177 \ && !(((c) >= 'a' && (c) <= 'z') \ || ((c) >= 'A' && (c) <= 'Z') \ || ((c) >= '0' && (c) <= '9'))) \ : SYNTAX (c) != Sword) # define ISSPACE(c) (SYNTAX (c) == Swhitespace) # define ISUPPER(c) (UPPERCASEP (c)) # define ISWORD(c) (SYNTAX (c) == Sword) #else /* not emacs */ /* Jim Meyering writes: "... Some ctype macros are valid only for character codes that isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when using /bin/cc or gcc but without giving an ansi option). So, all ctype uses should be through macros like ISPRINT... If STDC_HEADERS is defined, then autoconf has verified that the ctype macros don't need to be guarded with references to isascii. ... Defining isascii to 1 should let any compiler worth its salt eliminate the && through constant folding." Solaris defines some of these symbols so we must undefine them first. */ # undef ISASCII # if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) # define ISASCII(c) 1 # else # define ISASCII(c) isascii(c) # endif /* 1 if C is an ASCII character. */ # define IS_REAL_ASCII(c) ((c) < 0200) /* This distinction is not meaningful, except in Emacs. */ # define ISUNIBYTE(c) 1 # ifdef isblank # define ISBLANK(c) (ISASCII (c) && isblank (c)) # else # define ISBLANK(c) ((c) == ' ' || (c) == '\t') # endif # ifdef isgraph # define ISGRAPH(c) (ISASCII (c) && isgraph (c)) # else # define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) # endif # undef ISPRINT # define ISPRINT(c) (ISASCII (c) && isprint (c)) # define ISDIGIT(c) (ISASCII (c) && isdigit (c)) # define ISALNUM(c) (ISASCII (c) && isalnum (c)) # define ISALPHA(c) (ISASCII (c) && isalpha (c)) # define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) # define ISLOWER(c) (ISASCII (c) && islower (c)) # define ISPUNCT(c) (ISASCII (c) && ispunct (c)) # define ISSPACE(c) (ISASCII (c) && isspace (c)) # define ISUPPER(c) (ISASCII (c) && isupper (c)) # define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) # define ISWORD(c) ISALPHA(c) # ifdef _tolower # define TOLOWER(c) _tolower(c) # else # define TOLOWER(c) tolower(c) # endif /* How many characters in the character set. */ # define CHAR_SET_SIZE 256 # ifdef SYNTAX_TABLE extern char *re_syntax_table; # else /* not SYNTAX_TABLE */ static char re_syntax_table[CHAR_SET_SIZE]; static void init_syntax_once () { register int c; static int done = 0; if (done) return; bzero (re_syntax_table, sizeof re_syntax_table); for (c = 0; c < CHAR_SET_SIZE; ++c) if (ISALNUM (c)) re_syntax_table[c] = Sword; re_syntax_table['_'] = Sword; done = 1; } # endif /* not SYNTAX_TABLE */ # define SYNTAX(c) re_syntax_table[(c)] #endif /* not emacs */ #ifndef NULL # define NULL (void *)0 #endif /* We remove any previous definition of `SIGN_EXTEND_CHAR', since ours (we hope) works properly with all combinations of machines, compilers, `char' and `unsigned char' argument types. (Per Bothner suggested the basic approach.) */ #undef SIGN_EXTEND_CHAR #if __STDC__ # define SIGN_EXTEND_CHAR(c) ((signed char) (c)) #else /* not __STDC__ */ /* As in Harbison and Steele. */ # define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) #endif /* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we use `alloca' instead of `malloc'. This is because using malloc in re_search* or re_match* could cause memory leaks when C-g is used in Emacs; also, malloc is slower and causes storage fragmentation. On the other hand, malloc is more portable, and easier to debug. Because we sometimes use alloca, some routines have to be macros, not functions -- `alloca'-allocated space disappears at the end of the function it is called in. */ #ifdef REGEX_MALLOC # define REGEX_ALLOCATE malloc # define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) # define REGEX_FREE free #else /* not REGEX_MALLOC */ /* Emacs already defines alloca, sometimes. */ # ifndef alloca /* Make alloca work the best possible way. */ # ifdef __GNUC__ # define alloca __builtin_alloca # else /* not __GNUC__ */ # if HAVE_ALLOCA_H # include # endif /* HAVE_ALLOCA_H */ # endif /* not __GNUC__ */ # endif /* not alloca */ # define REGEX_ALLOCATE alloca /* Assumes a `char *destination' variable. */ # define REGEX_REALLOCATE(source, osize, nsize) \ (destination = (char *) alloca (nsize), \ memcpy (destination, source, osize)) /* No need to do anything to free, after alloca. */ # define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ #endif /* not REGEX_MALLOC */ /* Define how to allocate the failure stack. */ #if defined REL_ALLOC && defined REGEX_MALLOC # define REGEX_ALLOCATE_STACK(size) \ r_alloc (&failure_stack_ptr, (size)) # define REGEX_REALLOCATE_STACK(source, osize, nsize) \ r_re_alloc (&failure_stack_ptr, (nsize)) # define REGEX_FREE_STACK(ptr) \ r_alloc_free (&failure_stack_ptr) #else /* not using relocating allocator */ # ifdef REGEX_MALLOC # define REGEX_ALLOCATE_STACK malloc # define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) # define REGEX_FREE_STACK free # else /* not REGEX_MALLOC */ # define REGEX_ALLOCATE_STACK alloca # define REGEX_REALLOCATE_STACK(source, osize, nsize) \ REGEX_REALLOCATE (source, osize, nsize) /* No need to explicitly free anything. */ # define REGEX_FREE_STACK(arg) ((void)0) # endif /* not REGEX_MALLOC */ #endif /* not using relocating allocator */ /* True if `size1' is non-NULL and PTR is pointing anywhere inside `string1' or just past its end. This works if PTR is NULL, which is a good thing. */ #define FIRST_STRING_P(ptr) \ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) /* (Re)Allocate N items of type T using malloc, or fail. */ #define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) #define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) #define RETALLOC_IF(addr, n, t) \ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) #define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) #define BYTEWIDTH 8 /* In bits. */ #define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) #undef MAX #undef MIN #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) /* Type of source-pattern and string chars. */ typedef const unsigned char re_char; typedef char boolean; #define false 0 #define true 1 static int re_match_2_internal _RE_ARGS ((struct re_pattern_buffer *bufp, re_char *string1, int size1, re_char *string2, int size2, int pos, struct re_registers *regs, int stop)); /* These are the command codes that appear in compiled regular expressions. Some opcodes are followed by argument bytes. A command code can specify any interpretation whatsoever for its arguments. Zero bytes may appear in the compiled regular expression. */ typedef enum { no_op = 0, /* Succeed right away--no more backtracking. */ succeed, /* Followed by one byte giving n, then by n literal bytes. */ exactn, /* Matches any (more or less) character. */ anychar, /* Matches any one char belonging to specified set. First following byte is number of bitmap bytes. Then come bytes for a bitmap saying which chars are in. Bits in each byte are ordered low-bit-first. A character is in the set if its bit is 1. A character too large to have a bit in the map is automatically not in the set. If the length byte has the 0x80 bit set, then that stuff is followed by a range table: 2 bytes of flags for character sets (low 8 bits, high 8 bits) See RANGE_TABLE_WORK_BITS below. 2 bytes, the number of pairs that follow (upto 32767) pairs, each 2 multibyte characters, each multibyte character represented as 3 bytes. */ charset, /* Same parameters as charset, but match any character that is not one of those specified. */ charset_not, /* Start remembering the text that is matched, for storing in a register. Followed by one byte with the register number, in the range 0 to one less than the pattern buffer's re_nsub field. */ start_memory, /* Stop remembering the text that is matched and store it in a memory register. Followed by one byte with the register number, in the range 0 to one less than `re_nsub' in the pattern buffer. */ stop_memory, /* Match a duplicate of something remembered. Followed by one byte containing the register number. */ duplicate, /* Fail unless at beginning of line. */ begline, /* Fail unless at end of line. */ endline, /* Succeeds if at beginning of buffer (if emacs) or at beginning of string to be matched (if not). */ begbuf, /* Analogously, for end of buffer/string. */ endbuf, /* Followed by two byte relative address to which to jump. */ jump, /* Followed by two-byte relative address of place to resume at in case of failure. */ on_failure_jump, /* Like on_failure_jump, but pushes a placeholder instead of the current string position when executed. */ on_failure_keep_string_jump, /* Just like `on_failure_jump', except that it checks that we don't get stuck in an infinite loop (matching an empty string indefinitely). */ on_failure_jump_loop, /* Just like `on_failure_jump_loop', except that it checks for a different kind of loop (the kind that shows up with non-greedy operators). This operation has to be immediately preceded by a `no_op'. */ on_failure_jump_nastyloop, /* A smart `on_failure_jump' used for greedy * and + operators. It analyses the loop before which it is put and if the loop does not require backtracking, it changes itself to `on_failure_keep_string_jump' and short-circuits the loop, else it just defaults to changing itself into `on_failure_jump'. It assumes that it is pointing to just past a `jump'. */ on_failure_jump_smart, /* Followed by two-byte relative address and two-byte number n. After matching N times, jump to the address upon failure. Does not work if N starts at 0: use on_failure_jump_loop instead. */ succeed_n, /* Followed by two-byte relative address, and two-byte number n. Jump to the address N times, then fail. */ jump_n, /* Set the following two-byte relative address to the subsequent two-byte number. The address *includes* the two bytes of number. */ set_number_at, wordbeg, /* Succeeds if at word beginning. */ wordend, /* Succeeds if at word end. */ wordbound, /* Succeeds if at a word boundary. */ notwordbound, /* Succeeds if not at a word boundary. */ /* Matches any character whose syntax is specified. Followed by a byte which contains a syntax code, e.g., Sword. */ syntaxspec, /* Matches any character whose syntax is not that specified. */ notsyntaxspec #ifdef emacs ,before_dot, /* Succeeds if before point. */ at_dot, /* Succeeds if at point. */ after_dot, /* Succeeds if after point. */ /* Matches any character whose category-set contains the specified category. The operator is followed by a byte which contains a category code (mnemonic ASCII character). */ categoryspec, /* Matches any character whose category-set does not contain the specified category. The operator is followed by a byte which contains the category code (mnemonic ASCII character). */ notcategoryspec #endif /* emacs */ } re_opcode_t; /* Common operations on the compiled pattern. */ /* Store NUMBER in two contiguous bytes starting at DESTINATION. */ #define STORE_NUMBER(destination, number) \ do { \ (destination)[0] = (number) & 0377; \ (destination)[1] = (number) >> 8; \ } while (0) /* Same as STORE_NUMBER, except increment DESTINATION to the byte after where the number is stored. Therefore, DESTINATION must be an lvalue. */ #define STORE_NUMBER_AND_INCR(destination, number) \ do { \ STORE_NUMBER (destination, number); \ (destination) += 2; \ } while (0) /* Put into DESTINATION a number stored in two contiguous bytes starting at SOURCE. */ #define EXTRACT_NUMBER(destination, source) \ do { \ (destination) = *(source) & 0377; \ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ } while (0) #ifdef DEBUG static void extract_number _RE_ARGS ((int *dest, re_char *source)); static void extract_number (dest, source) int *dest; re_char *source; { int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; *dest += temp << 8; } # ifndef EXTRACT_MACROS /* To debug the macros. */ # undef EXTRACT_NUMBER # define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) # endif /* not EXTRACT_MACROS */ #endif /* DEBUG */ /* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. SOURCE must be an lvalue. */ #define EXTRACT_NUMBER_AND_INCR(destination, source) \ do { \ EXTRACT_NUMBER (destination, source); \ (source) += 2; \ } while (0) #ifdef DEBUG static void extract_number_and_incr _RE_ARGS ((int *destination, re_char **source)); static void extract_number_and_incr (destination, source) int *destination; re_char **source; { extract_number (destination, *source); *source += 2; } # ifndef EXTRACT_MACROS # undef EXTRACT_NUMBER_AND_INCR # define EXTRACT_NUMBER_AND_INCR(dest, src) \ extract_number_and_incr (&dest, &src) # endif /* not EXTRACT_MACROS */ #endif /* DEBUG */ /* Store a multibyte character in three contiguous bytes starting DESTINATION, and increment DESTINATION to the byte after where the character is stored. Therefore, DESTINATION must be an lvalue. */ #define STORE_CHARACTER_AND_INCR(destination, character) \ do { \ (destination)[0] = (character) & 0377; \ (destination)[1] = ((character) >> 8) & 0377; \ (destination)[2] = (character) >> 16; \ (destination) += 3; \ } while (0) /* Put into DESTINATION a character stored in three contiguous bytes starting at SOURCE. */ #define EXTRACT_CHARACTER(destination, source) \ do { \ (destination) = ((source)[0] \ | ((source)[1] << 8) \ | ((source)[2] << 16)); \ } while (0) /* Macros for charset. */ /* Size of bitmap of charset P in bytes. P is a start of charset, i.e. *P is (re_opcode_t) charset or (re_opcode_t) charset_not. */ #define CHARSET_BITMAP_SIZE(p) ((p)[1] & 0x7F) /* Nonzero if charset P has range table. */ #define CHARSET_RANGE_TABLE_EXISTS_P(p) ((p)[1] & 0x80) /* Return the address of range table of charset P. But not the start of table itself, but the before where the number of ranges is stored. `2 +' means to skip re_opcode_t and size of bitmap, and the 2 bytes of flags at the start of the range table. */ #define CHARSET_RANGE_TABLE(p) (&(p)[4 + CHARSET_BITMAP_SIZE (p)]) /* Extract the bit flags that start a range table. */ #define CHARSET_RANGE_TABLE_BITS(p) \ ((p)[2 + CHARSET_BITMAP_SIZE (p)] \ + (p)[3 + CHARSET_BITMAP_SIZE (p)] * 0x100) /* Test if C is listed in the bitmap of charset P. */ #define CHARSET_LOOKUP_BITMAP(p, c) \ ((c) < CHARSET_BITMAP_SIZE (p) * BYTEWIDTH \ && (p)[2 + (c) / BYTEWIDTH] & (1 << ((c) % BYTEWIDTH))) /* Return the address of end of RANGE_TABLE. COUNT is number of ranges (which is a pair of (start, end)) in the RANGE_TABLE. `* 2' is start of range and end of range. `* 3' is size of each start and end. */ #define CHARSET_RANGE_TABLE_END(range_table, count) \ ((range_table) + (count) * 2 * 3) /* Test if C is in RANGE_TABLE. A flag NOT is negated if C is in. COUNT is number of ranges in RANGE_TABLE. */ #define CHARSET_LOOKUP_RANGE_TABLE_RAW(not, c, range_table, count) \ do \ { \ re_wchar_t range_start, range_end; \ re_char *p; \ re_char *range_table_end \ = CHARSET_RANGE_TABLE_END ((range_table), (count)); \ \ for (p = (range_table); p < range_table_end; p += 2 * 3) \ { \ EXTRACT_CHARACTER (range_start, p); \ EXTRACT_CHARACTER (range_end, p + 3); \ \ if (range_start <= (c) && (c) <= range_end) \ { \ (not) = !(not); \ break; \ } \ } \ } \ while (0) /* Test if C is in range table of CHARSET. The flag NOT is negated if C is listed in it. */ #define CHARSET_LOOKUP_RANGE_TABLE(not, c, charset) \ do \ { \ /* Number of ranges in range table. */ \ int count; \ re_char *range_table = CHARSET_RANGE_TABLE (charset); \ \ EXTRACT_NUMBER_AND_INCR (count, range_table); \ CHARSET_LOOKUP_RANGE_TABLE_RAW ((not), (c), range_table, count); \ } \ while (0) /* If DEBUG is defined, Regex prints many voluminous messages about what it is doing (if the variable `debug' is nonzero). If linked with the main program in `iregex.c', you can enter patterns and strings interactively. And if linked with the main program in `main.c' and the other test files, you can run the already-written tests. */ #ifdef DEBUG /* We use standard I/O for debugging. */ # include /* It is useful to test things that ``must'' be true when debugging. */ # include static int debug = -100000; # define DEBUG_STATEMENT(e) e # define DEBUG_PRINT1(x) if (debug > 0) printf (x) # define DEBUG_PRINT2(x1, x2) if (debug > 0) printf (x1, x2) # define DEBUG_PRINT3(x1, x2, x3) if (debug > 0) printf (x1, x2, x3) # define DEBUG_PRINT4(x1, x2, x3, x4) if (debug > 0) printf (x1, x2, x3, x4) # define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ if (debug > 0) print_partial_compiled_pattern (s, e) # define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ if (debug > 0) print_double_string (w, s1, sz1, s2, sz2) /* Print the fastmap in human-readable form. */ void print_fastmap (fastmap) char *fastmap; { unsigned was_a_range = 0; unsigned i = 0; while (i < (1 << BYTEWIDTH)) { if (fastmap[i++]) { was_a_range = 0; putchar (i - 1); while (i < (1 << BYTEWIDTH) && fastmap[i]) { was_a_range = 1; i++; } if (was_a_range) { printf ("-"); putchar (i - 1); } } } putchar ('\n'); } /* Print a compiled pattern string in human-readable form, starting at the START pointer into it and ending just before the pointer END. */ void print_partial_compiled_pattern (start, end) re_char *start; re_char *end; { int mcnt, mcnt2; re_char *p = start; re_char *pend = end; if (start == NULL) { printf ("(null)\n"); return; } /* Loop over pattern commands. */ while (p < pend) { printf ("%d:\t", p - start); switch ((re_opcode_t) *p++) { case no_op: printf ("/no_op"); break; case succeed: printf ("/succeed"); break; case exactn: mcnt = *p++; printf ("/exactn/%d", mcnt); do { putchar ('/'); putchar (*p++); } while (--mcnt); break; case start_memory: printf ("/start_memory/%d", *p++); break; case stop_memory: printf ("/stop_memory/%d", *p++); break; case duplicate: printf ("/duplicate/%d", *p++); break; case anychar: printf ("/anychar"); break; case charset: case charset_not: { register int c, last = -100; register int in_range = 0; int length = CHARSET_BITMAP_SIZE (p - 1); int has_range_table = CHARSET_RANGE_TABLE_EXISTS_P (p - 1); printf ("/charset [%s", (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); assert (p + *p < pend); for (c = 0; c < 256; c++) if (c / 8 < length && (p[1 + (c/8)] & (1 << (c % 8)))) { /* Are we starting a range? */ if (last + 1 == c && ! in_range) { putchar ('-'); in_range = 1; } /* Have we broken a range? */ else if (last + 1 != c && in_range) { putchar (last); in_range = 0; } if (! in_range) putchar (c); last = c; } if (in_range) putchar (last); putchar (']'); p += 1 + length; if (has_range_table) { int count; printf ("has-range-table"); /* ??? Should print the range table; for now, just skip it. */ p += 2; /* skip range table bits */ EXTRACT_NUMBER_AND_INCR (count, p); p = CHARSET_RANGE_TABLE_END (p, count); } } break; case begline: printf ("/begline"); break; case endline: printf ("/endline"); break; case on_failure_jump: extract_number_and_incr (&mcnt, &p); printf ("/on_failure_jump to %d", p + mcnt - start); break; case on_failure_keep_string_jump: extract_number_and_incr (&mcnt, &p); printf ("/on_failure_keep_string_jump to %d", p + mcnt - start); break; case on_failure_jump_nastyloop: extract_number_and_incr (&mcnt, &p); printf ("/on_failure_jump_nastyloop to %d", p + mcnt - start); break; case on_failure_jump_loop: extract_number_and_incr (&mcnt, &p); printf ("/on_failure_jump_loop to %d", p + mcnt - start); break; case on_failure_jump_smart: extract_number_and_incr (&mcnt, &p); printf ("/on_failure_jump_smart to %d", p + mcnt - start); break; case jump: extract_number_and_incr (&mcnt, &p); printf ("/jump to %d", p + mcnt - start); break; case succeed_n: extract_number_and_incr (&mcnt, &p); extract_number_and_incr (&mcnt2, &p); printf ("/succeed_n to %d, %d times", p - 2 + mcnt - start, mcnt2); break; case jump_n: extract_number_and_incr (&mcnt, &p); extract_number_and_incr (&mcnt2, &p); printf ("/jump_n to %d, %d times", p - 2 + mcnt - start, mcnt2); break; case set_number_at: extract_number_and_incr (&mcnt, &p); extract_number_and_incr (&mcnt2, &p); printf ("/set_number_at location %d to %d", p - 2 + mcnt - start, mcnt2); break; case wordbound: printf ("/wordbound"); break; case notwordbound: printf ("/notwordbound"); break; case wordbeg: printf ("/wordbeg"); break; case wordend: printf ("/wordend"); case syntaxspec: printf ("/syntaxspec"); mcnt = *p++; printf ("/%d", mcnt); break; case notsyntaxspec: printf ("/notsyntaxspec"); mcnt = *p++; printf ("/%d", mcnt); break; # ifdef emacs case before_dot: printf ("/before_dot"); break; case at_dot: printf ("/at_dot"); break; case after_dot: printf ("/after_dot"); break; case categoryspec: printf ("/categoryspec"); mcnt = *p++; printf ("/%d", mcnt); break; case notcategoryspec: printf ("/notcategoryspec"); mcnt = *p++; printf ("/%d", mcnt); break; # endif /* emacs */ case begbuf: printf ("/begbuf"); break; case endbuf: printf ("/endbuf"); break; default: printf ("?%d", *(p-1)); } putchar ('\n'); } printf ("%d:\tend of pattern.\n", p - start); } void print_compiled_pattern (bufp) struct re_pattern_buffer *bufp; { re_char *buffer = bufp->buffer; print_partial_compiled_pattern (buffer, buffer + bufp->used); printf ("%ld bytes used/%ld bytes allocated.\n", bufp->used, bufp->allocated); if (bufp->fastmap_accurate && bufp->fastmap) { printf ("fastmap: "); print_fastmap (bufp->fastmap); } printf ("re_nsub: %d\t", bufp->re_nsub); printf ("regs_alloc: %d\t", bufp->regs_allocated); printf ("can_be_null: %d\t", bufp->can_be_null); printf ("no_sub: %d\t", bufp->no_sub); printf ("not_bol: %d\t", bufp->not_bol); printf ("not_eol: %d\t", bufp->not_eol); printf ("syntax: %lx\n", bufp->syntax); fflush (stdout); /* Perhaps we should print the translate table? */ } void print_double_string (where, string1, size1, string2, size2) re_char *where; re_char *string1; re_char *string2; int size1; int size2; { int this_char; if (where == NULL) printf ("(null)"); else { if (FIRST_STRING_P (where)) { for (this_char = where - string1; this_char < size1; this_char++) putchar (string1[this_char]); where = string2; } for (this_char = where - string2; this_char < size2; this_char++) putchar (string2[this_char]); } } #else /* not DEBUG */ # undef assert # define assert(e) # define DEBUG_STATEMENT(e) # define DEBUG_PRINT1(x) # define DEBUG_PRINT2(x1, x2) # define DEBUG_PRINT3(x1, x2, x3) # define DEBUG_PRINT4(x1, x2, x3, x4) # define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) # define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) #endif /* not DEBUG */ /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can also be assigned to arbitrarily: each pattern buffer stores its own syntax, so it can be changed between regex compilations. */ /* This has no initializer because initialized variables in Emacs become read-only after dumping. */ reg_syntax_t re_syntax_options; /* Specify the precise syntax of regexps for compilation. This provides for compatibility for various utilities which historically have different, incompatible syntaxes. The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ reg_syntax_t re_set_syntax (syntax) reg_syntax_t syntax; { reg_syntax_t ret = re_syntax_options; re_syntax_options = syntax; return ret; } WEAK_ALIAS (__re_set_syntax, re_set_syntax) /* This table gives an error message for each of the error codes listed in regex.h. Obviously the order here has to be same as there. POSIX doesn't require that we do anything for REG_NOERROR, but why not be nice? */ static const char *re_error_msgid[] = { gettext_noop ("Success"), /* REG_NOERROR */ gettext_noop ("No match"), /* REG_NOMATCH */ gettext_noop ("Invalid regular expression"), /* REG_BADPAT */ gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ gettext_noop ("Invalid character class name"), /* REG_ECTYPE */ gettext_noop ("Trailing backslash"), /* REG_EESCAPE */ gettext_noop ("Invalid back reference"), /* REG_ESUBREG */ gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */ gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */ gettext_noop ("Unmatched \\{"), /* REG_EBRACE */ gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */ gettext_noop ("Invalid range end"), /* REG_ERANGE */ gettext_noop ("Memory exhausted"), /* REG_ESPACE */ gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */ gettext_noop ("Premature end of regular expression"), /* REG_EEND */ gettext_noop ("Regular expression too big"), /* REG_ESIZE */ gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */ }; /* Avoiding alloca during matching, to placate r_alloc. */ /* Define MATCH_MAY_ALLOCATE unless we need to make sure that the searching and matching functions should not call alloca. On some systems, alloca is implemented in terms of malloc, and if we're using the relocating allocator routines, then malloc could cause a relocation, which might (if the strings being searched are in the ralloc heap) shift the data out from underneath the regexp routines. Here's another reason to avoid allocation: Emacs processes input from X in a signal handler; processing X input may call malloc; if input arrives while a matching routine is calling malloc, then we're scrod. But Emacs can't just block input while calling matching routines; then we don't notice interrupts when they come in. So, Emacs blocks input around all regexp calls except the matching calls, which it leaves unprotected, in the faith that they will not malloc. */ /* Normally, this is fine. */ #define MATCH_MAY_ALLOCATE /* When using GNU C, we are not REALLY using the C alloca, no matter what config.h may say. So don't take precautions for it. */ #ifdef __GNUC__ # undef C_ALLOCA #endif /* The match routines may not allocate if (1) they would do it with malloc and (2) it's not safe for them to use malloc. Note that if REL_ALLOC is defined, matching would not use malloc for the failure stack, but we would still use it for the register vectors; so REL_ALLOC should not affect this. */ #if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs # undef MATCH_MAY_ALLOCATE #endif /* Failure stack declarations and macros; both re_compile_fastmap and re_match_2 use a failure stack. These have to be macros because of REGEX_ALLOCATE_STACK. */ /* Approximate number of failure points for which to initially allocate space when matching. If this number is exceeded, we allocate more space, so it is not a hard limit. */ #ifndef INIT_FAILURE_ALLOC # define INIT_FAILURE_ALLOC 20 #endif /* Roughly the maximum number of failure points on the stack. Would be exactly that if always used TYPICAL_FAILURE_SIZE items each time we failed. This is a variable only so users of regex can assign to it; we never change it ourselves. We always multiply it by TYPICAL_FAILURE_SIZE before using it, so it should probably be a byte-count instead. */ # if defined MATCH_MAY_ALLOCATE /* Note that 4400 was enough to cause a crash on Alpha OSF/1, whose default stack limit is 2mb. In order for a larger value to work reliably, you have to try to make it accord with the process stack limit. */ size_t re_max_failures = 40000; # else size_t re_max_failures = 4000; # endif union fail_stack_elt { re_char *pointer; /* This should be the biggest `int' that's no bigger than a pointer. */ long integer; }; typedef union fail_stack_elt fail_stack_elt_t; typedef struct { fail_stack_elt_t *stack; size_t size; size_t avail; /* Offset of next open position. */ size_t frame; /* Offset of the cur constructed frame. */ } fail_stack_type; #define FAIL_STACK_EMPTY() (fail_stack.frame == 0) #define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) /* Define macros to initialize and free the failure stack. Do `return -2' if the alloc fails. */ #ifdef MATCH_MAY_ALLOCATE # define INIT_FAIL_STACK() \ do { \ fail_stack.stack = (fail_stack_elt_t *) \ REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * TYPICAL_FAILURE_SIZE \ * sizeof (fail_stack_elt_t)); \ \ if (fail_stack.stack == NULL) \ return -2; \ \ fail_stack.size = INIT_FAILURE_ALLOC; \ fail_stack.avail = 0; \ fail_stack.frame = 0; \ } while (0) # define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) #else # define INIT_FAIL_STACK() \ do { \ fail_stack.avail = 0; \ fail_stack.frame = 0; \ } while (0) # define RESET_FAIL_STACK() ((void)0) #endif /* Double the size of FAIL_STACK, up to a limit which allows approximately `re_max_failures' items. Return 1 if succeeds, and 0 if either ran out of memory allocating space for it or it was already too large. REGEX_REALLOCATE_STACK requires `destination' be declared. */ /* Factor to increase the failure stack size by when we increase it. This used to be 2, but 2 was too wasteful because the old discarded stacks added up to as much space were as ultimate, maximum-size stack. */ #define FAIL_STACK_GROWTH_FACTOR 4 #define GROW_FAIL_STACK(fail_stack) \ (((fail_stack).size * sizeof (fail_stack_elt_t) \ >= re_max_failures * TYPICAL_FAILURE_SIZE) \ ? 0 \ : ((fail_stack).stack \ = (fail_stack_elt_t *) \ REGEX_REALLOCATE_STACK ((fail_stack).stack, \ (fail_stack).size * sizeof (fail_stack_elt_t), \ MIN (re_max_failures * TYPICAL_FAILURE_SIZE, \ ((fail_stack).size * sizeof (fail_stack_elt_t) \ * FAIL_STACK_GROWTH_FACTOR))), \ \ (fail_stack).stack == NULL \ ? 0 \ : ((fail_stack).size \ = (MIN (re_max_failures * TYPICAL_FAILURE_SIZE, \ ((fail_stack).size * sizeof (fail_stack_elt_t) \ * FAIL_STACK_GROWTH_FACTOR)) \ / sizeof (fail_stack_elt_t)), \ 1))) /* Push a pointer value onto the failure stack. Assumes the variable `fail_stack'. Probably should only be called from within `PUSH_FAILURE_POINT'. */ #define PUSH_FAILURE_POINTER(item) \ fail_stack.stack[fail_stack.avail++].pointer = (item) /* This pushes an integer-valued item onto the failure stack. Assumes the variable `fail_stack'. Probably should only be called from within `PUSH_FAILURE_POINT'. */ #define PUSH_FAILURE_INT(item) \ fail_stack.stack[fail_stack.avail++].integer = (item) /* Push a fail_stack_elt_t value onto the failure stack. Assumes the variable `fail_stack'. Probably should only be called from within `PUSH_FAILURE_POINT'. */ #define PUSH_FAILURE_ELT(item) \ fail_stack.stack[fail_stack.avail++] = (item) /* These three POP... operations complement the three PUSH... operations. All assume that `fail_stack' is nonempty. */ #define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer #define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer #define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] /* Individual items aside from the registers. */ #define NUM_NONREG_ITEMS 3 /* Used to examine the stack (to detect infinite loops). */ #define FAILURE_PAT(h) fail_stack.stack[(h) - 1].pointer #define FAILURE_STR(h) (fail_stack.stack[(h) - 2].pointer) #define NEXT_FAILURE_HANDLE(h) fail_stack.stack[(h) - 3].integer #define TOP_FAILURE_HANDLE() fail_stack.frame #define ENSURE_FAIL_STACK(space) \ while (REMAINING_AVAIL_SLOTS <= space) { \ if (!GROW_FAIL_STACK (fail_stack)) \ return -2; \ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", (fail_stack).size);\ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ } /* Push register NUM onto the stack. */ #define PUSH_FAILURE_REG(num) \ do { \ char *destination; \ ENSURE_FAIL_STACK(3); \ DEBUG_PRINT4 (" Push reg %d (spanning %p -> %p)\n", \ num, regstart[num], regend[num]); \ PUSH_FAILURE_POINTER (regstart[num]); \ PUSH_FAILURE_POINTER (regend[num]); \ PUSH_FAILURE_INT (num); \ } while (0) /* Change the counter's value to VAL, but make sure that it will be reset when backtracking. */ #define PUSH_NUMBER(ptr,val) \ do { \ char *destination; \ int c; \ ENSURE_FAIL_STACK(3); \ EXTRACT_NUMBER (c, ptr); \ DEBUG_PRINT4 (" Push number %p = %d -> %d\n", ptr, c, val); \ PUSH_FAILURE_INT (c); \ PUSH_FAILURE_POINTER (ptr); \ PUSH_FAILURE_INT (-1); \ STORE_NUMBER (ptr, val); \ } while (0) /* Pop a saved register off the stack. */ #define POP_FAILURE_REG_OR_COUNT() \ do { \ int reg = POP_FAILURE_INT (); \ if (reg == -1) \ { \ /* It's a counter. */ \ /* Here, we discard `const', making re_match non-reentrant. */ \ unsigned char *ptr = (unsigned char*) POP_FAILURE_POINTER (); \ reg = POP_FAILURE_INT (); \ STORE_NUMBER (ptr, reg); \ DEBUG_PRINT3 (" Pop counter %p = %d\n", ptr, reg); \ } \ else \ { \ regend[reg] = POP_FAILURE_POINTER (); \ regstart[reg] = POP_FAILURE_POINTER (); \ DEBUG_PRINT4 (" Pop reg %d (spanning %p -> %p)\n", \ reg, regstart[reg], regend[reg]); \ } \ } while (0) /* Check that we are not stuck in an infinite loop. */ #define CHECK_INFINITE_LOOP(pat_cur, string_place) \ do { \ int failure = TOP_FAILURE_HANDLE(); \ /* Check for infinite matching loops */ \ while (failure > 0 && \ (FAILURE_STR (failure) == string_place \ || FAILURE_STR (failure) == NULL)) \ { \ assert (FAILURE_PAT (failure) >= bufp->buffer \ && FAILURE_PAT (failure) <= bufp->buffer + bufp->used); \ if (FAILURE_PAT (failure) == pat_cur) \ goto fail; \ DEBUG_PRINT2 (" Other pattern: %p\n", FAILURE_PAT (failure)); \ failure = NEXT_FAILURE_HANDLE(failure); \ } \ DEBUG_PRINT2 (" Other string: %p\n", FAILURE_STR (failure)); \ } while (0) /* Push the information about the state we will need if we ever fail back to it. Requires variables fail_stack, regstart, regend and num_regs be declared. GROW_FAIL_STACK requires `destination' be declared. Does `return FAILURE_CODE' if runs out of memory. */ #define PUSH_FAILURE_POINT(pattern, string_place) \ do { \ char *destination; \ /* Must be int, so when we don't save any registers, the arithmetic \ of 0 + -1 isn't done as unsigned. */ \ \ DEBUG_STATEMENT (nfailure_points_pushed++); \ DEBUG_PRINT1 ("\nPUSH_FAILURE_POINT:\n"); \ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail); \ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ \ ENSURE_FAIL_STACK (NUM_NONREG_ITEMS); \ \ DEBUG_PRINT1 ("\n"); \ \ DEBUG_PRINT2 (" Push frame index: %d\n", fail_stack.frame); \ PUSH_FAILURE_INT (fail_stack.frame); \ \ DEBUG_PRINT2 (" Push string %p: `", string_place); \ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, size2);\ DEBUG_PRINT1 ("'\n"); \ PUSH_FAILURE_POINTER (string_place); \ \ DEBUG_PRINT2 (" Push pattern %p: ", pattern); \ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern, pend); \ PUSH_FAILURE_POINTER (pattern); \ \ /* Close the frame by moving the frame pointer past it. */ \ fail_stack.frame = fail_stack.avail; \ } while (0) /* Estimate the size of data pushed by a typical failure stack entry. An estimate is all we need, because all we use this for is to choose a limit for how big to make the failure stack. */ /* BEWARE, the value `20' is hard-coded in emacs.c:main(). */ #define TYPICAL_FAILURE_SIZE 20 /* How many items can still be added to the stack without overflowing it. */ #define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) /* Pops what PUSH_FAIL_STACK pushes. We restore into the parameters, all of which should be lvalues: STR -- the saved data position. PAT -- the saved pattern position. REGSTART, REGEND -- arrays of string positions. Also assumes the variables `fail_stack' and (if debugging), `bufp', `pend', `string1', `size1', `string2', and `size2'. */ #define POP_FAILURE_POINT(str, pat) \ do { \ assert (!FAIL_STACK_EMPTY ()); \ \ /* Remove failure points and point to how many regs pushed. */ \ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ \ /* Pop the saved registers. */ \ while (fail_stack.frame < fail_stack.avail) \ POP_FAILURE_REG_OR_COUNT (); \ \ pat = POP_FAILURE_POINTER (); \ DEBUG_PRINT2 (" Popping pattern %p: ", pat); \ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ \ /* If the saved string location is NULL, it came from an \ on_failure_keep_string_jump opcode, and we want to throw away the \ saved NULL, thus retaining our current position in the string. */ \ str = POP_FAILURE_POINTER (); \ DEBUG_PRINT2 (" Popping string %p: `", str); \ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ DEBUG_PRINT1 ("'\n"); \ \ fail_stack.frame = POP_FAILURE_INT (); \ DEBUG_PRINT2 (" Popping frame index: %d\n", fail_stack.frame); \ \ assert (fail_stack.avail >= 0); \ assert (fail_stack.frame <= fail_stack.avail); \ \ DEBUG_STATEMENT (nfailure_points_popped++); \ } while (0) /* POP_FAILURE_POINT */ /* Registers are set to a sentinel when they haven't yet matched. */ #define REG_UNSET(e) ((e) == NULL) /* Subroutine declarations and macros for regex_compile. */ static reg_errcode_t regex_compile _RE_ARGS ((re_char *pattern, size_t size, reg_syntax_t syntax, struct re_pattern_buffer *bufp)); static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg)); static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg1, int arg2)); static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg, unsigned char *end)); static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg1, int arg2, unsigned char *end)); static boolean at_begline_loc_p _RE_ARGS ((re_char *pattern, re_char *p, reg_syntax_t syntax)); static boolean at_endline_loc_p _RE_ARGS ((re_char *p, re_char *pend, reg_syntax_t syntax)); static re_char *skip_one_char _RE_ARGS ((re_char *p)); static int analyse_first _RE_ARGS ((re_char *p, re_char *pend, char *fastmap, const int multibyte)); /* Fetch the next character in the uncompiled pattern---translating it if necessary. */ #define PATFETCH(c) \ do { \ PATFETCH_RAW (c); \ c = TRANSLATE (c); \ } while (0) /* Fetch the next character in the uncompiled pattern, with no translation. */ #define PATFETCH_RAW(c) \ do { \ int len; \ if (p == pend) return REG_EEND; \ c = RE_STRING_CHAR_AND_LENGTH (p, pend - p, len); \ p += len; \ } while (0) /* If `translate' is non-null, return translate[D], else just D. We cast the subscript to translate because some data is declared as `char *', to avoid warnings when a string constant is passed. But when we use a character as a subscript we must make it unsigned. */ #ifndef TRANSLATE # define TRANSLATE(d) \ (RE_TRANSLATE_P (translate) ? RE_TRANSLATE (translate, (d)) : (d)) #endif /* Macros for outputting the compiled pattern into `buffer'. */ /* If the buffer isn't allocated when it comes in, use this. */ #define INIT_BUF_SIZE 32 /* Make sure we have at least N more bytes of space in buffer. */ #define GET_BUFFER_SPACE(n) \ while ((size_t) (b - bufp->buffer + (n)) > bufp->allocated) \ EXTEND_BUFFER () /* Make sure we have one more byte of buffer space and then add C to it. */ #define BUF_PUSH(c) \ do { \ GET_BUFFER_SPACE (1); \ *b++ = (unsigned char) (c); \ } while (0) /* Ensure we have two more bytes of buffer space and then append C1 and C2. */ #define BUF_PUSH_2(c1, c2) \ do { \ GET_BUFFER_SPACE (2); \ *b++ = (unsigned char) (c1); \ *b++ = (unsigned char) (c2); \ } while (0) /* As with BUF_PUSH_2, except for three bytes. */ #define BUF_PUSH_3(c1, c2, c3) \ do { \ GET_BUFFER_SPACE (3); \ *b++ = (unsigned char) (c1); \ *b++ = (unsigned char) (c2); \ *b++ = (unsigned char) (c3); \ } while (0) /* Store a jump with opcode OP at LOC to location TO. We store a relative address offset by the three bytes the jump itself occupies. */ #define STORE_JUMP(op, loc, to) \ store_op1 (op, loc, (to) - (loc) - 3) /* Likewise, for a two-argument jump. */ #define STORE_JUMP2(op, loc, to, arg) \ store_op2 (op, loc, (to) - (loc) - 3, arg) /* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ #define INSERT_JUMP(op, loc, to) \ insert_op1 (op, loc, (to) - (loc) - 3, b) /* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ #define INSERT_JUMP2(op, loc, to, arg) \ insert_op2 (op, loc, (to) - (loc) - 3, arg, b) /* This is not an arbitrary limit: the arguments which represent offsets into the pattern are two bytes long. So if 2^16 bytes turns out to be too small, many things would have to change. */ /* Any other compiler which, like MSC, has allocation limit below 2^16 bytes will have to use approach similar to what was done below for MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up reallocating to 0 bytes. Such thing is not going to work too well. You have been warned!! */ #if defined _MSC_VER && !defined WIN32 /* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. */ # define MAX_BUF_SIZE 65500L #else # define MAX_BUF_SIZE (1L << 16) #endif /* Extend the buffer by twice its current size via realloc and reset the pointers that pointed into the old block to point to the correct places in the new one. If extending the buffer results in it being larger than MAX_BUF_SIZE, then flag memory exhausted. */ #if __BOUNDED_POINTERS__ # define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated) # define MOVE_BUFFER_POINTER(P) \ (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr) # define ELSE_EXTEND_BUFFER_HIGH_BOUND \ else \ { \ SET_HIGH_BOUND (b); \ SET_HIGH_BOUND (begalt); \ if (fixup_alt_jump) \ SET_HIGH_BOUND (fixup_alt_jump); \ if (laststart) \ SET_HIGH_BOUND (laststart); \ if (pending_exact) \ SET_HIGH_BOUND (pending_exact); \ } #else # define MOVE_BUFFER_POINTER(P) (P) += incr # define ELSE_EXTEND_BUFFER_HIGH_BOUND #endif #define EXTEND_BUFFER() \ do { \ re_char *old_buffer = bufp->buffer; \ if (bufp->allocated == MAX_BUF_SIZE) \ return REG_ESIZE; \ bufp->allocated <<= 1; \ if (bufp->allocated > MAX_BUF_SIZE) \ bufp->allocated = MAX_BUF_SIZE; \ RETALLOC (bufp->buffer, bufp->allocated, unsigned char); \ if (bufp->buffer == NULL) \ return REG_ESPACE; \ /* If the buffer moved, move all the pointers into it. */ \ if (old_buffer != bufp->buffer) \ { \ int incr = bufp->buffer - old_buffer; \ MOVE_BUFFER_POINTER (b); \ MOVE_BUFFER_POINTER (begalt); \ if (fixup_alt_jump) \ MOVE_BUFFER_POINTER (fixup_alt_jump); \ if (laststart) \ MOVE_BUFFER_POINTER (laststart); \ if (pending_exact) \ MOVE_BUFFER_POINTER (pending_exact); \ } \ ELSE_EXTEND_BUFFER_HIGH_BOUND \ } while (0) /* Since we have one byte reserved for the register number argument to {start,stop}_memory, the maximum number of groups we can report things about is what fits in that byte. */ #define MAX_REGNUM 255 /* But patterns can have more than `MAX_REGNUM' registers. We just ignore the excess. */ typedef unsigned regnum_t; /* Macros for the compile stack. */ /* Since offsets can go either forwards or backwards, this type needs to be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ /* int may be not enough when sizeof(int) == 2. */ typedef long pattern_offset_t; typedef struct { pattern_offset_t begalt_offset; pattern_offset_t fixup_alt_jump; pattern_offset_t laststart_offset; regnum_t regnum; } compile_stack_elt_t; typedef struct { compile_stack_elt_t *stack; unsigned size; unsigned avail; /* Offset of next open position. */ } compile_stack_type; #define INIT_COMPILE_STACK_SIZE 32 #define COMPILE_STACK_EMPTY (compile_stack.avail == 0) #define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) /* The next available element. */ #define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) /* Structure to manage work area for range table. */ struct range_table_work_area { int *table; /* actual work area. */ int allocated; /* allocated size for work area in bytes. */ int used; /* actually used size in words. */ int bits; /* flag to record character classes */ }; /* Make sure that WORK_AREA can hold more N multibyte characters. */ #define EXTEND_RANGE_TABLE_WORK_AREA(work_area, n) \ do { \ if (((work_area).used + (n)) * sizeof (int) > (work_area).allocated) \ { \ (work_area).allocated += 16 * sizeof (int); \ if ((work_area).table) \ (work_area).table \ = (int *) realloc ((work_area).table, (work_area).allocated); \ else \ (work_area).table \ = (int *) malloc ((work_area).allocated); \ if ((work_area).table == 0) \ FREE_STACK_RETURN (REG_ESPACE); \ } \ } while (0) #define SET_RANGE_TABLE_WORK_AREA_BIT(work_area, bit) \ (work_area).bits |= (bit) /* Bits used to implement the multibyte-part of the various character classes such as [:alnum:] in a charset's range table. */ #define BIT_WORD 0x1 #define BIT_LOWER 0x2 #define BIT_PUNCT 0x4 #define BIT_SPACE 0x8 #define BIT_UPPER 0x10 #define BIT_MULTIBYTE 0x20 /* Set a range (RANGE_START, RANGE_END) to WORK_AREA. */ #define SET_RANGE_TABLE_WORK_AREA(work_area, range_start, range_end) \ do { \ EXTEND_RANGE_TABLE_WORK_AREA ((work_area), 2); \ (work_area).table[(work_area).used++] = (range_start); \ (work_area).table[(work_area).used++] = (range_end); \ } while (0) /* Free allocated memory for WORK_AREA. */ #define FREE_RANGE_TABLE_WORK_AREA(work_area) \ do { \ if ((work_area).table) \ free ((work_area).table); \ } while (0) #define CLEAR_RANGE_TABLE_WORK_USED(work_area) ((work_area).used = 0, (work_area).bits = 0) #define RANGE_TABLE_WORK_USED(work_area) ((work_area).used) #define RANGE_TABLE_WORK_BITS(work_area) ((work_area).bits) #define RANGE_TABLE_WORK_ELT(work_area, i) ((work_area).table[i]) /* Set the bit for character C in a list. */ #define SET_LIST_BIT(c) (b[((c)) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH)) /* Get the next unsigned number in the uncompiled pattern. */ #define GET_UNSIGNED_NUMBER(num) \ do { if (p != pend) \ { \ PATFETCH (c); \ while ('0' <= c && c <= '9') \ { \ if (num < 0) \ num = 0; \ num = num * 10 + c - '0'; \ if (p == pend) \ break; \ PATFETCH (c); \ } \ } \ } while (0) #if WIDE_CHAR_SUPPORT /* The GNU C library provides support for user-defined character classes and the functions from ISO C amendement 1. */ # ifdef CHARCLASS_NAME_MAX # define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX # else /* This shouldn't happen but some implementation might still have this problem. Use a reasonable default value. */ # define CHAR_CLASS_MAX_LENGTH 256 # endif typedef wctype_t re_wctype_t; typedef wchar_t re_wchar_t; # define re_wctype wctype # define re_iswctype iswctype # define re_wctype_to_bit(cc) 0 #else # define CHAR_CLASS_MAX_LENGTH 9 /* Namely, `multibyte'. */ # define btowc(c) c /* Character classes. */ typedef enum { RECC_ERROR = 0, RECC_ALNUM, RECC_ALPHA, RECC_WORD, RECC_GRAPH, RECC_PRINT, RECC_LOWER, RECC_UPPER, RECC_PUNCT, RECC_CNTRL, RECC_DIGIT, RECC_XDIGIT, RECC_BLANK, RECC_SPACE, RECC_MULTIBYTE, RECC_NONASCII, RECC_ASCII, RECC_UNIBYTE } re_wctype_t; typedef int re_wchar_t; /* Map a string to the char class it names (if any). */ static re_wctype_t re_wctype (str) re_char *str; { const char *string = str; if (STREQ (string, "alnum")) return RECC_ALNUM; else if (STREQ (string, "alpha")) return RECC_ALPHA; else if (STREQ (string, "word")) return RECC_WORD; else if (STREQ (string, "ascii")) return RECC_ASCII; else if (STREQ (string, "nonascii")) return RECC_NONASCII; else if (STREQ (string, "graph")) return RECC_GRAPH; else if (STREQ (string, "lower")) return RECC_LOWER; else if (STREQ (string, "print")) return RECC_PRINT; else if (STREQ (string, "punct")) return RECC_PUNCT; else if (STREQ (string, "space")) return RECC_SPACE; else if (STREQ (string, "upper")) return RECC_UPPER; else if (STREQ (string, "unibyte")) return RECC_UNIBYTE; else if (STREQ (string, "multibyte")) return RECC_MULTIBYTE; else if (STREQ (string, "digit")) return RECC_DIGIT; else if (STREQ (string, "xdigit")) return RECC_XDIGIT; else if (STREQ (string, "cntrl")) return RECC_CNTRL; else if (STREQ (string, "blank")) return RECC_BLANK; else return 0; } /* True iff CH is in the char class CC. */ static boolean re_iswctype (ch, cc) int ch; re_wctype_t cc; { switch (cc) { case RECC_ALNUM: return ISALNUM (ch); case RECC_ALPHA: return ISALPHA (ch); case RECC_BLANK: return ISBLANK (ch); case RECC_CNTRL: return ISCNTRL (ch); case RECC_DIGIT: return ISDIGIT (ch); case RECC_GRAPH: return ISGRAPH (ch); case RECC_LOWER: return ISLOWER (ch); case RECC_PRINT: return ISPRINT (ch); case RECC_PUNCT: return ISPUNCT (ch); case RECC_SPACE: return ISSPACE (ch); case RECC_UPPER: return ISUPPER (ch); case RECC_XDIGIT: return ISXDIGIT (ch); case RECC_ASCII: return IS_REAL_ASCII (ch); case RECC_NONASCII: return !IS_REAL_ASCII (ch); case RECC_UNIBYTE: return ISUNIBYTE (ch); case RECC_MULTIBYTE: return !ISUNIBYTE (ch); case RECC_WORD: return ISWORD (ch); case RECC_ERROR: return false; default: abort(); } } /* Return a bit-pattern to use in the range-table bits to match multibyte chars of class CC. */ static int re_wctype_to_bit (cc) re_wctype_t cc; { switch (cc) { case RECC_NONASCII: case RECC_PRINT: case RECC_GRAPH: case RECC_MULTIBYTE: return BIT_MULTIBYTE; case RECC_ALPHA: case RECC_ALNUM: case RECC_WORD: return BIT_WORD; case RECC_LOWER: return BIT_LOWER; case RECC_UPPER: return BIT_UPPER; case RECC_PUNCT: return BIT_PUNCT; case RECC_SPACE: return BIT_SPACE; case RECC_ASCII: case RECC_DIGIT: case RECC_XDIGIT: case RECC_CNTRL: case RECC_BLANK: case RECC_UNIBYTE: case RECC_ERROR: return 0; default: abort(); } } #endif /* Explicit quit checking is only used on NTemacs. */ #if defined WINDOWSNT && defined emacs && defined QUIT extern int immediate_quit; # define IMMEDIATE_QUIT_CHECK \ do { \ if (immediate_quit) QUIT; \ } while (0) #else # define IMMEDIATE_QUIT_CHECK ((void)0) #endif #ifndef MATCH_MAY_ALLOCATE /* If we cannot allocate large objects within re_match_2_internal, we make the fail stack and register vectors global. The fail stack, we grow to the maximum size when a regexp is compiled. The register vectors, we adjust in size each time we compile a regexp, according to the number of registers it needs. */ static fail_stack_type fail_stack; /* Size with which the following vectors are currently allocated. That is so we can make them bigger as needed, but never make them smaller. */ static int regs_allocated_size; static re_char ** regstart, ** regend; static re_char **best_regstart, **best_regend; /* Make the register vectors big enough for NUM_REGS registers, but don't make them smaller. */ static regex_grow_registers (num_regs) int num_regs; { if (num_regs > regs_allocated_size) { RETALLOC_IF (regstart, num_regs, re_char *); RETALLOC_IF (regend, num_regs, re_char *); RETALLOC_IF (best_regstart, num_regs, re_char *); RETALLOC_IF (best_regend, num_regs, re_char *); regs_allocated_size = num_regs; } } #endif /* not MATCH_MAY_ALLOCATE */ static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type compile_stack, regnum_t regnum)); /* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. Returns one of error codes defined in `regex.h', or zero for success. Assumes the `allocated' (and perhaps `buffer') and `translate' fields are set in BUFP on entry. If it succeeds, results are put in BUFP (if it returns an error, the contents of BUFP are undefined): `buffer' is the compiled pattern; `syntax' is set to SYNTAX; `used' is set to the length of the compiled pattern; `fastmap_accurate' is zero; `re_nsub' is the number of subexpressions in PATTERN; `not_bol' and `not_eol' are zero; The `fastmap' field is neither examined nor set. */ /* Insert the `jump' from the end of last alternative to "here". The space for the jump has already been allocated. */ #define FIXUP_ALT_JUMP() \ do { \ if (fixup_alt_jump) \ STORE_JUMP (jump, fixup_alt_jump, b); \ } while (0) /* Return, freeing storage we allocated. */ #define FREE_STACK_RETURN(value) \ do { \ FREE_RANGE_TABLE_WORK_AREA (range_table_work); \ free (compile_stack.stack); \ return value; \ } while (0) static reg_errcode_t regex_compile (pattern, size, syntax, bufp) re_char *pattern; size_t size; reg_syntax_t syntax; struct re_pattern_buffer *bufp; { /* We fetch characters from PATTERN here. */ register re_wchar_t c, c1; /* A random temporary spot in PATTERN. */ re_char *p1; /* Points to the end of the buffer, where we should append. */ register unsigned char *b; /* Keeps track of unclosed groups. */ compile_stack_type compile_stack; /* Points to the current (ending) position in the pattern. */ #ifdef AIX /* `const' makes AIX compiler fail. */ unsigned char *p = pattern; #else re_char *p = pattern; #endif re_char *pend = pattern + size; /* How to translate the characters in the pattern. */ RE_TRANSLATE_TYPE translate = bufp->translate; /* Address of the count-byte of the most recently inserted `exactn' command. This makes it possible to tell if a new exact-match character can be added to that command or if the character requires a new `exactn' command. */ unsigned char *pending_exact = 0; /* Address of start of the most recently finished expression. This tells, e.g., postfix * where to find the start of its operand. Reset at the beginning of groups and alternatives. */ unsigned char *laststart = 0; /* Address of beginning of regexp, or inside of last group. */ unsigned char *begalt; /* Place in the uncompiled pattern (i.e., the {) to which to go back if the interval is invalid. */ re_char *beg_interval; /* Address of the place where a forward jump should go to the end of the containing expression. Each alternative of an `or' -- except the last -- ends with a forward jump of this sort. */ unsigned char *fixup_alt_jump = 0; /* Counts open-groups as they are encountered. Remembered for the matching close-group on the compile stack, so the same register number is put in the stop_memory as the start_memory. */ regnum_t regnum = 0; /* Work area for range table of charset. */ struct range_table_work_area range_table_work; /* If the object matched can contain multibyte characters. */ const boolean multibyte = RE_MULTIBYTE_P (bufp); #ifdef DEBUG debug++; DEBUG_PRINT1 ("\nCompiling pattern: "); if (debug > 0) { unsigned debug_count; for (debug_count = 0; debug_count < size; debug_count++) putchar (pattern[debug_count]); putchar ('\n'); } #endif /* DEBUG */ /* Initialize the compile stack. */ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); if (compile_stack.stack == NULL) return REG_ESPACE; compile_stack.size = INIT_COMPILE_STACK_SIZE; compile_stack.avail = 0; range_table_work.table = 0; range_table_work.allocated = 0; /* Initialize the pattern buffer. */ bufp->syntax = syntax; bufp->fastmap_accurate = 0; bufp->not_bol = bufp->not_eol = 0; /* Set `used' to zero, so that if we return an error, the pattern printer (for debugging) will think there's no pattern. We reset it at the end. */ bufp->used = 0; /* Always count groups, whether or not bufp->no_sub is set. */ bufp->re_nsub = 0; #if !defined emacs && !defined SYNTAX_TABLE /* Initialize the syntax table. */ init_syntax_once (); #endif if (bufp->allocated == 0) { if (bufp->buffer) { /* If zero allocated, but buffer is non-null, try to realloc enough space. This loses if buffer's address is bogus, but that is the user's responsibility. */ RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); } else { /* Caller did not allocate a buffer. Do it for them. */ bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); } if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE); bufp->allocated = INIT_BUF_SIZE; } begalt = b = bufp->buffer; /* Loop through the uncompiled pattern until we're at the end. */ while (p != pend) { PATFETCH (c); switch (c) { case '^': { if ( /* If at start of pattern, it's an operator. */ p == pattern + 1 /* If context independent, it's an operator. */ || syntax & RE_CONTEXT_INDEP_ANCHORS /* Otherwise, depends on what's come before. */ || at_begline_loc_p (pattern, p, syntax)) BUF_PUSH ((syntax & RE_NO_NEWLINE_ANCHOR) ? begbuf : begline); else goto normal_char; } break; case '$': { if ( /* If at end of pattern, it's an operator. */ p == pend /* If context independent, it's an operator. */ || syntax & RE_CONTEXT_INDEP_ANCHORS /* Otherwise, depends on what's next. */ || at_endline_loc_p (p, pend, syntax)) BUF_PUSH ((syntax & RE_NO_NEWLINE_ANCHOR) ? endbuf : endline); else goto normal_char; } break; case '+': case '?': if ((syntax & RE_BK_PLUS_QM) || (syntax & RE_LIMITED_OPS)) goto normal_char; handle_plus: case '*': /* If there is no previous pattern... */ if (!laststart) { if (syntax & RE_CONTEXT_INVALID_OPS) FREE_STACK_RETURN (REG_BADRPT); else if (!(syntax & RE_CONTEXT_INDEP_OPS)) goto normal_char; } { /* 1 means zero (many) matches is allowed. */ boolean zero_times_ok = 0, many_times_ok = 0; boolean greedy = 1; /* If there is a sequence of repetition chars, collapse it down to just one (the right one). We can't combine interval operators with these because of, e.g., `a{2}*', which should only match an even number of `a's. */ for (;;) { if ((syntax & RE_FRUGAL) && c == '?' && (zero_times_ok || many_times_ok)) greedy = 0; else { zero_times_ok |= c != '+'; many_times_ok |= c != '?'; } if (p == pend) break; else if (*p == '*' || (!(syntax & RE_BK_PLUS_QM) && (*p == '+' || *p == '?'))) ; else if (syntax & RE_BK_PLUS_QM && *p == '\\') { if (p+1 == pend) FREE_STACK_RETURN (REG_EESCAPE); if (p[1] == '+' || p[1] == '?') PATFETCH (c); /* Gobble up the backslash. */ else break; } else break; /* If we get here, we found another repeat character. */ PATFETCH (c); } /* Star, etc. applied to an empty pattern is equivalent to an empty pattern. */ if (!laststart || laststart == b) break; /* Now we know whether or not zero matches is allowed and also whether or not two or more matches is allowed. */ if (greedy) { if (many_times_ok) { boolean simple = skip_one_char (laststart) == b; unsigned int startoffset = 0; re_opcode_t ofj = /* Check if the loop can match the empty string. */ (simple || !analyse_first (laststart, b, NULL, 0)) ? on_failure_jump : on_failure_jump_loop; assert (skip_one_char (laststart) <= b); if (!zero_times_ok && simple) { /* Since simple * loops can be made faster by using on_failure_keep_string_jump, we turn simple P+ into PP* if P is simple. */ unsigned char *p1, *p2; startoffset = b - laststart; GET_BUFFER_SPACE (startoffset); p1 = b; p2 = laststart; while (p2 < p1) *b++ = *p2++; zero_times_ok = 1; } GET_BUFFER_SPACE (6); if (!zero_times_ok) /* A + loop. */ STORE_JUMP (ofj, b, b + 6); else /* Simple * loops can use on_failure_keep_string_jump depending on what follows. But since we don't know that yet, we leave the decision up to on_failure_jump_smart. */ INSERT_JUMP (simple ? on_failure_jump_smart : ofj, laststart + startoffset, b + 6); b += 3; STORE_JUMP (jump, b, laststart + startoffset); b += 3; } else { /* A simple ? pattern. */ assert (zero_times_ok); GET_BUFFER_SPACE (3); INSERT_JUMP (on_failure_jump, laststart, b + 3); b += 3; } } else /* not greedy */ { /* I wish the greedy and non-greedy cases could be merged. */ GET_BUFFER_SPACE (7); /* We might use less. */ if (many_times_ok) { boolean emptyp = analyse_first (laststart, b, NULL, 0); /* The non-greedy multiple match looks like a repeat..until: we only need a conditional jump at the end of the loop */ if (emptyp) BUF_PUSH (no_op); STORE_JUMP (emptyp ? on_failure_jump_nastyloop : on_failure_jump, b, laststart); b += 3; if (zero_times_ok) { /* The repeat...until naturally matches one or more. To also match zero times, we need to first jump to the end of the loop (its conditional jump). */ INSERT_JUMP (jump, laststart, b); b += 3; } } else { /* non-greedy a?? */ INSERT_JUMP (jump, laststart, b + 3); b += 3; INSERT_JUMP (on_failure_jump, laststart, laststart + 6); b += 3; } } } pending_exact = 0; break; case '.': laststart = b; BUF_PUSH (anychar); break; case '[': { CLEAR_RANGE_TABLE_WORK_USED (range_table_work); if (p == pend) FREE_STACK_RETURN (REG_EBRACK); /* Ensure that we have enough space to push a charset: the opcode, the length count, and the bitset; 34 bytes in all. */ GET_BUFFER_SPACE (34); laststart = b; /* We test `*p == '^' twice, instead of using an if statement, so we only need one BUF_PUSH. */ BUF_PUSH (*p == '^' ? charset_not : charset); if (*p == '^') p++; /* Remember the first position in the bracket expression. */ p1 = p; /* Push the number of bytes in the bitmap. */ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); /* Clear the whole map. */ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); /* charset_not matches newline according to a syntax bit. */ if ((re_opcode_t) b[-2] == charset_not && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) SET_LIST_BIT ('\n'); /* Read in characters and ranges, setting map bits. */ for (;;) { boolean escaped_char = false; const unsigned char *p2 = p; if (p == pend) FREE_STACK_RETURN (REG_EBRACK); PATFETCH (c); /* \ might escape characters inside [...] and [^...]. */ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') { if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); PATFETCH (c); escaped_char = true; } else { /* Could be the end of the bracket expression. If it's not (i.e., when the bracket expression is `[]' so far), the ']' character bit gets set way below. */ if (c == ']' && p2 != p1) break; } /* What should we do for the character which is greater than 0x7F, but not BASE_LEADING_CODE_P? XXX */ /* See if we're at the beginning of a possible character class. */ if (!escaped_char && syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') { /* Leave room for the null. */ unsigned char str[CHAR_CLASS_MAX_LENGTH + 1]; const unsigned char *class_beg; PATFETCH (c); c1 = 0; class_beg = p; /* If pattern is `[[:'. */ if (p == pend) FREE_STACK_RETURN (REG_EBRACK); for (;;) { PATFETCH (c); if ((c == ':' && *p == ']') || p == pend) break; if (c1 < CHAR_CLASS_MAX_LENGTH) str[c1++] = c; else /* This is in any case an invalid class name. */ str[0] = '\0'; } str[c1] = '\0'; /* If isn't a word bracketed by `[:' and `:]': undo the ending character, the letters, and leave the leading `:' and `[' (but set bits for them). */ if (c == ':' && *p == ']') { int ch; re_wctype_t cc; cc = re_wctype (str); if (cc == 0) FREE_STACK_RETURN (REG_ECTYPE); /* Throw away the ] at the end of the character class. */ PATFETCH (c); if (p == pend) FREE_STACK_RETURN (REG_EBRACK); /* Most character classes in a multibyte match just set a flag. Exceptions are is_blank, is_digit, is_cntrl, and is_xdigit, since they can only match ASCII characters. We don't need to handle them for multibyte. They are distinguished by a negative wctype. */ if (multibyte) SET_RANGE_TABLE_WORK_AREA_BIT (range_table_work, re_wctype_to_bit (cc)); for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) { int translated = TRANSLATE (ch); if (re_iswctype (btowc (ch), cc)) SET_LIST_BIT (translated); } /* Repeat the loop. */ continue; } else { /* Go back to right after the "[:". */ p = class_beg; SET_LIST_BIT ('['); /* Because the `:' may starts the range, we can't simply set bit and repeat the loop. Instead, just set it to C and handle below. */ c = ':'; } } if (p < pend && p[0] == '-' && p[1] != ']') { /* Discard the `-'. */ PATFETCH (c1); /* Fetch the character which ends the range. */ PATFETCH (c1); if (SINGLE_BYTE_CHAR_P (c)) { if (! SINGLE_BYTE_CHAR_P (c1)) { /* Handle a range starting with a character of less than 256, and ending with a character of not less than 256. Split that into two ranges, the low one ending at 0377, and the high one starting at the smallest character in the charset of C1 and ending at C1. */ int charset = CHAR_CHARSET (c1); int c2 = MAKE_CHAR (charset, 0, 0); SET_RANGE_TABLE_WORK_AREA (range_table_work, c2, c1); c1 = 0377; } } else if (!SAME_CHARSET_P (c, c1)) FREE_STACK_RETURN (REG_ERANGE); } else /* Range from C to C. */ c1 = c; /* Set the range ... */ if (SINGLE_BYTE_CHAR_P (c)) /* ... into bitmap. */ { re_wchar_t this_char; int range_start = c, range_end = c1; /* If the start is after the end, the range is empty. */ if (range_start > range_end) { if (syntax & RE_NO_EMPTY_RANGES) FREE_STACK_RETURN (REG_ERANGE); /* Else, repeat the loop. */ } else { for (this_char = range_start; this_char <= range_end; this_char++) SET_LIST_BIT (TRANSLATE (this_char)); } } else /* ... into range table. */ SET_RANGE_TABLE_WORK_AREA (range_table_work, c, c1); } /* Discard any (non)matching list bytes that are all 0 at the end of the map. Decrease the map-length byte too. */ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) b[-1]--; b += b[-1]; /* Build real range table from work area. */ if (RANGE_TABLE_WORK_USED (range_table_work) || RANGE_TABLE_WORK_BITS (range_table_work)) { int i; int used = RANGE_TABLE_WORK_USED (range_table_work); /* Allocate space for COUNT + RANGE_TABLE. Needs two bytes for flags, two for COUNT, and three bytes for each character. */ GET_BUFFER_SPACE (4 + used * 3); /* Indicate the existence of range table. */ laststart[1] |= 0x80; /* Store the character class flag bits into the range table. If not in emacs, these flag bits are always 0. */ *b++ = RANGE_TABLE_WORK_BITS (range_table_work) & 0xff; *b++ = RANGE_TABLE_WORK_BITS (range_table_work) >> 8; STORE_NUMBER_AND_INCR (b, used / 2); for (i = 0; i < used; i++) STORE_CHARACTER_AND_INCR (b, RANGE_TABLE_WORK_ELT (range_table_work, i)); } } break; case '(': if (syntax & RE_NO_BK_PARENS) goto handle_open; else goto normal_char; case ')': if (syntax & RE_NO_BK_PARENS) goto handle_close; else goto normal_char; case '\n': if (syntax & RE_NEWLINE_ALT) goto handle_alt; else goto normal_char; case '|': if (syntax & RE_NO_BK_VBAR) goto handle_alt; else goto normal_char; case '{': if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) goto handle_interval; else goto normal_char; case '\\': if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); /* Do not translate the character after the \, so that we can distinguish, e.g., \B from \b, even if we normally would translate, e.g., B to b. */ PATFETCH_RAW (c); switch (c) { case '(': if (syntax & RE_NO_BK_PARENS) goto normal_backslash; handle_open: { int shy = 0; if (p+1 < pend) { /* Look for a special (?...) construct */ if ((syntax & RE_SHY_GROUPS) && *p == '?') { PATFETCH (c); /* Gobble up the '?'. */ PATFETCH (c); switch (c) { case ':': shy = 1; break; default: /* Only (?:...) is supported right now. */ FREE_STACK_RETURN (REG_BADPAT); } } } if (!shy) { bufp->re_nsub++; regnum++; } if (COMPILE_STACK_FULL) { RETALLOC (compile_stack.stack, compile_stack.size << 1, compile_stack_elt_t); if (compile_stack.stack == NULL) return REG_ESPACE; compile_stack.size <<= 1; } /* These are the values to restore when we hit end of this group. They are all relative offsets, so that if the whole pattern moves because of realloc, they will still be valid. */ COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; COMPILE_STACK_TOP.fixup_alt_jump = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; COMPILE_STACK_TOP.regnum = shy ? -regnum : regnum; /* Do not push a start_memory for groups beyond the last one we can represent in the compiled pattern. */ if (regnum <= MAX_REGNUM && !shy) BUF_PUSH_2 (start_memory, regnum); compile_stack.avail++; fixup_alt_jump = 0; laststart = 0; begalt = b; /* If we've reached MAX_REGNUM groups, then this open won't actually generate any code, so we'll have to clear pending_exact explicitly. */ pending_exact = 0; break; } case ')': if (syntax & RE_NO_BK_PARENS) goto normal_backslash; if (COMPILE_STACK_EMPTY) { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_backslash; else FREE_STACK_RETURN (REG_ERPAREN); } handle_close: FIXUP_ALT_JUMP (); /* See similar code for backslashed left paren above. */ if (COMPILE_STACK_EMPTY) { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_char; else FREE_STACK_RETURN (REG_ERPAREN); } /* Since we just checked for an empty stack above, this ``can't happen''. */ assert (compile_stack.avail != 0); { /* We don't just want to restore into `regnum', because later groups should continue to be numbered higher, as in `(ab)c(de)' -- the second group is #2. */ regnum_t this_group_regnum; compile_stack.avail--; begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; fixup_alt_jump = COMPILE_STACK_TOP.fixup_alt_jump ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 : 0; laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; this_group_regnum = COMPILE_STACK_TOP.regnum; /* If we've reached MAX_REGNUM groups, then this open won't actually generate any code, so we'll have to clear pending_exact explicitly. */ pending_exact = 0; /* We're at the end of the group, so now we know how many groups were inside this one. */ if (this_group_regnum <= MAX_REGNUM && this_group_regnum > 0) BUF_PUSH_2 (stop_memory, this_group_regnum); } break; case '|': /* `\|'. */ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) goto normal_backslash; handle_alt: if (syntax & RE_LIMITED_OPS) goto normal_char; /* Insert before the previous alternative a jump which jumps to this alternative if the former fails. */ GET_BUFFER_SPACE (3); INSERT_JUMP (on_failure_jump, begalt, b + 6); pending_exact = 0; b += 3; /* The alternative before this one has a jump after it which gets executed if it gets matched. Adjust that jump so it will jump to this alternative's analogous jump (put in below, which in turn will jump to the next (if any) alternative's such jump, etc.). The last such jump jumps to the correct final destination. A picture: _____ _____ | | | | | v | v a | b | c If we are at `b', then fixup_alt_jump right now points to a three-byte space after `a'. We'll put in the jump, set fixup_alt_jump to right after `b', and leave behind three bytes which we'll fill in when we get to after `c'. */ FIXUP_ALT_JUMP (); /* Mark and leave space for a jump after this alternative, to be filled in later either by next alternative or when know we're at the end of a series of alternatives. */ fixup_alt_jump = b; GET_BUFFER_SPACE (3); b += 3; laststart = 0; begalt = b; break; case '{': /* If \{ is a literal. */ if (!(syntax & RE_INTERVALS) /* If we're at `\{' and it's not the open-interval operator. */ || (syntax & RE_NO_BK_BRACES)) goto normal_backslash; handle_interval: { /* If got here, then the syntax allows intervals. */ /* At least (most) this many matches must be made. */ int lower_bound = 0, upper_bound = -1; beg_interval = p; if (p == pend) FREE_STACK_RETURN (REG_EBRACE); GET_UNSIGNED_NUMBER (lower_bound); if (c == ',') GET_UNSIGNED_NUMBER (upper_bound); else /* Interval such as `{1}' => match exactly once. */ upper_bound = lower_bound; if (lower_bound < 0 || upper_bound > RE_DUP_MAX || (upper_bound >= 0 && lower_bound > upper_bound)) FREE_STACK_RETURN (REG_BADBR); if (!(syntax & RE_NO_BK_BRACES)) { if (c != '\\') FREE_STACK_RETURN (REG_BADBR); PATFETCH (c); } if (c != '}') FREE_STACK_RETURN (REG_BADBR); /* We just parsed a valid interval. */ /* If it's invalid to have no preceding re. */ if (!laststart) { if (syntax & RE_CONTEXT_INVALID_OPS) FREE_STACK_RETURN (REG_BADRPT); else if (syntax & RE_CONTEXT_INDEP_OPS) laststart = b; else goto unfetch_interval; } if (upper_bound == 0) /* If the upper bound is zero, just drop the sub pattern altogether. */ b = laststart; else if (lower_bound == 1 && upper_bound == 1) /* Just match it once: nothing to do here. */ ; /* Otherwise, we have a nontrivial interval. When we're all done, the pattern will look like: set_number_at set_number_at succeed_n jump_n (The upper bound and `jump_n' are omitted if `upper_bound' is 1, though.) */ else { /* If the upper bound is > 1, we need to insert more at the end of the loop. */ unsigned int nbytes = (upper_bound < 0 ? 3 : upper_bound > 1 ? 5 : 0); unsigned int startoffset = 0; GET_BUFFER_SPACE (20); /* We might use less. */ if (lower_bound == 0) { /* A succeed_n that starts with 0 is really a a simple on_failure_jump_loop. */ INSERT_JUMP (on_failure_jump_loop, laststart, b + 3 + nbytes); b += 3; } else { /* Initialize lower bound of the `succeed_n', even though it will be set during matching by its attendant `set_number_at' (inserted next), because `re_compile_fastmap' needs to know. Jump to the `jump_n' we might insert below. */ INSERT_JUMP2 (succeed_n, laststart, b + 5 + nbytes, lower_bound); b += 5; /* Code to initialize the lower bound. Insert before the `succeed_n'. The `5' is the last two bytes of this `set_number_at', plus 3 bytes of the following `succeed_n'. */ insert_op2 (set_number_at, laststart, 5, lower_bound, b); b += 5; startoffset += 5; } if (upper_bound < 0) { /* A negative upper bound stands for infinity, in which case it degenerates to a plain jump. */ STORE_JUMP (jump, b, laststart + startoffset); b += 3; } else if (upper_bound > 1) { /* More than one repetition is allowed, so append a backward jump to the `succeed_n' that starts this interval. When we've reached this during matching, we'll have matched the interval once, so jump back only `upper_bound - 1' times. */ STORE_JUMP2 (jump_n, b, laststart + startoffset, upper_bound - 1); b += 5; /* The location we want to set is the second parameter of the `jump_n'; that is `b-2' as an absolute address. `laststart' will be the `set_number_at' we're about to insert; `laststart+3' the number to set, the source for the relative address. But we are inserting into the middle of the pattern -- so everything is getting moved up by 5. Conclusion: (b - 2) - (laststart + 3) + 5, i.e., b - laststart. We insert this at the beginning of the loop so that if we fail during matching, we'll reinitialize the bounds. */ insert_op2 (set_number_at, laststart, b - laststart, upper_bound - 1, b); b += 5; } } pending_exact = 0; beg_interval = NULL; } break; unfetch_interval: /* If an invalid interval, match the characters as literals. */ assert (beg_interval); p = beg_interval; beg_interval = NULL; /* normal_char and normal_backslash need `c'. */ c = '{'; if (!(syntax & RE_NO_BK_BRACES)) { assert (p > pattern && p[-1] == '\\'); goto normal_backslash; } else goto normal_char; #ifdef emacs /* There is no way to specify the before_dot and after_dot operators. rms says this is ok. --karl */ case '=': BUF_PUSH (at_dot); break; case 's': laststart = b; PATFETCH (c); BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); break; case 'S': laststart = b; PATFETCH (c); BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); break; case 'c': laststart = b; PATFETCH_RAW (c); BUF_PUSH_2 (categoryspec, c); break; case 'C': laststart = b; PATFETCH_RAW (c); BUF_PUSH_2 (notcategoryspec, c); break; #endif /* emacs */ case 'w': if (syntax & RE_NO_GNU_OPS) goto normal_char; laststart = b; BUF_PUSH_2 (syntaxspec, Sword); break; case 'W': if (syntax & RE_NO_GNU_OPS) goto normal_char; laststart = b; BUF_PUSH_2 (notsyntaxspec, Sword); break; case '<': if (syntax & RE_NO_GNU_OPS) goto normal_char; BUF_PUSH (wordbeg); break; case '>': if (syntax & RE_NO_GNU_OPS) goto normal_char; BUF_PUSH (wordend); break; case 'b': if (syntax & RE_NO_GNU_OPS) goto normal_char; BUF_PUSH (wordbound); break; case 'B': if (syntax & RE_NO_GNU_OPS) goto normal_char; BUF_PUSH (notwordbound); break; case '`': if (syntax & RE_NO_GNU_OPS) goto normal_char; BUF_PUSH (begbuf); break; case '\'': if (syntax & RE_NO_GNU_OPS) goto normal_char; BUF_PUSH (endbuf); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { regnum_t reg; if (syntax & RE_NO_BK_REFS) goto normal_backslash; reg = c - '0'; /* Can't back reference to a subexpression before its end. */ if (reg > regnum || group_in_compile_stack (compile_stack, reg)) FREE_STACK_RETURN (REG_ESUBREG); laststart = b; BUF_PUSH_2 (duplicate, reg); } break; case '+': case '?': if (syntax & RE_BK_PLUS_QM) goto handle_plus; else goto normal_backslash; default: normal_backslash: /* You might think it would be useful for \ to mean not to translate; but if we don't translate it it will never match anything. */ c = TRANSLATE (c); goto normal_char; } break; default: /* Expects the character in `c'. */ normal_char: /* If no exactn currently being built. */ if (!pending_exact /* If last exactn not at current position. */ || pending_exact + *pending_exact + 1 != b /* We have only one byte following the exactn for the count. */ || *pending_exact >= (1 << BYTEWIDTH) - MAX_MULTIBYTE_LENGTH /* If followed by a repetition operator. */ || (p != pend && (*p == '*' || *p == '^')) || ((syntax & RE_BK_PLUS_QM) ? p + 1 < pend && *p == '\\' && (p[1] == '+' || p[1] == '?') : p != pend && (*p == '+' || *p == '?')) || ((syntax & RE_INTERVALS) && ((syntax & RE_NO_BK_BRACES) ? p != pend && *p == '{' : p + 1 < pend && p[0] == '\\' && p[1] == '{'))) { /* Start building a new exactn. */ laststart = b; BUF_PUSH_2 (exactn, 0); pending_exact = b - 1; } GET_BUFFER_SPACE (MAX_MULTIBYTE_LENGTH); { int len; if (multibyte) len = CHAR_STRING (c, b); else *b = c, len = 1; b += len; (*pending_exact) += len; } break; } /* switch (c) */ } /* while p != pend */ /* Through the pattern now. */ FIXUP_ALT_JUMP (); if (!COMPILE_STACK_EMPTY) FREE_STACK_RETURN (REG_EPAREN); /* If we don't want backtracking, force success the first time we reach the end of the compiled pattern. */ if (syntax & RE_NO_POSIX_BACKTRACKING) BUF_PUSH (succeed); free (compile_stack.stack); /* We have succeeded; set the length of the buffer. */ bufp->used = b - bufp->buffer; #ifdef DEBUG if (debug > 0) { re_compile_fastmap (bufp); DEBUG_PRINT1 ("\nCompiled pattern: \n"); print_compiled_pattern (bufp); } debug--; #endif /* DEBUG */ #ifndef MATCH_MAY_ALLOCATE /* Initialize the failure stack to the largest possible stack. This isn't necessary unless we're trying to avoid calling alloca in the search and match routines. */ { int num_regs = bufp->re_nsub + 1; if (fail_stack.size < re_max_failures * TYPICAL_FAILURE_SIZE) { fail_stack.size = re_max_failures * TYPICAL_FAILURE_SIZE; if (! fail_stack.stack) fail_stack.stack = (fail_stack_elt_t *) malloc (fail_stack.size * sizeof (fail_stack_elt_t)); else fail_stack.stack = (fail_stack_elt_t *) realloc (fail_stack.stack, (fail_stack.size * sizeof (fail_stack_elt_t))); } regex_grow_registers (num_regs); } #endif /* not MATCH_MAY_ALLOCATE */ return REG_NOERROR; } /* regex_compile */ /* Subroutines for `regex_compile'. */ /* Store OP at LOC followed by two-byte integer parameter ARG. */ static void store_op1 (op, loc, arg) re_opcode_t op; unsigned char *loc; int arg; { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg); } /* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ static void store_op2 (op, loc, arg1, arg2) re_opcode_t op; unsigned char *loc; int arg1, arg2; { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg1); STORE_NUMBER (loc + 3, arg2); } /* Copy the bytes from LOC to END to open up three bytes of space at LOC for OP followed by two-byte integer parameter ARG. */ static void insert_op1 (op, loc, arg, end) re_opcode_t op; unsigned char *loc; int arg; unsigned char *end; { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; while (pfrom != loc) *--pto = *--pfrom; store_op1 (op, loc, arg); } /* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ static void insert_op2 (op, loc, arg1, arg2, end) re_opcode_t op; unsigned char *loc; int arg1, arg2; unsigned char *end; { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; while (pfrom != loc) *--pto = *--pfrom; store_op2 (op, loc, arg1, arg2); } /* P points to just after a ^ in PATTERN. Return true if that ^ comes after an alternative or a begin-subexpression. We assume there is at least one character before the ^. */ static boolean at_begline_loc_p (pattern, p, syntax) re_char *pattern, *p; reg_syntax_t syntax; { re_char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; return /* After a subexpression? */ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) /* After an alternative? */ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)) /* After a shy subexpression? */ || ((syntax & RE_SHY_GROUPS) && prev - 2 >= pattern && prev[-1] == '?' && prev[-2] == '(' && (syntax & RE_NO_BK_PARENS || (prev - 3 >= pattern && prev[-3] == '\\'))); } /* The dual of at_begline_loc_p. This one is for $. We assume there is at least one character after the $, i.e., `P < PEND'. */ static boolean at_endline_loc_p (p, pend, syntax) re_char *p, *pend; reg_syntax_t syntax; { re_char *next = p; boolean next_backslash = *next == '\\'; re_char *next_next = p + 1 < pend ? p + 1 : 0; return /* Before a subexpression? */ (syntax & RE_NO_BK_PARENS ? *next == ')' : next_backslash && next_next && *next_next == ')') /* Before an alternative? */ || (syntax & RE_NO_BK_VBAR ? *next == '|' : next_backslash && next_next && *next_next == '|'); } /* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ static boolean group_in_compile_stack (compile_stack, regnum) compile_stack_type compile_stack; regnum_t regnum; { int this_element; for (this_element = compile_stack.avail - 1; this_element >= 0; this_element--) if (compile_stack.stack[this_element].regnum == regnum) return true; return false; } /* analyse_first. If fastmap is non-NULL, go through the pattern and fill fastmap with all the possible leading chars. If fastmap is NULL, don't bother filling it up (obviously) and only return whether the pattern could potentially match the empty string. Return 1 if p..pend might match the empty string. Return 0 if p..pend matches at least one char. Return -1 if fastmap was not updated accurately. */ static int analyse_first (p, pend, fastmap, multibyte) re_char *p, *pend; char *fastmap; const int multibyte; { int j, k; boolean not; /* If all elements for base leading-codes in fastmap is set, this flag is set true. */ boolean match_any_multibyte_characters = false; assert (p); /* The loop below works as follows: - It has a working-list kept in the PATTERN_STACK and which basically starts by only containing a pointer to the first operation. - If the opcode we're looking at is a match against some set of chars, then we add those chars to the fastmap and go on to the next work element from the worklist (done via `break'). - If the opcode is a control operator on the other hand, we either ignore it (if it's meaningless at this point, such as `start_memory') or execute it (if it's a jump). If the jump has several destinations (i.e. `on_failure_jump'), then we push the other destination onto the worklist. We guarantee termination by ignoring backward jumps (more or less), so that `p' is monotonically increasing. More to the point, we never set `p' (or push) anything `<= p1'. */ while (p < pend) { /* `p1' is used as a marker of how far back a `on_failure_jump' can go without being ignored. It is normally equal to `p' (which prevents any backward `on_failure_jump') except right after a plain `jump', to allow patterns such as: 0: jump 10 3..9: 10: on_failure_jump 3 as used for the *? operator. */ re_char *p1 = p; switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) { case succeed: return 1; continue; case duplicate: /* If the first character has to match a backreference, that means that the group was empty (since it already matched). Since this is the only case that interests us here, we can assume that the backreference must match the empty string. */ p++; continue; /* Following are the cases which match a character. These end with `break'. */ case exactn: if (fastmap) { int c = RE_STRING_CHAR (p + 1, pend - p); if (SINGLE_BYTE_CHAR_P (c)) fastmap[c] = 1; else fastmap[p[1]] = 1; } break; case anychar: /* We could put all the chars except for \n (and maybe \0) but we don't bother since it is generally not worth it. */ if (!fastmap) break; return -1; case charset_not: /* Chars beyond end of bitmap are possible matches. All the single-byte codes can occur in multibyte buffers. So any that are not listed in the charset are possible matches, even in multibyte buffers. */ if (!fastmap) break; for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) fastmap[j] = 1; /* Fallthrough */ case charset: if (!fastmap) break; not = (re_opcode_t) *(p - 1) == charset_not; for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH - 1, p++; j >= 0; j--) if (!!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) ^ not) fastmap[j] = 1; if ((not && multibyte) /* Any character set can possibly contain a character which doesn't match the specified set of characters. */ || (CHARSET_RANGE_TABLE_EXISTS_P (&p[-2]) && CHARSET_RANGE_TABLE_BITS (&p[-2]) != 0)) /* If we can match a character class, we can match any character set. */ { set_fastmap_for_multibyte_characters: if (match_any_multibyte_characters == false) { for (j = 0x80; j < 0xA0; j++) /* XXX */ if (BASE_LEADING_CODE_P (j)) fastmap[j] = 1; match_any_multibyte_characters = true; } } else if (!not && CHARSET_RANGE_TABLE_EXISTS_P (&p[-2]) && match_any_multibyte_characters == false) { /* Set fastmap[I] 1 where I is a base leading code of each multibyte character in the range table. */ int c, count; /* Make P points the range table. `+ 2' is to skip flag bits for a character class. */ p += CHARSET_BITMAP_SIZE (&p[-2]) + 2; /* Extract the number of ranges in range table into COUNT. */ EXTRACT_NUMBER_AND_INCR (count, p); for (; count > 0; count--, p += 2 * 3) /* XXX */ { /* Extract the start of each range. */ EXTRACT_CHARACTER (c, p); j = CHAR_CHARSET (c); fastmap[CHARSET_LEADING_CODE_BASE (j)] = 1; } } break; case syntaxspec: case notsyntaxspec: if (!fastmap) break; #ifndef emacs not = (re_opcode_t)p[-1] == notsyntaxspec; k = *p++; for (j = 0; j < (1 << BYTEWIDTH); j++) if ((SYNTAX (j) == (enum syntaxcode) k) ^ not) fastmap[j] = 1; break; #else /* emacs */ /* This match depends on text properties. These end with aborting optimizations. */ return -1; case categoryspec: case notcategoryspec: if (!fastmap) break; not = (re_opcode_t)p[-1] == notcategoryspec; k = *p++; for (j = 0; j < (1 << BYTEWIDTH); j++) if ((CHAR_HAS_CATEGORY (j, k)) ^ not) fastmap[j] = 1; if (multibyte) /* Any character set can possibly contain a character whose category is K (or not). */ goto set_fastmap_for_multibyte_characters; break; /* All cases after this match the empty string. These end with `continue'. */ case before_dot: case at_dot: case after_dot: #endif /* !emacs */ case no_op: case begline: case endline: case begbuf: case endbuf: case wordbound: case notwordbound: case wordbeg: case wordend: continue; case jump: EXTRACT_NUMBER_AND_INCR (j, p); if (j < 0) /* Backward jumps can only go back to code that we've already visited. `re_compile' should make sure this is true. */ break; p += j; switch (SWITCH_ENUM_CAST ((re_opcode_t) *p)) { case on_failure_jump: case on_failure_keep_string_jump: case on_failure_jump_loop: case on_failure_jump_nastyloop: case on_failure_jump_smart: p++; break; default: continue; }; /* Keep `p1' to allow the `on_failure_jump' we are jumping to to jump back to "just after here". */ /* Fallthrough */ case on_failure_jump: case on_failure_keep_string_jump: case on_failure_jump_nastyloop: case on_failure_jump_loop: case on_failure_jump_smart: EXTRACT_NUMBER_AND_INCR (j, p); if (p + j <= p1) ; /* Backward jump to be ignored. */ else { /* We have to look down both arms. We first go down the "straight" path so as to minimize stack usage when going through alternatives. */ int r = analyse_first (p, pend, fastmap, multibyte); if (r) return r; p += j; } continue; case jump_n: /* This code simply does not properly handle forward jump_n. */ DEBUG_STATEMENT (EXTRACT_NUMBER (j, p); assert (j < 0)); p += 4; /* jump_n can either jump or fall through. The (backward) jump case has already been handled, so we only need to look at the fallthrough case. */ continue; case succeed_n: /* If N == 0, it should be an on_failure_jump_loop instead. */ DEBUG_STATEMENT (EXTRACT_NUMBER (j, p + 2); assert (j > 0)); p += 4; /* We only care about one iteration of the loop, so we don't need to consider the case where this behaves like an on_failure_jump. */ continue; case set_number_at: p += 4; continue; case start_memory: case stop_memory: p += 1; continue; default: abort (); /* We have listed all the cases. */ } /* switch *p++ */ /* Getting here means we have found the possible starting characters for one path of the pattern -- and that the empty string does not match. We need not follow this path further. */ return 0; } /* while p */ /* We reached the end without matching anything. */ return 1; } /* analyse_first */ /* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible characters can start a string that matches the pattern. This fastmap is used by re_search to skip quickly over impossible starting points. Character codes above (1 << BYTEWIDTH) are not represented in the fastmap, but the leading codes are represented. Thus, the fastmap indicates which character sets could start a match. The caller must supply the address of a (1 << BYTEWIDTH)-byte data area as BUFP->fastmap. We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in the pattern buffer. Returns 0 if we succeed, -2 if an internal error. */ int re_compile_fastmap (bufp) struct re_pattern_buffer *bufp; { char *fastmap = bufp->fastmap; int analysis; assert (fastmap && bufp->buffer); bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ bufp->fastmap_accurate = 1; /* It will be when we're done. */ analysis = analyse_first (bufp->buffer, bufp->buffer + bufp->used, fastmap, RE_MULTIBYTE_P (bufp)); bufp->can_be_null = (analysis != 0); return 0; } /* re_compile_fastmap */ /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated using the malloc library routine, and must each be at least NUM_REGS * sizeof (regoff_t) bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ void re_set_registers (bufp, regs, num_regs, starts, ends) struct re_pattern_buffer *bufp; struct re_registers *regs; unsigned num_regs; regoff_t *starts, *ends; { if (num_regs) { bufp->regs_allocated = REGS_REALLOCATE; regs->num_regs = num_regs; regs->start = starts; regs->end = ends; } else { bufp->regs_allocated = REGS_UNALLOCATED; regs->num_regs = 0; regs->start = regs->end = (regoff_t *) 0; } } WEAK_ALIAS (__re_set_registers, re_set_registers) /* Searching routines. */ /* Like re_search_2, below, but only one string is specified, and doesn't let you say where to stop matching. */ int re_search (bufp, string, size, startpos, range, regs) struct re_pattern_buffer *bufp; const char *string; int size, startpos, range; struct re_registers *regs; { return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); } WEAK_ALIAS (__re_search, re_search) /* End address of virtual concatenation of string. */ #define STOP_ADDR_VSTRING(P) \ (((P) >= size1 ? string2 + size2 : string1 + size1)) /* Address of POS in the concatenation of virtual string. */ #define POS_ADDR_VSTRING(POS) \ (((POS) >= size1 ? string2 - size1 : string1) + (POS)) /* Using the compiled pattern in BUFP->buffer, first tries to match the virtual concatenation of STRING1 and STRING2, starting first at index STARTPOS, then at STARTPOS + 1, and so on. STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. RANGE is how far to scan while trying to match. RANGE = 0 means try only at STARTPOS; in general, the last start tried is STARTPOS + RANGE. In REGS, return the indices of the virtual concatenation of STRING1 and STRING2 that matched the entire BUFP->buffer and its contained subexpressions. Do not consider matching one past the index STOP in the virtual concatenation of STRING1 and STRING2. We return either the position in the strings at which the match was found, -1 if no match, or -2 if error (such as failure stack overflow). */ int re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop) struct re_pattern_buffer *bufp; const char *str1, *str2; int size1, size2; int startpos; int range; struct re_registers *regs; int stop; { int val; re_char *string1 = (re_char*) str1; re_char *string2 = (re_char*) str2; register char *fastmap = bufp->fastmap; register RE_TRANSLATE_TYPE translate = bufp->translate; int total_size = size1 + size2; int endpos = startpos + range; boolean anchored_start; /* Nonzero if we have to concern multibyte character. */ const boolean multibyte = RE_MULTIBYTE_P (bufp); /* Check for out-of-range STARTPOS. */ if (startpos < 0 || startpos > total_size) return -1; /* Fix up RANGE if it might eventually take us outside the virtual concatenation of STRING1 and STRING2. Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ if (endpos < 0) range = 0 - startpos; else if (endpos > total_size) range = total_size - startpos; /* If the search isn't to be a backwards one, don't waste time in a search for a pattern anchored at beginning of buffer. */ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) { if (startpos > 0) return -1; else range = 0; } #ifdef emacs /* In a forward search for something that starts with \=. don't keep searching past point. */ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) { range = PT_BYTE - BEGV_BYTE - startpos; if (range < 0) return -1; } #endif /* emacs */ /* Update the fastmap now if not correct already. */ if (fastmap && !bufp->fastmap_accurate) re_compile_fastmap (bufp); /* See whether the pattern is anchored. */ anchored_start = (bufp->buffer[0] == begline); #ifdef emacs gl_state.object = re_match_object; { int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (startpos)); SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1); } #endif /* Loop through the string, looking for a place to start matching. */ for (;;) { /* If the pattern is anchored, skip quickly past places we cannot match. We don't bother to treat startpos == 0 specially because that case doesn't repeat. */ if (anchored_start && startpos > 0) { if (! ((startpos <= size1 ? string1[startpos - 1] : string2[startpos - size1 - 1]) == '\n')) goto advance; } /* If a fastmap is supplied, skip quickly over characters that cannot be the start of a match. If the pattern can match the null string, however, we don't need to skip characters; we want the first null string. */ if (fastmap && startpos < total_size && !bufp->can_be_null) { register re_char *d; register re_wchar_t buf_ch; d = POS_ADDR_VSTRING (startpos); if (range > 0) /* Searching forwards. */ { register int lim = 0; int irange = range; if (startpos < size1 && startpos + range >= size1) lim = range - (size1 - startpos); /* Written out as an if-else to avoid testing `translate' inside the loop. */ if (RE_TRANSLATE_P (translate)) { if (multibyte) while (range > lim) { int buf_charlen; buf_ch = STRING_CHAR_AND_LENGTH (d, range - lim, buf_charlen); buf_ch = RE_TRANSLATE (translate, buf_ch); if (buf_ch >= 0400 || fastmap[buf_ch]) break; range -= buf_charlen; d += buf_charlen; } else while (range > lim && !fastmap[RE_TRANSLATE (translate, *d)]) { d++; range--; } } else while (range > lim && !fastmap[*d]) { d++; range--; } startpos += irange - range; } else /* Searching backwards. */ { int room = (startpos >= size1 ? size2 + size1 - startpos : size1 - startpos); buf_ch = RE_STRING_CHAR (d, room); buf_ch = TRANSLATE (buf_ch); if (! (buf_ch >= 0400 || fastmap[buf_ch])) goto advance; } } /* If can't match the null string, and that's all we have left, fail. */ if (range >= 0 && startpos == total_size && fastmap && !bufp->can_be_null) return -1; val = re_match_2_internal (bufp, string1, size1, string2, size2, startpos, regs, stop); #ifndef REGEX_MALLOC # ifdef C_ALLOCA alloca (0); # endif #endif if (val >= 0) return startpos; if (val == -2) return -2; advance: if (!range) break; else if (range > 0) { /* Update STARTPOS to the next character boundary. */ if (multibyte) { re_char *p = POS_ADDR_VSTRING (startpos); re_char *pend = STOP_ADDR_VSTRING (startpos); int len = MULTIBYTE_FORM_LENGTH (p, pend - p); range -= len; if (range < 0) break; startpos += len; } else { range--; startpos++; } } else { range++; startpos--; /* Update STARTPOS to the previous character boundary. */ if (multibyte) { re_char *p = POS_ADDR_VSTRING (startpos); int len = 0; /* Find the head of multibyte form. */ while (!CHAR_HEAD_P (*p)) p--, len++; /* Adjust it. */ #if 0 /* XXX */ if (MULTIBYTE_FORM_LENGTH (p, len + 1) != (len + 1)) ; else #endif { range += len; if (range > 0) break; startpos -= len; } } } } return -1; } /* re_search_2 */ WEAK_ALIAS (__re_search_2, re_search_2) /* Declarations and macros for re_match_2. */ static int bcmp_translate _RE_ARGS((re_char *s1, re_char *s2, register int len, RE_TRANSLATE_TYPE translate, const int multibyte)); /* This converts PTR, a pointer into one of the search strings `string1' and `string2' into an offset from the beginning of that string. */ #define POINTER_TO_OFFSET(ptr) \ (FIRST_STRING_P (ptr) \ ? ((regoff_t) ((ptr) - string1)) \ : ((regoff_t) ((ptr) - string2 + size1))) /* Call before fetching a character with *d. This switches over to string2 if necessary. Check re_match_2_internal for a discussion of why end_match_2 might not be within string2 (but be equal to end_match_1 instead). */ #define PREFETCH() \ while (d == dend) \ { \ /* End of string2 => fail. */ \ if (dend == end_match_2) \ goto fail; \ /* End of string1 => advance to string2. */ \ d = string2; \ dend = end_match_2; \ } /* Call before fetching a char with *d if you already checked other limits. This is meant for use in lookahead operations like wordend, etc.. where we might need to look at parts of the string that might be outside of the LIMITs (i.e past `stop'). */ #define PREFETCH_NOLIMIT() \ if (d == end1) \ { \ d = string2; \ dend = end_match_2; \ } \ /* Test if at very beginning or at very end of the virtual concatenation of `string1' and `string2'. If only one string, it's `string2'. */ #define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) #define AT_STRINGS_END(d) ((d) == end2) /* Test if D points to a character which is word-constituent. We have two special cases to check for: if past the end of string1, look at the first character in string2; and if before the beginning of string2, look at the last character in string1. */ #define WORDCHAR_P(d) \ (SYNTAX ((d) == end1 ? *string2 \ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ == Sword) /* Disabled due to a compiler bug -- see comment at case wordbound */ /* The comment at case wordbound is following one, but we don't use AT_WORD_BOUNDARY anymore to support multibyte form. The DEC Alpha C compiler 3.x generates incorrect code for the test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of AT_WORD_BOUNDARY, so this code is disabled. Expanding the macro and introducing temporary variables works around the bug. */ #if 0 /* Test if the character before D and the one at D differ with respect to being word-constituent. */ #define AT_WORD_BOUNDARY(d) \ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) #endif /* Free everything we malloc. */ #ifdef MATCH_MAY_ALLOCATE # define FREE_VAR(var) if (var) { REGEX_FREE (var); var = NULL; } else # define FREE_VARIABLES() \ do { \ REGEX_FREE_STACK (fail_stack.stack); \ FREE_VAR (regstart); \ FREE_VAR (regend); \ FREE_VAR (best_regstart); \ FREE_VAR (best_regend); \ } while (0) #else # define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ #endif /* not MATCH_MAY_ALLOCATE */ /* Optimization routines. */ /* If the operation is a match against one or more chars, return a pointer to the next operation, else return NULL. */ static re_char * skip_one_char (p) re_char *p; { switch (SWITCH_ENUM_CAST (*p++)) { case anychar: break; case exactn: p += *p + 1; break; case charset_not: case charset: if (CHARSET_RANGE_TABLE_EXISTS_P (p - 1)) { int mcnt; p = CHARSET_RANGE_TABLE (p - 1); EXTRACT_NUMBER_AND_INCR (mcnt, p); p = CHARSET_RANGE_TABLE_END (p, mcnt); } else p += 1 + CHARSET_BITMAP_SIZE (p - 1); break; case syntaxspec: case notsyntaxspec: #ifdef emacs case categoryspec: case notcategoryspec: #endif /* emacs */ p++; break; default: p = NULL; } return p; } /* Jump over non-matching operations. */ static unsigned char * skip_noops (p, pend) unsigned char *p, *pend; { int mcnt; while (p < pend) { switch (SWITCH_ENUM_CAST ((re_opcode_t) *p)) { case start_memory: case stop_memory: p += 2; break; case no_op: p += 1; break; case jump: p += 1; EXTRACT_NUMBER_AND_INCR (mcnt, p); p += mcnt; break; default: return p; } } assert (p == pend); return p; } /* Non-zero if "p1 matches something" implies "p2 fails". */ static int mutually_exclusive_p (bufp, p1, p2) struct re_pattern_buffer *bufp; unsigned char *p1, *p2; { re_opcode_t op2; const boolean multibyte = RE_MULTIBYTE_P (bufp); unsigned char *pend = bufp->buffer + bufp->used; assert (p1 >= bufp->buffer && p1 < pend && p2 >= bufp->buffer && p2 <= pend); /* Skip over open/close-group commands. If what follows this loop is a ...+ construct, look at what begins its body, since we will have to match at least one of that. */ p2 = skip_noops (p2, pend); /* The same skip can be done for p1, except that this function is only used in the case where p1 is a simple match operator. */ /* p1 = skip_noops (p1, pend); */ assert (p1 >= bufp->buffer && p1 < pend && p2 >= bufp->buffer && p2 <= pend); op2 = p2 == pend ? succeed : *p2; switch (SWITCH_ENUM_CAST (op2)) { case succeed: case endbuf: /* If we're at the end of the pattern, we can change. */ if (skip_one_char (p1)) { DEBUG_PRINT1 (" End of pattern: fast loop.\n"); return 1; } break; case endline: case exactn: { register re_wchar_t c = (re_opcode_t) *p2 == endline ? '\n' : RE_STRING_CHAR (p2 + 2, pend - p2 - 2); if ((re_opcode_t) *p1 == exactn) { if (c != RE_STRING_CHAR (p1 + 2, pend - p1 - 2)) { DEBUG_PRINT3 (" '%c' != '%c' => fast loop.\n", c, p1[2]); return 1; } } else if ((re_opcode_t) *p1 == charset || (re_opcode_t) *p1 == charset_not) { int not = (re_opcode_t) *p1 == charset_not; /* Test if C is listed in charset (or charset_not) at `p1'. */ if (SINGLE_BYTE_CHAR_P (c)) { if (c < CHARSET_BITMAP_SIZE (p1) * BYTEWIDTH && p1[2 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) not = !not; } else if (CHARSET_RANGE_TABLE_EXISTS_P (p1)) CHARSET_LOOKUP_RANGE_TABLE (not, c, p1); /* `not' is equal to 1 if c would match, which means that we can't change to pop_failure_jump. */ if (!not) { DEBUG_PRINT1 (" No match => fast loop.\n"); return 1; } } else if ((re_opcode_t) *p1 == anychar && c == '\n') { DEBUG_PRINT1 (" . != \\n => fast loop.\n"); return 1; } } break; case charset: { if ((re_opcode_t) *p1 == exactn) /* Reuse the code above. */ return mutually_exclusive_p (bufp, p2, p1); /* It is hard to list up all the character in charset P2 if it includes multibyte character. Give up in such case. */ else if (!multibyte || !CHARSET_RANGE_TABLE_EXISTS_P (p2)) { /* Now, we are sure that P2 has no range table. So, for the size of bitmap in P2, `p2[1]' is enough. But P1 may have range table, so the size of bitmap table of P1 is extracted by using macro `CHARSET_BITMAP_SIZE'. Since we know that all the character listed in P2 is ASCII, it is enough to test only bitmap table of P1. */ if ((re_opcode_t) *p1 == charset) { int idx; /* We win if the charset inside the loop has no overlap with the one after the loop. */ for (idx = 0; (idx < (int) p2[1] && idx < CHARSET_BITMAP_SIZE (p1)); idx++) if ((p2[2 + idx] & p1[2 + idx]) != 0) break; if (idx == p2[1] || idx == CHARSET_BITMAP_SIZE (p1)) { DEBUG_PRINT1 (" No match => fast loop.\n"); return 1; } } else if ((re_opcode_t) *p1 == charset_not) { int idx; /* We win if the charset_not inside the loop lists every character listed in the charset after. */ for (idx = 0; idx < (int) p2[1]; idx++) if (! (p2[2 + idx] == 0 || (idx < CHARSET_BITMAP_SIZE (p1) && ((p2[2 + idx] & ~ p1[2 + idx]) == 0)))) break; if (idx == p2[1]) { DEBUG_PRINT1 (" No match => fast loop.\n"); return 1; } } } } break; case charset_not: switch (SWITCH_ENUM_CAST (*p1)) { case exactn: case charset: /* Reuse the code above. */ return mutually_exclusive_p (bufp, p2, p1); case charset_not: /* When we have two charset_not, it's very unlikely that they don't overlap. The union of the two sets of excluded chars should cover all possible chars, which, as a matter of fact, is virtually impossible in multibyte buffers. */ ; } break; case wordend: case notsyntaxspec: return ((re_opcode_t) *p1 == syntaxspec && p1[1] == (op2 == wordend ? Sword : p2[1])); case wordbeg: case syntaxspec: return ((re_opcode_t) *p1 == notsyntaxspec && p1[1] == (op2 == wordend ? Sword : p2[1])); case wordbound: return (((re_opcode_t) *p1 == notsyntaxspec || (re_opcode_t) *p1 == syntaxspec) && p1[1] == Sword); #ifdef emacs case categoryspec: return ((re_opcode_t) *p1 == notcategoryspec && p1[1] == p2[1]); case notcategoryspec: return ((re_opcode_t) *p1 == categoryspec && p1[1] == p2[1]); #endif /* emacs */ default: ; } /* Safe default. */ return 0; } /* Matching routines. */ #ifndef emacs /* Emacs never uses this. */ /* re_match is like re_match_2 except it takes only a single string. */ int re_match (bufp, string, size, pos, regs) struct re_pattern_buffer *bufp; const char *string; int size, pos; struct re_registers *regs; { int result = re_match_2_internal (bufp, NULL, 0, (re_char*) string, size, pos, regs, size); # if defined C_ALLOCA && !defined REGEX_MALLOC alloca (0); # endif return result; } WEAK_ALIAS (__re_match, re_match) #endif /* not emacs */ #ifdef emacs /* In Emacs, this is the string or buffer in which we are matching. It is used for looking up syntax properties. */ Lisp_Object re_match_object; #endif /* re_match_2 matches the compiled pattern in BUFP against the the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 and SIZE2, respectively). We start matching at POS, and stop matching at STOP. If REGS is non-null and the `no_sub' field of BUFP is nonzero, we store offsets for the substring each group matched in REGS. See the documentation for exactly how many groups we fill. We return -1 if no match, -2 if an internal error (such as the failure stack overflowing). Otherwise, we return the length of the matched substring. */ int re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) struct re_pattern_buffer *bufp; const char *string1, *string2; int size1, size2; int pos; struct re_registers *regs; int stop; { int result; #ifdef emacs int charpos; gl_state.object = re_match_object; charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (pos)); SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1); #endif result = re_match_2_internal (bufp, (re_char*) string1, size1, (re_char*) string2, size2, pos, regs, stop); #if defined C_ALLOCA && !defined REGEX_MALLOC alloca (0); #endif return result; } WEAK_ALIAS (__re_match_2, re_match_2) /* This is a separate function so that we can force an alloca cleanup afterwards. */ static int re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) struct re_pattern_buffer *bufp; re_char *string1, *string2; int size1, size2; int pos; struct re_registers *regs; int stop; { /* General temporaries. */ int mcnt; size_t reg; boolean not; /* Just past the end of the corresponding string. */ re_char *end1, *end2; /* Pointers into string1 and string2, just past the last characters in each to consider matching. */ re_char *end_match_1, *end_match_2; /* Where we are in the data, and the end of the current string. */ re_char *d, *dend; /* Used sometimes to remember where we were before starting matching an operator so that we can go back in case of failure. This "atomic" behavior of matching opcodes is indispensable to the correctness of the on_failure_keep_string_jump optimization. */ re_char *dfail; /* Where we are in the pattern, and the end of the pattern. */ re_char *p = bufp->buffer; re_char *pend = p + bufp->used; /* We use this to map every character in the string. */ RE_TRANSLATE_TYPE translate = bufp->translate; /* Nonzero if we have to concern multibyte character. */ const boolean multibyte = RE_MULTIBYTE_P (bufp); /* Failure point stack. Each place that can handle a failure further down the line pushes a failure point on this stack. It consists of regstart, and regend for all registers corresponding to the subexpressions we're currently inside, plus the number of such registers, and, finally, two char *'s. The first char * is where to resume scanning the pattern; the second one is where to resume scanning the strings. */ #ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ fail_stack_type fail_stack; #endif #ifdef DEBUG unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; #endif #if defined REL_ALLOC && defined REGEX_MALLOC /* This holds the pointer to the failure stack, when it is allocated relocatably. */ fail_stack_elt_t *failure_stack_ptr; #endif /* We fill all the registers internally, independent of what we return, for use in backreferences. The number here includes an element for register zero. */ size_t num_regs = bufp->re_nsub + 1; /* Information on the contents of registers. These are pointers into the input strings; they record just what was matched (on this attempt) by a subexpression part of the pattern, that is, the regnum-th regstart pointer points to where in the pattern we began matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ #ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ re_char **regstart, **regend; #endif /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; #ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ re_char **best_regstart, **best_regend; #endif /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything else (see below). Also, we never need info about register 0 for any of the other register vectors, and it seems rather a kludge to treat `best_regend' differently than the rest. So we keep track of the end of the best match so far in a separate variable. We initialize this to NULL so that when we backtrack the first time and need to test it, it's not garbage. */ re_char *match_end = NULL; #ifdef DEBUG /* Counts the total number of registers pushed. */ unsigned num_regs_pushed = 0; #endif DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); INIT_FAIL_STACK (); #ifdef MATCH_MAY_ALLOCATE /* Do not bother to initialize all the register variables if there are no groups in the pattern, as it takes a fair amount of time. If there are groups, we include space for register 0 (the whole pattern), even though we never use it, since it simplifies the array indexing. We should fix this. */ if (bufp->re_nsub) { regstart = REGEX_TALLOC (num_regs, re_char *); regend = REGEX_TALLOC (num_regs, re_char *); best_regstart = REGEX_TALLOC (num_regs, re_char *); best_regend = REGEX_TALLOC (num_regs, re_char *); if (!(regstart && regend && best_regstart && best_regend)) { FREE_VARIABLES (); return -2; } } else { /* We must initialize all our variables to NULL, so that `FREE_VARIABLES' doesn't try to free them. */ regstart = regend = best_regstart = best_regend = NULL; } #endif /* MATCH_MAY_ALLOCATE */ /* The starting position is bogus. */ if (pos < 0 || pos > size1 + size2) { FREE_VARIABLES (); return -1; } /* Initialize subexpression text positions to -1 to mark ones that no start_memory/stop_memory has been seen for. Also initialize the register information struct. */ for (reg = 1; reg < num_regs; reg++) regstart[reg] = regend[reg] = NULL; /* We move `string1' into `string2' if the latter's empty -- but not if `string1' is null. */ if (size2 == 0 && string1 != NULL) { string2 = string1; size2 = size1; string1 = 0; size1 = 0; } end1 = string1 + size1; end2 = string2 + size2; /* `p' scans through the pattern as `d' scans through the data. `dend' is the end of the input string that `d' points within. `d' is advanced into the following input string whenever necessary, but this happens before fetching; therefore, at the beginning of the loop, `d' can be pointing at the end of a string, but it cannot equal `string2'. */ if (pos >= size1) { /* Only match within string2. */ d = string2 + pos - size1; dend = end_match_2 = string2 + stop - size1; end_match_1 = end1; /* Just to give it a value. */ } else { if (stop < size1) { /* Only match within string1. */ end_match_1 = string1 + stop; /* BEWARE! When we reach end_match_1, PREFETCH normally switches to string2. But in the present case, this means that just doing a PREFETCH makes us jump from `stop' to `gap' within the string. What we really want here is for the search to stop as soon as we hit end_match_1. That's why we set end_match_2 to end_match_1 (since PREFETCH fails as soon as we hit end_match_2). */ end_match_2 = end_match_1; } else { /* It's important to use this code when stop == size so that moving `d' from end1 to string2 will not prevent the d == dend check from catching the end of string. */ end_match_1 = end1; end_match_2 = string2 + stop - size1; } d = string1 + pos; dend = end_match_1; } DEBUG_PRINT1 ("The compiled pattern is: "); DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); DEBUG_PRINT1 ("The string to match is: `"); DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); DEBUG_PRINT1 ("'\n"); /* This loops over pattern commands. It exits by returning from the function if the match is complete, or it drops through if the match fails at this starting point in the input data. */ for (;;) { DEBUG_PRINT2 ("\n%p: ", p); if (p == pend) { /* End of pattern means we might have succeeded. */ DEBUG_PRINT1 ("end of pattern ... "); /* If we haven't matched the entire string, and we want the longest match, try backtracking. */ if (d != end_match_2) { /* 1 if this match ends in the same string (string1 or string2) as the best previous match. */ boolean same_str_p = (FIRST_STRING_P (match_end) == FIRST_STRING_P (d)); /* 1 if this match is the best seen so far. */ boolean best_match_p; /* AIX compiler got confused when this was combined with the previous declaration. */ if (same_str_p) best_match_p = d > match_end; else best_match_p = !FIRST_STRING_P (d); DEBUG_PRINT1 ("backtracking.\n"); if (!FAIL_STACK_EMPTY ()) { /* More failure points to try. */ /* If exceeds best match so far, save it. */ if (!best_regs_set || best_match_p) { best_regs_set = true; match_end = d; DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); for (reg = 1; reg < num_regs; reg++) { best_regstart[reg] = regstart[reg]; best_regend[reg] = regend[reg]; } } goto fail; } /* If no failure points, don't restore garbage. And if last match is real best match, don't restore second best one. */ else if (best_regs_set && !best_match_p) { restore_best_regs: /* Restore best match. It may happen that `dend == end_match_1' while the restored d is in string2. For example, the pattern `x.*y.*z' against the strings `x-' and `y-z-', if the two strings are not consecutive in memory. */ DEBUG_PRINT1 ("Restoring best registers.\n"); d = match_end; dend = ((d >= string1 && d <= end1) ? end_match_1 : end_match_2); for (reg = 1; reg < num_regs; reg++) { regstart[reg] = best_regstart[reg]; regend[reg] = best_regend[reg]; } } } /* d != end_match_2 */ succeed_label: DEBUG_PRINT1 ("Accepting match.\n"); /* If caller wants register contents data back, do it. */ if (regs && !bufp->no_sub) { /* Have the register data arrays been allocated? */ if (bufp->regs_allocated == REGS_UNALLOCATED) { /* No. So allocate them with malloc. We need one extra element beyond `num_regs' for the `-1' marker GNU code uses. */ regs->num_regs = MAX (RE_NREGS, num_regs + 1); regs->start = TALLOC (regs->num_regs, regoff_t); regs->end = TALLOC (regs->num_regs, regoff_t); if (regs->start == NULL || regs->end == NULL) { FREE_VARIABLES (); return -2; } bufp->regs_allocated = REGS_REALLOCATE; } else if (bufp->regs_allocated == REGS_REALLOCATE) { /* Yes. If we need more elements than were already allocated, reallocate them. If we need fewer, just leave it alone. */ if (regs->num_regs < num_regs + 1) { regs->num_regs = num_regs + 1; RETALLOC (regs->start, regs->num_regs, regoff_t); RETALLOC (regs->end, regs->num_regs, regoff_t); if (regs->start == NULL || regs->end == NULL) { FREE_VARIABLES (); return -2; } } } else { /* These braces fend off a "empty body in an else-statement" warning under GCC when assert expands to nothing. */ assert (bufp->regs_allocated == REGS_FIXED); } /* Convert the pointer data in `regstart' and `regend' to indices. Register zero has to be set differently, since we haven't kept track of any info for it. */ if (regs->num_regs > 0) { regs->start[0] = pos; regs->end[0] = POINTER_TO_OFFSET (d); } /* Go through the first `min (num_regs, regs->num_regs)' registers, since that is all we initialized. */ for (reg = 1; reg < MIN (num_regs, regs->num_regs); reg++) { if (REG_UNSET (regstart[reg]) || REG_UNSET (regend[reg])) regs->start[reg] = regs->end[reg] = -1; else { regs->start[reg] = (regoff_t) POINTER_TO_OFFSET (regstart[reg]); regs->end[reg] = (regoff_t) POINTER_TO_OFFSET (regend[reg]); } } /* If the regs structure we return has more elements than were in the pattern, set the extra elements to -1. If we (re)allocated the registers, this is the case, because we always allocate enough to have at least one -1 at the end. */ for (reg = num_regs; reg < regs->num_regs; reg++) regs->start[reg] = regs->end[reg] = -1; } /* regs && !bufp->no_sub */ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", nfailure_points_pushed, nfailure_points_popped, nfailure_points_pushed - nfailure_points_popped); DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); mcnt = POINTER_TO_OFFSET (d) - pos; DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); FREE_VARIABLES (); return mcnt; } /* Otherwise match next pattern command. */ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) { /* Ignore these. Used to ignore the n of succeed_n's which currently have n == 0. */ case no_op: DEBUG_PRINT1 ("EXECUTING no_op.\n"); break; case succeed: DEBUG_PRINT1 ("EXECUTING succeed.\n"); goto succeed_label; /* Match the next n pattern characters exactly. The following byte in the pattern defines n, and the n bytes after that are the characters to match. */ case exactn: mcnt = *p++; DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); /* Remember the start point to rollback upon failure. */ dfail = d; /* This is written out as an if-else so we don't waste time testing `translate' inside the loop. */ if (RE_TRANSLATE_P (translate)) { if (multibyte) do { int pat_charlen, buf_charlen; unsigned int pat_ch, buf_ch; PREFETCH (); pat_ch = STRING_CHAR_AND_LENGTH (p, pend - p, pat_charlen); buf_ch = STRING_CHAR_AND_LENGTH (d, dend - d, buf_charlen); if (RE_TRANSLATE (translate, buf_ch) != pat_ch) { d = dfail; goto fail; } p += pat_charlen; d += buf_charlen; mcnt -= pat_charlen; } while (mcnt > 0); else do { PREFETCH (); if (RE_TRANSLATE (translate, *d) != *p++) { d = dfail; goto fail; } d++; } while (--mcnt); } else { do { PREFETCH (); if (*d++ != *p++) { d = dfail; goto fail; } } while (--mcnt); } break; /* Match any character except possibly a newline or a null. */ case anychar: { int buf_charlen; re_wchar_t buf_ch; DEBUG_PRINT1 ("EXECUTING anychar.\n"); PREFETCH (); buf_ch = RE_STRING_CHAR_AND_LENGTH (d, dend - d, buf_charlen); buf_ch = TRANSLATE (buf_ch); if ((!(bufp->syntax & RE_DOT_NEWLINE) && buf_ch == '\n') || ((bufp->syntax & RE_DOT_NOT_NULL) && buf_ch == '\000')) goto fail; DEBUG_PRINT2 (" Matched `%d'.\n", *d); d += buf_charlen; } break; case charset: case charset_not: { register unsigned int c; boolean not = (re_opcode_t) *(p - 1) == charset_not; int len; /* Start of actual range_table, or end of bitmap if there is no range table. */ re_char *range_table; /* Nonzero if there is a range table. */ int range_table_exists; /* Number of ranges of range table. This is not included in the initial byte-length of the command. */ int count = 0; DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); range_table_exists = CHARSET_RANGE_TABLE_EXISTS_P (&p[-1]); if (range_table_exists) { range_table = CHARSET_RANGE_TABLE (&p[-1]); /* Past the bitmap. */ EXTRACT_NUMBER_AND_INCR (count, range_table); } PREFETCH (); c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len); c = TRANSLATE (c); /* The character to match. */ if (SINGLE_BYTE_CHAR_P (c)) { /* Lookup bitmap. */ /* Cast to `unsigned' instead of `unsigned char' in case the bit list is a full 32 bytes long. */ if (c < (unsigned) (CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH) && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) not = !not; } #ifdef emacs else if (range_table_exists) { int class_bits = CHARSET_RANGE_TABLE_BITS (&p[-1]); if ( (class_bits & BIT_LOWER && ISLOWER (c)) | (class_bits & BIT_MULTIBYTE) | (class_bits & BIT_PUNCT && ISPUNCT (c)) | (class_bits & BIT_SPACE && ISSPACE (c)) | (class_bits & BIT_UPPER && ISUPPER (c)) | (class_bits & BIT_WORD && ISWORD (c))) not = !not; else CHARSET_LOOKUP_RANGE_TABLE_RAW (not, c, range_table, count); } #endif /* emacs */ if (range_table_exists) p = CHARSET_RANGE_TABLE_END (range_table, count); else p += CHARSET_BITMAP_SIZE (&p[-1]) + 1; if (!not) goto fail; d += len; break; } /* The beginning of a group is represented by start_memory. The argument is the register number. The text matched within the group is recorded (in the internal registers data structure) under the register number. */ case start_memory: DEBUG_PRINT2 ("EXECUTING start_memory %d:\n", *p); /* In case we need to undo this operation (via backtracking). */ PUSH_FAILURE_REG ((unsigned int)*p); regstart[*p] = d; regend[*p] = NULL; /* probably unnecessary. -sm */ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); /* Move past the register number and inner group count. */ p += 1; break; /* The stop_memory opcode represents the end of a group. Its argument is the same as start_memory's: the register number. */ case stop_memory: DEBUG_PRINT2 ("EXECUTING stop_memory %d:\n", *p); assert (!REG_UNSET (regstart[*p])); /* Strictly speaking, there should be code such as: assert (REG_UNSET (regend[*p])); PUSH_FAILURE_REGSTOP ((unsigned int)*p); But the only info to be pushed is regend[*p] and it is known to be UNSET, so there really isn't anything to push. Not pushing anything, on the other hand deprives us from the guarantee that regend[*p] is UNSET since undoing this operation will not reset its value properly. This is not important since the value will only be read on the next start_memory or at the very end and both events can only happen if this stop_memory is *not* undone. */ regend[*p] = d; DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); /* Move past the register number and the inner group count. */ p += 1; break; /* \ has been turned into a `duplicate' command which is followed by the numeric value of as the register number. */ case duplicate: { register re_char *d2, *dend2; int regno = *p++; /* Get which register to match against. */ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); /* Can't back reference a group which we've never matched. */ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) goto fail; /* Where in input to try to start matching. */ d2 = regstart[regno]; /* Remember the start point to rollback upon failure. */ dfail = d; /* Where to stop matching; if both the place to start and the place to stop matching are in the same string, then set to the place to stop, otherwise, for now have to use the end of the first string. */ dend2 = ((FIRST_STRING_P (regstart[regno]) == FIRST_STRING_P (regend[regno])) ? regend[regno] : end_match_1); for (;;) { /* If necessary, advance to next segment in register contents. */ while (d2 == dend2) { if (dend2 == end_match_2) break; if (dend2 == regend[regno]) break; /* End of string1 => advance to string2. */ d2 = string2; dend2 = regend[regno]; } /* At end of register contents => success */ if (d2 == dend2) break; /* If necessary, advance to next segment in data. */ PREFETCH (); /* How many characters left in this segment to match. */ mcnt = dend - d; /* Want how many consecutive characters we can match in one shot, so, if necessary, adjust the count. */ if (mcnt > dend2 - d2) mcnt = dend2 - d2; /* Compare that many; failure if mismatch, else move past them. */ if (RE_TRANSLATE_P (translate) ? bcmp_translate (d, d2, mcnt, translate, multibyte) : memcmp (d, d2, mcnt)) { d = dfail; goto fail; } d += mcnt, d2 += mcnt; } } break; /* begline matches the empty string at the beginning of the string (unless `not_bol' is set in `bufp'), and after newlines. */ case begline: DEBUG_PRINT1 ("EXECUTING begline.\n"); if (AT_STRINGS_BEG (d)) { if (!bufp->not_bol) break; } else { unsigned char c; GET_CHAR_BEFORE_2 (c, d, string1, end1, string2, end2); if (c == '\n') break; } /* In all other cases, we fail. */ goto fail; /* endline is the dual of begline. */ case endline: DEBUG_PRINT1 ("EXECUTING endline.\n"); if (AT_STRINGS_END (d)) { if (!bufp->not_eol) break; } else { PREFETCH_NOLIMIT (); if (*d == '\n') break; } goto fail; /* Match at the very beginning of the data. */ case begbuf: DEBUG_PRINT1 ("EXECUTING begbuf.\n"); if (AT_STRINGS_BEG (d)) break; goto fail; /* Match at the very end of the data. */ case endbuf: DEBUG_PRINT1 ("EXECUTING endbuf.\n"); if (AT_STRINGS_END (d)) break; goto fail; /* on_failure_keep_string_jump is used to optimize `.*\n'. It pushes NULL as the value for the string on the stack. Then `POP_FAILURE_POINT' will keep the current value for the string, instead of restoring it. To see why, consider matching `foo\nbar' against `.*\n'. The .* matches the foo; then the . fails against the \n. But the next thing we want to do is match the \n against the \n; if we restored the string value, we would be back at the foo. Because this is used only in specific cases, we don't need to check all the things that `on_failure_jump' does, to make sure the right things get saved on the stack. Hence we don't share its code. The only reason to push anything on the stack at all is that otherwise we would have to change `anychar's code to do something besides goto fail in this case; that seems worse than this. */ case on_failure_keep_string_jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT3 ("EXECUTING on_failure_keep_string_jump %d (to %p):\n", mcnt, p + mcnt); PUSH_FAILURE_POINT (p - 3, NULL); break; /* A nasty loop is introduced by the non-greedy *? and +?. With such loops, the stack only ever contains one failure point at a time, so that a plain on_failure_jump_loop kind of cycle detection cannot work. Worse yet, such a detection can not only fail to detect a cycle, but it can also wrongly detect a cycle (between different instantiations of the same loop. So the method used for those nasty loops is a little different: We use a special cycle-detection-stack-frame which is pushed when the on_failure_jump_nastyloop failure-point is *popped*. This special frame thus marks the beginning of one iteration through the loop and we can hence easily check right here whether something matched between the beginning and the end of the loop. */ case on_failure_jump_nastyloop: EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT3 ("EXECUTING on_failure_jump_nastyloop %d (to %p):\n", mcnt, p + mcnt); assert ((re_opcode_t)p[-4] == no_op); CHECK_INFINITE_LOOP (p - 4, d); PUSH_FAILURE_POINT (p - 3, d); break; /* Simple loop detecting on_failure_jump: just check on the failure stack if the same spot was already hit earlier. */ case on_failure_jump_loop: on_failure: EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT3 ("EXECUTING on_failure_jump_loop %d (to %p):\n", mcnt, p + mcnt); CHECK_INFINITE_LOOP (p - 3, d); PUSH_FAILURE_POINT (p - 3, d); break; /* Uses of on_failure_jump: Each alternative starts with an on_failure_jump that points to the beginning of the next alternative. Each alternative except the last ends with a jump that in effect jumps past the rest of the alternatives. (They really jump to the ending jump of the following alternative, because tensioning these jumps is a hassle.) Repeats start with an on_failure_jump that points past both the repetition text and either the following jump or pop_failure_jump back to this on_failure_jump. */ case on_failure_jump: IMMEDIATE_QUIT_CHECK; EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT3 ("EXECUTING on_failure_jump %d (to %p):\n", mcnt, p + mcnt); PUSH_FAILURE_POINT (p -3, d); break; /* This operation is used for greedy *. Compare the beginning of the repeat with what in the pattern follows its end. If we can establish that there is nothing that they would both match, i.e., that we would have to backtrack because of (as in, e.g., `a*a') then we can use a non-backtracking loop based on on_failure_keep_string_jump instead of on_failure_jump. */ case on_failure_jump_smart: IMMEDIATE_QUIT_CHECK; EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT3 ("EXECUTING on_failure_jump_smart %d (to %p).\n", mcnt, p + mcnt); { re_char *p1 = p; /* Next operation. */ /* Here, we discard `const', making re_match non-reentrant. */ unsigned char *p2 = (unsigned char*) p + mcnt; /* Jump dest. */ unsigned char *p3 = (unsigned char*) p - 3; /* opcode location. */ p -= 3; /* Reset so that we will re-execute the instruction once it's been changed. */ EXTRACT_NUMBER (mcnt, p2 - 2); /* Ensure this is a indeed the trivial kind of loop we are expecting. */ assert (skip_one_char (p1) == p2 - 3); assert ((re_opcode_t) p2[-3] == jump && p2 + mcnt == p); DEBUG_STATEMENT (debug += 2); if (mutually_exclusive_p (bufp, p1, p2)) { /* Use a fast `on_failure_keep_string_jump' loop. */ DEBUG_PRINT1 (" smart exclusive => fast loop.\n"); *p3 = (unsigned char) on_failure_keep_string_jump; STORE_NUMBER (p2 - 2, mcnt + 3); } else { /* Default to a safe `on_failure_jump' loop. */ DEBUG_PRINT1 (" smart default => slow loop.\n"); *p3 = (unsigned char) on_failure_jump; } DEBUG_STATEMENT (debug -= 2); } break; /* Unconditionally jump (without popping any failure points). */ case jump: unconditional_jump: IMMEDIATE_QUIT_CHECK; EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); p += mcnt; /* Do the jump. */ DEBUG_PRINT2 ("(to %p).\n", p); break; /* Have to succeed matching what follows at least n times. After that, handle like `on_failure_jump'. */ case succeed_n: /* Signedness doesn't matter since we only compare MCNT to 0. */ EXTRACT_NUMBER (mcnt, p + 2); DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); /* Originally, mcnt is how many times we HAVE to succeed. */ if (mcnt != 0) { /* Here, we discard `const', making re_match non-reentrant. */ unsigned char *p2 = (unsigned char*) p + 2; /* counter loc. */ mcnt--; p += 4; PUSH_NUMBER (p2, mcnt); } else /* The two bytes encoding mcnt == 0 are two no_op opcodes. */ goto on_failure; break; case jump_n: /* Signedness doesn't matter since we only compare MCNT to 0. */ EXTRACT_NUMBER (mcnt, p + 2); DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); /* Originally, this is how many times we CAN jump. */ if (mcnt != 0) { /* Here, we discard `const', making re_match non-reentrant. */ unsigned char *p2 = (unsigned char*) p + 2; /* counter loc. */ mcnt--; PUSH_NUMBER (p2, mcnt); goto unconditional_jump; } /* If don't have to jump any more, skip over the rest of command. */ else p += 4; break; case set_number_at: { unsigned char *p2; /* Location of the counter. */ DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Here, we discard `const', making re_match non-reentrant. */ p2 = (unsigned char*) p + mcnt; /* Signedness doesn't matter since we only copy MCNT's bits . */ EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT3 (" Setting %p to %d.\n", p2, mcnt); PUSH_NUMBER (p2, mcnt); break; } case wordbound: case notwordbound: not = (re_opcode_t) *(p - 1) == notwordbound; DEBUG_PRINT2 ("EXECUTING %swordbound.\n", not?"not":""); /* We SUCCEED (or FAIL) in one of the following cases: */ /* Case 1: D is at the beginning or the end of string. */ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) not = !not; else { /* C1 is the character before D, S1 is the syntax of C1, C2 is the character at D, and S2 is the syntax of C2. */ re_wchar_t c1, c2; int s1, s2; #ifdef emacs int offset = PTR_TO_OFFSET (d - 1); int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset); UPDATE_SYNTAX_TABLE (charpos); #endif GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2); s1 = SYNTAX (c1); #ifdef emacs UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1); #endif PREFETCH_NOLIMIT (); c2 = RE_STRING_CHAR (d, dend - d); s2 = SYNTAX (c2); if (/* Case 2: Only one of S1 and S2 is Sword. */ ((s1 == Sword) != (s2 == Sword)) /* Case 3: Both of S1 and S2 are Sword, and macro WORD_BOUNDARY_P (C1, C2) returns nonzero. */ || ((s1 == Sword) && WORD_BOUNDARY_P (c1, c2))) not = !not; } if (not) break; else goto fail; case wordbeg: DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); /* We FAIL in one of the following cases: */ /* Case 1: D is at the end of string. */ if (AT_STRINGS_END (d)) goto fail; else { /* C1 is the character before D, S1 is the syntax of C1, C2 is the character at D, and S2 is the syntax of C2. */ re_wchar_t c1, c2; int s1, s2; #ifdef emacs int offset = PTR_TO_OFFSET (d); int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset); UPDATE_SYNTAX_TABLE (charpos); #endif PREFETCH (); c2 = RE_STRING_CHAR (d, dend - d); s2 = SYNTAX (c2); /* Case 2: S2 is not Sword. */ if (s2 != Sword) goto fail; /* Case 3: D is not at the beginning of string ... */ if (!AT_STRINGS_BEG (d)) { GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2); #ifdef emacs UPDATE_SYNTAX_TABLE_BACKWARD (charpos - 1); #endif s1 = SYNTAX (c1); /* ... and S1 is Sword, and WORD_BOUNDARY_P (C1, C2) returns 0. */ if ((s1 == Sword) && !WORD_BOUNDARY_P (c1, c2)) goto fail; } } break; case wordend: DEBUG_PRINT1 ("EXECUTING wordend.\n"); /* We FAIL in one of the following cases: */ /* Case 1: D is at the beginning of string. */ if (AT_STRINGS_BEG (d)) goto fail; else { /* C1 is the character before D, S1 is the syntax of C1, C2 is the character at D, and S2 is the syntax of C2. */ re_wchar_t c1, c2; int s1, s2; #ifdef emacs int offset = PTR_TO_OFFSET (d) - 1; int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset); UPDATE_SYNTAX_TABLE (charpos); #endif GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2); s1 = SYNTAX (c1); /* Case 2: S1 is not Sword. */ if (s1 != Sword) goto fail; /* Case 3: D is not at the end of string ... */ if (!AT_STRINGS_END (d)) { PREFETCH_NOLIMIT (); c2 = RE_STRING_CHAR (d, dend - d); #ifdef emacs UPDATE_SYNTAX_TABLE_FORWARD (charpos); #endif s2 = SYNTAX (c2); /* ... and S2 is Sword, and WORD_BOUNDARY_P (C1, C2) returns 0. */ if ((s2 == Sword) && !WORD_BOUNDARY_P (c1, c2)) goto fail; } } break; case syntaxspec: case notsyntaxspec: not = (re_opcode_t) *(p - 1) == notsyntaxspec; mcnt = *p++; DEBUG_PRINT3 ("EXECUTING %ssyntaxspec %d.\n", not?"not":"", mcnt); PREFETCH (); #ifdef emacs { int offset = PTR_TO_OFFSET (d); int pos1 = SYNTAX_TABLE_BYTE_TO_CHAR (offset); UPDATE_SYNTAX_TABLE (pos1); } #endif { int len; re_wchar_t c; c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len); if ((SYNTAX (c) != (enum syntaxcode) mcnt) ^ not) goto fail; d += len; } break; #ifdef emacs case before_dot: DEBUG_PRINT1 ("EXECUTING before_dot.\n"); if (PTR_BYTE_POS (d) >= PT_BYTE) goto fail; break; case at_dot: DEBUG_PRINT1 ("EXECUTING at_dot.\n"); if (PTR_BYTE_POS (d) != PT_BYTE) goto fail; break; case after_dot: DEBUG_PRINT1 ("EXECUTING after_dot.\n"); if (PTR_BYTE_POS (d) <= PT_BYTE) goto fail; break; case categoryspec: case notcategoryspec: not = (re_opcode_t) *(p - 1) == notcategoryspec; mcnt = *p++; DEBUG_PRINT3 ("EXECUTING %scategoryspec %d.\n", not?"not":"", mcnt); PREFETCH (); { int len; re_wchar_t c; c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len); if ((!CHAR_HAS_CATEGORY (c, mcnt)) ^ not) goto fail; d += len; } break; #endif /* emacs */ default: abort (); } continue; /* Successfully executed one pattern command; keep going. */ /* We goto here if a matching operation fails. */ fail: IMMEDIATE_QUIT_CHECK; if (!FAIL_STACK_EMPTY ()) { re_char *str, *pat; /* A restart point is known. Restore to that state. */ DEBUG_PRINT1 ("\nFAIL:\n"); POP_FAILURE_POINT (str, pat); switch (SWITCH_ENUM_CAST ((re_opcode_t) *pat++)) { case on_failure_keep_string_jump: assert (str == NULL); goto continue_failure_jump; case on_failure_jump_nastyloop: assert ((re_opcode_t)pat[-2] == no_op); PUSH_FAILURE_POINT (pat - 2, str); /* Fallthrough */ case on_failure_jump_loop: case on_failure_jump: case succeed_n: d = str; continue_failure_jump: EXTRACT_NUMBER_AND_INCR (mcnt, pat); p = pat + mcnt; break; case no_op: /* A special frame used for nastyloops. */ goto fail; default: abort(); } assert (p >= bufp->buffer && p <= pend); if (d >= string1 && d <= end1) dend = end_match_1; } else break; /* Matching at this starting point really fails. */ } /* for (;;) */ if (best_regs_set) goto restore_best_regs; FREE_VARIABLES (); return -1; /* Failure to match. */ } /* re_match_2 */ /* Subroutine definitions for re_match_2. */ /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ static int bcmp_translate (s1, s2, len, translate, multibyte) re_char *s1, *s2; register int len; RE_TRANSLATE_TYPE translate; const int multibyte; { register re_char *p1 = s1, *p2 = s2; re_char *p1_end = s1 + len; re_char *p2_end = s2 + len; /* FIXME: Checking both p1 and p2 presumes that the two strings might have different lengths, but relying on a single `len' would break this. -sm */ while (p1 < p1_end && p2 < p2_end) { int p1_charlen, p2_charlen; re_wchar_t p1_ch, p2_ch; p1_ch = RE_STRING_CHAR_AND_LENGTH (p1, p1_end - p1, p1_charlen); p2_ch = RE_STRING_CHAR_AND_LENGTH (p2, p2_end - p2, p2_charlen); if (RE_TRANSLATE (translate, p1_ch) != RE_TRANSLATE (translate, p2_ch)) return 1; p1 += p1_charlen, p2 += p2_charlen; } if (p1 != p1_end || p2 != p2_end) return 1; return 0; } /* Entry points for GNU code. */ /* re_compile_pattern is the GNU regular expression compiler: it compiles PATTERN (of length SIZE) and puts the result in BUFP. Returns 0 if the pattern was valid, otherwise an error string. Assumes the `allocated' (and perhaps `buffer') and `translate' fields are set in BUFP on entry. We call regex_compile to do the actual compilation. */ const char * re_compile_pattern (pattern, length, bufp) const char *pattern; size_t length; struct re_pattern_buffer *bufp; { reg_errcode_t ret; /* GNU code is written to assume at least RE_NREGS registers will be set (and at least one extra will be -1). */ bufp->regs_allocated = REGS_UNALLOCATED; /* And GNU code determines whether or not to get register information by passing null for the REGS argument to re_match, etc., not by setting no_sub. */ bufp->no_sub = 0; ret = regex_compile ((re_char*) pattern, length, re_syntax_options, bufp); if (!ret) return NULL; return gettext (re_error_msgid[(int) ret]); } WEAK_ALIAS (__re_compile_pattern, re_compile_pattern) /* Entry points compatible with 4.2 BSD regex library. We don't define them unless specifically requested. */ #if defined _REGEX_RE_COMP || defined _LIBC /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; char * # ifdef _LIBC /* Make these definitions weak in libc, so POSIX programs can redefine these names if they don't use our functions, and still use regcomp/regexec below without link errors. */ weak_function # endif re_comp (s) const char *s; { reg_errcode_t ret; if (!s) { if (!re_comp_buf.buffer) /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ return (char *) gettext ("No previous regular expression"); return 0; } if (!re_comp_buf.buffer) { re_comp_buf.buffer = (unsigned char *) malloc (200); if (re_comp_buf.buffer == NULL) /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); re_comp_buf.allocated = 200; re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); if (re_comp_buf.fastmap == NULL) /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); } /* Since `re_exec' always passes NULL for the `regs' argument, we don't need to initialize the pattern buffer fields which affect it. */ ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); if (!ret) return NULL; /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ return (char *) gettext (re_error_msgid[(int) ret]); } int # ifdef _LIBC weak_function # endif re_exec (s) const char *s; { const int len = strlen (s); return 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); } #endif /* _REGEX_RE_COMP */ /* POSIX.2 functions. Don't define these for Emacs. */ #ifndef emacs /* regcomp takes a regular expression as a string and compiles it. PREG is a regex_t *. We do not expect any fields to be initialized, since POSIX says we shouldn't. Thus, we set `buffer' to the compiled pattern; `used' to the length of the compiled pattern; `syntax' to RE_SYNTAX_POSIX_EXTENDED if the REG_EXTENDED bit in CFLAGS is set; otherwise, to RE_SYNTAX_POSIX_BASIC; `fastmap' to an allocated space for the fastmap; `fastmap_accurate' to zero; `re_nsub' to the number of subexpressions in PATTERN. PATTERN is the address of the pattern string. CFLAGS is a series of bits which affect compilation. If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we use POSIX basic syntax. If REG_NEWLINE is set, then . and [^...] don't match newline. Also, regexec will try a match beginning after every newline. If REG_ICASE is set, then we considers upper- and lowercase versions of letters to be equivalent when matching. If REG_NOSUB is set, then when PREG is passed to regexec, that routine will report only success or failure, and nothing about the registers. It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ int regcomp (preg, pattern, cflags) regex_t *__restrict preg; const char *__restrict pattern; int cflags; { reg_errcode_t ret; reg_syntax_t syntax = (cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; /* regex_compile will allocate the space for the compiled pattern. */ preg->buffer = 0; preg->allocated = 0; preg->used = 0; /* Try to allocate space for the fastmap. */ preg->fastmap = (char *) malloc (1 << BYTEWIDTH); if (cflags & REG_ICASE) { unsigned i; preg->translate = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE * sizeof (*(RE_TRANSLATE_TYPE)0)); if (preg->translate == NULL) return (int) REG_ESPACE; /* Map uppercase characters to corresponding lowercase ones. */ for (i = 0; i < CHAR_SET_SIZE; i++) preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; } else preg->translate = NULL; /* If REG_NEWLINE is set, newlines are treated differently. */ if (cflags & REG_NEWLINE) { /* REG_NEWLINE implies neither . nor [^...] match newline. */ syntax &= ~RE_DOT_NEWLINE; syntax |= RE_HAT_LISTS_NOT_NEWLINE; } else syntax |= RE_NO_NEWLINE_ANCHOR; preg->no_sub = !!(cflags & REG_NOSUB); /* POSIX says a null character in the pattern terminates it, so we can use strlen here in compiling the pattern. */ ret = regex_compile ((re_char*) pattern, strlen (pattern), syntax, preg); /* POSIX doesn't distinguish between an unmatched open-group and an unmatched close-group: both are REG_EPAREN. */ if (ret == REG_ERPAREN) ret = REG_EPAREN; if (ret == REG_NOERROR && preg->fastmap) { /* Compute the fastmap now, since regexec cannot modify the pattern buffer. */ re_compile_fastmap (preg); if (preg->can_be_null) { /* The fastmap can't be used anyway. */ free (preg->fastmap); preg->fastmap = NULL; } } return (int) ret; } WEAK_ALIAS (__regcomp, regcomp) /* regexec searches for a given pattern, specified by PREG, in the string STRING. If NMATCH is zero or REG_NOSUB was set in the cflags argument to `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at least NMATCH elements, and we set them to the offsets of the corresponding matched substrings. EFLAGS specifies `execution flags' which affect matching: if REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. We return 0 if we find a match and REG_NOMATCH if not. */ int regexec (preg, string, nmatch, pmatch, eflags) const regex_t *__restrict preg; const char *__restrict string; size_t nmatch; regmatch_t pmatch[]; int eflags; { int ret; struct re_registers regs; regex_t private_preg; int len = strlen (string); boolean want_reg_info = !preg->no_sub && nmatch > 0 && pmatch; private_preg = *preg; private_preg.not_bol = !!(eflags & REG_NOTBOL); private_preg.not_eol = !!(eflags & REG_NOTEOL); /* The user has told us exactly how many registers to return information about, via `nmatch'. We have to pass that on to the matching routines. */ private_preg.regs_allocated = REGS_FIXED; if (want_reg_info) { regs.num_regs = nmatch; regs.start = TALLOC (nmatch * 2, regoff_t); if (regs.start == NULL) return (int) REG_NOMATCH; regs.end = regs.start + nmatch; } /* Instead of using not_eol to implement REG_NOTEOL, we could simply pass (&private_preg, string, len + 1, 0, len, ...) pretending the string was a little bit longer but still only matching the real part. This works because the `endline' will check for a '\n' and will find a '\0', correctly deciding that this is not the end of a line. But it doesn't work out so nicely for REG_NOTBOL, since we don't have a convenient '\0' there. For all we know, the string could be preceded by '\n' which would throw things off. */ /* Perform the searching operation. */ ret = re_search (&private_preg, string, len, /* start: */ 0, /* range: */ len, want_reg_info ? ®s : (struct re_registers *) 0); /* Copy the register information to the POSIX structure. */ if (want_reg_info) { if (ret >= 0) { unsigned r; for (r = 0; r < nmatch; r++) { pmatch[r].rm_so = regs.start[r]; pmatch[r].rm_eo = regs.end[r]; } } /* If we needed the temporary register info, free the space now. */ free (regs.start); } /* We want zero return to mean success, unlike `re_search'. */ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; } WEAK_ALIAS (__regexec, regexec) /* Returns a message corresponding to an error code, ERRCODE, returned from either regcomp or regexec. We don't use PREG here. */ size_t regerror (errcode, preg, errbuf, errbuf_size) int errcode; const regex_t *preg; char *errbuf; size_t errbuf_size; { const char *msg; size_t msg_size; if (errcode < 0 || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0]))) /* Only error codes returned by the rest of the code should be passed to this routine. If we are given anything else, or if other regex code generates an invalid error code, then the program has a bug. Dump core so we can fix it. */ abort (); msg = gettext (re_error_msgid[errcode]); msg_size = strlen (msg) + 1; /* Includes the null. */ if (errbuf_size != 0) { if (msg_size > errbuf_size) { strncpy (errbuf, msg, errbuf_size - 1); errbuf[errbuf_size - 1] = 0; } else strcpy (errbuf, msg); } return msg_size; } WEAK_ALIAS (__regerror, regerror) /* Free dynamically allocated space used by PREG. */ void regfree (preg) regex_t *preg; { if (preg->buffer != NULL) free (preg->buffer); preg->buffer = NULL; preg->allocated = 0; preg->used = 0; if (preg->fastmap != NULL) free (preg->fastmap); preg->fastmap = NULL; preg->fastmap_accurate = 0; if (preg->translate != NULL) free (preg->translate); preg->translate = NULL; } WEAK_ALIAS (__regfree, regfree) #endif /* not emacs */ gnats-4.1.0/gnats/regex.h0000644000175000017500000005166507633154562016011 0ustar chewiechewie00000000000000/* Definitions for data structures and routines for the regular expression library, version 0.12. Copyright (C) 1985,89,90,91,92,93,95,2000 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _REGEX_H #define _REGEX_H 1 /* Allow the use in C++ code. */ #ifdef __cplusplus extern "C" { #endif /* POSIX says that must be included (by the caller) before . */ #if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS /* VMS doesn't have `size_t' in , even though POSIX says it should be there. */ # include #endif /* The following bits are used to determine the regexp syntax we recognize. The set/not-set meanings where historically chosen so that Emacs syntax had the value 0. The bits are given in alphabetical order, and the definitions shifted by one from the previous bit; thus, when we add or remove a bit, only one other definition need change. */ typedef unsigned long int reg_syntax_t; /* If this bit is not set, then \ inside a bracket expression is literal. If set, then such a \ quotes the following character. */ #define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) /* If this bit is not set, then + and ? are operators, and \+ and \? are literals. If set, then \+ and \? are operators and + and ? are literals. */ #define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) /* If this bit is set, then character classes are supported. They are: [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. If not set, then character classes are not supported. */ #define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: ^ is an anchor if it is at the beginning of a regular expression or after an open-group or an alternation operator; $ is an anchor if it is at the end of a regular expression, or before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. We already implemented a previous draft which made those constructs invalid, though, so we haven't changed the code back. */ #define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) /* If this bit is set, then special characters are always special regardless of where they are in the pattern. If this bit is not set, then special characters are special only in some contexts; otherwise they are ordinary. Specifically, * + ? and intervals are only special when not after the beginning, open-group, or alternation operator. */ #define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) /* If this bit is set, then *, +, ?, and { cannot be first in an re or immediately after an alternation or begin-group operator. */ #define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) /* If this bit is set, then . matches newline. If not set, then it doesn't. */ #define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) /* If this bit is set, then . doesn't match NUL. If not set, then it does. */ #define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) /* If this bit is set, nonmatching lists [^...] do not match newline. If not set, they do. */ #define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) /* If this bit is set, either \{...\} or {...} defines an interval, depending on RE_NO_BK_BRACES. If not set, \{, \}, {, and } are literals. */ #define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) /* If this bit is set, +, ? and | aren't recognized as operators. If not set, they are. */ #define RE_LIMITED_OPS (RE_INTERVALS << 1) /* If this bit is set, newline is an alternation operator. If not set, newline is literal. */ #define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) /* If this bit is set, then `{...}' defines an interval, and \{ and \} are literals. If not set, then `\{...\}' defines an interval. */ #define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) /* If this bit is set, (...) defines a group, and \( and \) are literals. If not set, \(...\) defines a group, and ( and ) are literals. */ #define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) /* If this bit is set, then \ matches . If not set, then \ is a back-reference. */ #define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) /* If this bit is set, then | is an alternation operator, and \| is literal. If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) /* If this bit is set, then an ending range point collating higher than the starting range point, as in [z-a], is invalid. If not set, then when ending range point collates higher than the starting range point, the range is ignored. */ #define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) /* If this bit is set, then an unmatched ) is ordinary. If not set, then an unmatched ) is invalid. */ #define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) /* If this bit is set, succeed as soon as we match the whole pattern, without further backtracking. */ #define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) /* If this bit is set, do not process the GNU regex operators. If not set, then the GNU regex operators are recognized. */ #define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) /* If this bit is set, then *?, +? and ?? match non greedily. */ #define RE_FRUGAL (RE_NO_GNU_OPS << 1) /* If this bit is set, then (?:...) is treated as a shy group. */ #define RE_SHY_GROUPS (RE_FRUGAL << 1) /* If this bit is set, ^ and $ only match at beg/end of buffer. */ #define RE_NO_NEWLINE_ANCHOR (RE_SHY_GROUPS << 1) /* If this bit is set, turn on internal regex debugging. If not set, and debugging was on, turn it off. This only works if regex.c is compiled -DDEBUG. We define this bit always, so that all that's needed to turn on debugging is to recompile regex.c; the calling code can always have this bit set, and it won't affect anything in the normal case. */ #define RE_DEBUG (RE_NO_NEWLINE_ANCHOR << 1) /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is stored in the pattern buffer, so changing this does not affect already-compiled regexps. */ extern reg_syntax_t re_syntax_options; #ifdef emacs /* In Emacs, this is the string or buffer in which we are matching. It is used for looking up syntax properties. */ extern Lisp_Object re_match_object; #endif /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so don't delete them!) */ /* [[[begin syntaxes]]] */ #define RE_SYNTAX_EMACS \ (RE_CHAR_CLASSES | RE_INTERVALS | RE_SHY_GROUPS | RE_FRUGAL) #define RE_SYNTAX_AWK \ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) #define RE_SYNTAX_GNU_AWK \ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) #define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | RE_INTERVALS | RE_NO_GNU_OPS) #define RE_SYNTAX_GREP \ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ | RE_NEWLINE_ALT) #define RE_SYNTAX_EGREP \ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ | RE_NO_BK_VBAR) #define RE_SYNTAX_POSIX_EGREP \ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ #define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC #define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC /* Syntax bits common to both basic and extended POSIX regex syntax. */ #define _RE_SYNTAX_POSIX_COMMON \ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ | RE_INTERVALS | RE_NO_EMPTY_RANGES) #define RE_SYNTAX_POSIX_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this isn't minimal, since other operators, such as \`, aren't disabled. */ #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) #define RE_SYNTAX_POSIX_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is removed and RE_NO_BK_REFS is added. */ #define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ /* Maximum number of duplicates an interval can allow. Some systems (erroneously) define this in other header files, but we want our value, so remove any previous define. */ #ifdef RE_DUP_MAX # undef RE_DUP_MAX #endif /* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ #define RE_DUP_MAX (0x7fff) /* POSIX `cflags' bits (i.e., information for `regcomp'). */ /* If this bit is set, then use extended regular expression syntax. If not set, then use basic regular expression syntax. */ #define REG_EXTENDED 1 /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define REG_ICASE (REG_EXTENDED << 1) /* If this bit is set, then anchors do not match at newline characters in the string. If not set, then anchors do match at newlines. */ #define REG_NEWLINE (REG_ICASE << 1) /* If this bit is set, then report only success or fail in regexec. If not set, then returns differ between not matching and errors. */ #define REG_NOSUB (REG_NEWLINE << 1) /* POSIX `eflags' bits (i.e., information for regexec). */ /* If this bit is set, then the beginning-of-line operator doesn't match the beginning of the string (presumably because it's not the beginning of a line). If not set, then the beginning-of-line operator does match the beginning of the string. */ #define REG_NOTBOL 1 /* Like REG_NOTBOL, except for the end-of-line. */ #define REG_NOTEOL (1 << 1) /* If any error codes are removed, changed, or added, update the `re_error_msg' table in regex.c. */ typedef enum { #ifdef _XOPEN_SOURCE REG_ENOSYS = -1, /* This will never happen for this implementation. */ #endif REG_NOERROR = 0, /* Success. */ REG_NOMATCH, /* Didn't find a match (for regexec). */ /* POSIX regcomp return error codes. (In the order listed in the standard.) */ REG_BADPAT, /* Invalid pattern. */ REG_ECOLLATE, /* Not implemented. */ REG_ECTYPE, /* Invalid character class name. */ REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ REG_EBRACK, /* Unmatched left bracket. */ REG_EPAREN, /* Parenthesis imbalance. */ REG_EBRACE, /* Unmatched \{. */ REG_BADBR, /* Invalid contents of \{\}. */ REG_ERANGE, /* Invalid range end. */ REG_ESPACE, /* Ran out of memory. */ REG_BADRPT, /* No preceding re for repetition op. */ /* Error codes we've added. */ REG_EEND, /* Premature end. */ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ } reg_errcode_t; /* This data structure represents a compiled pattern. Before calling the pattern compiler, the fields `buffer', `allocated', `fastmap', `translate', and `no_sub' can be set. After the pattern has been compiled, the `re_nsub' field is available. All other fields are private to the regex routines. */ #ifndef RE_TRANSLATE_TYPE # define RE_TRANSLATE_TYPE char * #endif struct re_pattern_buffer { /* [[[begin pattern_buffer]]] */ /* Space that holds the compiled pattern. It is declared as `unsigned char *' because its elements are sometimes used as array indexes. */ unsigned char *buffer; /* Number of bytes to which `buffer' points. */ size_t allocated; /* Number of bytes actually used in `buffer'. */ size_t used; /* Syntax setting with which the pattern was compiled. */ reg_syntax_t syntax; /* Pointer to a fastmap, if any, otherwise zero. re_search uses the fastmap, if there is one, to skip over impossible starting points for matches. */ char *fastmap; /* Either a translate table to apply to all characters before comparing them, or zero for no translation. The translation is applied to a pattern when it is compiled and to a string when it is matched. */ RE_TRANSLATE_TYPE translate; /* Number of subexpressions found by the compiler. */ size_t re_nsub; /* Zero if this pattern cannot match the empty string, one else. Well, in truth it's used only in `re_search_2', to see whether or not we should use the fastmap, so we don't set this absolutely perfectly; see `re_compile_fastmap'. */ unsigned can_be_null : 1; /* If REGS_UNALLOCATED, allocate space in the `regs' structure for `max (RE_NREGS, re_nsub + 1)' groups. If REGS_REALLOCATE, reallocate space if necessary. If REGS_FIXED, use what's there. */ #define REGS_UNALLOCATED 0 #define REGS_REALLOCATE 1 #define REGS_FIXED 2 unsigned regs_allocated : 2; /* Set to zero when `regex_compile' compiles a pattern; set to one by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; /* If set, `re_match_2' does not return information about subexpressions. */ unsigned no_sub : 1; /* If set, a beginning-of-line anchor doesn't match at the beginning of the string. */ unsigned not_bol : 1; /* Similarly for an end-of-line anchor. */ unsigned not_eol : 1; #ifdef emacs /* If true, multi-byte form in the `buffer' should be recognized as a multibyte character. */ unsigned multibyte : 1; #endif /* [[[end pattern_buffer]]] */ }; typedef struct re_pattern_buffer regex_t; /* Type for byte offsets within the string. POSIX mandates this. */ typedef int regoff_t; /* This is the structure we store register match data in. See regex.texinfo for a full description of what registers match. */ struct re_registers { unsigned num_regs; regoff_t *start; regoff_t *end; }; /* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, `re_match_2' returns information about at least this many registers the first time a `regs' structure is passed. */ #ifndef RE_NREGS # define RE_NREGS 30 #endif /* POSIX specification for registers. Aside from the different names than `re_registers', POSIX uses an array of structures, instead of a structure of arrays. */ typedef struct { regoff_t rm_so; /* Byte offset from string's start to substring's start. */ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ } regmatch_t; /* Declarations for routines. */ /* To avoid duplicating every routine declaration -- once with a prototype (if we are ANSI), and once without (if we aren't) -- we use the following macro to declare argument types. This unfortunately clutters up the declarations a bit, but I think it's worth it. */ #if defined __STDC__ || defined PROTOTYPES # define _RE_ARGS(args) args #else /* not __STDC__ || PROTOTYPES */ # define _RE_ARGS(args) () #endif /* not __STDC__ || PROTOTYPES */ /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); /* Compile the regular expression PATTERN, with length LENGTH and syntax given by the global `re_syntax_options', into the buffer BUFFER. Return NULL if successful, and an error string if not. */ extern const char *re_compile_pattern _RE_ARGS ((const char *pattern, size_t length, struct re_pattern_buffer *buffer)); /* Compile a fastmap for the compiled pattern in BUFFER; used to accelerate searches. Return 0 if successful and -2 if was an internal error. */ extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); /* Search in the string STRING (with length LENGTH) for the pattern compiled into BUFFER. Start searching at position START, for RANGE characters. Return the starting position of the match, -1 for no match, or -2 for an internal error. Also return register information in REGS (if REGS and BUFFER->no_sub are nonzero). */ extern int re_search _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, int length, int start, int range, struct re_registers *regs)); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ extern int re_search_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop)); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ extern int re_match _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, int length, int start, struct re_registers *regs)); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ extern int re_match_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, int length1, const char *string2, int length2, int start, struct re_registers *regs, int stop)); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated with malloc, and must each be at least `NUM_REGS * sizeof (regoff_t)' bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ extern void re_set_registers _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, unsigned num_regs, regoff_t *starts, regoff_t *ends)); #if defined _REGEX_RE_COMP || defined _LIBC # ifndef _CRAY /* 4.2 bsd compatibility. */ extern char *re_comp _RE_ARGS ((const char *)); extern int re_exec _RE_ARGS ((const char *)); # endif #endif /* GCC 2.95 and later have "__restrict"; C99 compilers have "restrict", and "configure" may have defined "restrict". */ #ifndef __restrict # if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) # if defined restrict || 199901L <= __STDC_VERSION__ # define __restrict restrict # else # define __restrict # endif # endif #endif /* For now unconditionally define __restrict_arr to expand to nothing. Ideally we would have a test for the compiler which allows defining it to restrict. */ #undef __restrict_arr #define __restrict_arr /* POSIX compatibility. */ extern int regcomp _RE_ARGS ((regex_t *__restrict __preg, const char *__restrict __pattern, int __cflags)); extern int regexec _RE_ARGS ((const regex_t *__restrict __preg, const char *__restrict __string, size_t __nmatch, regmatch_t __pmatch[__restrict_arr], int __eflags)); extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, char *__errbuf, size_t __errbuf_size)); extern void regfree _RE_ARGS ((regex_t *__preg)); #ifdef __cplusplus } #endif /* C++ */ #endif /* regex.h */ /* Local variables: make-backup-files: t version-control: t trim-versions-without-asking: nil End: */ gnats-4.1.0/gnats/responsible0000644000175000017500000000227007374555634016771 0ustar chewiechewie00000000000000# # People responsible for a given PR. # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # person:full name:address # # * The `person' can either be an abbreviated name, or the person's # username (local to the GNATS site) which should be listed in the PR. # * The `full name' is simply their name, as in "Diane Williams". # * The `address' field is either empty for local addresses, or should # the electronic mail address of the person. # # Note that all contact names that appear in other admin files (submitter # and category) are also mapped through this file when email is sent. # # You MUST have this entry for GNATS to work. It must be named # gnats-admin. If you want the GNATS administrator to have a # different e-mail address than `gnats-admin', add the desired address # in the `address' (third) field of this entry. # gnats-admin: GNATS administrator: # # Sample remote people: # # Bill is a local user, so `mail bill' will work. Al is remote, so he # should receive the message as `al@senate.gov'. Finally, joe is # another local user. # #bill:Bill Clinton: # #al:Al Gore:al@senate.gov # #joe:Joe McCarthy: gnats-4.1.0/gnats/rmcat.sh0000644000175000017500000000355207331325174016152 0ustar chewiechewie00000000000000#!/bin/sh # Delete a category from GNATS. # Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. # Contributed by Brendan Kehoe (brendan@cygnus.com). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. prog=rmcat if [ $# -eq 0 ]; then echo "usage: $prog category [category...]" exit 1 fi GNATS_DB_DIR="`query-pr --print-directory-for-database`" if [ ! -d "$GNATS_DB_DIR" ] then echo "No directory $GNATS_DB_DIR" exit 1 fi for i in "$@"; do if query-pr --list-categories | grep "^${i}:" >/dev/null 2>&1; then echo "$prog: category \`$i' is still in the categories file, please remove it." continue fi if [ ! -d "$GNATS_DB_DIR/$i" ]; then echo "$prog: no directory for category \`$i'" continue fi if [ "`ls $GNATS_DB_DIR/\"$i\"/* 2>/dev/null`" != "" ]; then echo "$prog: bug reports are still in \`$i', remove them or recategorize them." continue fi echo -n "Trying to delete \'$i'..." # Can't test return value of rmdir on old SunOSes...rrgh rmdir "$GNATS_DB_DIR/$i" 2>/dev/null if [ -d "$GNATS_DB_DIR/$i" ] ; then echo echo "$prog: could not remove \`$GNATS_DB_DIR/$i'" continue fi echo 'done.' done exit 0 gnats-4.1.0/gnats/states0000644000175000017500000000563707552641370015750 0ustar chewiechewie00000000000000# Possible states for a PR. # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # state[:type[:description]] # # that is, any of the following are okay: # # suspended # suspended:closed # suspended:closed:No solution yet, work on it also suspended for the time being. # suspended::No solution yet, work on it also suspended for the time being. # # * `state' is the name of the state; it can contain alphanumerics, # "-", "_", and ".", but no other characters. # # * `type' is the optional name of the state type; it can contain # alphanumerics, "-", "_", and ".", but no other characters. The # only defined state types are "open" and "closed". The "open" state # isn't currently used for anything. Changing the state of a PR to # any state of type "closed" will set the Closed-Date field with a # time stamp. Changing the state of a PR from one "closed" state to # another will leave the Closed-Date field as it was. Changing the # state of a PR from any state of type "closed" to a non-closed # state will clear the Closed-Date field. The --skip-closed option # of query-pr refers to all states of type ``closed'', not to a # specific state name of ``closed''. # # `description' is an optional one-line description of what this # state means. Any character is okay in the description; a newline # ends it, however. GNATS does not currently use the description # for anything, but certain external tools (such as TkGnats and # Gnatsweb) look for it, so it's a good idea include one for every # state. # # The first listed state is the default state for an incoming Problem # Report. The last listed state is considered one of the final # ("closed") states for a Problem Report and will be forced to have a # type of "closed". Once a PR is in this state, its life-cycle is # usually over unless someone re-opens it. # It is recommended that the first state always be "open", as some # external tools may look for this to determine whether or not a PR # has been acted on. Change at your own risk. open::Default state for a new problem report. # The middle states are what you think is useful; customize them as # you wish. You can add or delete states here; it is not required # that there be three of them. Depending on your definition of the # suspended state, you may want to set its type to be "closed". analyzed::Problem examined, understood; difficulty of solution estimated. suspended::No solution yet, work on it also suspended for the time being. feedback::Problem solved, now awaiting originator's reaction to fix. # Where old PRs go to die. Like "open", there may be external tools # which look for this state to know if a PR is still active. Change # at your own risk. The last state will be forced to be a "closed" type # even if you specify something else. closed:closed:This PR no longer active; it is resolved or otherwise defunct. gnats-4.1.0/gnats/submitters0000644000175000017500000000410207062077331016624 0ustar chewiechewie00000000000000# # submitters database for GNATS # # Any line which begins with a `#' is considered a comment, and GNATS # will ignore it. # # Each entry has the format: # # submitter:full submitter name:type:response-time:contact:notify-others # # * submitter: The name of the site, customer, etc., sending the # report in. # * full submitter name: The description, like `Foo Widgets Inc.'. # * submitter type: Can be contract type, level of expertise, etc. # * response time: If the database dbconfig file has the # notify-about-expired-prs entry set to true, GNATS will use this # field to schedule when at_pr should notify the gnats-admin, # responsible person and submitter contact that the PR wasn't # analyzed within the agreed response time. # * contact: Principal contact for the submitter. # * notify: Others who should be Cc'd on any submitted PRs coming from # this submitter. These people are only notified when a PR is # initially created, not on edits. # # The submitter contact: and notify: fields are mapped through the responsible # file when trying to determine email addresses. # # The first submitter entry in the file is used as the submitter # for PRs with invalid/empty submitter fields. None of the fields have # any special meaning (in particular, the "unknown" name isn't explicitly # referred to) and can be changed to any desired value. # unknown:The Unknown Submitter:none:-1:gnats-admin: # # Sample submitters: # # For the submitter `foo', we will know that they have a "six-month" # contract, and that `joe' is the person who should worry about PRs # coming from Foo Widgets Inc. There is no reply-time. #foo:Foo Widgets Inc.:six-month::joe: # # For the submitter `dod', they have a "DARPA" contract and `bill' is # to be given a copy of the PR, in addition to whomever might be # responsible for the category the PR was filed under. There is a # four-hour response time, and that `al' should also get a copy of the PR. #dod:Department of Defense:DARPA:4:bill:al # # A `test' submitter, for send-pr and general GNATS testing. #test:Test Non-Submitter:test:1:gnats-admin: gnats-4.1.0/gnats/gnugetopt.c0000644000175000017500000007314210207435253016666 0ustar chewiechewie00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 Free Software Foundation, Inc. NOTE: This source is derived from an old version taken from the GNU C Library (glibc). 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE #if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_LONG) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC # include # define _(msgid) gettext (msgid) # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "gnugetopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # if HAVE_STRINGS_H # include # endif # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } # ifdef text_set_element text_set_element (__libc_subinit, store_args_and_env); # endif /* text_set_element */ # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } #endif /* ! HAVE_GETOPT || ! HAVE_GETOPT_LONG */ #ifndef HAVE_GETOPT int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* ! HAVE_GETOPT */ #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ gnats-4.1.0/gnats/gnugetopt.h0000644000175000017500000001167410207435253016675 0ustar chewiechewie00000000000000/* Declarations for getopt. Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000, 2002 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if defined (__STDC__) && __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if defined (__STDC__) && __STDC__ /* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is undefined, we haven't run the autoconf check so provide the declaration without arguments. If it is 0, we checked and failed to find the declaration so provide a fully prototyped one. If it is 1, we found it so don't provide any declaration at all. */ #if !HAVE_DECL_GETOPT #if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in unistd.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else #ifndef __cplusplus extern int getopt (); #endif /* __cplusplus */ #endif #endif /* !HAVE_DECL_GETOPT */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* __STDC__ */ #ifdef __cplusplus } #endif #endif /* getopt.h */ gnats-4.1.0/gnats/gnugetopt1.c0000644000175000017500000001074510207435253016747 0ustar chewiechewie00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. NOTE: This source is derived from an old version taken from the GNU C Library (glibc). 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "gnugetopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE #ifndef HAVE_GETOPT_LONG /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* ! HAVE_GETOPT_LONG */ #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ gnats-4.1.0/gnats/ansidecl.h0000644000175000017500000002445410207435253016443 0ustar chewiechewie00000000000000/* ANSI and traditional C compatability macros Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ANSI and traditional C compatibility macros ANSI C is assumed if __STDC__ is #defined. Macro ANSI C definition Traditional C definition ----- ---- - ---------- ----------- - ---------- ANSI_PROTOTYPES 1 not defined PTR `void *' `char *' PTRCONST `void *const' `char *' LONG_DOUBLE `long double' `double' const not defined `' volatile not defined `' signed not defined `' VA_START(ap, var) va_start(ap, var) va_start(ap) Note that it is safe to write "void foo();" indicating a function with no return value, in all K+R compilers we have been able to test. For declaring functions with prototypes, we also provide these: PARAMS ((prototype)) -- for functions which take a fixed number of arguments. Use this when declaring the function. When defining the function, write a K+R style argument list. For example: char *strcpy PARAMS ((char *dest, char *source)); ... char * strcpy (dest, source) char *dest; char *source; { ... } VPARAMS ((prototype, ...)) -- for functions which take a variable number of arguments. Use PARAMS to declare the function, VPARAMS to define it. For example: int printf PARAMS ((const char *format, ...)); ... int printf VPARAMS ((const char *format, ...)) { ... } For writing functions which take variable numbers of arguments, we also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These hide the differences between K+R and C89 more thoroughly than the simple VA_START() macro mentioned above. VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls corresponding to the list of fixed arguments. Then use va_arg normally to get the variable arguments, or pass your va_list object around. You do not declare the va_list yourself; VA_OPEN does it for you. Here is a complete example: int printf VPARAMS ((const char *format, ...)) { int result; VA_OPEN (ap, format); VA_FIXEDARG (ap, const char *, format); result = vfprintf (stdout, format, ap); VA_CLOSE (ap); return result; } You can declare variables either before or after the VA_OPEN, VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning and end of a block. They must appear at the same nesting level, and any variables declared after VA_OPEN go out of scope at VA_CLOSE. Unfortunately, with a K+R compiler, that includes the argument list. You can have multiple instances of VA_OPEN/VA_CLOSE pairs in a single function in case you need to traverse the argument list more than once. For ease of writing code which uses GCC extensions but needs to be portable to other compilers, we provide the GCC_VERSION macro that simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various wrappers around __attribute__. Also, __extension__ will be #defined to nothing if it doesn't work. See below. This header also defines a lot of obsolete macros: CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID, AND, DOTS, NOARGS. Don't use them. */ #ifndef _ANSIDECL_H #define _ANSIDECL_H 1 /* Every source file includes this file, so they will all get the switch for lint. */ /* LINTLIBRARY */ /* Using MACRO(x,y) in cpp #if conditionals does not work with some older preprocessors. Thus we can't define something like this: #define HAVE_GCC_VERSION(MAJOR, MINOR) \ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) and then test "#if HAVE_GCC_VERSION(2,7)". So instead we use the macro below and test it against specific values. */ /* This macro simplifies testing whether we are using gcc, and if it is of a particular minimum version. (Both major & minor numbers are significant.) This macro will evaluate to 0 if we are not using gcc at all. */ #ifndef GCC_VERSION #define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) #endif /* GCC_VERSION */ #if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus)) /* All known AIX compilers implement these things (but don't always define __STDC__). The RISC/OS MIPS compiler defines these things in SVR4 mode, but does not define __STDC__. */ /* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other C++ compilers, does not define __STDC__, though it acts as if this was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ #define ANSI_PROTOTYPES 1 #define PTR void * #define PTRCONST void *const #define LONG_DOUBLE long double #define PARAMS(ARGS) ARGS #define VPARAMS(ARGS) ARGS #define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR) /* variadic function helper macros */ /* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's use without inhibiting further decls and without declaring an actual variable. */ #define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy #define VA_CLOSE(AP) } va_end(AP); } #define VA_FIXEDARG(AP, T, N) struct Qdmy #undef const #undef volatile #undef signed /* inline requires special treatment; it's in C99, and GCC >=2.7 supports it too, but it's not in C89. */ #undef inline #if __STDC_VERSION__ > 199901L /* it's a keyword */ #else # if GCC_VERSION >= 2007 # define inline __inline__ /* __inline__ prevents -pedantic warnings */ # else # define inline /* nothing */ # endif #endif /* These are obsolete. Do not use. */ #ifndef IN_GCC #define CONST const #define VOLATILE volatile #define SIGNED signed #define PROTO(type, name, arglist) type name arglist #define EXFUN(name, proto) name proto #define DEFUN(name, arglist, args) name(args) #define DEFUN_VOID(name) name(void) #define AND , #define DOTS , ... #define NOARGS void #endif /* ! IN_GCC */ #else /* Not ANSI C. */ #undef ANSI_PROTOTYPES #define PTR char * #define PTRCONST PTR #define LONG_DOUBLE double #define PARAMS(args) () #define VPARAMS(args) (va_alist) va_dcl #define VA_START(va_list, var) va_start(va_list) #define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy #define VA_CLOSE(AP) } va_end(AP); } #define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE) /* some systems define these in header files for non-ansi mode */ #undef const #undef volatile #undef signed #undef inline #define const #define volatile #define signed #define inline #ifndef IN_GCC #define CONST #define VOLATILE #define SIGNED #define PROTO(type, name, arglist) type name () #define EXFUN(name, proto) name() #define DEFUN(name, arglist, args) name arglist args; #define DEFUN_VOID(name) name() #define AND ; #define DOTS #define NOARGS #endif /* ! IN_GCC */ #endif /* ANSI C. */ /* Define macros for some gcc attributes. This permits us to use the macros freely, and know that they will come into play for the version of gcc in which they are supported. */ #if (GCC_VERSION < 2007) # define __attribute__(x) #endif /* Attribute __malloc__ on functions was valid as of gcc 2.96. */ #ifndef ATTRIBUTE_MALLOC # if (GCC_VERSION >= 2096) # define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) # else # define ATTRIBUTE_MALLOC # endif /* GNUC >= 2.96 */ #endif /* ATTRIBUTE_MALLOC */ /* Attributes on labels were valid as of gcc 2.93. */ #ifndef ATTRIBUTE_UNUSED_LABEL # if (GCC_VERSION >= 2093) # define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED # else # define ATTRIBUTE_UNUSED_LABEL # endif /* GNUC >= 2.93 */ #endif /* ATTRIBUTE_UNUSED_LABEL */ #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) #endif /* ATTRIBUTE_UNUSED */ #ifndef ATTRIBUTE_NORETURN #define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) #endif /* ATTRIBUTE_NORETURN */ /* Attribute `nonnull' was valid as of gcc 3.3. */ #ifndef ATTRIBUTE_NONNULL # if (GCC_VERSION >= 3003) # define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) # else # define ATTRIBUTE_NONNULL(m) # endif /* GNUC >= 3.3 */ #endif /* ATTRIBUTE_NONNULL */ /* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. This was the case for the `printf' format attribute by itself before GCC 3.3, but as of 3.3 we need to add the `nonnull' attribute to retain this behavior. */ #ifndef ATTRIBUTE_PRINTF #define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) #define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) #define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) #define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) #define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) #define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) #endif /* ATTRIBUTE_PRINTF */ /* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A NULL format specifier was allowed as of gcc 3.3. */ #ifndef ATTRIBUTE_NULL_PRINTF # if (GCC_VERSION >= 3003) # define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) # else # define ATTRIBUTE_NULL_PRINTF(m, n) # endif /* GNUC >= 3.3 */ # define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) # define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) # define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) # define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) # define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) #endif /* ATTRIBUTE_NULL_PRINTF */ /* We use __extension__ in some places to suppress -pedantic warnings about GCC extensions. This feature didn't work properly before gcc 2.8. */ #if GCC_VERSION < 2008 #define __extension__ #endif #endif /* ansidecl.h */ gnats-4.1.0/gnats/getdate.c0000600000175000017500000017345310212665120016257 0ustar chewiechewie00000000000000/* A Bison parser, made from ./getdate.y by GNU bison 1.35. */ #define YYBISON 1 /* Identify Bison output. */ # define tAGO 257 # define tDST 258 # define tDAY 259 # define tDAY_UNIT 260 # define tDAYZONE 261 # define tHOUR_UNIT 262 # define tLOCAL_ZONE 263 # define tMERIDIAN 264 # define tMINUTE_UNIT 265 # define tMONTH 266 # define tMONTH_UNIT 267 # define tSEC_UNIT 268 # define tYEAR_UNIT 269 # define tZONE 270 # define tSNUMBER 271 # define tUNUMBER 272 #line 1 "./getdate.y" /* Parse a string into an internal time stamp. Copyright 1999, 2000 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Originally written by Steven M. Bellovin while at the University of North Carolina at Chapel Hill. Later tweaked by a couple of people on Usenet. Completely overhauled by Rich $alz and Jim Berets in August, 1990. Modified by Paul Eggert in August 1999 to do the right thing about local DST. Unlike previous versions, this version is reentrant. */ #ifdef HAVE_CONFIG_H # include # ifdef HAVE_ALLOCA_H # include # endif #endif /* Since the code of getdate.y is not included in the Emacs executable itself, there is no need to #define static in this file. Even if the code were included in the Emacs executable, it probably wouldn't do any harm to #undef it here; this will only cause problems if we try to write to a static variable, which I don't think this code needs to do. */ #ifdef emacs # undef static #endif #include #if HAVE_STDLIB_H # include /* for `free'; used by Bison 1.27 */ #endif #if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII) # define IN_CTYPE_DOMAIN(c) 1 #else # define IN_CTYPE_DOMAIN(c) isascii (c) #endif #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) #define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) #define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) /* ISDIGIT differs from ISDIGIT_LOCALE, as follows: - Its arg may be any int or unsigned int; it need not be an unsigned char. - It's guaranteed to evaluate its argument exactly once. - It's typically faster. Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless it's important to use the locale's definition of `digit' even when the host does not conform to Posix. */ #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) #if STDC_HEADERS || HAVE_STRING_H # include #endif #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ # define __attribute__(x) #endif #ifndef ATTRIBUTE_UNUSED # define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) #endif #define EPOCH_YEAR 1970 #define TM_YEAR_BASE 1900 #define HOUR(x) ((x) * 60) /* An integer value, and the number of digits in its textual representation. */ typedef struct { int value; int digits; } textint; /* An entry in the lexical lookup table. */ typedef struct { char const *name; int type; int value; } table; /* Meridian: am, pm, or 24-hour style. */ enum { MERam, MERpm, MER24 }; /* Information passed to and from the parser. */ typedef struct { /* The input string remaining to be parsed. */ const char *input; /* N, if this is the Nth Tuesday. */ int day_ordinal; /* Day of week; Sunday is 0. */ int day_number; /* tm_isdst flag for the local zone. */ int local_isdst; /* Time zone, in minutes east of UTC. */ int time_zone; /* Style used for time. */ int meridian; /* Gregorian year, month, day, hour, minutes, and seconds. */ textint year; int month; int day; int hour; int minutes; int seconds; /* Relative year, month, day, hour, minutes, and seconds. */ int rel_year; int rel_month; int rel_day; int rel_hour; int rel_minutes; int rel_seconds; /* Counts of nonterminals of various flavors parsed so far. */ int dates_seen; int days_seen; int local_zones_seen; int rels_seen; int times_seen; int zones_seen; /* Table of local time zone abbrevations, terminated by a null entry. */ table local_time_zone_table[3]; } parser_control; #define PC (* (parser_control *) parm) #define YYLEX_PARAM parm #define YYPARSE_PARAM parm static int yyerror (); static int yylex (); #line 172 "./getdate.y" #ifndef YYSTYPE typedef union { int intval; textint textintval; } yystype; # define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif #ifndef YYDEBUG # define YYDEBUG 0 #endif #define YYFINAL 64 #define YYFLAG -32768 #define YYNTBASE 22 /* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ #define YYTRANSLATE(x) ((unsigned)(x) <= 272 ? yytranslate[x] : 33) /* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ static const char yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 20, 2, 2, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; #if YYDEBUG static const short yyprhs[] = { 0, 0, 1, 4, 6, 8, 10, 12, 14, 16, 18, 21, 26, 31, 38, 45, 47, 50, 52, 54, 57, 59, 62, 65, 69, 75, 79, 83, 86, 91, 94, 98, 101, 103, 106, 109, 111, 114, 117, 119, 122, 125, 127, 130, 133, 135, 138, 141, 143, 146, 149, 151, 153, 154 }; static const short yyrhs[] = { -1, 22, 23, 0, 24, 0, 25, 0, 26, 0, 28, 0, 27, 0, 29, 0, 31, 0, 18, 10, 0, 18, 19, 18, 32, 0, 18, 19, 18, 17, 0, 18, 19, 18, 19, 18, 32, 0, 18, 19, 18, 19, 18, 17, 0, 9, 0, 9, 4, 0, 16, 0, 7, 0, 16, 4, 0, 5, 0, 5, 20, 0, 18, 5, 0, 18, 21, 18, 0, 18, 21, 18, 21, 18, 0, 18, 17, 17, 0, 18, 12, 17, 0, 12, 18, 0, 12, 18, 20, 18, 0, 18, 12, 0, 18, 12, 18, 0, 30, 3, 0, 30, 0, 18, 15, 0, 17, 15, 0, 15, 0, 18, 13, 0, 17, 13, 0, 13, 0, 18, 6, 0, 17, 6, 0, 6, 0, 18, 8, 0, 17, 8, 0, 8, 0, 18, 11, 0, 17, 11, 0, 11, 0, 18, 14, 0, 17, 14, 0, 14, 0, 18, 0, 0, 10, 0 }; #endif #if YYDEBUG /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const short yyrline[] = { 0, 189, 191, 194, 197, 199, 201, 203, 205, 207, 210, 218, 225, 233, 240, 251, 254, 258, 261, 263, 267, 273, 278, 285, 291, 311, 318, 326, 331, 337, 342, 350, 360, 363, 366, 368, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 390, 392, 394, 396, 398, 402, 438, 441 }; #endif #if (YYDEBUG) || defined YYERROR_VERBOSE /* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ static const char *const yytname[] = { "$", "error", "$undefined.", "tAGO", "tDST", "tDAY", "tDAY_UNIT", "tDAYZONE", "tHOUR_UNIT", "tLOCAL_ZONE", "tMERIDIAN", "tMINUTE_UNIT", "tMONTH", "tMONTH_UNIT", "tSEC_UNIT", "tYEAR_UNIT", "tZONE", "tSNUMBER", "tUNUMBER", "':'", "','", "'/'", "spec", "item", "time", "local_zone", "zone", "day", "date", "rel", "relunit", "number", "o_merid", 0 }; #endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const short yyr1[] = { 0, 22, 22, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 32, 32 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const short yyr2[] = { 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 4, 4, 6, 6, 1, 2, 1, 1, 2, 1, 2, 2, 3, 5, 3, 3, 2, 4, 2, 3, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, 1 }; /* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const short yydefact[] = { 1, 0, 20, 41, 18, 44, 15, 47, 0, 38, 50, 35, 17, 0, 51, 2, 3, 4, 5, 7, 6, 8, 32, 9, 21, 16, 27, 19, 40, 43, 46, 37, 49, 34, 22, 39, 42, 10, 45, 29, 36, 48, 33, 0, 0, 0, 31, 0, 26, 30, 25, 52, 23, 28, 53, 12, 0, 11, 0, 52, 24, 14, 13, 0, 0 }; static const short yydefgoto[] = { 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 57 }; static const short yypact[] = { -32768, 0, 1,-32768,-32768,-32768, 19,-32768, -14,-32768, -32768,-32768, 32, 26, 14,-32768,-32768,-32768,-32768,-32768, -32768,-32768, 27,-32768,-32768,-32768, 22,-32768,-32768,-32768, -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -16, -32768,-32768,-32768, 29, 25, 30,-32768, 31,-32768,-32768, -32768, 28, 23,-32768,-32768,-32768, 33,-32768, 34, -7, -32768,-32768,-32768, 50,-32768 }; static const short yypgoto[] = { -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -6 }; #define YYLAST 53 static const short yytable[] = { 63, 48, 49, 54, 26, 2, 3, 4, 5, 6, 61, 7, 8, 9, 10, 11, 12, 13, 14, 34, 35, 24, 36, 25, 37, 38, 39, 40, 41, 42, 46, 43, 28, 44, 29, 45, 27, 30, 54, 31, 32, 33, 47, 51, 58, 55, 50, 56, 52, 53, 64, 59, 60, 62 }; static const short yycheck[] = { 0, 17, 18, 10, 18, 5, 6, 7, 8, 9, 17, 11, 12, 13, 14, 15, 16, 17, 18, 5, 6, 20, 8, 4, 10, 11, 12, 13, 14, 15, 3, 17, 6, 19, 8, 21, 4, 11, 10, 13, 14, 15, 20, 18, 21, 17, 17, 19, 18, 18, 0, 18, 18, 59 }; #define YYPURE 1 /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ #line 3 "/usr/share/bison/bison.simple" /* Skeleton output parser for bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* This is the parser code that is written into each bison parser when the %semantic_parser declaration is not specified in the grammar. It was written by Richard Stallman by simplifying the hairy parser used when %semantic_parser is specified. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ #if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) /* The parser invokes alloca or malloc; define the necessary symbols. */ # if YYSTACK_USE_ALLOCA # define YYSTACK_ALLOC alloca # else # ifndef YYSTACK_USE_ALLOCA # if defined (alloca) || defined (_ALLOCA_H) # define YYSTACK_ALLOC alloca # else # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # else # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif # define YYSTACK_ALLOC malloc # define YYSTACK_FREE free # endif #endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ #if (! defined (yyoverflow) \ && (! defined (__cplusplus) \ || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { short yyss; YYSTYPE yyvs; # if YYLSP_NEEDED YYLTYPE yyls; # endif }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # if YYLSP_NEEDED # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAX) # else # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAX) # endif /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ register YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (0) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) # define YYSIZE_T __SIZE_TYPE__ #endif #if ! defined (YYSIZE_T) && defined (size_t) # define YYSIZE_T size_t #endif #if ! defined (YYSIZE_T) # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif #endif #if ! defined (YYSIZE_T) # define YYSIZE_T unsigned int #endif #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY -2 #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrlab1 /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yychar1 = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ { \ yyerror ("syntax error: cannot back up"); \ YYERROR; \ } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Compute the default location (before the actions are run). When YYLLOC_DEFAULT is run, CURRENT is set the location of the first token. By default, to implement support for ranges, extend its range to the last symbol. */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.last_line = Rhs[N].last_line; \ Current.last_column = Rhs[N].last_column; #endif /* YYLEX -- calling `yylex' with the right arguments. */ #if YYPURE # if YYLSP_NEEDED # ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) # else # define YYLEX yylex (&yylval, &yylloc) # endif # else /* !YYLSP_NEEDED */ # ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, YYLEX_PARAM) # else # define YYLEX yylex (&yylval) # endif # endif /* !YYLSP_NEEDED */ #else /* !YYPURE */ # define YYLEX yylex () #endif /* !YYPURE */ /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #if YYMAXDEPTH == 0 # undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #ifdef YYERROR_VERBOSE # ifndef yystrlen # if defined (__GLIBC__) && defined (_STRING_H) # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T # if defined (__STDC__) || defined (__cplusplus) yystrlen (const char *yystr) # else yystrlen (yystr) const char *yystr; # endif { register const char *yys = yystr; while (*yys++ != '\0') continue; return yys - yystr - 1; } # endif # endif # ifndef yystpcpy # if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) # include # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * # if defined (__STDC__) || defined (__cplusplus) yystpcpy (char *yydest, const char *yysrc) # else yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; # endif { register char *yyd = yydest; register const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif #endif #line 316 "/usr/share/bison/bison.simple" /* The user can define YYPARSE_PARAM as the name of an argument to be passed into yyparse. The argument should have type void *. It should actually point to an object. Grammar actions can access the variable by casting it to the proper pointer type. */ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) # define YYPARSE_PARAM_ARG void *YYPARSE_PARAM # define YYPARSE_PARAM_DECL # else # define YYPARSE_PARAM_ARG YYPARSE_PARAM # define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; # endif #else /* !YYPARSE_PARAM */ # define YYPARSE_PARAM_ARG # define YYPARSE_PARAM_DECL #endif /* !YYPARSE_PARAM */ /* Prevent warning if -Wstrict-prototypes. */ #ifdef __GNUC__ # ifdef YYPARSE_PARAM int yyparse (void *); # else int yyparse (void); # endif #endif /* YY_DECL_VARIABLES -- depending whether we use a pure parser, variables are global, or local to YYPARSE. */ #define YY_DECL_NON_LSP_VARIABLES \ /* The lookahead symbol. */ \ int yychar; \ \ /* The semantic value of the lookahead symbol. */ \ YYSTYPE yylval; \ \ /* Number of parse errors so far. */ \ int yynerrs; #if YYLSP_NEEDED # define YY_DECL_VARIABLES \ YY_DECL_NON_LSP_VARIABLES \ \ /* Location data for the lookahead symbol. */ \ YYLTYPE yylloc; #else # define YY_DECL_VARIABLES \ YY_DECL_NON_LSP_VARIABLES #endif /* If nonreentrant, generate the variables here. */ #if !YYPURE YY_DECL_VARIABLES #endif /* !YYPURE */ int yyparse (YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL { /* If reentrant, generate the variables here. */ #if YYPURE YY_DECL_VARIABLES #endif /* !YYPURE */ register int yystate; register int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* Lookahead token as an internal (translated) token number. */ int yychar1 = 0; /* Three stacks and their tools: `yyss': related to states, `yyvs': related to semantic values, `yyls': related to locations. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ short yyssa[YYINITDEPTH]; short *yyss = yyssa; register short *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; register YYSTYPE *yyvsp; #if YYLSP_NEEDED /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp; #endif #if YYLSP_NEEDED # define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) #else # define YYPOPSTACK (yyvsp--, yyssp--) #endif YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYLSP_NEEDED YYLTYPE yyloc; #endif /* When reducing, the number of symbols on the RHS of the reduced rule. */ int yylen; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; #if YYLSP_NEEDED yylsp = yyls; #endif goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyssp >= yyss + yystacksize - 1) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; short *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. */ # if YYLSP_NEEDED YYLTYPE *yyls1 = yyls; /* This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow ("parser stack overflow", &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; # else yyoverflow ("parser stack overflow", &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); # endif yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyoverflowlab; # else /* Extend the stack our own way. */ if (yystacksize >= YYMAXDEPTH) goto yyoverflowlab; yystacksize *= 2; if (yystacksize > YYMAXDEPTH) yystacksize = YYMAXDEPTH; { short *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyoverflowlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); # if YYLSP_NEEDED YYSTACK_RELOCATE (yyls); # endif # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; #if YYLSP_NEEDED yylsp = yyls + yysize - 1; #endif YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyssp >= yyss + yystacksize - 1) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* yyresume: */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYFLAG) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* yychar is either YYEMPTY or YYEOF or a valid token in external form. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } /* Convert token to internal form (in yychar1) for indexing tables with */ if (yychar <= 0) /* This means end of input. */ { yychar1 = 0; yychar = YYEOF; /* Don't call YYLEX any more */ YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yychar1 = YYTRANSLATE (yychar); #if YYDEBUG /* We have to keep this `#if YYDEBUG', since we use variables which are defined only if `YYDEBUG' is set. */ if (yydebug) { YYFPRINTF (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); /* Give the individual parser a way to print the precise meaning of a token, for further debugging info. */ # ifdef YYPRINT YYPRINT (stderr, yychar, yylval); # endif YYFPRINTF (stderr, ")\n"); } #endif } yyn += yychar1; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) goto yydefault; yyn = yytable[yyn]; /* yyn is what to do for this token type in this state. Negative => reduce, -yyn is rule number. Positive => shift, yyn is new state. New state is final state => don't bother to shift, just return success. 0, or most negative number => error. */ if (yyn < 0) { if (yyn == YYFLAG) goto yyerrlab; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrlab; if (yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ YYDPRINTF ((stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1])); /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; #if YYLSP_NEEDED *++yylsp = yylloc; #endif /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; yystate = yyn; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to the semantic value of the lookahead token. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; #if YYLSP_NEEDED /* Similarly for the default location. Let the user run additional commands if for instance locations are ranges. */ yyloc = yylsp[1-yylen]; YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); #endif #if YYDEBUG /* We have to keep this `#if YYDEBUG', since we use variables which are defined only if `YYDEBUG' is set. */ if (yydebug) { int yyi; YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", yyn, yyrline[yyn]); /* Print the symbols being reduced, and their result. */ for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); } #endif switch (yyn) { case 3: #line 196 "./getdate.y" { PC.times_seen++; ; break;} case 4: #line 198 "./getdate.y" { PC.local_zones_seen++; ; break;} case 5: #line 200 "./getdate.y" { PC.zones_seen++; ; break;} case 6: #line 202 "./getdate.y" { PC.dates_seen++; ; break;} case 7: #line 204 "./getdate.y" { PC.days_seen++; ; break;} case 8: #line 206 "./getdate.y" { PC.rels_seen++; ; break;} case 10: #line 212 "./getdate.y" { PC.hour = yyvsp[-1].textintval.value; PC.minutes = 0; PC.seconds = 0; PC.meridian = yyvsp[0].intval; ; break;} case 11: #line 219 "./getdate.y" { PC.hour = yyvsp[-3].textintval.value; PC.minutes = yyvsp[-1].textintval.value; PC.seconds = 0; PC.meridian = yyvsp[0].intval; ; break;} case 12: #line 226 "./getdate.y" { PC.hour = yyvsp[-3].textintval.value; PC.minutes = yyvsp[-1].textintval.value; PC.meridian = MER24; PC.zones_seen++; PC.time_zone = yyvsp[0].textintval.value % 100 + (yyvsp[0].textintval.value / 100) * 60; ; break;} case 13: #line 234 "./getdate.y" { PC.hour = yyvsp[-5].textintval.value; PC.minutes = yyvsp[-3].textintval.value; PC.seconds = yyvsp[-1].textintval.value; PC.meridian = yyvsp[0].intval; ; break;} case 14: #line 241 "./getdate.y" { PC.hour = yyvsp[-5].textintval.value; PC.minutes = yyvsp[-3].textintval.value; PC.seconds = yyvsp[-1].textintval.value; PC.meridian = MER24; PC.zones_seen++; PC.time_zone = yyvsp[0].textintval.value % 100 + (yyvsp[0].textintval.value / 100) * 60; ; break;} case 15: #line 253 "./getdate.y" { PC.local_isdst = yyvsp[0].intval; ; break;} case 16: #line 255 "./getdate.y" { PC.local_isdst = yyvsp[-1].intval < 0 ? 1 : yyvsp[-1].intval + 1; ; break;} case 17: #line 260 "./getdate.y" { PC.time_zone = yyvsp[0].intval; ; break;} case 18: #line 262 "./getdate.y" { PC.time_zone = yyvsp[0].intval + 60; ; break;} case 19: #line 264 "./getdate.y" { PC.time_zone = yyvsp[-1].intval + 60; ; break;} case 20: #line 269 "./getdate.y" { PC.day_ordinal = 1; PC.day_number = yyvsp[0].intval; ; break;} case 21: #line 274 "./getdate.y" { PC.day_ordinal = 1; PC.day_number = yyvsp[-1].intval; ; break;} case 22: #line 279 "./getdate.y" { PC.day_ordinal = yyvsp[-1].textintval.value; PC.day_number = yyvsp[0].intval; ; break;} case 23: #line 287 "./getdate.y" { PC.month = yyvsp[-2].textintval.value; PC.day = yyvsp[0].textintval.value; ; break;} case 24: #line 292 "./getdate.y" { /* Interpret as YYYY/MM/DD if the first value has 4 or more digits, otherwise as MM/DD/YY. The goal in recognizing YYYY/MM/DD is solely to support legacy machine-generated dates like those in an RCS log listing. If you want portability, use the ISO 8601 format. */ if (4 <= yyvsp[-4].textintval.digits) { PC.year = yyvsp[-4].textintval; PC.month = yyvsp[-2].textintval.value; PC.day = yyvsp[0].textintval.value; } else { PC.month = yyvsp[-4].textintval.value; PC.day = yyvsp[-2].textintval.value; PC.year = yyvsp[0].textintval; } ; break;} case 25: #line 312 "./getdate.y" { /* ISO 8601 format. YYYY-MM-DD. */ PC.year = yyvsp[-2].textintval; PC.month = -yyvsp[-1].textintval.value; PC.day = -yyvsp[0].textintval.value; ; break;} case 26: #line 319 "./getdate.y" { /* e.g. 17-JUN-1992. */ PC.day = yyvsp[-2].textintval.value; PC.month = yyvsp[-1].intval; PC.year.value = -yyvsp[0].textintval.value; PC.year.digits = yyvsp[0].textintval.digits; ; break;} case 27: #line 327 "./getdate.y" { PC.month = yyvsp[-1].intval; PC.day = yyvsp[0].textintval.value; ; break;} case 28: #line 332 "./getdate.y" { PC.month = yyvsp[-3].intval; PC.day = yyvsp[-2].textintval.value; PC.year = yyvsp[0].textintval; ; break;} case 29: #line 338 "./getdate.y" { PC.day = yyvsp[-1].textintval.value; PC.month = yyvsp[0].intval; ; break;} case 30: #line 343 "./getdate.y" { PC.day = yyvsp[-2].textintval.value; PC.month = yyvsp[-1].intval; PC.year = yyvsp[0].textintval; ; break;} case 31: #line 352 "./getdate.y" { PC.rel_seconds = -PC.rel_seconds; PC.rel_minutes = -PC.rel_minutes; PC.rel_hour = -PC.rel_hour; PC.rel_day = -PC.rel_day; PC.rel_month = -PC.rel_month; PC.rel_year = -PC.rel_year; ; break;} case 33: #line 365 "./getdate.y" { PC.rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 34: #line 367 "./getdate.y" { PC.rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 35: #line 369 "./getdate.y" { PC.rel_year += yyvsp[0].intval; ; break;} case 36: #line 371 "./getdate.y" { PC.rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 37: #line 373 "./getdate.y" { PC.rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 38: #line 375 "./getdate.y" { PC.rel_month += yyvsp[0].intval; ; break;} case 39: #line 377 "./getdate.y" { PC.rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 40: #line 379 "./getdate.y" { PC.rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 41: #line 381 "./getdate.y" { PC.rel_day += yyvsp[0].intval ; break;} case 42: #line 383 "./getdate.y" { PC.rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 43: #line 385 "./getdate.y" { PC.rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 44: #line 387 "./getdate.y" { PC.rel_hour += yyvsp[0].intval ; break;} case 45: #line 389 "./getdate.y" { PC.rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 46: #line 391 "./getdate.y" { PC.rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 47: #line 393 "./getdate.y" { PC.rel_minutes += yyvsp[0].intval ; break;} case 48: #line 395 "./getdate.y" { PC.rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 49: #line 397 "./getdate.y" { PC.rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; ; break;} case 50: #line 399 "./getdate.y" { PC.rel_seconds += yyvsp[0].intval; ; break;} case 51: #line 404 "./getdate.y" { if (PC.dates_seen && ! PC.rels_seen && (PC.times_seen || 2 < yyvsp[0].textintval.digits)) PC.year = yyvsp[0].textintval; else { if (4 < yyvsp[0].textintval.digits) { PC.dates_seen++; PC.day = yyvsp[0].textintval.value % 100; PC.month = (yyvsp[0].textintval.value / 100) % 100; PC.year.value = yyvsp[0].textintval.value / 10000; PC.year.digits = yyvsp[0].textintval.digits - 4; } else { PC.times_seen++; if (yyvsp[0].textintval.digits <= 2) { PC.hour = yyvsp[0].textintval.value; PC.minutes = 0; } else { PC.hour = yyvsp[0].textintval.value / 100; PC.minutes = yyvsp[0].textintval.value % 100; } PC.seconds = 0; PC.meridian = MER24; } } ; break;} case 52: #line 440 "./getdate.y" { yyval.intval = MER24; ; break;} case 53: #line 442 "./getdate.y" { yyval.intval = yyvsp[0].intval; ; break;} } #line 706 "/usr/share/bison/bison.simple" yyvsp -= yylen; yyssp -= yylen; #if YYLSP_NEEDED yylsp -= yylen; #endif #if YYDEBUG if (yydebug) { short *yyssp1 = yyss - 1; YYFPRINTF (stderr, "state stack now"); while (yyssp1 != yyssp) YYFPRINTF (stderr, " %d", *++yyssp1); YYFPRINTF (stderr, "\n"); } #endif *++yyvsp = yyval; #if YYLSP_NEEDED *++yylsp = yyloc; #endif /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTBASE] + *yyssp; if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTBASE]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #ifdef YYERROR_VERBOSE yyn = yypact[yystate]; if (yyn > YYFLAG && yyn < YYLAST) { YYSIZE_T yysize = 0; char *yymsg; int yyx, yycount; yycount = 0; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ for (yyx = yyn < 0 ? -yyn : 0; yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) if (yycheck[yyx + yyn] == yyx) yysize += yystrlen (yytname[yyx]) + 15, yycount++; yysize += yystrlen ("parse error, unexpected ") + 1; yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); yymsg = (char *) YYSTACK_ALLOC (yysize); if (yymsg != 0) { char *yyp = yystpcpy (yymsg, "parse error, unexpected "); yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); if (yycount < 5) { yycount = 0; for (yyx = yyn < 0 ? -yyn : 0; yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) if (yycheck[yyx + yyn] == yyx) { const char *yyq = ! yycount ? ", expecting " : " or "; yyp = yystpcpy (yyp, yyq); yyp = yystpcpy (yyp, yytname[yyx]); yycount++; } } yyerror (yymsg); YYSTACK_FREE (yymsg); } else yyerror ("parse error; also virtual memory exhausted"); } else #endif /* defined (YYERROR_VERBOSE) */ yyerror ("parse error"); } goto yyerrlab1; /*--------------------------------------------------. | yyerrlab1 -- error raised explicitly by an action | `--------------------------------------------------*/ yyerrlab1: if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ /* return failure if at end of input */ if (yychar == YYEOF) YYABORT; YYDPRINTF ((stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1])); yychar = YYEMPTY; } /* Else will try to reuse lookahead token after shifting the error token. */ yyerrstatus = 3; /* Each real token shifted decrements this */ goto yyerrhandle; /*-------------------------------------------------------------------. | yyerrdefault -- current state does not do anything special for the | | error token. | `-------------------------------------------------------------------*/ yyerrdefault: #if 0 /* This is wrong; only states that explicitly want error tokens should shift them. */ /* If its default is to accept any token, ok. Otherwise pop it. */ yyn = yydefact[yystate]; if (yyn) goto yydefault; #endif /*---------------------------------------------------------------. | yyerrpop -- pop the current state because it cannot handle the | | error token | `---------------------------------------------------------------*/ yyerrpop: if (yyssp == yyss) YYABORT; yyvsp--; yystate = *--yyssp; #if YYLSP_NEEDED yylsp--; #endif #if YYDEBUG if (yydebug) { short *yyssp1 = yyss - 1; YYFPRINTF (stderr, "Error: state stack now"); while (yyssp1 != yyssp) YYFPRINTF (stderr, " %d", *++yyssp1); YYFPRINTF (stderr, "\n"); } #endif /*--------------. | yyerrhandle. | `--------------*/ yyerrhandle: yyn = yypact[yystate]; if (yyn == YYFLAG) goto yyerrdefault; yyn += YYTERROR; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) goto yyerrdefault; yyn = yytable[yyn]; if (yyn < 0) { if (yyn == YYFLAG) goto yyerrpop; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrpop; if (yyn == YYFINAL) YYACCEPT; YYDPRINTF ((stderr, "Shifting error token, ")); *++yyvsp = yylval; #if YYLSP_NEEDED *++yylsp = yylloc; #endif yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; /*---------------------------------------------. | yyoverflowab -- parser overflow comes here. | `---------------------------------------------*/ yyoverflowlab: yyerror ("parser stack overflow"); yyresult = 2; /* Fall through. */ yyreturn: #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 445 "./getdate.y" /* Include this file down here because bison inserts code above which may define-away `const'. We want the prototype for get_date to have the same signature as the function definition. */ #include "getdate.h" #ifndef gmtime struct tm *gmtime (); #endif #ifndef localtime struct tm *localtime (); #endif #ifndef mktime time_t mktime (); #endif static table const meridian_table[] = { { "AM", tMERIDIAN, MERam }, { "A.M.", tMERIDIAN, MERam }, { "PM", tMERIDIAN, MERpm }, { "P.M.", tMERIDIAN, MERpm }, { 0, 0, 0 } }; static table const dst_table[] = { { "DST", tDST, 0 } }; static table const month_and_day_table[] = { { "JANUARY", tMONTH, 1 }, { "FEBRUARY", tMONTH, 2 }, { "MARCH", tMONTH, 3 }, { "APRIL", tMONTH, 4 }, { "MAY", tMONTH, 5 }, { "JUNE", tMONTH, 6 }, { "JULY", tMONTH, 7 }, { "AUGUST", tMONTH, 8 }, { "SEPTEMBER",tMONTH, 9 }, { "SEPT", tMONTH, 9 }, { "OCTOBER", tMONTH, 10 }, { "NOVEMBER", tMONTH, 11 }, { "DECEMBER", tMONTH, 12 }, { "SUNDAY", tDAY, 0 }, { "MONDAY", tDAY, 1 }, { "TUESDAY", tDAY, 2 }, { "TUES", tDAY, 2 }, { "WEDNESDAY",tDAY, 3 }, { "WEDNES", tDAY, 3 }, { "THURSDAY", tDAY, 4 }, { "THUR", tDAY, 4 }, { "THURS", tDAY, 4 }, { "FRIDAY", tDAY, 5 }, { "SATURDAY", tDAY, 6 }, { 0, 0, 0 } }; static table const time_units_table[] = { { "YEAR", tYEAR_UNIT, 1 }, { "MONTH", tMONTH_UNIT, 1 }, { "FORTNIGHT",tDAY_UNIT, 14 }, { "WEEK", tDAY_UNIT, 7 }, { "DAY", tDAY_UNIT, 1 }, { "HOUR", tHOUR_UNIT, 1 }, { "MINUTE", tMINUTE_UNIT, 1 }, { "MIN", tMINUTE_UNIT, 1 }, { "SECOND", tSEC_UNIT, 1 }, { "SEC", tSEC_UNIT, 1 }, { 0, 0, 0 } }; /* Assorted relative-time words. */ static table const relative_time_table[] = { { "TOMORROW", tMINUTE_UNIT, 24 * 60 }, { "YESTERDAY",tMINUTE_UNIT, - (24 * 60) }, { "TODAY", tMINUTE_UNIT, 0 }, { "NOW", tMINUTE_UNIT, 0 }, { "LAST", tUNUMBER, -1 }, { "THIS", tUNUMBER, 0 }, { "NEXT", tUNUMBER, 1 }, { "FIRST", tUNUMBER, 1 }, /*{ "SECOND", tUNUMBER, 2 }, */ { "THIRD", tUNUMBER, 3 }, { "FOURTH", tUNUMBER, 4 }, { "FIFTH", tUNUMBER, 5 }, { "SIXTH", tUNUMBER, 6 }, { "SEVENTH", tUNUMBER, 7 }, { "EIGHTH", tUNUMBER, 8 }, { "NINTH", tUNUMBER, 9 }, { "TENTH", tUNUMBER, 10 }, { "ELEVENTH", tUNUMBER, 11 }, { "TWELFTH", tUNUMBER, 12 }, { "AGO", tAGO, 1 }, { 0, 0, 0 } }; /* The time zone table. This table is necessarily incomplete, as time zone abbreviations are ambiguous; e.g. Australians interpret "EST" as Eastern time in Australia, not as US Eastern Standard Time. You cannot rely on getdate to handle arbitrary time zone abbreviations; use numeric abbreviations like `-0500' instead. */ static table const time_zone_table[] = { { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ { "UTC", tZONE, HOUR ( 0) }, { "WET", tZONE, HOUR ( 0) }, /* Western European */ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */ { "CET", tZONE, HOUR ( 1) }, /* Central European */ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */ { "MET", tZONE, HOUR ( 1) }, /* Middle European */ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */ { "GST", tZONE, HOUR (10) }, /* Guam Standard */ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */ { 0, 0, 0 } }; /* Military time zone table. */ static table const military_table[] = { { "A", tZONE, -HOUR ( 1) }, { "B", tZONE, -HOUR ( 2) }, { "C", tZONE, -HOUR ( 3) }, { "D", tZONE, -HOUR ( 4) }, { "E", tZONE, -HOUR ( 5) }, { "F", tZONE, -HOUR ( 6) }, { "G", tZONE, -HOUR ( 7) }, { "H", tZONE, -HOUR ( 8) }, { "I", tZONE, -HOUR ( 9) }, { "K", tZONE, -HOUR (10) }, { "L", tZONE, -HOUR (11) }, { "M", tZONE, -HOUR (12) }, { "N", tZONE, HOUR ( 1) }, { "O", tZONE, HOUR ( 2) }, { "P", tZONE, HOUR ( 3) }, { "Q", tZONE, HOUR ( 4) }, { "R", tZONE, HOUR ( 5) }, { "S", tZONE, HOUR ( 6) }, { "T", tZONE, HOUR ( 7) }, { "U", tZONE, HOUR ( 8) }, { "V", tZONE, HOUR ( 9) }, { "W", tZONE, HOUR (10) }, { "X", tZONE, HOUR (11) }, { "Y", tZONE, HOUR (12) }, { "Z", tZONE, HOUR ( 0) }, { 0, 0, 0 } }; static int to_hour (int hours, int meridian) { switch (meridian) { case MER24: return 0 <= hours && hours < 24 ? hours : -1; case MERam: return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1; case MERpm: return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1; default: abort (); } /* NOTREACHED */ } static int to_year (textint textyear) { int year = textyear.value; if (year < 0) year = -year; /* XPG4 suggests that years 00-68 map to 2000-2068, and years 69-99 map to 1969-1999. */ if (textyear.digits == 2) year += year < 69 ? 2000 : 1900; return year; } static table const * lookup_zone (parser_control const *pc, char const *name) { table const *tp; /* Try local zone abbreviations first; they're more likely to be right. */ for (tp = pc->local_time_zone_table; tp->name; tp++) if (strcmp (name, tp->name) == 0) return tp; for (tp = time_zone_table; tp->name; tp++) if (strcmp (name, tp->name) == 0) return tp; return 0; } #if ! HAVE_TM_GMTOFF /* Yield the difference between *A and *B, measured in seconds, ignoring leap seconds. The body of this function is taken directly from the GNU C Library; see src/strftime.c. */ static int tm_diff (struct tm const *a, struct tm const *b) { /* Compute intervening leap days correctly even if year is negative. Take care to avoid int overflow in leap day calculations, but it's OK to assume that A and B are close to each other. */ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3); int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3); int a100 = a4 / 25 - (a4 % 25 < 0); int b100 = b4 / 25 - (b4 % 25 < 0); int a400 = a100 >> 2; int b400 = b100 >> 2; int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); int years = a->tm_year - b->tm_year; int days = (365 * years + intervening_leap_days + (a->tm_yday - b->tm_yday)); return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec)); } #endif /* ! HAVE_TM_GMTOFF */ static table const * lookup_word (parser_control const *pc, char *word) { char *p; char *q; size_t wordlen; table const *tp; int i; int abbrev; /* Make it uppercase. */ for (p = word; *p; p++) if (ISLOWER ((unsigned char) *p)) *p = toupper ((unsigned char) *p); for (tp = meridian_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* See if we have an abbreviation for a month. */ wordlen = strlen (word); abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.'); for (tp = month_and_day_table; tp->name; tp++) if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0) return tp; if ((tp = lookup_zone (pc, word))) return tp; if (strcmp (word, dst_table[0].name) == 0) return dst_table; for (tp = time_units_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* Strip off any plural and try the units table again. */ if (word[wordlen - 1] == 'S') { word[wordlen - 1] = '\0'; for (tp = time_units_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */ } for (tp = relative_time_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* Military time zones. */ if (wordlen == 1) for (tp = military_table; tp->name; tp++) if (word[0] == tp->name[0]) return tp; /* Drop out any periods and try the time zone table again. */ for (i = 0, p = q = word; (*p = *q); q++) if (*q == '.') i = 1; else p++; if (i && (tp = lookup_zone (pc, word))) return tp; return 0; } static int yylex (YYSTYPE *lvalp, parser_control *pc) { unsigned char c; int count; for (;;) { while (c = *pc->input, ISSPACE (c)) pc->input++; if (ISDIGIT (c) || c == '-' || c == '+') { char const *p; int sign; int value; if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; c = *++pc->input; if (! ISDIGIT (c)) /* skip the '-' sign */ continue; } else sign = 0; p = pc->input; value = 0; do { value = 10 * value + c - '0'; c = *++p; } while (ISDIGIT (c)); lvalp->textintval.value = sign < 0 ? -value : value; lvalp->textintval.digits = p - pc->input; pc->input = p; return sign ? tSNUMBER : tUNUMBER; } if (ISALPHA (c)) { char buff[20]; char *p = buff; table const *tp; do { if (p < buff + sizeof buff - 1) *p++ = c; c = *++pc->input; } while (ISALPHA (c) || c == '.'); *p = '\0'; tp = lookup_word (pc, buff); if (! tp) return '?'; lvalp->intval = tp->value; return tp->type; } if (c != '(') return *pc->input++; count = 0; do { c = *pc->input++; if (c == '\0') return c; if (c == '(') count++; else if (c == ')') count--; } while (count > 0); } } /* Do nothing if the parser reports an error. */ static int yyerror (char *s ATTRIBUTE_UNUSED) { return 0; } /* Parse a date/time string P. Return the corresponding time_t value, or (time_t) -1 if there is an error. P can be an incomplete or relative time specification; if so, use *NOW as the basis for the returned time. */ time_t get_date (const char *p, const time_t *now) { time_t Start = now ? *now : time (0); struct tm *tmp = localtime (&Start); struct tm tm; struct tm tm0; parser_control pc; if (! tmp) return -1; pc.input = p; pc.year.value = tmp->tm_year + TM_YEAR_BASE; pc.year.digits = 4; pc.month = tmp->tm_mon + 1; pc.day = tmp->tm_mday; pc.hour = tmp->tm_hour; pc.minutes = tmp->tm_min; pc.seconds = tmp->tm_sec; tm.tm_isdst = tmp->tm_isdst; pc.meridian = MER24; pc.rel_seconds = 0; pc.rel_minutes = 0; pc.rel_hour = 0; pc.rel_day = 0; pc.rel_month = 0; pc.rel_year = 0; pc.dates_seen = 0; pc.days_seen = 0; pc.rels_seen = 0; pc.times_seen = 0; pc.local_zones_seen = 0; pc.zones_seen = 0; #if HAVE_TM_ZONE pc.local_time_zone_table[0].name = tmp->tm_zone; pc.local_time_zone_table[0].type = tLOCAL_ZONE; pc.local_time_zone_table[0].value = tmp->tm_isdst; pc.local_time_zone_table[1].name = 0; /* Probe the names used in the next three calendar quarters, looking for a tm_isdst different from the one we already have. */ { int quarter; for (quarter = 1; quarter <= 3; quarter++) { time_t probe = Start + quarter * (90 * 24 * 60 * 60); struct tm *probe_tm = localtime (&probe); if (probe_tm && probe_tm->tm_zone && probe_tm->tm_isdst != pc.local_time_zone_table[0].value) { { pc.local_time_zone_table[1].name = probe_tm->tm_zone; pc.local_time_zone_table[1].type = tLOCAL_ZONE; pc.local_time_zone_table[1].value = probe_tm->tm_isdst; pc.local_time_zone_table[2].name = 0; } break; } } } #else #if HAVE_TZNAME { # ifndef tzname extern char *tzname[]; # endif int i; for (i = 0; i < 2; i++) { pc.local_time_zone_table[i].name = tzname[i]; pc.local_time_zone_table[i].type = tLOCAL_ZONE; pc.local_time_zone_table[i].value = i; } pc.local_time_zone_table[i].name = 0; } #else pc.local_time_zone_table[0].name = 0; #endif #endif if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name && ! strcmp (pc.local_time_zone_table[0].name, pc.local_time_zone_table[1].name)) { /* This locale uses the same abbrevation for standard and daylight times. So if we see that abbreviation, we don't know whether it's daylight time. */ pc.local_time_zone_table[0].value = -1; pc.local_time_zone_table[1].name = 0; } if (yyparse (&pc) != 0 || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen || 1 < (pc.local_zones_seen + pc.zones_seen) || (pc.local_zones_seen && 1 < pc.local_isdst)) return -1; tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year; tm.tm_mon = pc.month - 1 + pc.rel_month; tm.tm_mday = pc.day + pc.rel_day; if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen)) { tm.tm_hour = to_hour (pc.hour, pc.meridian); if (tm.tm_hour < 0) return -1; tm.tm_min = pc.minutes; tm.tm_sec = pc.seconds; } else { tm.tm_hour = tm.tm_min = tm.tm_sec = 0; } /* Let mktime deduce tm_isdst if we have an absolute time stamp, or if the relative time stamp mentions days, months, or years. */ if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day | pc.rel_month | pc.rel_year) tm.tm_isdst = -1; /* But if the input explicitly specifies local time with or without DST, give mktime that information. */ if (pc.local_zones_seen) tm.tm_isdst = pc.local_isdst; tm0 = tm; Start = mktime (&tm); if (Start == (time_t) -1) { /* Guard against falsely reporting errors near the time_t boundaries when parsing times in other time zones. For example, if the min time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead of UTC, then the min localtime value is 1970-01-01 08:00:00; if we apply mktime to 1970-01-01 00:00:00 we will get an error, so we apply mktime to 1970-01-02 08:00:00 instead and adjust the time zone by 24 hours to compensate. This algorithm assumes that there is no DST transition within a day of the time_t boundaries. */ if (pc.zones_seen) { tm = tm0; if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE) { tm.tm_mday++; pc.time_zone += 24 * 60; } else { tm.tm_mday--; pc.time_zone -= 24 * 60; } Start = mktime (&tm); } if (Start == (time_t) -1) return Start; } if (pc.days_seen && ! pc.dates_seen) { tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7 + 7 * (pc.day_ordinal - (0 < pc.day_ordinal))); Start = mktime (&tm); if (Start == (time_t) -1) return Start; } if (pc.zones_seen) { int delta = pc.time_zone * 60; #ifdef HAVE_TM_GMTOFF delta -= tm.tm_gmtoff; #else struct tm *gmt = gmtime (&Start); if (! gmt) return -1; delta -= tm_diff (&tm, gmt); #endif if ((Start < Start - delta) != (delta < 0)) return -1; /* time_t overflow */ Start -= delta; } /* Add relative hours, minutes, and seconds. Ignore leap seconds; i.e. "+ 10 minutes" means 600 seconds, even if one of them is a leap second. Typically this is not what the user wants, but it's too hard to do it the other way, because the time zone indicator must be applied before relative times, and if mktime is applied again the time zone will be lost. */ { time_t t0 = Start; long d1 = 60 * 60 * (long) pc.rel_hour; time_t t1 = t0 + d1; long d2 = 60 * (long) pc.rel_minutes; time_t t2 = t1 + d2; int d3 = pc.rel_seconds; time_t t3 = t2 + d3; if ((d1 / (60 * 60) ^ pc.rel_hour) | (d2 / 60 ^ pc.rel_minutes) | ((t0 + d1 < t0) ^ (d1 < 0)) | ((t1 + d2 < t1) ^ (d2 < 0)) | ((t2 + d3 < t2) ^ (d3 < 0))) return -1; Start = t3; } return Start; } #if TEST #include int main (int ac, char **av) { char buff[BUFSIZ]; time_t d; printf ("Enter date, or blank line to exit.\n\t> "); fflush (stdout); buff[BUFSIZ - 1] = 0; while (fgets (buff, BUFSIZ - 1, stdin) && buff[0]) { d = get_date (buff, 0); if (d == (time_t) -1) printf ("Bad format - couldn't convert.\n"); else printf ("%s", ctime (&d)); printf ("\t> "); fflush (stdout); } return 0; } #endif /* defined TEST */ gnats-4.1.0/gnats/fconfig.h0000600000175000017500000000421010212665124016246 0ustar chewiechewie00000000000000#ifndef BISON_FCONFIG_TAB_H # define BISON_FCONFIG_TAB_H #ifndef YYSTYPE typedef union { int intval; char *sval; struct qstring *qstr; AdmFieldDesc *adm_field_des; FieldList flist; StringList *stringlist; InputTemplate *inputlist; MailAddress *mailaddr; MailAddressList *mailaddrlist; } yystype; # define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif # define FIELD 257 # define STRINGTYPE 258 # define QDEFAULT 259 # define MATCHING 260 # define ENUM 261 # define MULTIENUMTOK 262 # define VALUES 263 # define DEFAULT 264 # define EXACT_REGEXP 265 # define INEXACT_REGEXP 266 # define ALL 267 # define FORMAT 268 # define ENUMSEPARATORSTOK 269 # define MULTITEXTTYPE 270 # define DATETYPE 271 # define ENUM_IN_FILE 272 # define MULTI_ENUM_IN_FILE 273 # define PATHTOK 274 # define FIELDSTOK 275 # define KEYTOK 276 # define QSTRING 277 # define INTVAL 278 # define TEXTSEARCH 279 # define QUERYTOK 280 # define FORMATTOK 281 # define INDEXTOK 282 # define SEPARATORTOK 283 # define RESTRICTEDTOK 284 # define NOSPACESTOK 285 # define INTEGERTOK 286 # define INPUTDEFAULTTOK 287 # define BUILTINTOK 288 # define ALLOWANYVALUETOK 289 # define REQUIRETOK 290 # define APPENDFIELDTOK 291 # define SETFIELDTOK 292 # define CHANGETOK 293 # define DESCRIPTIONTOK 294 # define INPUTTOK 295 # define DATABASEINFOTOK 296 # define DEBUGMODETOK 297 # define KEEPRECTOK 298 # define NOTIFYEXPTOK 299 # define LIBEXECDIRTOK 300 # define SUBMITTERACKTOK 301 # define BUSINESSDAYTOK 302 # define BUSINESSWEEKTOK 303 # define CREATECATEGORYDIRSTOK 304 # define FALSETOK 305 # define TRUETOK 306 # define MAILFORMATTOK 307 # define TOADDRESSESTOK 308 # define FROMADDRESSTOK 309 # define REPLYTOTOK 310 # define FIXEDTOK 311 # define BODYTOK 312 # define HEADERTOK 313 # define AUDITTRAILFMTTOK 314 # define ADDAUDITTRAILTOK 315 # define REQUIRECHANGEREASONTOK 316 # define READONLYTOK 317 # define BINARYINDEXTOK 318 # define RAWTOK 319 # define BADTOK 320 # define AUXFLAGSTOK 321 # define PRLISTTOK 322 # define MAXPRSTOK 323 # define EDITONLYTOK 324 # define VIRTUALFORMATTOK 325 # define CATPERMSTOK 326 extern YYSTYPE fconflval; #endif /* not BISON_FCONFIG_TAB_H */ gnats-4.1.0/gnats/fconfig.c0000600000175000017500000021713210212665124016252 0ustar chewiechewie00000000000000/* A Bison parser, made from ./fconfig.y by GNU bison 1.35. */ #define YYBISON 1 /* Identify Bison output. */ #define yyparse fconfparse #define yylex fconflex #define yyerror fconferror #define yylval fconflval #define yychar fconfchar #define yydebug fconfdebug #define yynerrs fconfnerrs # define FIELD 257 # define STRINGTYPE 258 # define QDEFAULT 259 # define MATCHING 260 # define ENUM 261 # define MULTIENUMTOK 262 # define VALUES 263 # define DEFAULT 264 # define EXACT_REGEXP 265 # define INEXACT_REGEXP 266 # define ALL 267 # define FORMAT 268 # define ENUMSEPARATORSTOK 269 # define MULTITEXTTYPE 270 # define DATETYPE 271 # define ENUM_IN_FILE 272 # define MULTI_ENUM_IN_FILE 273 # define PATHTOK 274 # define FIELDSTOK 275 # define KEYTOK 276 # define QSTRING 277 # define INTVAL 278 # define TEXTSEARCH 279 # define QUERYTOK 280 # define FORMATTOK 281 # define INDEXTOK 282 # define SEPARATORTOK 283 # define RESTRICTEDTOK 284 # define NOSPACESTOK 285 # define INTEGERTOK 286 # define INPUTDEFAULTTOK 287 # define BUILTINTOK 288 # define ALLOWANYVALUETOK 289 # define REQUIRETOK 290 # define APPENDFIELDTOK 291 # define SETFIELDTOK 292 # define CHANGETOK 293 # define DESCRIPTIONTOK 294 # define INPUTTOK 295 # define DATABASEINFOTOK 296 # define DEBUGMODETOK 297 # define KEEPRECTOK 298 # define NOTIFYEXPTOK 299 # define LIBEXECDIRTOK 300 # define SUBMITTERACKTOK 301 # define BUSINESSDAYTOK 302 # define BUSINESSWEEKTOK 303 # define CREATECATEGORYDIRSTOK 304 # define FALSETOK 305 # define TRUETOK 306 # define MAILFORMATTOK 307 # define TOADDRESSESTOK 308 # define FROMADDRESSTOK 309 # define REPLYTOTOK 310 # define FIXEDTOK 311 # define BODYTOK 312 # define HEADERTOK 313 # define AUDITTRAILFMTTOK 314 # define ADDAUDITTRAILTOK 315 # define REQUIRECHANGEREASONTOK 316 # define READONLYTOK 317 # define BINARYINDEXTOK 318 # define RAWTOK 319 # define BADTOK 320 # define AUXFLAGSTOK 321 # define PRLISTTOK 322 # define MAXPRSTOK 323 # define EDITONLYTOK 324 # define VIRTUALFORMATTOK 325 # define CATPERMSTOK 326 #line 1 "./fconfig.y" #include "gnats.h" #include "index.h" #include "field.h" extern DatabaseInfo databaseBeingDefined; static FieldDef currField; static ChangeActions currChange; static FieldEdit *currEdit; static QueryFormat *qformat; static FieldList requiredFlds; static InputTemplate *inputTemplate; static MailMessageFormat mailFormat; IndexDesc indexEntry; static int badFile; struct qstring; extern char *takeQString (struct qstring *str); extern char *qStrVal (struct qstring *str); #line 21 "./fconfig.y" #ifndef YYSTYPE typedef union { int intval; char *sval; struct qstring *qstr; AdmFieldDesc *adm_field_des; FieldList flist; StringList *stringlist; InputTemplate *inputlist; MailAddress *mailaddr; MailAddressList *mailaddrlist; } yystype; # define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif #ifndef YYDEBUG # define YYDEBUG 0 #endif #define YYFINAL 348 #define YYFLAG -32768 #define YYNTBASE 77 /* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ #define YYTRANSLATE(x) ((unsigned)(x) <= 326 ? yytranslate[x] : 165) /* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ static const char yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 73, 76, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 }; #if YYDEBUG static const short yyprhs[] = { 0, 0, 2, 4, 13, 18, 23, 24, 26, 28, 31, 34, 37, 40, 43, 46, 51, 56, 59, 62, 64, 66, 68, 69, 71, 74, 79, 84, 87, 89, 92, 94, 96, 98, 100, 103, 105, 107, 110, 112, 115, 118, 120, 126, 132, 134, 137, 142, 147, 152, 157, 162, 167, 168, 171, 175, 179, 183, 185, 186, 188, 191, 196, 201, 204, 207, 209, 212, 214, 216, 219, 221, 227, 232, 234, 236, 237, 239, 241, 244, 245, 249, 253, 254, 258, 261, 263, 266, 268, 271, 273, 276, 281, 286, 288, 290, 293, 295, 298, 301, 308, 313, 315, 317, 319, 322, 324, 327, 330, 333, 335, 338, 340, 343, 346, 348, 350, 352, 355, 357, 360, 362, 367, 369, 371, 374, 375, 377, 379, 382, 387, 392, 395, 398, 401, 404, 406, 409, 412, 413, 415, 417, 420, 425, 430, 432, 435, 437, 442, 447, 449, 451, 453, 456, 459, 464, 469, 471, 473, 476, 479, 482, 487, 492, 495, 496, 501, 506, 508, 511, 516, 521, 523, 526, 528, 531, 536, 541, 544, 546, 549, 551, 553, 558, 563, 568, 571, 574, 578, 582, 584, 586, 589, 592, 594, 596, 600, 602 }; static const short yyrhs[] = { 78, 0, 80, 0, 79, 84, 127, 164, 151, 95, 139, 145, 0, 42, 73, 81, 74, 0, 42, 73, 80, 74, 0, 0, 1, 0, 82, 0, 81, 82, 0, 43, 83, 0, 44, 83, 0, 45, 83, 0, 46, 23, 0, 47, 83, 0, 48, 24, 75, 24, 0, 49, 24, 75, 24, 0, 50, 83, 0, 72, 23, 0, 51, 0, 52, 0, 85, 0, 0, 86, 0, 85, 86, 0, 87, 73, 88, 74, 0, 87, 73, 80, 74, 0, 3, 23, 0, 89, 0, 88, 89, 0, 91, 0, 125, 0, 124, 0, 90, 0, 71, 158, 0, 92, 0, 94, 0, 16, 109, 0, 17, 0, 32, 109, 0, 68, 110, 0, 4, 0, 4, 6, 73, 93, 74, 0, 4, 6, 73, 80, 74, 0, 23, 0, 93, 23, 0, 7, 73, 112, 74, 0, 18, 73, 117, 74, 0, 19, 73, 119, 74, 0, 8, 73, 113, 74, 0, 7, 73, 80, 74, 0, 18, 73, 80, 74, 0, 0, 95, 96, 0, 98, 100, 74, 0, 98, 100, 74, 0, 39, 99, 73, 0, 23, 0, 0, 101, 0, 100, 101, 0, 36, 73, 102, 74, 0, 36, 73, 80, 74, 0, 38, 104, 0, 37, 104, 0, 61, 0, 60, 158, 0, 62, 0, 103, 0, 102, 103, 0, 23, 0, 105, 73, 106, 107, 74, 0, 105, 73, 80, 74, 0, 23, 0, 23, 0, 0, 108, 0, 23, 0, 108, 23, 0, 0, 73, 121, 74, 0, 73, 80, 74, 0, 0, 73, 111, 74, 0, 69, 24, 0, 115, 0, 112, 115, 0, 114, 0, 113, 114, 0, 115, 0, 15, 23, 0, 9, 73, 116, 74, 0, 9, 73, 80, 74, 0, 121, 0, 23, 0, 116, 23, 0, 118, 0, 117, 118, 0, 20, 23, 0, 21, 73, 122, 74, 22, 23, 0, 21, 73, 80, 74, 0, 121, 0, 35, 0, 120, 0, 117, 120, 0, 118, 0, 15, 23, 0, 10, 23, 0, 33, 23, 0, 123, 0, 122, 123, 0, 23, 0, 5, 11, 0, 5, 12, 0, 25, 0, 30, 0, 31, 0, 34, 23, 0, 97, 0, 40, 23, 0, 63, 0, 67, 73, 126, 74, 0, 70, 0, 23, 0, 126, 23, 0, 0, 128, 0, 129, 0, 128, 129, 0, 130, 73, 131, 74, 0, 130, 73, 80, 74, 0, 26, 23, 0, 132, 133, 0, 134, 132, 0, 21, 13, 0, 136, 0, 135, 136, 0, 136, 135, 0, 0, 134, 0, 65, 0, 27, 23, 0, 21, 73, 137, 74, 0, 21, 73, 80, 74, 0, 138, 0, 137, 138, 0, 23, 0, 140, 73, 141, 74, 0, 140, 73, 80, 74, 0, 80, 0, 28, 0, 142, 0, 141, 142, 0, 20, 23, 0, 21, 73, 143, 74, 0, 21, 73, 80, 74, 0, 144, 0, 138, 0, 143, 138, 0, 29, 23, 0, 64, 83, 0, 41, 73, 146, 74, 0, 41, 73, 80, 74, 0, 149, 147, 0, 0, 36, 73, 148, 74, 0, 36, 73, 80, 74, 0, 138, 0, 148, 138, 0, 21, 73, 150, 74, 0, 21, 73, 80, 74, 0, 23, 0, 150, 23, 0, 152, 0, 151, 152, 0, 153, 73, 154, 74, 0, 153, 73, 80, 74, 0, 53, 23, 0, 155, 0, 154, 155, 0, 156, 0, 157, 0, 54, 73, 160, 74, 0, 55, 73, 161, 74, 0, 56, 73, 160, 74, 0, 58, 158, 0, 59, 158, 0, 159, 131, 74, 0, 159, 80, 74, 0, 73, 0, 161, 0, 160, 161, 0, 57, 23, 0, 162, 0, 163, 0, 162, 76, 163, 0, 23, 0, 60, 158, 0 }; #endif #if YYDEBUG /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const short yyrline[] = { 0, 62, 63, 66, 69, 70, 71, 76, 78, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 111, 112, 115, 116, 121, 122, 125, 128, 133, 148, 149, 152, 153, 154, 155, 158, 164, 165, 166, 170, 174, 178, 184, 187, 190, 193, 197, 203, 207, 212, 217, 226, 227, 230, 231, 234, 240, 251, 260, 263, 268, 269, 272, 273, 274, 278, 283, 286, 290, 295, 296, 299, 307, 308, 311, 322, 327, 330, 334, 339, 346, 347, 348, 351, 352, 355, 360, 361, 364, 365, 368, 369, 374, 375, 376, 379, 383, 389, 390, 393, 396, 423, 424, 425, 430, 431, 434, 435, 440, 443, 448, 453, 460, 468, 471, 476, 479, 482, 485, 495, 496, 499, 502, 505, 510, 514, 520, 521, 524, 525, 528, 532, 538, 548, 549, 552, 553, 554, 555, 558, 559, 562, 567, 572, 573, 576, 579, 585, 599, 603, 607, 610, 615, 616, 619, 622, 623, 624, 627, 630, 635, 638, 643, 644, 647, 652, 653, 656, 662, 665, 671, 675, 680, 702, 729, 730, 733, 737, 743, 757, 758, 761, 765, 769, 772, 775, 780, 783, 786, 787, 793, 803, 808, 818, 823, 830, 833, 843, 849 }; #endif #if (YYDEBUG) || defined YYERROR_VERBOSE /* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ static const char *const yytname[] = { "$", "error", "$undefined.", "FIELD", "STRINGTYPE", "QDEFAULT", "MATCHING", "ENUM", "MULTIENUMTOK", "VALUES", "DEFAULT", "EXACT_REGEXP", "INEXACT_REGEXP", "ALL", "FORMAT", "ENUMSEPARATORSTOK", "MULTITEXTTYPE", "DATETYPE", "ENUM_IN_FILE", "MULTI_ENUM_IN_FILE", "PATHTOK", "FIELDSTOK", "KEYTOK", "QSTRING", "INTVAL", "TEXTSEARCH", "QUERYTOK", "FORMATTOK", "INDEXTOK", "SEPARATORTOK", "RESTRICTEDTOK", "NOSPACESTOK", "INTEGERTOK", "INPUTDEFAULTTOK", "BUILTINTOK", "ALLOWANYVALUETOK", "REQUIRETOK", "APPENDFIELDTOK", "SETFIELDTOK", "CHANGETOK", "DESCRIPTIONTOK", "INPUTTOK", "DATABASEINFOTOK", "DEBUGMODETOK", "KEEPRECTOK", "NOTIFYEXPTOK", "LIBEXECDIRTOK", "SUBMITTERACKTOK", "BUSINESSDAYTOK", "BUSINESSWEEKTOK", "CREATECATEGORYDIRSTOK", "FALSETOK", "TRUETOK", "MAILFORMATTOK", "TOADDRESSESTOK", "FROMADDRESSTOK", "REPLYTOTOK", "FIXEDTOK", "BODYTOK", "HEADERTOK", "AUDITTRAILFMTTOK", "ADDAUDITTRAILTOK", "REQUIRECHANGEREASONTOK", "READONLYTOK", "BINARYINDEXTOK", "RAWTOK", "BADTOK", "AUXFLAGSTOK", "PRLISTTOK", "MAXPRSTOK", "EDITONLYTOK", "VIRTUALFORMATTOK", "CATPERMSTOK", "'{'", "'}'", "'-'", "'|'", "config", "configEnts", "databaseInfo", "parseError", "databaseInfoList", "databaseInfoEnt", "booleanVal", "fieldDecStmt", "fieldDecList", "fieldDec", "startFieldDec", "fieldDataList", "fieldData", "virtualFieldFormat", "fieldDataType", "stringType", "regexpList", "enumType", "globalChangeEnts", "globalChangeEnt", "changeClause", "changeHeader", "optChangeExpr", "changeOpts", "changeOpt", "reqFieldNameList", "reqFieldNameEnt", "fieldEditOpts", "fieldEditName", "fieldEditFormat", "optFieldEditFieldList", "fieldEditFieldList", "optSimple", "prListOpts", "prListOptList", "enumcontents", "multienumcontents", "multiEnumItem", "enumItem", "enumValueList", "enumFileContents", "enumFileItem", "multiEnumFileContents", "multiEnumFileItem", "defaultFieldVal", "enumFieldList", "enumFieldMember", "queryDefault", "miscOptions", "auxFlagsList", "optQueryList", "queryList", "query", "queryBegin", "queryFmt", "queryFieldDesc", "optQueryOpts", "queryOpts", "queryPrintf", "queryfields", "queryFieldsList", "FieldListMember", "indexDescription", "indexheader", "indexlist", "indexEnt", "indexFieldList", "indexSep", "inputDescription", "inputEnt", "requiredFields", "requiredFieldsList", "inputFields", "inputFieldsList", "mailFormatList", "mailFormat", "mailFormatHeader", "mailFormatBody", "mailFormatEnt", "bodyFormat", "headerFormat", "plainFormat", "plainFormatHeader", "mailAddressList", "mailAddress", "mailAddressTries", "MailAddressMember", "auditTrailFmt", 0 }; #endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const short yyr1[] = { 0, 77, 77, 78, 79, 79, 79, 80, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 88, 88, 89, 89, 89, 89, 90, 91, 91, 91, 91, 91, 91, 92, 92, 92, 93, 93, 94, 94, 94, 94, 94, 94, 95, 95, 96, 97, 98, 99, 99, 100, 100, 101, 101, 101, 101, 101, 101, 101, 102, 102, 103, 104, 104, 105, 106, 107, 107, 108, 108, 109, 109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115, 115, 116, 116, 117, 117, 118, 118, 118, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 126, 126, 127, 127, 128, 128, 129, 129, 130, 131, 131, 132, 132, 132, 132, 133, 133, 134, 135, 136, 136, 137, 137, 138, 139, 139, 139, 140, 141, 141, 142, 142, 142, 142, 143, 143, 144, 144, 145, 145, 146, 147, 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 154, 154, 155, 155, 155, 155, 155, 156, 157, 158, 158, 159, 160, 160, 161, 161, 162, 162, 163, 164 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const short yyr2[] = { 0, 1, 1, 8, 4, 4, 0, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 1, 1, 1, 0, 1, 2, 4, 4, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 5, 5, 1, 2, 4, 4, 4, 4, 4, 4, 0, 2, 3, 3, 3, 1, 0, 1, 2, 4, 4, 2, 2, 1, 2, 1, 1, 2, 1, 5, 4, 1, 1, 0, 1, 1, 2, 0, 3, 3, 0, 3, 2, 1, 2, 1, 2, 1, 2, 4, 4, 1, 1, 2, 1, 2, 2, 6, 4, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 4, 1, 1, 2, 0, 1, 1, 2, 4, 4, 2, 2, 2, 2, 1, 2, 2, 0, 1, 1, 2, 4, 4, 1, 2, 1, 4, 4, 1, 1, 1, 2, 2, 4, 4, 1, 1, 2, 2, 2, 4, 4, 2, 0, 4, 4, 1, 2, 4, 4, 1, 2, 1, 2, 4, 4, 2, 1, 2, 1, 1, 4, 4, 4, 2, 2, 3, 3, 1, 1, 2, 2, 1, 1, 3, 1, 2 }; /* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const short yydefact[] = { 0, 7, 0, 1, 22, 2, 0, 0, 125, 21, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 27, 0, 0, 126, 127, 0, 24, 0, 19, 20, 10, 11, 12, 13, 14, 0, 0, 17, 18, 5, 4, 9, 131, 0, 0, 128, 0, 41, 0, 0, 0, 79, 38, 0, 0, 114, 115, 116, 79, 0, 58, 0, 120, 0, 82, 122, 0, 0, 0, 28, 33, 30, 35, 36, 118, 0, 32, 31, 0, 0, 189, 197, 0, 0, 52, 173, 0, 0, 0, 140, 0, 0, 138, 0, 0, 135, 0, 112, 113, 0, 0, 0, 37, 0, 0, 39, 117, 57, 0, 119, 0, 0, 40, 34, 26, 25, 29, 0, 0, 0, 0, 65, 67, 0, 59, 15, 16, 0, 0, 177, 0, 174, 0, 134, 0, 141, 130, 129, 132, 139, 133, 0, 136, 137, 0, 0, 0, 0, 0, 0, 85, 93, 0, 0, 87, 89, 0, 0, 0, 0, 102, 0, 0, 96, 101, 0, 0, 96, 0, 103, 56, 123, 0, 0, 0, 0, 73, 64, 0, 63, 66, 55, 60, 188, 187, 150, 149, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 180, 181, 146, 0, 0, 144, 44, 0, 0, 0, 107, 108, 50, 46, 86, 90, 49, 88, 81, 80, 98, 0, 51, 47, 97, 106, 97, 104, 48, 124, 121, 84, 83, 70, 0, 0, 68, 0, 0, 0, 3, 0, 0, 0, 0, 185, 186, 176, 175, 179, 143, 142, 145, 43, 45, 42, 94, 0, 0, 111, 0, 0, 109, 62, 61, 69, 74, 0, 75, 54, 0, 0, 0, 0, 0, 0, 0, 151, 156, 196, 0, 0, 190, 193, 194, 0, 0, 92, 95, 91, 100, 0, 110, 72, 77, 0, 76, 0, 0, 0, 164, 153, 0, 159, 160, 148, 147, 152, 192, 182, 191, 0, 183, 184, 0, 71, 78, 0, 162, 161, 0, 163, 0, 157, 0, 195, 99, 171, 0, 0, 0, 155, 154, 158, 170, 172, 169, 0, 167, 0, 166, 165, 168, 0, 0, 0 }; static const short yydefgoto[] = { 346, 3, 4, 5, 22, 23, 34, 8, 9, 10, 11, 72, 73, 74, 75, 76, 211, 77, 134, 191, 78, 79, 112, 127, 128, 238, 239, 181, 182, 271, 298, 299, 106, 116, 178, 153, 157, 158, 159, 261, 166, 167, 172, 173, 155, 264, 265, 80, 81, 176, 26, 27, 28, 29, 95, 96, 142, 97, 98, 99, 207, 208, 193, 194, 279, 280, 327, 281, 243, 302, 324, 342, 303, 332, 88, 89, 90, 201, 202, 203, 204, 85, 86, 284, 285, 286, 287, 48 }; static const short yypact[] = { 23,-32768, -52,-32768, 25,-32768, 7, 9, 12, 25, -32768, -9, -15, -15, -15, 71, -15, 80, 82, -15, 85, 36, 212,-32768,-32768, 96, 61, 12,-32768, 54, -32768, 140,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 94, 119,-32768,-32768,-32768,-32768,-32768,-32768, 79, 70,-32768, 21, 154, 175, 108, 124, 127,-32768, 129, 131,-32768, -32768,-32768, 127, 190, 213, 214,-32768, 162, 169,-32768, 79, 171, 159,-32768,-32768,-32768,-32768,-32768,-32768, 187, -32768,-32768, 219, 228,-32768,-32768, 21, 240, 70,-32768, 193, 14, 245,-32768, 196, 197, 207, 2, 259, 256, 215,-32768,-32768, 152, 186, 106,-32768, 211, 254,-32768, -32768,-32768, 217,-32768, 262, 222,-32768,-32768,-32768,-32768, -32768, 220, 269, 269, 79,-32768,-32768, 76,-32768,-32768, -32768, 221, 224,-32768, 181,-32768, 34,-32768, 95,-32768, -32768,-32768,-32768,-32768,-32768, 229,-32768,-32768, 132, 230, 271, 273, 226, 8,-32768,-32768, 278, 0,-32768,-32768, 231, 232, 281, 234,-32768, 235, 10,-32768,-32768, 285, 254, 236, 237,-32768,-32768,-32768, 17, 288, 239, 182, -32768,-32768, 242,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -32768,-32768, 187, 275, 244, 246, 247, 248, 79, 79, 249, 223,-32768,-32768,-32768,-32768, 251, 24,-32768,-32768, 252, 46, 191,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -32768,-32768,-32768,-32768, 227,-32768,-32768,-32768,-32768, 236, -32768,-32768,-32768,-32768,-32768,-32768,-32768, 255, 48,-32768, 250, 179, 257,-32768, 38, 86, 86, 86,-32768,-32768, -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 258, 50,-32768, 260, 52,-32768,-32768,-32768,-32768,-32768, 261, 295,-32768, 167, 299, 263, 301, -15, 264, 41, -32768,-32768,-32768, 305, -11,-32768, 265,-32768, 266, 11, -32768,-32768,-32768,-32768, 309,-32768,-32768,-32768, 268, 310, 270, 272, 274, 303,-32768, 95,-32768,-32768,-32768,-32768, -32768,-32768,-32768,-32768, 314,-32768,-32768, 321,-32768,-32768, 253,-32768,-32768, 276,-32768, 277,-32768, 55,-32768,-32768, -32768, 279, 72, 95,-32768,-32768,-32768,-32768,-32768,-32768, 280,-32768, 77,-32768,-32768,-32768, 345, 347,-32768 }; static const short yypgoto[] = { -32768,-32768,-32768, -6,-32768, 328, -12,-32768,-32768, 343, -32768,-32768, 283,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -32768, 225,-32768, 164, -124,-32768, 120, 238,-32768,-32768, -32768,-32768, 298,-32768,-32768,-32768,-32768, 200, -87,-32768, 267, -89,-32768, 192, -94,-32768, 99,-32768,-32768,-32768, -32768,-32768, 337,-32768, 282, 284,-32768, 286, 287, 289, -32768, -202,-32768,-32768,-32768, 87,-32768,-32768,-32768,-32768, -32768,-32768,-32768,-32768,-32768, 290,-32768,-32768, 166,-32768, -32768, -64,-32768, 118, -135,-32768, 56,-32768 }; #define YYLAST 387 static const short yytable[] = { 21, 35, 36, 186, 38, 255, 117, 41, 1, 149, 150, 161, 282, 168, 168, 156, 154, 149, 150, 171, 150, 6, 1, 91, 1, 71, -6, 137, 7, 92, 162, 163, 24, 151, 282, 1, 32, 33, 25, 1, 232, 151, 91, 151, 94, 164, 283, 205, 92, -6, 12, 13, 14, 15, 16, 17, 18, 19, 274, 275, 184, 274, 275, 312, 31, 2, 217, 276, 283, 257, 276, 236, 168, 291, 219, 262, 168, 227, 205, 20, 131, 229, 216, -6, 226, 316, 93, 138, 195, 196, 197, 233, 198, 199, 37, 338, 1, 152, 254, 160, 205, 165, 277, 326, 39, 277, 40, 1, 42, 282, 43, 288, 121, 122, 123, 309, 150, 186, 205, 46, 258, 47, 267, 87, 292, 336, 294, 50, 190, 335, 200, 341, 206, 1, 248, 249, 124, 125, 126, 151, 345, 1, 210, 283, 51, 52, 339, 53, 54, 313, 185, 344, 84, 1, 313, 209, 55, 56, 57, 58, 100, 149, 150, 51, 52, 59, 53, 54, 1, 82, 60, 61, 62, 237, 63, 55, 56, 57, 58, 64, 65, 103, 1, 1, 59, 151, 101, 102, 300, 60, 61, 62, 1, 63, 83, 149, 150, 104, 64, 65, 105, 156, 107, 66, 108, 236, 260, 67, 68, 189, 69, 70, 1, 110, 259, 121, 122, 123, 263, 151, 64, 150, 66, 121, 122, 123, 67, 68, 1, 69, 70, 162, 163, 119, 270, 114, 111, 113, 278, 124, 125, 126, 115, 129, 151, 118, 164, 124, 125, 126, 262, 1, 130, 272, 1, 12, 13, 14, 15, 16, 17, 18, 19, 133, 150, 307, 136, 301, 139, 169, 140, 141, 93, 269, 162, 163, 330, 195, 196, 197, 145, 198, 199, 92, 20, 175, 44, 151, 148, 164, 174, 177, 180, 179, 213, 187, 214, 251, 188, 325, 215, 218, 138, 212, 223, 221, 222, 224, 228, 225, -105, 231, 234, 235, 331, 240, 242, 244, 297, 245, 246, 247, 304, 250, 306, 253, 256, 340, 311, 266, 273, 317, 290, 319, 293, 296, 305, 282, 308, 323, 315, 314, 318, 320, 329, 347, 321, 348, 322, 333, 45, 334, 30, 337, 343, 120, 241, 220, 268, 192, 109, 183, 230, 295, 49, 289, 310, 252, 132, 0, 328, 0, 0, 0, 0, 170, 0, 0, 135, 0, 0, 144, 143, 0, 0, 0, 147, 146 }; static const short yycheck[] = { 6, 13, 14, 127, 16, 207, 70, 19, 1, 9, 10, 105, 23, 107, 108, 15, 103, 9, 10, 108, 10, 73, 1, 21, 1, 31, 3, 13, 3, 27, 20, 21, 23, 33, 23, 1, 51, 52, 26, 1, 23, 33, 21, 33, 50, 35, 57, 23, 27, 26, 43, 44, 45, 46, 47, 48, 49, 50, 20, 21, 124, 20, 21, 74, 73, 42, 153, 29, 57, 23, 29, 23, 166, 23, 74, 23, 170, 166, 23, 72, 86, 170, 74, 60, 74, 74, 65, 73, 54, 55, 56, 74, 58, 59, 23, 23, 1, 103, 74, 105, 23, 107, 64, 305, 24, 64, 24, 1, 23, 23, 74, 246, 36, 37, 38, 74, 10, 241, 23, 23, 74, 60, 74, 53, 74, 327, 74, 73, 134, 74, 136, 333, 138, 1, 198, 199, 60, 61, 62, 33, 342, 1, 148, 57, 4, 5, 74, 7, 8, 284, 74, 74, 73, 1, 289, 23, 16, 17, 18, 19, 6, 9, 10, 4, 5, 25, 7, 8, 1, 75, 30, 31, 32, 179, 34, 16, 17, 18, 19, 39, 40, 73, 1, 1, 25, 33, 11, 12, 21, 30, 31, 32, 1, 34, 75, 9, 10, 73, 39, 40, 73, 15, 73, 63, 73, 23, 212, 67, 68, 28, 70, 71, 1, 23, 23, 36, 37, 38, 224, 33, 39, 10, 63, 36, 37, 38, 67, 68, 1, 70, 71, 20, 21, 74, 240, 73, 23, 23, 244, 60, 61, 62, 73, 24, 33, 74, 35, 60, 61, 62, 23, 1, 24, 74, 1, 43, 44, 45, 46, 47, 48, 49, 50, 23, 10, 277, 73, 273, 23, 15, 74, 74, 65, 23, 20, 21, 23, 54, 55, 56, 21, 58, 59, 27, 72, 23, 74, 33, 73, 35, 73, 69, 23, 73, 23, 74, 23, 74, 74, 305, 74, 23, 73, 73, 23, 74, 74, 73, 23, 74, 74, 74, 24, 74, 320, 73, 41, 73, 23, 73, 73, 73, 23, 74, 23, 74, 74, 333, 23, 74, 73, 22, 74, 23, 74, 74, 73, 23, 74, 36, 74, 76, 74, 73, 23, 0, 74, 0, 74, 73, 22, 74, 9, 74, 74, 72, 192, 157, 238, 134, 62, 123, 170, 264, 27, 247, 279, 201, 86, -1, 314, -1, -1, -1, -1, 108, -1, -1, 88, -1, -1, 97, 96, -1, -1, -1, 99, 98 }; /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ #line 3 "/usr/share/bison/bison.simple" /* Skeleton output parser for bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* This is the parser code that is written into each bison parser when the %semantic_parser declaration is not specified in the grammar. It was written by Richard Stallman by simplifying the hairy parser used when %semantic_parser is specified. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ #if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) /* The parser invokes alloca or malloc; define the necessary symbols. */ # if YYSTACK_USE_ALLOCA # define YYSTACK_ALLOC alloca # else # ifndef YYSTACK_USE_ALLOCA # if defined (alloca) || defined (_ALLOCA_H) # define YYSTACK_ALLOC alloca # else # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # else # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif # define YYSTACK_ALLOC malloc # define YYSTACK_FREE free # endif #endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ #if (! defined (yyoverflow) \ && (! defined (__cplusplus) \ || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { short yyss; YYSTYPE yyvs; # if YYLSP_NEEDED YYLTYPE yyls; # endif }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # if YYLSP_NEEDED # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAX) # else # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAX) # endif /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ register YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (0) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) # define YYSIZE_T __SIZE_TYPE__ #endif #if ! defined (YYSIZE_T) && defined (size_t) # define YYSIZE_T size_t #endif #if ! defined (YYSIZE_T) # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif #endif #if ! defined (YYSIZE_T) # define YYSIZE_T unsigned int #endif #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY -2 #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrlab1 /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yychar1 = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ { \ yyerror ("syntax error: cannot back up"); \ YYERROR; \ } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Compute the default location (before the actions are run). When YYLLOC_DEFAULT is run, CURRENT is set the location of the first token. By default, to implement support for ranges, extend its range to the last symbol. */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.last_line = Rhs[N].last_line; \ Current.last_column = Rhs[N].last_column; #endif /* YYLEX -- calling `yylex' with the right arguments. */ #if YYPURE # if YYLSP_NEEDED # ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) # else # define YYLEX yylex (&yylval, &yylloc) # endif # else /* !YYLSP_NEEDED */ # ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, YYLEX_PARAM) # else # define YYLEX yylex (&yylval) # endif # endif /* !YYLSP_NEEDED */ #else /* !YYPURE */ # define YYLEX yylex () #endif /* !YYPURE */ /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #if YYMAXDEPTH == 0 # undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #ifdef YYERROR_VERBOSE # ifndef yystrlen # if defined (__GLIBC__) && defined (_STRING_H) # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T # if defined (__STDC__) || defined (__cplusplus) yystrlen (const char *yystr) # else yystrlen (yystr) const char *yystr; # endif { register const char *yys = yystr; while (*yys++ != '\0') continue; return yys - yystr - 1; } # endif # endif # ifndef yystpcpy # if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) # include # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * # if defined (__STDC__) || defined (__cplusplus) yystpcpy (char *yydest, const char *yysrc) # else yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; # endif { register char *yyd = yydest; register const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif #endif #line 316 "/usr/share/bison/bison.simple" /* The user can define YYPARSE_PARAM as the name of an argument to be passed into yyparse. The argument should have type void *. It should actually point to an object. Grammar actions can access the variable by casting it to the proper pointer type. */ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) # define YYPARSE_PARAM_ARG void *YYPARSE_PARAM # define YYPARSE_PARAM_DECL # else # define YYPARSE_PARAM_ARG YYPARSE_PARAM # define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; # endif #else /* !YYPARSE_PARAM */ # define YYPARSE_PARAM_ARG # define YYPARSE_PARAM_DECL #endif /* !YYPARSE_PARAM */ /* Prevent warning if -Wstrict-prototypes. */ #ifdef __GNUC__ # ifdef YYPARSE_PARAM int yyparse (void *); # else int yyparse (void); # endif #endif /* YY_DECL_VARIABLES -- depending whether we use a pure parser, variables are global, or local to YYPARSE. */ #define YY_DECL_NON_LSP_VARIABLES \ /* The lookahead symbol. */ \ int yychar; \ \ /* The semantic value of the lookahead symbol. */ \ YYSTYPE yylval; \ \ /* Number of parse errors so far. */ \ int yynerrs; #if YYLSP_NEEDED # define YY_DECL_VARIABLES \ YY_DECL_NON_LSP_VARIABLES \ \ /* Location data for the lookahead symbol. */ \ YYLTYPE yylloc; #else # define YY_DECL_VARIABLES \ YY_DECL_NON_LSP_VARIABLES #endif /* If nonreentrant, generate the variables here. */ #if !YYPURE YY_DECL_VARIABLES #endif /* !YYPURE */ int yyparse (YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL { /* If reentrant, generate the variables here. */ #if YYPURE YY_DECL_VARIABLES #endif /* !YYPURE */ register int yystate; register int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* Lookahead token as an internal (translated) token number. */ int yychar1 = 0; /* Three stacks and their tools: `yyss': related to states, `yyvs': related to semantic values, `yyls': related to locations. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ short yyssa[YYINITDEPTH]; short *yyss = yyssa; register short *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; register YYSTYPE *yyvsp; #if YYLSP_NEEDED /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp; #endif #if YYLSP_NEEDED # define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) #else # define YYPOPSTACK (yyvsp--, yyssp--) #endif YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYLSP_NEEDED YYLTYPE yyloc; #endif /* When reducing, the number of symbols on the RHS of the reduced rule. */ int yylen; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; #if YYLSP_NEEDED yylsp = yyls; #endif goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyssp >= yyss + yystacksize - 1) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; short *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. */ # if YYLSP_NEEDED YYLTYPE *yyls1 = yyls; /* This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow ("parser stack overflow", &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; # else yyoverflow ("parser stack overflow", &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); # endif yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyoverflowlab; # else /* Extend the stack our own way. */ if (yystacksize >= YYMAXDEPTH) goto yyoverflowlab; yystacksize *= 2; if (yystacksize > YYMAXDEPTH) yystacksize = YYMAXDEPTH; { short *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyoverflowlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); # if YYLSP_NEEDED YYSTACK_RELOCATE (yyls); # endif # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; #if YYLSP_NEEDED yylsp = yyls + yysize - 1; #endif YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyssp >= yyss + yystacksize - 1) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* yyresume: */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYFLAG) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* yychar is either YYEMPTY or YYEOF or a valid token in external form. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } /* Convert token to internal form (in yychar1) for indexing tables with */ if (yychar <= 0) /* This means end of input. */ { yychar1 = 0; yychar = YYEOF; /* Don't call YYLEX any more */ YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yychar1 = YYTRANSLATE (yychar); #if YYDEBUG /* We have to keep this `#if YYDEBUG', since we use variables which are defined only if `YYDEBUG' is set. */ if (yydebug) { YYFPRINTF (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); /* Give the individual parser a way to print the precise meaning of a token, for further debugging info. */ # ifdef YYPRINT YYPRINT (stderr, yychar, yylval); # endif YYFPRINTF (stderr, ")\n"); } #endif } yyn += yychar1; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) goto yydefault; yyn = yytable[yyn]; /* yyn is what to do for this token type in this state. Negative => reduce, -yyn is rule number. Positive => shift, yyn is new state. New state is final state => don't bother to shift, just return success. 0, or most negative number => error. */ if (yyn < 0) { if (yyn == YYFLAG) goto yyerrlab; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrlab; if (yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ YYDPRINTF ((stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1])); /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; #if YYLSP_NEEDED *++yylsp = yylloc; #endif /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; yystate = yyn; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to the semantic value of the lookahead token. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; #if YYLSP_NEEDED /* Similarly for the default location. Let the user run additional commands if for instance locations are ranges. */ yyloc = yylsp[1-yylen]; YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); #endif #if YYDEBUG /* We have to keep this `#if YYDEBUG', since we use variables which are defined only if `YYDEBUG' is set. */ if (yydebug) { int yyi; YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", yyn, yyrline[yyn]); /* Print the symbols being reduced, and their result. */ for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); } #endif switch (yyn) { case 6: #line 71 "./fconfig.y" { fconferror ("Missing/bad database info section"); ; break;} case 7: #line 76 "./fconfig.y" { badFile = 1; ; break;} case 10: #line 82 "./fconfig.y" { setDebugMode (databaseBeingDefined, yyvsp[0].intval); ; break;} case 11: #line 85 "./fconfig.y" { setKeepReceivedHeaders (databaseBeingDefined, yyvsp[0].intval); ; break;} case 12: #line 88 "./fconfig.y" { setNotifyExpire (databaseBeingDefined, yyvsp[0].intval); ; break;} case 13: #line 91 "./fconfig.y" { setBinDir (databaseBeingDefined, qStrVal (yyvsp[0].qstr)); ; break;} case 14: #line 94 "./fconfig.y" { setSubmitterAck (databaseBeingDefined, yyvsp[0].intval); ; break;} case 15: #line 97 "./fconfig.y" { setBusinessDay (databaseBeingDefined, yyvsp[-2].intval, yyvsp[0].intval); ; break;} case 16: #line 100 "./fconfig.y" { setBusinessWeek(databaseBeingDefined,yyvsp[-2].intval, yyvsp[0].intval); ; break;} case 17: #line 103 "./fconfig.y" { setCreateCategoryDirs (databaseBeingDefined, yyvsp[0].intval); ; break;} case 18: #line 106 "./fconfig.y" { setCategoryDirPerms (databaseBeingDefined, qStrVal (yyvsp[0].qstr)); ; break;} case 19: #line 111 "./fconfig.y" { yyval.intval = 0; ; break;} case 20: #line 112 "./fconfig.y" { yyval.intval = 1; ; break;} case 22: #line 116 "./fconfig.y" { fconferror ("Missing/bad field declarations"); ; break;} case 25: #line 125 "./fconfig.y" { currField = NULL; ; break;} case 26: #line 128 "./fconfig.y" { currField = NULL; ; break;} case 27: #line 133 "./fconfig.y" { char *fname = takeQString (yyvsp[0].qstr); currField = newFieldDef (databaseBeingDefined, fname); if (currField == NULL) { char *msg; asprintf (&msg, "Duplicate field definition for %s\n", fname); fconferror (msg); free (msg); } currField->default_value = NULL; ; break;} case 34: #line 158 "./fconfig.y" { currField->virtualFormat = qformat; qformat = NULL; ; break;} case 37: #line 166 "./fconfig.y" { currField->datatype = MultiText; currField->defaultSearchType = NilSearch; ; break;} case 38: #line 170 "./fconfig.y" { currField->datatype = Date; currField->defaultSearchType = LessThan; ; break;} case 39: #line 174 "./fconfig.y" { currField->datatype = Integer; currField->defaultSearchType = NilSearch; ; break;} case 40: #line 178 "./fconfig.y" { currField->datatype = PRListType; currField->defaultSearchType = RegCmp; ; break;} case 41: #line 184 "./fconfig.y" { currField->datatype = Text; ; break;} case 42: #line 187 "./fconfig.y" { currField->datatype = TextWithRegex; ; break;} case 44: #line 193 "./fconfig.y" { yyval.stringlist = new_string_list_ent (takeQString (yyvsp[0].qstr), NULL); currField->regex = yyval.stringlist; ; break;} case 45: #line 197 "./fconfig.y" { yyvsp[-1].stringlist->next = new_string_list_ent (takeQString (yyvsp[0].qstr), NULL); yyval.stringlist = yyvsp[-1].stringlist->next; ; break;} case 46: #line 203 "./fconfig.y" { currField->datatype = Enum; currField->defaultSearchType = RegCmp; ; break;} case 47: #line 207 "./fconfig.y" { currField->datatype = Enum; currField->defaultSearchType = RegCmp; initAdmField (currField); ; break;} case 48: #line 212 "./fconfig.y" { currField->datatype = MultiEnum; currField->defaultSearchType = RegCmp; initAdmField (currField); ; break;} case 49: #line 217 "./fconfig.y" { currField->datatype = MultiEnum; currField->defaultSearchType = RegCmp; if (currField->multiEnumSeparator == NULL) { currField->multiEnumSeparator = xstrdup (DEFAULT_MULTIENUM_SEPARATOR); } ; break;} case 54: #line 234 "./fconfig.y" { addGlobalChangeActions (databaseBeingDefined, currChange); currChange = NULL; ; break;} case 55: #line 240 "./fconfig.y" { ChangeActions *p = &(currField->changeActions); while (*p != NULL) { p = &((*p)->next); } *p = currChange; currChange = NULL; ; break;} case 56: #line 251 "./fconfig.y" { currChange = newChangeAction (databaseBeingDefined, yyvsp[-1].sval); if (yyvsp[-1].sval != NULL) { free (yyvsp[-1].sval); } ; break;} case 57: #line 260 "./fconfig.y" { yyval.sval = takeQString (yyvsp[0].qstr); ; break;} case 58: #line 263 "./fconfig.y" { yyval.sval = NULL; ; break;} case 63: #line 274 "./fconfig.y" { currChange->edits = currEdit; currEdit = NULL; ; break;} case 64: #line 278 "./fconfig.y" { currEdit->append = 1; currChange->edits = currEdit; currEdit = NULL; ; break;} case 65: #line 283 "./fconfig.y" { currChange->addAuditTrail = 1; ; break;} case 66: #line 286 "./fconfig.y" { currChange->auditTrailFormat = qformat; qformat = NULL; ; break;} case 67: #line 290 "./fconfig.y" { currChange->requireChangeReason = 1; ; break;} case 70: #line 299 "./fconfig.y" { FieldList foo = newFieldListEnt (databaseBeingDefined, qStrVal (yyvsp[0].qstr), currChange->requiredFields); currChange->requiredFields = foo; ; break;} case 73: #line 311 "./fconfig.y" { currEdit = (FieldEdit *) xmalloc (sizeof (FieldEdit)); currEdit->expr = NULL; currEdit->fieldToEditName = takeQString (yyvsp[0].qstr); currEdit->append = 0; currEdit->textFormat = NULL; currEdit->fieldsForFormat = NULL; currEdit->next = NULL; ; break;} case 74: #line 322 "./fconfig.y" { currEdit->textFormat = takeQString (yyvsp[0].qstr); ; break;} case 75: #line 327 "./fconfig.y" { currEdit->fieldsForFormat = NULL; ; break;} case 76: #line 330 "./fconfig.y" { ; break;} case 77: #line 334 "./fconfig.y" { yyval.flist = newFieldListEnt (databaseBeingDefined, qStrVal (yyvsp[0].qstr), NULL); currEdit->fieldsForFormat = yyval.flist; ; break;} case 78: #line 339 "./fconfig.y" { yyval.flist = newFieldListEnt (databaseBeingDefined, qStrVal (yyvsp[0].qstr), NULL); yyvsp[-1].flist->next = yyval.flist; ; break;} case 84: #line 355 "./fconfig.y" { currField->maxPrsPerLine = yyvsp[0].intval; ; break;} case 90: #line 369 "./fconfig.y" { currField->multiEnumSeparator = takeQString (yyvsp[0].qstr); ; break;} case 94: #line 379 "./fconfig.y" { yyval.stringlist = new_string_list_ent (takeQString (yyvsp[0].qstr), NULL); currField->enumValues = yyval.stringlist; ; break;} case 95: #line 383 "./fconfig.y" { yyvsp[-1].stringlist->next = new_string_list_ent (takeQString (yyvsp[0].qstr), NULL); yyval.stringlist = yyvsp[-1].stringlist->next; ; break;} case 98: #line 393 "./fconfig.y" { currField->adm_db_name = takeQString (yyvsp[0].qstr); ; break;} case 99: #line 396 "./fconfig.y" { AdmFieldDesc *p; int which = 0; for (p = currField->adm_field_des; p != NULL; p = p->next) { if (strcmp (p->name, qStrVal (yyvsp[0].qstr)) == 0) { break; } which++; } if (p != NULL) { currField->key_field = which; } else { char *msg; asprintf (&msg, "Invalid adm subfield %s\n", qStrVal (yyvsp[0].qstr)); fconferror (msg); free (msg); } ; break;} case 102: #line 425 "./fconfig.y" { currField->allow_any_value = 1; ; break;} case 106: #line 435 "./fconfig.y" { currField->multiEnumSeparator = takeQString (yyvsp[0].qstr); ; break;} case 107: #line 440 "./fconfig.y" { currField->default_value = takeQString (yyvsp[0].qstr); ; break;} case 108: #line 443 "./fconfig.y" { currField->input_default_value = takeQString (yyvsp[0].qstr); ; break;} case 109: #line 448 "./fconfig.y" { currField->adm_db_fields = 1; currField->adm_field_des = yyvsp[0].adm_field_des; yyval.adm_field_des = yyvsp[0].adm_field_des; ; break;} case 110: #line 453 "./fconfig.y" { yyvsp[-1].adm_field_des->next = yyvsp[0].adm_field_des; yyval.adm_field_des = yyvsp[0].adm_field_des; currField->adm_db_fields++; ; break;} case 111: #line 460 "./fconfig.y" { yyval.adm_field_des = (AdmFieldDesc *) xmalloc (sizeof (AdmFieldDesc)); yyval.adm_field_des->name = takeQString (yyvsp[0].qstr); yyval.adm_field_des->next = NULL; ; break;} case 112: #line 468 "./fconfig.y" { currField->defaultSearchType = RegCmp; ; break;} case 113: #line 471 "./fconfig.y" { currField->defaultSearchType = RegFind; ; break;} case 114: #line 476 "./fconfig.y" { currField->textsearch = 1; ; break;} case 115: #line 479 "./fconfig.y" { currField->restricted = 1; ; break;} case 116: #line 482 "./fconfig.y" { currField->nospaces = 1; ; break;} case 117: #line 485 "./fconfig.y" { if (setBuiltinField (currField, qStrVal (yyvsp[0].qstr)) != 0) { char *msg; asprintf (&msg, "Invalid builtin fieldname %s", qStrVal (yyvsp[0].qstr)); fconferror (msg); free (msg); } ; break;} case 119: #line 496 "./fconfig.y" { currField->description = takeQString (yyvsp[0].qstr); ; break;} case 120: #line 499 "./fconfig.y" { currField->readonly = 1; ; break;} case 121: #line 502 "./fconfig.y" { currField->auxFlags = yyvsp[-1].stringlist; ; break;} case 122: #line 505 "./fconfig.y" { currField->editonly = 1; ; break;} case 123: #line 510 "./fconfig.y" { yyval.stringlist = new_string_list_ent (takeQString (yyvsp[0].qstr), NULL); currField->auxFlags = yyval.stringlist; ; break;} case 124: #line 514 "./fconfig.y" { yyvsp[-1].stringlist->next = new_string_list_ent (takeQString (yyvsp[0].qstr), NULL); yyval.stringlist = yyvsp[-1].stringlist->next; ; break;} case 129: #line 528 "./fconfig.y" { addQueryFormat (databaseBeingDefined, qformat); qformat = NULL; ; break;} case 130: #line 532 "./fconfig.y" { freeQueryFormat (qformat); qformat = NULL; ; break;} case 131: #line 538 "./fconfig.y" { qformat = (QueryFormat *) xmalloc (sizeof (QueryFormat)); qformat->name = takeQString (yyvsp[0].qstr); qformat->printf = NULL; qformat->separator = NULL; qformat->fields = NULL; qformat->next = NULL; ; break;} case 140: #line 562 "./fconfig.y" { qformat->rawQuery = 1; ; break;} case 141: #line 567 "./fconfig.y" { qformat->printf = takeQString (yyvsp[0].qstr); ; break;} case 144: #line 576 "./fconfig.y" { qformat->fields = yyvsp[0].flist; ; break;} case 145: #line 579 "./fconfig.y" { yyvsp[-1].flist->next = yyvsp[0].flist; yyval.flist = yyvsp[0].flist; ; break;} case 146: #line 585 "./fconfig.y" { yyval.flist = newFieldListEnt (databaseBeingDefined, qStrVal (yyvsp[0].qstr), NULL); if (parseComplexFieldIndex (yyval.flist->ent) != 0) { char *msg; asprintf (&msg, "Field %s is invalid\n", qStrVal (yyvsp[0].qstr)); fconferror (msg); free (msg); } ; break;} case 147: #line 599 "./fconfig.y" { setIndexDesc (databaseBeingDefined, indexEntry); indexEntry = NULL; ; break;} case 148: #line 603 "./fconfig.y" { freeIndexDesc (indexEntry); indexEntry = NULL; ; break;} case 150: #line 610 "./fconfig.y" { indexEntry = newIndexDesc (databaseBeingDefined); ; break;} case 153: #line 619 "./fconfig.y" { setIndexDescPath (indexEntry, qStrVal (yyvsp[0].qstr)); ; break;} case 157: #line 627 "./fconfig.y" { addFieldToIndex (indexEntry, yyvsp[0].flist); ; break;} case 158: #line 630 "./fconfig.y" { addFieldToIndex (indexEntry, yyvsp[0].flist); ; break;} case 159: #line 635 "./fconfig.y" { setIndexDescSeparator (indexEntry, takeQString (yyvsp[0].qstr)); ; break;} case 160: #line 638 "./fconfig.y" { setIndexDescBinary (indexEntry, yyvsp[0].intval); ; break;} case 163: #line 647 "./fconfig.y" { setInputTemplate (databaseBeingDefined, yyvsp[-1].inputlist); ; break;} case 165: #line 653 "./fconfig.y" { setRequiredInputFields (databaseBeingDefined, requiredFlds); ; break;} case 166: #line 656 "./fconfig.y" { freeFieldList (requiredFlds); requiredFlds = NULL; ; break;} case 167: #line 662 "./fconfig.y" { requiredFlds = yyvsp[0].flist; ; break;} case 168: #line 665 "./fconfig.y" { yyvsp[-1].flist->next = yyvsp[0].flist; yyval.flist = yyvsp[0].flist; ; break;} case 169: #line 671 "./fconfig.y" { yyval.inputlist = inputTemplate; inputTemplate = NULL; ; break;} case 170: #line 675 "./fconfig.y" { yyval.inputlist = NULL; ; break;} case 171: #line 680 "./fconfig.y" { yyval.inputlist = (InputTemplate *) xmalloc (sizeof (InputTemplate)); yyval.inputlist->index = find_field_index (databaseBeingDefined, qStrVal (yyvsp[0].qstr)); if (yyval.inputlist->index == InvalidFieldIndex) { char *msg; asprintf (&msg, "Field %s is invalid\n", qStrVal (yyvsp[0].qstr)); fconferror (msg); free (yyval.inputlist); free (msg); inputTemplate = NULL; } else { inputTemplate = yyval.inputlist; yyval.inputlist->next = NULL; } ; break;} case 172: #line 702 "./fconfig.y" { yyval.inputlist = (InputTemplate *) xmalloc (sizeof (InputTemplate)); yyval.inputlist->index = find_field_index (databaseBeingDefined, qStrVal (yyvsp[0].qstr)); if (yyval.inputlist->index == InvalidFieldIndex) { char *msg; asprintf (&msg, "Field %s is invalid\n", qStrVal (yyvsp[0].qstr)); fconferror (msg); free (msg); free (yyval.inputlist); } else { yyval.inputlist->next = NULL; yyvsp[-1].inputlist->next = yyval.inputlist; if (inputTemplate == NULL) { inputTemplate = yyval.inputlist; } } ; break;} case 175: #line 733 "./fconfig.y" { addMessageFormat (databaseBeingDefined, mailFormat); mailFormat = NULL; ; break;} case 176: #line 737 "./fconfig.y" { freeMessageFormat (mailFormat); mailFormat = NULL; ; break;} case 177: #line 743 "./fconfig.y" { mailFormat = (MailMessageFormat) xmalloc (sizeof (struct mail_message_format)); mailFormat->name = takeQString (yyvsp[0].qstr); mailFormat->toAddresses = NULL; mailFormat->fromAddress = NULL; mailFormat->replyTo = NULL; mailFormat->body = NULL; mailFormat->header = NULL; mailFormat->next = NULL; ; break;} case 180: #line 761 "./fconfig.y" { mailFormat->body = qformat; qformat = NULL; ; break;} case 181: #line 765 "./fconfig.y" { mailFormat->header = qformat; qformat = NULL; ; break;} case 182: #line 769 "./fconfig.y" { mailFormat->toAddresses = yyvsp[-1].mailaddrlist; ; break;} case 183: #line 772 "./fconfig.y" { mailFormat->fromAddress = yyvsp[-1].mailaddr; ; break;} case 184: #line 775 "./fconfig.y" { mailFormat->replyTo = yyvsp[-1].mailaddrlist; ; break;} case 188: #line 787 "./fconfig.y" { freeQueryFormat (qformat); qformat = NULL; ; break;} case 189: #line 793 "./fconfig.y" { qformat = (QueryFormat *) xmalloc (sizeof (QueryFormat)); qformat->name = NULL; qformat->printf = NULL; qformat->separator = NULL; qformat->fields = NULL; qformat->next = NULL; ; break;} case 190: #line 803 "./fconfig.y" { yyval.mailaddrlist = (MailAddressList *) xmalloc (sizeof (MailAddressList)); yyval.mailaddrlist->address = yyvsp[0].mailaddr; yyval.mailaddrlist->next = NULL; ; break;} case 191: #line 808 "./fconfig.y" { MailAddressList *lp = yyval.mailaddrlist; while (lp->next != NULL) { lp = lp->next; } lp->next = (MailAddressList *) xmalloc (sizeof (MailAddressList)); lp->next->address = yyvsp[0].mailaddr; lp->next->next = NULL; ; break;} case 192: #line 818 "./fconfig.y" { yyval.mailaddr = (MailAddress *) xmalloc (sizeof (MailAddress)); yyval.mailaddr->fixedAddress = takeQString (yyvsp[0].qstr); yyval.mailaddr->addresses = NULL; ; break;} case 193: #line 823 "./fconfig.y" { yyval.mailaddr = (MailAddress *) xmalloc (sizeof (MailAddress)); yyval.mailaddr->fixedAddress = NULL; yyval.mailaddr->addresses = yyvsp[0].flist; ; break;} case 194: #line 830 "./fconfig.y" { yyval.flist = yyvsp[0].flist; ; break;} case 195: #line 833 "./fconfig.y" { FieldList p = yyval.flist; while (p->next != NULL) { p = p->next; } p->next = yyvsp[0].flist; ; break;} case 196: #line 843 "./fconfig.y" { yyval.flist = newFieldListEnt (databaseBeingDefined, qStrVal (yyvsp[0].qstr), NULL); ; break;} case 197: #line 849 "./fconfig.y" { setAuditTrailFormat (databaseBeingDefined, qformat); ; break;} } #line 706 "/usr/share/bison/bison.simple" yyvsp -= yylen; yyssp -= yylen; #if YYLSP_NEEDED yylsp -= yylen; #endif #if YYDEBUG if (yydebug) { short *yyssp1 = yyss - 1; YYFPRINTF (stderr, "state stack now"); while (yyssp1 != yyssp) YYFPRINTF (stderr, " %d", *++yyssp1); YYFPRINTF (stderr, "\n"); } #endif *++yyvsp = yyval; #if YYLSP_NEEDED *++yylsp = yyloc; #endif /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTBASE] + *yyssp; if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTBASE]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #ifdef YYERROR_VERBOSE yyn = yypact[yystate]; if (yyn > YYFLAG && yyn < YYLAST) { YYSIZE_T yysize = 0; char *yymsg; int yyx, yycount; yycount = 0; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ for (yyx = yyn < 0 ? -yyn : 0; yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) if (yycheck[yyx + yyn] == yyx) yysize += yystrlen (yytname[yyx]) + 15, yycount++; yysize += yystrlen ("parse error, unexpected ") + 1; yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); yymsg = (char *) YYSTACK_ALLOC (yysize); if (yymsg != 0) { char *yyp = yystpcpy (yymsg, "parse error, unexpected "); yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); if (yycount < 5) { yycount = 0; for (yyx = yyn < 0 ? -yyn : 0; yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) if (yycheck[yyx + yyn] == yyx) { const char *yyq = ! yycount ? ", expecting " : " or "; yyp = yystpcpy (yyp, yyq); yyp = yystpcpy (yyp, yytname[yyx]); yycount++; } } yyerror (yymsg); YYSTACK_FREE (yymsg); } else yyerror ("parse error; also virtual memory exhausted"); } else #endif /* defined (YYERROR_VERBOSE) */ yyerror ("parse error"); } goto yyerrlab1; /*--------------------------------------------------. | yyerrlab1 -- error raised explicitly by an action | `--------------------------------------------------*/ yyerrlab1: if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ /* return failure if at end of input */ if (yychar == YYEOF) YYABORT; YYDPRINTF ((stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1])); yychar = YYEMPTY; } /* Else will try to reuse lookahead token after shifting the error token. */ yyerrstatus = 3; /* Each real token shifted decrements this */ goto yyerrhandle; /*-------------------------------------------------------------------. | yyerrdefault -- current state does not do anything special for the | | error token. | `-------------------------------------------------------------------*/ yyerrdefault: #if 0 /* This is wrong; only states that explicitly want error tokens should shift them. */ /* If its default is to accept any token, ok. Otherwise pop it. */ yyn = yydefact[yystate]; if (yyn) goto yydefault; #endif /*---------------------------------------------------------------. | yyerrpop -- pop the current state because it cannot handle the | | error token | `---------------------------------------------------------------*/ yyerrpop: if (yyssp == yyss) YYABORT; yyvsp--; yystate = *--yyssp; #if YYLSP_NEEDED yylsp--; #endif #if YYDEBUG if (yydebug) { short *yyssp1 = yyss - 1; YYFPRINTF (stderr, "Error: state stack now"); while (yyssp1 != yyssp) YYFPRINTF (stderr, " %d", *++yyssp1); YYFPRINTF (stderr, "\n"); } #endif /*--------------. | yyerrhandle. | `--------------*/ yyerrhandle: yyn = yypact[yystate]; if (yyn == YYFLAG) goto yyerrdefault; yyn += YYTERROR; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) goto yyerrdefault; yyn = yytable[yyn]; if (yyn < 0) { if (yyn == YYFLAG) goto yyerrpop; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrpop; if (yyn == YYFINAL) YYACCEPT; YYDPRINTF ((stderr, "Shifting error token, ")); *++yyvsp = yylval; #if YYLSP_NEEDED *++yylsp = yylloc; #endif yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; /*---------------------------------------------. | yyoverflowab -- parser overflow comes here. | `---------------------------------------------*/ yyoverflowlab: yyerror ("parser stack overflow"); yyresult = 2; /* Fall through. */ yyreturn: #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 853 "./fconfig.y" gnats-4.1.0/gnats/fconfigl.c0000600000175000017500000021333310212665124016425 0ustar chewiechewie00000000000000 #line 3 "" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 31 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef unsigned int yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) #define yywrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ (yytext_ptr) -= (yy_more_len); \ yyleng = (size_t) (yy_cp - (yytext_ptr)); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 82 #define YY_END_OF_BUFFER 83 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[636] = { 0, 0, 0, 81, 81, 0, 0, 83, 80, 78, 79, 69, 75, 77, 76, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 68, 67, 81, 82, 73, 72, 74, 82, 78, 75, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 73, 71, 70, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 20, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 3, 0, 0, 30, 0, 58, 0, 0, 0, 24, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 25, 0, 47, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 28, 0, 0, 0, 0, 0, 0, 17, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 52, 0, 35, 16, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 64, 56, 29, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 55, 42, 43, 66, 0, 10, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 11, 39, 38, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 33, 34, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[36] = { 0, 1, 2, 3, 4, 2, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[642] = { 0, 0, 0, 34, 38, 41, 43, 658, 659, 655, 659, 659, 0, 659, 649, 36, 35, 29, 47, 41, 49, 642, 633, 640, 635, 33, 629, 629, 56, 621, 60, 635, 54, 61, 659, 659, 0, 659, 0, 659, 659, 644, 644, 0, 638, 632, 624, 619, 56, 620, 628, 58, 612, 625, 610, 72, 619, 607, 625, 614, 64, 607, 609, 621, 76, 70, 619, 63, 609, 65, 621, 599, 619, 611, 593, 87, 85, 591, 615, 592, 600, 593, 0, 0, 659, 659, 611, 594, 602, 597, 607, 603, 579, 591, 592, 595, 598, 88, 578, 596, 593, 576, 582, 590, 574, 580, 585, 577, 576, 583, 581, 562, 565, 563, 577, 566, 659, 575, 568, 575, 579, 557, 560, 565, 570, 564, 560, 553, 659, 565, 557, 547, 547, 561, 563, 565, 543, 560, 555, 539, 539, 556, 534, 542, 535, 547, 535, 659, 532, 537, 542, 529, 545, 659, 539, 525, 527, 545, 537, 522, 535, 535, 534, 536, 538, 530, 511, 532, 523, 512, 523, 531, 505, 529, 518, 510, 515, 522, 516, 513, 659, 511, 495, 520, 493, 507, 498, 516, 496, 506, 493, 506, 659, 504, 488, 487, 508, 501, 506, 492, 478, 492, 495, 485, 493, 496, 498, 484, 485, 479, 475, 493, 659, 472, 491, 469, 486, 469, 659, 482, 483, 485, 477, 480, 475, 473, 469, 460, 94, 473, 451, 473, 455, 474, 457, 472, 452, 459, 449, 465, 456, 459, 459, 444, 460, 456, 458, 460, 438, 455, 457, 441, 435, 435, 453, 432, 437, 429, 432, 433, 444, 427, 659, 442, 659, 438, 659, 422, 429, 435, 421, 426, 433, 421, 421, 415, 427, 418, 425, 424, 430, 414, 407, 421, 411, 404, 417, 418, 400, 400, 413, 416, 399, 659, 404, 405, 400, 393, 394, 403, 400, 410, 389, 382, 402, 399, 389, 659, 383, 390, 381, 394, 394, 393, 398, 397, 389, 659, 382, 388, 374, 383, 391, 375, 367, 363, 367, 383, 376, 659, 377, 370, 366, 381, 359, 375, 362, 364, 357, 368, 374, 352, 346, 355, 367, 349, 353, 352, 366, 365, 361, 363, 356, 350, 334, 352, 349, 351, 337, 336, 347, 345, 352, 340, 336, 659, 338, 326, 333, 325, 345, 340, 336, 334, 315, 659, 335, 332, 324, 318, 330, 330, 314, 325, 332, 331, 330, 318, 659, 322, 324, 92, 320, 304, 313, 316, 306, 659, 315, 313, 300, 311, 310, 301, 312, 295, 294, 309, 296, 296, 659, 659, 298, 292, 659, 304, 659, 296, 299, 293, 283, 659, 292, 281, 284, 278, 275, 289, 283, 288, 280, 290, 285, 280, 283, 274, 659, 273, 287, 261, 278, 264, 274, 261, 259, 273, 659, 258, 278, 270, 261, 253, 252, 270, 659, 251, 659, 659, 264, 251, 250, 265, 256, 266, 240, 257, 237, 255, 242, 251, 251, 659, 247, 240, 236, 235, 247, 234, 239, 246, 659, 242, 230, 248, 226, 233, 230, 223, 223, 228, 238, 227, 232, 230, 659, 659, 237, 224, 235, 218, 217, 217, 659, 211, 659, 205, 203, 207, 220, 215, 222, 213, 223, 201, 212, 213, 659, 216, 207, 195, 203, 199, 204, 213, 195, 192, 659, 210, 659, 192, 659, 659, 197, 200, 185, 190, 197, 659, 196, 183, 180, 187, 192, 192, 178, 180, 189, 187, 167, 184, 659, 168, 177, 182, 182, 162, 186, 185, 659, 659, 659, 659, 170, 161, 179, 162, 180, 168, 171, 171, 170, 168, 157, 154, 169, 168, 151, 143, 154, 161, 153, 159, 659, 164, 138, 151, 154, 155, 138, 138, 137, 129, 137, 138, 44, 68, 659, 80, 100, 96, 659, 659, 659, 659, 90, 659, 100, 96, 105, 93, 659, 94, 110, 118, 113, 104, 659, 118, 114, 123, 109, 119, 115, 110, 659, 121, 116, 111, 112, 125, 113, 114, 659, 659, 659, 659, 140, 144, 148, 152, 156, 158 } ; static yyconst flex_int16_t yy_def[642] = { 0, 635, 1, 636, 636, 637, 637, 635, 635, 635, 635, 635, 638, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 639, 635, 640, 635, 635, 641, 635, 638, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 639, 640, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 0, 635, 635, 635, 635, 635, 635 } ; static yyconst flex_int16_t yy_nxt[695] = { 0, 8, 9, 10, 11, 12, 13, 14, 8, 15, 16, 17, 18, 19, 20, 8, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 8, 33, 8, 8, 8, 34, 35, 34, 37, 37, 52, 37, 37, 37, 67, 37, 39, 40, 39, 40, 45, 41, 606, 41, 49, 56, 53, 46, 54, 50, 59, 47, 55, 68, 57, 51, 48, 71, 60, 77, 89, 74, 80, 61, 58, 75, 62, 93, 78, 105, 81, 79, 118, 72, 98, 115, 94, 607, 99, 90, 110, 111, 119, 122, 123, 112, 120, 106, 129, 152, 100, 113, 276, 153, 116, 114, 431, 608, 133, 277, 134, 609, 130, 131, 135, 132, 610, 611, 612, 613, 614, 615, 616, 278, 432, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 36, 36, 36, 36, 38, 38, 38, 38, 43, 43, 605, 43, 82, 604, 603, 82, 83, 83, 84, 84, 84, 84, 602, 601, 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, 570, 569, 568, 567, 566, 565, 564, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, 540, 539, 538, 537, 536, 535, 534, 533, 532, 531, 530, 529, 528, 527, 526, 525, 524, 523, 522, 521, 520, 519, 518, 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 458, 457, 456, 455, 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, 437, 436, 435, 434, 433, 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 128, 127, 126, 125, 124, 121, 117, 109, 108, 107, 104, 103, 102, 101, 97, 96, 95, 92, 91, 88, 87, 86, 44, 42, 85, 76, 73, 70, 69, 66, 65, 64, 63, 44, 42, 635, 7, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635 } ; static yyconst flex_int16_t yy_chk[695] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 17, 3, 4, 4, 25, 4, 5, 5, 6, 6, 15, 5, 594, 6, 16, 19, 17, 15, 18, 16, 20, 15, 18, 25, 19, 16, 15, 28, 20, 32, 48, 30, 33, 20, 19, 30, 20, 51, 32, 60, 33, 32, 67, 28, 55, 65, 51, 595, 55, 48, 64, 64, 67, 69, 69, 64, 67, 60, 75, 97, 55, 64, 228, 97, 65, 64, 391, 597, 76, 228, 76, 598, 75, 75, 76, 75, 599, 604, 606, 607, 608, 609, 611, 228, 391, 612, 613, 614, 615, 617, 618, 619, 620, 621, 622, 623, 625, 626, 627, 628, 629, 630, 631, 636, 636, 636, 636, 637, 637, 637, 637, 638, 638, 593, 638, 639, 592, 591, 639, 640, 640, 641, 641, 641, 641, 590, 589, 588, 587, 586, 585, 584, 583, 581, 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, 570, 569, 568, 567, 566, 565, 564, 563, 562, 557, 556, 555, 554, 553, 552, 551, 549, 548, 547, 546, 545, 544, 543, 542, 541, 540, 539, 538, 536, 535, 534, 533, 532, 529, 527, 525, 524, 523, 522, 521, 520, 519, 518, 517, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, 503, 501, 500, 499, 498, 497, 496, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, 479, 478, 477, 476, 475, 474, 473, 472, 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 458, 455, 453, 452, 451, 450, 449, 448, 447, 445, 444, 443, 442, 441, 440, 439, 438, 437, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, 420, 419, 418, 417, 415, 413, 412, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398, 396, 395, 394, 393, 392, 390, 389, 387, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 376, 374, 373, 372, 371, 370, 369, 368, 367, 366, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, 316, 315, 314, 313, 312, 311, 310, 309, 308, 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, 296, 295, 294, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 265, 263, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 227, 226, 225, 224, 223, 222, 221, 220, 219, 217, 216, 215, 214, 213, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 152, 151, 150, 149, 148, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 81, 80, 79, 78, 77, 74, 73, 72, 71, 70, 68, 66, 63, 62, 61, 59, 58, 57, 56, 54, 53, 52, 50, 49, 47, 46, 45, 44, 42, 41, 31, 29, 27, 26, 24, 23, 22, 21, 14, 9, 7, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected static int yy_more_flag = 0; static int yy_more_len = 0; #define yymore() ((yy_more_flag) = 1) #define YY_MORE_ADJ (yy_more_len) #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "./fconfigl.l" #line 2 "./fconfigl.l" #include "gnats.h" #include "fconfig.h" #define YY_INPUT(buf, result, max_size) { \ extern int (*yyinpfunc)(char *, int); \ result = (yyinpfunc)((buf), (max_size)); \ } int fconfig_lineno; static struct qstring { char *str; struct qstring *prev, *next; } *qstringList; char * qStrVal (struct qstring *str) { return str->str; } char * takeQString (struct qstring *str) { char *res = str->str; if (str->prev != NULL) { str->prev->next = str->next; } else { qstringList = str->next; } if (str->next != NULL) { str->next->prev = (str->prev); } free (str); return res; } void cleanLexer (void) { struct qstring *p = qstringList; while (p != NULL) { struct qstring *next = p->next; free (p->str); free (p); p = next; } qstringList = NULL; } /* This is pretty crummy. */ static struct qstring * lexQString (char *str) { int len = strlen (str) - 1; char *dest; int z; struct qstring *res = (struct qstring *) xmalloc (sizeof (struct qstring)); res->str = xmalloc (len + 1); dest = res->str; if (qstringList == NULL) { res->next = NULL; res->prev = NULL; } else { res->next = qstringList; qstringList->prev = res; res->prev = NULL; } qstringList = res; for (z = 0; z < len; z++) { if (str[z] == '\\') { z++; if (z < len) { switch (str[z]) { case '\n': break; case 'n': *(dest++) = '\n'; break; case 't': *(dest++) = '\t'; break; case 'r': *(dest++) = '\r'; break; case '"': *(dest++) = '"'; break; case '\\': *(dest++) = '\\'; break; default: *(dest++) = '\\'; *(dest++) = str[z]; break; } } } else { *(dest++) = str[z]; } } *(dest) = '\0'; return res; } #line 934 "" #define INITIAL 0 #define BadTok 1 #define QuoteLex 2 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 131 "./fconfigl.l" #line 1087 "" if ( (yy_init) ) { (yy_init) = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { (yy_more_len) = 0; if ( (yy_more_flag) ) { (yy_more_len) = (yy_c_buf_p) - (yytext_ptr); (yy_more_flag) = 0; } yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 636 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 659 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 132 "./fconfigl.l" { return FIELD; } YY_BREAK case 2: YY_RULE_SETUP #line 136 "./fconfigl.l" { return STRINGTYPE; } YY_BREAK case 3: YY_RULE_SETUP #line 140 "./fconfigl.l" { return MULTITEXTTYPE; } YY_BREAK case 4: YY_RULE_SETUP #line 144 "./fconfigl.l" { return DATETYPE; } YY_BREAK case 5: YY_RULE_SETUP #line 148 "./fconfigl.l" { return PATHTOK; } YY_BREAK case 6: YY_RULE_SETUP #line 152 "./fconfigl.l" { return QDEFAULT; } YY_BREAK case 7: YY_RULE_SETUP #line 156 "./fconfigl.l" { return MATCHING; } YY_BREAK case 8: YY_RULE_SETUP #line 160 "./fconfigl.l" { return ENUM; } YY_BREAK case 9: YY_RULE_SETUP #line 164 "./fconfigl.l" { return MULTIENUMTOK; } YY_BREAK case 10: YY_RULE_SETUP #line 168 "./fconfigl.l" { return ENUM_IN_FILE; } YY_BREAK case 11: YY_RULE_SETUP #line 172 "./fconfigl.l" { return MULTI_ENUM_IN_FILE; } YY_BREAK case 12: YY_RULE_SETUP #line 176 "./fconfigl.l" { return KEYTOK; } YY_BREAK case 13: YY_RULE_SETUP #line 180 "./fconfigl.l" { return FIELDSTOK; } YY_BREAK case 14: YY_RULE_SETUP #line 184 "./fconfigl.l" { return VALUES; } YY_BREAK case 15: YY_RULE_SETUP #line 188 "./fconfigl.l" { return DEFAULT; } YY_BREAK case 16: YY_RULE_SETUP #line 192 "./fconfigl.l" { return INPUTDEFAULTTOK; } YY_BREAK case 17: YY_RULE_SETUP #line 196 "./fconfigl.l" { return EXACT_REGEXP; } YY_BREAK case 18: YY_RULE_SETUP #line 200 "./fconfigl.l" { return INEXACT_REGEXP; } YY_BREAK case 19: YY_RULE_SETUP #line 204 "./fconfigl.l" { return ALL; } YY_BREAK case 20: YY_RULE_SETUP #line 208 "./fconfigl.l" { return FORMATTOK; } YY_BREAK case 21: YY_RULE_SETUP #line 212 "./fconfigl.l" { return TEXTSEARCH; } YY_BREAK case 22: YY_RULE_SETUP #line 216 "./fconfigl.l" { return QUERYTOK; } YY_BREAK case 23: YY_RULE_SETUP #line 220 "./fconfigl.l" { return INDEXTOK; } YY_BREAK case 24: YY_RULE_SETUP #line 224 "./fconfigl.l" { return SEPARATORTOK; } YY_BREAK case 25: YY_RULE_SETUP #line 228 "./fconfigl.l" { return RESTRICTEDTOK; } YY_BREAK case 26: YY_RULE_SETUP #line 232 "./fconfigl.l" { return INTEGERTOK; } YY_BREAK case 27: YY_RULE_SETUP #line 236 "./fconfigl.l" { return NOSPACESTOK; } YY_BREAK case 28: YY_RULE_SETUP #line 240 "./fconfigl.l" { return BUILTINTOK; } YY_BREAK case 29: YY_RULE_SETUP #line 244 "./fconfigl.l" { return ALLOWANYVALUETOK; } YY_BREAK case 30: YY_RULE_SETUP #line 248 "./fconfigl.l" { return CHANGETOK; } YY_BREAK case 31: YY_RULE_SETUP #line 252 "./fconfigl.l" { return REQUIRETOK; } YY_BREAK case 32: YY_RULE_SETUP #line 256 "./fconfigl.l" { return APPENDFIELDTOK; } YY_BREAK case 33: YY_RULE_SETUP #line 260 "./fconfigl.l" { return SETFIELDTOK; } YY_BREAK case 34: YY_RULE_SETUP #line 264 "./fconfigl.l" { return DESCRIPTIONTOK; } YY_BREAK case 35: YY_RULE_SETUP #line 268 "./fconfigl.l" { return INPUTTOK; } YY_BREAK case 36: YY_RULE_SETUP #line 272 "./fconfigl.l" { return DATABASEINFOTOK; } YY_BREAK case 37: YY_RULE_SETUP #line 276 "./fconfigl.l" { return DEBUGMODETOK; } YY_BREAK case 38: YY_RULE_SETUP #line 280 "./fconfigl.l" { return KEEPRECTOK; } YY_BREAK case 39: YY_RULE_SETUP #line 284 "./fconfigl.l" { return NOTIFYEXPTOK; } YY_BREAK case 40: YY_RULE_SETUP #line 288 "./fconfigl.l" { return SUBMITTERACKTOK; } YY_BREAK case 41: YY_RULE_SETUP #line 292 "./fconfigl.l" { return LIBEXECDIRTOK; } YY_BREAK case 42: YY_RULE_SETUP #line 296 "./fconfigl.l" { return BUSINESSDAYTOK; } YY_BREAK case 43: YY_RULE_SETUP #line 300 "./fconfigl.l" { return BUSINESSWEEKTOK; } YY_BREAK case 44: YY_RULE_SETUP #line 304 "./fconfigl.l" { return CREATECATEGORYDIRSTOK; } YY_BREAK case 45: YY_RULE_SETUP #line 308 "./fconfigl.l" { return FALSETOK; } YY_BREAK case 46: YY_RULE_SETUP #line 312 "./fconfigl.l" { return TRUETOK; } YY_BREAK case 47: YY_RULE_SETUP #line 316 "./fconfigl.l" { return ENUMSEPARATORSTOK; } YY_BREAK case 48: YY_RULE_SETUP #line 320 "./fconfigl.l" { return MAILFORMATTOK; } YY_BREAK case 49: YY_RULE_SETUP #line 324 "./fconfigl.l" { return TOADDRESSESTOK; } YY_BREAK case 50: YY_RULE_SETUP #line 328 "./fconfigl.l" { return FROMADDRESSTOK; } YY_BREAK case 51: YY_RULE_SETUP #line 332 "./fconfigl.l" { return REPLYTOTOK; } YY_BREAK case 52: YY_RULE_SETUP #line 336 "./fconfigl.l" { return FIXEDTOK; } YY_BREAK case 53: YY_RULE_SETUP #line 340 "./fconfigl.l" { return BODYTOK; } YY_BREAK case 54: YY_RULE_SETUP #line 344 "./fconfigl.l" { return HEADERTOK; } YY_BREAK case 55: YY_RULE_SETUP #line 348 "./fconfigl.l" { return AUDITTRAILFMTTOK; } YY_BREAK case 56: YY_RULE_SETUP #line 352 "./fconfigl.l" { return ADDAUDITTRAILTOK; } YY_BREAK case 57: YY_RULE_SETUP #line 356 "./fconfigl.l" { return REQUIRECHANGEREASONTOK; } YY_BREAK case 58: YY_RULE_SETUP #line 360 "./fconfigl.l" { return READONLYTOK; } YY_BREAK case 59: YY_RULE_SETUP #line 364 "./fconfigl.l" { return BINARYINDEXTOK; } YY_BREAK case 60: YY_RULE_SETUP #line 368 "./fconfigl.l" { return AUXFLAGSTOK; } YY_BREAK case 61: YY_RULE_SETUP #line 372 "./fconfigl.l" { return PRLISTTOK; } YY_BREAK case 62: YY_RULE_SETUP #line 376 "./fconfigl.l" { return MAXPRSTOK; } YY_BREAK case 63: YY_RULE_SETUP #line 380 "./fconfigl.l" { return EDITONLYTOK; } YY_BREAK case 64: YY_RULE_SETUP #line 384 "./fconfigl.l" { return VIRTUALFORMATTOK; } YY_BREAK case 65: YY_RULE_SETUP #line 388 "./fconfigl.l" { return RAWTOK; } YY_BREAK case 66: YY_RULE_SETUP #line 392 "./fconfigl.l" { return CATPERMSTOK; } YY_BREAK case 67: YY_RULE_SETUP #line 396 "./fconfigl.l" { return '|'; } YY_BREAK case 68: YY_RULE_SETUP #line 400 "./fconfigl.l" { return yytext[0]; } YY_BREAK case 69: YY_RULE_SETUP #line 404 "./fconfigl.l" { BEGIN(QuoteLex); } YY_BREAK case 70: /* rule 70 can match eol */ YY_RULE_SETUP #line 408 "./fconfigl.l" { fconfig_lineno++; yymore (); } YY_BREAK case 71: YY_RULE_SETUP #line 409 "./fconfigl.l" { yymore (); } YY_BREAK case 72: /* rule 72 can match eol */ YY_RULE_SETUP #line 410 "./fconfigl.l" { fprintf (stderr, "Warning: unquoted newline within quoted string at line %d\n", fconfig_lineno); fconfig_lineno++; yymore (); } YY_BREAK case 73: YY_RULE_SETUP #line 416 "./fconfigl.l" { yymore (); } YY_BREAK case 74: YY_RULE_SETUP #line 417 "./fconfigl.l" { fconflval.qstr = lexQString (yytext); BEGIN (0); return QSTRING; } YY_BREAK case 75: YY_RULE_SETUP #line 423 "./fconfigl.l" /* A comment */ YY_BREAK case 76: YY_RULE_SETUP #line 425 "./fconfigl.l" { fconflval.intval = atoi (yytext); return INTVAL; } YY_BREAK case 77: YY_RULE_SETUP #line 430 "./fconfigl.l" { return '-'; } YY_BREAK case 78: YY_RULE_SETUP #line 434 "./fconfigl.l" /* The usual "eat up whitespace" */ YY_BREAK case 79: /* rule 79 can match eol */ YY_RULE_SETUP #line 435 "./fconfigl.l" { fconfig_lineno++; } YY_BREAK case 80: YY_RULE_SETUP #line 439 "./fconfigl.l" { BEGIN (BadTok); yymore (); } YY_BREAK case 81: YY_RULE_SETUP #line 444 "./fconfigl.l" { fprintf (stderr, "Unrecognized token %s at line %d\n", yytext, fconfig_lineno); BEGIN (0); return BADTOK; } YY_BREAK case 82: YY_RULE_SETUP #line 450 "./fconfigl.l" ECHO; YY_BREAK #line 1751 "" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(BadTok): case YY_STATE_EOF(QuoteLex): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 636 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 636 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 635); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param str a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yy_str ) { return yy_scan_bytes(yy_str,strlen(yy_str) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * bytes, int len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < len; ++i ) buf[i] = bytes[i]; buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param line_number * */ void yyset_lineno (int line_number ) { yylineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str ) { yyin = in_str ; } void yyset_out (FILE * out_str ) { yyout = out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int bdebug ) { yy_flex_debug = bdebug ; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #undef YY_NEW_FILE #undef YY_FLUSH_BUFFER #undef yy_set_bol #undef yy_new_buffer #undef yy_set_interactive #undef yytext_ptr #undef YY_DO_BEFORE_ACTION #ifdef YY_DECL_IS_OURS #undef YY_DECL_IS_OURS #undef YY_DECL #endif #line 450 "./fconfigl.l" gnats-4.1.0/send-pr/0000755000175000017500000000000010212665130014726 5ustar chewiechewie00000000000000gnats-4.1.0/send-pr/COPYING0000644000175000017500000004312706620401137015773 0ustar chewiechewie00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. gnats-4.1.0/send-pr/ChangeLog0000644000175000017500000012216010207421262016502 0ustar chewiechewie000000000000002005-02-24 Chad Walstrom * Makefile.in (install-norm-arch-dep): Added mkinstalldir call to install the manpage directories. send-pr.1 and install-sid.8 were not being installed otherwise. 2004-11-29 Chad Walstrom * Makefile.in (install-norm-arch-dep): Added "all" to the dependency list. Prepended send-pr.conf with $(srcdir) variable, since it's not a generated file. (send-pr.1): Added send-pr.man to dependency list (install-sid.8): Added install-sid.man to dependency list 2004-11-17 Chad Walstrom * configure.in: Update version to 4.1.0 * configure: regenerated 2004-11-12 Chad Walstrom * install-sid.sh: Fixed sed expression typo. Added environment variables for prefix and sysconfdir for replacement by configure. * send-pr.sh: Rolled back change to MAILPROG, reassigning it a null string. Re-added "echo" before @ECHO_N@... 2004-10-03 Chad Walstrom * configure.in: Updated PACKAGE_VERSION to 4.1 * configure: regenerated 2004-10-02 Chad Walstrom * install-sid.man: New file * Makefile.in (install-sid.8): New target to install manpage (install-norm-arch-dep, DISTFILES): Added install-sid.man, install-sid.8 2004-10-02 Chad Walstrom * configure, configure.in: Took advantage of autoconf's ability to set program versions. Cleaned up generation of DEFAULT_RELEASE substitution variable. Added DEFAULT_MAIL_AGENT generation script from ../gnats/configure.in. Generated install-sid and send-pr files using autoconf rather than sed scripts in Makefile.in. * Makefile.in (send-pr.1): Substitute xSYSCONFDIRx rather than xPREFIXx. (install-sid): Removed. Being generated by configure. (send-pr): Removed. Being generated by configure. (install-norm-arch-dep, DISTFILES): Added send-pr.conf * send-pr.man (FILES): Indicate the new $HOME/.send-pr.conf file. Replaced xPREFIXx for xSYSCONFDIRx. * send-pr.conf: New file * send-pr.sh: If $HOME/.send-pr.conf exists, source it following @sysconfdir@/gnats/send-pr.conf. Also indicated that send-pr will fail if "unknown" used as a SUBMITTER id. Used autoconf substitution variables @ECHO_N@ and @ECHO_C@ to replace ECHON1 and ECHON2 variables. * install-sid.sh (usage): Added the usage function (main): Rewrite. No longer edit the send-pr application. Instead, edit or create the site configuration file SYSCONFDIR/gnats/send-pr.conf or the $HOME/.send-pr.conf file. Added safe temp file generation using mktemp, if it's available. 2004-06-09 Chad Walstrom * Makefile.in: Prepended the $(DESTDIR) variable to all destination targets. 2003-08-30 Mel Hatzis , Andrew J. Gray * send-pr.sh: Use show-prnum option to pr-edit, display PR number. 2003-07-27 Andrew J. Gray * Makefile.in (VERSION): Increased to 4.0. 2002-12-01 Andrew J. Gray * Makefile.in (VERSION): Increased to 4.0-beta2. 2002-11-03 Yngve Svendsen * send-pr.man: Rewrite for GNATS 4. - Makefile.in (send-pr.1): Substitute xPREFIXx. * MANIFEST: Remove it. Completely outdated. * INSTALL, MANIFEST, README: Tidy up. * send-pr.man: Remove the -c option. 2002-10-29 Yngve Svendsen * send-pr.sh: Add newline at the end. Catched by Lars Henriksen. 2002-10-24 Yngve Svendsen * send-pr.sh: Remove --cc | -c option. It has been superseded by the Notify-List functionality. * send-pr.sh: Remove X-Gnats-Notify header from mail format. It is no longer supported in GNATS and has been replaced by the Notify-List field. 2002-05-20 Milan Zamazal * send-pr.sh: ORGANIZATION setting fix. 2002-05-19 Milan Zamazal * send-pr.sh (USAGE): Long options take their arguments separated by a space, not the equal sign. 2001-12-27 Milan Zamazal * Makefile.in (VERSION): Increased to 4.0-beta1. 2001-12-10 Milan Zamazal * Makefile.in (send-pr.elc, send-pr.el, send-pr.el, EMACS): Removed. (all, install-norm-arch-indep, uninstall, clean): send-pr.el related things removed. (sysconfdir): Defined. * send-pr-el.in: Removed. 2001-09-06 Milan Zamazal * Makefile.in (install-norm): `all-gnats' mate removed. 2001-08-29 Milan Zamazal * Makefile.in (lispdir): The value is @lispdir@, not @LISPDIR@. (all-gnats): New target. (all-tools): New target. 2001-08-04 Milan Zamazal * aclocal.m4: Renamed to `acinclude.m4'. * configure.in (AC_LISPDIR): Changed to `AC_PATH_LISPDIR'. * aclocal.m4: Regenerated. * configure: Regenerated. * acinclude.m4 (AC_FIND_PROGRAM): Removed. (AC_LISPDIR): Likewise. 2001-08-03 Milan Zamazal * ChangeLog: Emacs variables removed. 2001-08-03 Yngve Svendsen * configure.in: Check for the mktemp command and set MKTEMP accordingly. * configure: Regenerated. * Makefile.in: Substitute xMKTEMPx. * send-pr.sh: Use mktemp to generate temp files safely on platforms where it is available. 2001-06-24 Milan Zamazal * Makefile.in: Documentation support removed. 2001-06-21 Milan Zamazal * All Texinfo and man files moved to ../doc/. 2001-06-12 Yngve Svendsen * fields.texi: Fixed cross-references to revised manual sections. 2001-05-27 Yngve Svendsen * send-pr.sh: Protect brackets in `tr' invocations by backslashes. `-d|--database' option added. 2001-04-15 Milan Zamazal * send-pr-el.in (gnats::get-config): Buffer checking fixed (Debian bug fix). 2001-04-08 Milan Zamazal * send-pr.sh: Typo in the variable name within the explanation of the missing $ORGANIZATION value fixed. 2001-01-22 Milan Zamazal * Makefile.in (send-pr): Substitute xSYSCONFDIRx. * send-pr.sh: Allow redefinition of configuration variables in a separate configuration file. Here documents delimiter fixed. (REPLYTO): Variable name typo fixed. 2001-01-21 Milan Zamazal * send-pr.sh (USAGE): Updated and improved. 2001-01-15 Yngve Svendsen * fields.texi: Spelling fix. Tue Mar 21 20:11:17 2000 Bob Manson * send-pr.sh: Add improved support for templates and the -P option. Add a MAILPROG variable so PRs can be submitted via mail as needed. Mon Feb 28 14:20:07 2000 Bob Manson * send-pr.sh: Fix typo. (Patch from Adrian Ashley .) Mon Feb 21 18:14:08 2000 Bob Manson * send-pr.sh: Include the user's email address as part of the Originator: field. Also, if a field's list of defalt values is longer than 160 characters, instead of inclding the list as a prompted value, use the field's description instead. * categories: Deleted, no longer used. Wed Jan 5 21:56:07 2000 Bob Manson * send-pr.sh: Remove any and all traces of GNATS_ADDR. Tue Jan 4 17:20:29 2000 Bob Manson * send-pr.sh: Really don't send mail. I mean it. :-) * configure.in: Added --with-submitter and --with-organization options. * send-pr.sh: Make the check for field type case-insensitive. Don't list all the categories in the field; instead say "choose from a category listed above". Make the default submitter and organization work. (DEFAULT_GNATS_ADDR): Make it `bugs'. * Deleted a bunch of other unused Makefile.in and configure.in parameters. We no longer send mail, so deleted checks for sendmail. Mon Dec 27 20:58:57 1999 Bob Manson * Makefile.in: Removed dist references. Wed Dec 8 19:26:03 1999 Bob Manson * send-pr.sh: Major changes to work with the 4.0 enhancements. In particular, it no longer uses a static template, and it has little knowledge of specific PR fields. It also relies on pr-edit to do most of the PR validation, and invokes query-pr to get the info about what fields exist, their datatypes, etc. 1999-10-26 Jason Molenda (jsm@bugshack.cygnus.com) * configure: Regenerate with autoconf 2.13. * Makefile.in (VERSION): Set to 4.0-alpha. 1999-10-25 Andreas Luik * send-pr-el.in (send-pr:submit-pr): Portability fix; use char-after instead of char-before. 1999-10-25 Andreas Luik * Makefile.in (mostlyclean): Also remove *.aux. (distclean): Also remove config.log. (maintainer-clean): Accept this as the same as realclean. Thu Aug 26 11:25:44 1999 Bob Manson Fix from "Andreas Luik" or . * send-pr-el.in (send-pr:submit-pr): Ensure that there is a final newline in the buffer before the submission is set. Wed Jul 29 16:04:03 1998 Rick Macdonald * Makefile.in (VERSION): Up to 3.107. * Makefile.in: when you follow the install instructions and run "make install" as root, "mkcat" later fails because root owns the files and directories that mkcat needs to write. I added a chown to GNATS_USER of the gnats/dist directory. Sun Jun 28 12:12:58 1998 Paul Traina * Makefile.in (VERSION): Up to 3.106. * send-pr.sh: Check REPLY_TO, REPLYTO, and LOGNAME. (From FreeBSD) * send-pr.sh: List all available categories up at the top of send-pr instead of in the categories line (handle more than a few small categories) (From FreeBSD) * send-pr.sh: Check that the synopsis field is not empty. make the Subject field match the synopsis field if it was left empty by the user. (From FreeBSD) * send-pr.sh: Do *not* include user's .signature file in the organization field. It's almost always too much data or annoying. Thu Dec 18 16:30:03 1997 Karl Fogel * Makefile.in (TEXINPUTS): include ../gnats, since states.texi refers to nodes from there. * states.texi (States): reference customizable states. * fields.texi (Problem Report fields): reference "categories file", not "categories". Tue Nov 25 16:00:00 1997 Abe Feldman * s-usage.texi: Added note about deriving the submitter ID from the "From:" header when incoming PR is unformatted Fri Oct 31 17:00:00 1997 Abe Feldman * s-usage.texi: New node, "Submitting via e-mail" on how to submit a problem report via direct e-mail. Mon Aug 18 14:11:13 1997 Brendan Kehoe * Makefile.in (VERSION): Up to 3.104. I forgot to modify this for 3.103. Tue Jul 29 20:36:47 1997 Ken Raeburn * aclocal.m4 (AC_LISPDIR): Don't use the word "checking" in AC_MSG_CHECKING string. Thu Jul 17 10:42:02 1997 David J. MacKenzie * Makefile.in: Use the modern standard file system layout (libexec, share, etc. instead of putting non-libraries in lib). * s-usage.texi, send-pr.texi: Clean up a few formatting errors, duplicated text, typos, etc. Add a few missing examples. Document the new file system layout. Tue Jul 15 13:45:39 1997 Brendan Kehoe Fix from "Jonathan I. Kamens" . Make it possible to separately install the architecture-dependent pieces for the main server on one machine, and the independent pieces for the clients. * Makefile.in (SEND_PR_INSTALL_ARCH_DEP): Define. (install-arch-dep, install-tools-arch-dep, install-gnats-arch-dep): New dependencies. (install-norm-arch-indep, install-norm-arch-dep): New rules. (install-norm): Moved from here. Fix from "Jonathan I. Kamens" . * send-pr-el.in (send-pr:submit-pr): If the PR has already sent, prompt the user before agreeing to resend it. (send-pr:send-pr-mode): Declare SEND-PR:::SENT and set it to nil. Fri May 16 18:30:29 1997 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.102. Tue May 6 16:06:44 1997 Brendan Kehoe * send-pr.sh: Don't trap on a SIGINT, which can come from emacs when it gets a ^G, and isn't a sign of a problem. Thu Mar 20 00:04:18 1997 Geoffrey Noer * Makefile.in, categ.texi, send-pr.texi: update company information (name change to Cygnus Solutions, new location, phone) Sun Dec 29 02:17:58 1996 Angela Marie Thomas (angela@cygnus.com) * send-pr.sh: make sure DATADIR is set correctly when GCC_EXEC_PREFIX is used. Mon Dec 2 14:30:17 1996 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.101. Thu Nov 7 06:32:37 1996 Brendan Kehoe * send-pr-el.in (gnats::indent): Fix to be 17, not 16, so we don't have the values in the wrong column. Thu Sep 5 14:35:55 1996 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.99. Wed Aug 21 17:22:51 1996 Brendan Kehoe * configure.in: If $prefix is NONE, use $ac_default_prefix for setting of GNATS_ROOT. * configure: Regenerate. * aclocal.m4: Use $ac_default_prefix if prefix is set to NONE. Tue Aug 20 10:19:53 1996 Brendan Kehoe * send-pr-el.in (gnats::get-config): Catch when RET is a null string, replacing it with nil, to fix functioning under emacs18. Fix from "Jonathan I. Kamens" . * send-pr-el.in (send-pr::insert-template): Use call-process instead of shell-command, to avoid "Mark set" msg in minibuf. Fix pointed out by "Jonathan I. Kamens" . * send-pr-el.in (send-pr::start-up): Fix logic for use of MAIL-DEFAULT-REPLY-TO, to always get REPLYTO if it hasn't been set to a string. Thu Aug 8 17:21:27 1996 Brendan Kehoe * Makefile.in (VERSION): Up to version 3.98. * Makefile.in (send-pr.info): Depend on version.texi. (all): Depend upon version.texi. (install-gnats-dist): Install from the current directory. Wed Jun 26 12:16:13 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) * Makefile.in (VPATH, INSTALL, INSTALL_PROGRAM, INSTALL_DATA, bindir, libdir, datadir, mandir, infodir, includedir): Use autoconf-set values. (docdir): Removed. * configure.in (AC_PREREQ): autoconf 2.5 or higher. (AC_PROG_INSTALL): Added. * configure: Rebuilt. * aclocal.m4 (LISPDIR): default is $(prefix)/share/emacs/... Fri May 10 12:40:49 1996 Tom Tromey * install-sid.sh: Added location-independence code. * Makefile.in (exec_prefix): Set to @exec_prefix@. * send-pr.sh: Added location-independence code. Wed May 8 09:12:13 1996 Tom Tromey * Makefile.in (all): Depend on send-pr.el. Tue May 7 19:28:57 1996 Gordon Irlam * Makefile.in (all): Don't build or install send-pr.elc. Wed Mar 6 12:52:07 1996 J.T. Conklin * send-pr.man: Changed -v to -V. Tue Mar 5 12:59:30 1996 Brendan Kehoe * aclocal.m4: Check for .../share/emacs/site-lisp first. * configure: Regenerated with autoconf 2.7. Tue Feb 20 17:46:13 1996 Brendan Kehoe * Makefile.in (TEXINPUTS): Add definition. (send-pr.dvi): Use it. Tue Feb 13 16:06:31 1996 Brendan Kehoe * Makefile.in (install-gnats-dist): Only try to install the info files if they exist. (mostlyclean): Also delete *.cps. (distclean): Also delete TAGS and version.texi. (realclean): Don't delete *info or version.texi. (install-gnats-dist): Also install version.texi. Wed Nov 8 18:05:29 1995 Brendan Kehoe * send-pr-el.in (gnats::patch-exec-path): Use replace-match inside a while loop instead of replace-string. Fri Oct 13 17:47:28 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.97. Thu Sep 14 14:50:53 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.96. Tue Sep 5 16:14:51 1995 Brendan Kehoe * send-pr-el.in (send-pr::start-up): Use the REPLYTO env setting if mail-default-reply-to is t. Thu Aug 31 11:58:05 1995 Brendan Kehoe * send-pr-el.in (send-pr::fields): Fix Class's default value to reference DEFAULT_CLASS, not DEFAULT_CONFIDENTIAL. Mon Aug 28 16:52:46 1995 Brendan Kehoe * send-pr.sh: New argument -s/--severity, to let you specify the severity on the command line. New argument -c/--cc, to give a Cc: header. Thu Aug 3 13:32:39 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.95. Wed Jul 26 18:26:31 1995 Brendan Kehoe * Makefile.in (install-gnats-dist): Also put in INSTALL and MANIFEST. Mon Jul 17 10:11:11 1995 Brendan Kehoe * Makefile.in (VERSION): Up to 3.93. * Makefile.in (prefix): Use @prefix@, not /usr/local, for the default. Thu Jul 13 13:02:52 1995 Brendan Kehoe * send-pr-el.in (gnats::position-on-field): Add new arg QUIET. Only give the error if QUIET is nil. (gnats::field-contents): Pass T to position-on-field. * Makefile.in (VERSION): Update to 3.92. Wed Jul 12 12:26:49 1995 Brendan Kehoe * Makefile.in (EMACS): Define variable to use ../emacs19/src/emacs if it's there. (send-pr.elc): Use that instead of just `emacs'. Fri Jul 7 13:43:48 1995 Brendan Kehoe * aclocal.m4: Use AC_MSG_* for AC_LISPDIR. * configure: Regenerate. Thu Jul 6 19:22:53 1995 Brendan Kehoe * send-pr-el.in (gnats::get-config): Also match `.:' for NetBSD. Mon Jun 12 08:32:57 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (stamp-gnats): Don't depend on ../gnats/Makefile. Fri Mar 24 15:04:58 1995 Jason Merrill * aclocal.m4 (AC_LISPDIR): Tweak quoting to work with bash. * configure: Regenerate. Mon Feb 13 02:04:13 1995 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh: Be a little more elegant about how we set LOGNAME. Sun Feb 12 22:59:44 1995 Brendan Kehoe (brendan@cygnus.com) * configure.in: Only set GNATS_SITE and GNATS_ADDR if we aren't given environment variables with them set. * configure: Generated new one. Fri Feb 3 12:10:35 1995 J.T. Conklin * send-pr.sh: Added missing ` (backquote) to expression used to determine whether TMPDIR ends in a slash. Tue Jan 31 10:48:39 1995 J.T. Conklin * send-pr.sh: Use REPLYTO instead of REPLY_TO. Set REPLYTO to LOGNAME if it is unset. Fri Dec 30 16:52:40 1994 Ian Lance Taylor * Makefile.in (install-norm): Stop make from printing an error message of send-pr.elc does not exist. Thu Oct 6 13:05:19 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr-el.in (gnats::get-config): Go to point-min after running the shell command on the region. (send-pr::start-up): Likewise, after inserting the site template. * send-pr.sh (TMPDIR): If TMPDIR ends in a slash, cut it off to avoid emacs send-pr not working. Wed Oct 5 13:11:27 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr-el.in (send-pr::start-up): Call insert-template instead of running `send-pr -P' every time. (send-pr::template-alist): Declare. (send-pr::insert-template): New function. * send-pr-el.in (gnats::get-config): Check get-buffer before using looking-at, since shell-command-on-region wipes it out if there's no output (which will be the case for variables not set in the config file). * send-pr-el.in (gnats::find-safe-default-directory): New function. Thu Sep 29 18:37:34 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * aclocal.m4 (AC_LISPDIR): Set LISPDIR using commas in the sed, not slashes. * configure: Generate a new one. Tue Aug 30 13:55:22 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * aclocal.m4: Change from Jason, to try to use PREFIX on the LISPDIR if possible before going with /usr/local. Mon Aug 1 11:31:47 1994 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr-el.in (send-pr::start-up): Always start at the beginning of the buffer when searching for `^SEND-PR:'. Sun Jul 17 19:13:17 1994 Jason Molenda (crash@sendai.cygnus.com) * categories: add `dos' for real this time. Wed May 11 15:46:48 1994 Bill Cox (bill@rtl.cygnus.com) * Makefile.in: Delete install commands which attempt to 'chown' the script to user 'gnats', who not exist in the end-user's system. Fri May 6 17:40:12 1994 Jason Molenda (crash@sendai.cygnus.com) * categories: add 'dos', 'gcov', 'gasp', and 'install'. Thu Apr 21 12:55:52 1994 James Clark (jjc@jclark.com) * send-pr.sh (ORGANIZATION): don't use quotes in the ${ORG-"\t$ORG_C"} thing. It tickles a bug in bourne shell. Wed Apr 6 17:16:28 1994 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats::get-config): Use shell-command-on-region instead of shell-command. (send-pr::start-up): Ditto. Wed Apr 6 17:14:36 1994 Cheryl Bien (bien@aero.org) * send-pr.sh (ORIGINATOR): Use awk instead of cut. Tue Mar 22 17:12:24 1994 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: DATADIR is under $(prefix), not $(exec_prefix). Sat Jan 15 19:12:45 1994 Jason Merrill (jason@deneb.cygnus.com) * aclocal.m4 (AC_LISPDIR): Handle case where $(prefix) is not specified on the command line. Mon Jan 10 17:21:33 1994 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr:submit-pr): If called from command line, save buffer on C-c C-c. * send-pr.sh: Clean up template. * Makefile.in, configure.in: Don't use AC_PROG_INSTALL after all. * aclocal.m4 (AC_LISPDIR): Check for --with-lispdir option. Fri Jan 7 11:43:02 1994 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats:change-field): If not called interactively, just use the default value. * Makefile.in (uninstall): Fix. * configure.in: Add call to AC_PROG_INSTALL. * Makefile.in (INSTALL*): Use it. * send-pr.sh: Only modify GNATS_ADDR if USER_GNATS_SITE is different from GNATS_SITE. * send-pr-el.in (send-pr:submit-pr): If the user ran send-pr from the command line with $EDITOR == emacs, don't submit the PR here. (send-pr:::spawn-to-send): Variable to control this behavior. Thu Jan 6 22:51:15 1994 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr::fields): Default for Submitter-Id should be SUBMITTER, not DEFAULT_SUBMITTER. * aclocal.m4 (AC_PASSWD): New macro to figure out how to read the passwd database (cat, ypcat, niscat). * configure.in: Use it. * Makefile.in (PASSWD, send-pr): Use it. * send-pr.sh: Use it. Fri Dec 10 11:48:44 1993 Jason Merrill (jason@deneb.cygnus.com) * Version 3.2 Thu Dec 2 09:11:40 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (mostlyclean): Don't delete version.texi. (realclean): Do delete version.texi. Tue Nov 30 15:37:59 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-gnats-dist): Use send-pr.1 rather than send-pr.man. Mon Nov 22 15:43:40 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-gnats-dist): Make sure $(datadir)/gnats/dist is writable by user gnats. Fri Nov 19 16:53:53 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats::emacs-19p): Avoid confusion wrt Epoch. Fri Nov 12 16:27:00 1993 Jason Merrill (jason@deneb.cygnus.com) Fri Nov 12 15:48:01 1993 "Jonathan I. Kamens" (jik@security.ov.com) * send-pr.sh: Deal with categories longer than 12 chars. Wed Nov 3 12:22:22 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-tools): Always install Cygnus category list. (install-categories): Always install categories as 'cygnus'. Tue Nov 2 21:43:12 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats:change-field): If not currently in a field, deal. (gnats::current-field): Ditto. (gnats::set-field): save-excursion. (gnats::set-mail-field): Ditto. Tue Nov 2 18:33:08 1993 Jeffrey Osier (jeffrey@thepub.cygnus.com) * Makefile.in (send-pr.info): depends on other .texi files * *.texi: more fixes to bring up to par Mon Nov 1 10:05:10 1993 Jeffrey Osier (jeffrey@thepub.cygnus.com) * gnats/*.texi, send-pr/*.texi, gnats/man/*.man: up to date Wed Oct 27 18:49:39 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (send-pr.info): Fix (send-pr.dvi): Fix Wed Oct 27 14:14:12 1993 Jeffrey Osier (jeffrey@cygnus.com) * .Makefile.in: reflect new doc strategy * send-pr.texi, s-usage.texi, fields.texi, categ.texi, states.texi: The New Doc Strategy. Some info is also included into the regular GNATS docs, so it's modular now. Tue Oct 26 16:20:08 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr:submit-pr): Use the right site * Makefile.in (install-gnats-dist): Lose the -o gnats bunk. Change $GNATS_ROOT/gnats-dist to $(datadir)/gnats/dist Wed Oct 20 18:09:20 1993 Jason Merrill (jason@deneb.cygnus.com) * configure.in (MAIL_AGENT): Also look in /usr/ucblib. * Makefile.in (uninstall): Don't use {}. Tue Oct 19 14:06:56 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (send-pr.el): Subst in SUBMITTER. (install-gnats-dist): Make it work. * send-pr.sh: On second thought, don't try to guess the FQDN at all. * send-pr.sh (HOSTNAME): Massage hosts where `hostname` does not produce the FQDN, but `hostname`.`domainname` does. * send-pr-el.in (send-pr:send-pr): On some Emacs 18ses, switch-to-buffer returns nil when it succeeds. Ignore it. Mon Oct 18 16:10:59 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Deal with echo -n / echo \c stuff, massage SunOS 4.1.3 sendmail. Fix $0/$COMMAND bug in awk script. * aclocal.m4: Create, with AC_FIND_PROGRAM and AC_ECHON. * Makefile.in (VPATH): Add def. (GNATS_ROOT, etc): Replace default values with @@ stuff. (CC, RANLIB): Give default (unused) values. (most targets): Change @@s to xxs. (send-pr): Subst in ECHON. (install-categories): Don't use -o. Thu Oct 14 22:12:27 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Don't use 'eval' when calling MAIL_AGENT, as it breaks Ultrix sh and wasn't useful anyway. Wed Oct 13 15:55:52 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh (GNATS_SITE): Move after config, subst in. * Makefile.in (MAIL_AGENT): Add definition. (SEND_PR_INSTALL): Dependencies of install. (send-pr): Subst in MAIL_AGENT. (install): Use SEND_PR_INSTALL. (install-norm): Don't install categories file. (install-categories): New target to install categories file. (install-gnats-dist): Look for send-pr.texi in the right place. (stamp-gnats): Deal with MAIL_AGENT and SEND_PR_INSTALL Tue Oct 12 15:50:00 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (setenv): Define for old emacses Tue Oct 12 14:36:28 1993 JT Conklin (conklin@talisman.kaleida.com) * send-pr.sh (COMMAND): Add missing quote. Fri Oct 1 15:06:01 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (VERSION): Bump to 3.01.5 Tue Sep 28 13:35:45 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-gnats-dist): Fix creation of send-pr-el.in * send-pr-el.in (send-pr::start-up): Clear cruft inserted by bdamaged .cshrc files * Makefile.in (send-pr.elc): New target (uninstall): Now does something * send-pr-el.in (gnats::functionp): Fix ref to free var Fri Sep 17 10:22:26 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) * Makefile.in (install-gnats): add missing backslash Fri Sep 10 17:03:22 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (Makefile): Make it work with stamp-gnats (DEFAULT_RELEASE): Make more general Thu Sep 9 17:58:50 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in: Add appropriate defaults for reporting bugs to Cygnus Remove problem quotes Depend on ../install.sh * send-pr-el.in: Fix various Emacs 18 problems Wed Sep 8 16:27:35 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-gnats): Remove directory creation stuff (install-gnats-dist): Ditto * send-pr-el.in (gnats:change-field): Allow the caller to specify a default value [used by update-responsible]. Tue Sep 7 14:12:35 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (install-gnats-dist): Unset submitter for gnats-dist * send-pr.sh: Made install-sid message more explicit Fri Sep 3 14:10:27 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Change $LIBDIR to $DATADIR * send-pr-el.in (various): Replace libdir with datadir (send-pr::start-up): Support mail-self-blind (gnats::mail-position-on-field): Create field if it's not there (gnats:previous-field): Check for keyword before point first (gnats::looking-after): Revert from (point-marker) to (point) * Makefile.in (stamp-gnats): Depend on Makefile (send-pr.texi): sed(1) in version number and usage info so that clients only get single texi file. (various): Change $(libdir) to $(datadir) (install): Default to install-gnats, since the rule checks for ../gnats (stamp-gnats): Replace install dependencies * send-pr.texi: Move to send-pr.texi.in, change version number to @VERSION@ Tue Aug 31 12:02:14 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr:submit-pr): Bury the right buffer. (send-pr::fields): Move all possible values and defaults into this monolithic table (send-pr::start-up): Replace all the querys with a mapcar over send-pr::fields (gnats::competing-read-and-replace): Lose (gnats::find-field): Lose (gnats::position-on-field): Create (gnats::mail-position-on-field): Create (gnats::field-contents): Create (gnats::functionp): Create (gnats::field-values): Create (gnats::field-default): Create (gnats::field-type): Create (gnats::field-action): Create (send-pr::maybe-change-field): Create (gnats:change-field): Create, bind to ^C^F (gnats::set-field): Create (gnats::set-mail-field): Create (gnats:beginning-of-field): Create (gnats::current-field): Create (gnats::after-keyword): Fix doc string (gnats::patch-exec-path): Don't use send-pr::err-buffer-name (gnats::get-value-from-shell): Ditto Fri Aug 27 08:34:58 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats::*-keyword): Add grouping * send-pr.sh: Accommodate shells that don't support functions. * send-pr-el.in (send-pr:submit-pr): Fix behavior on send Thu Aug 26 14:31:21 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr::set-sites): Use send-pr:libdir, not gnats:libdir. (send-pr::start-up): Put buffer in send-pr-mode. (send-pr:submit-pr): Make sure err-buffer exists before trying to use it. (send-pr:send-pr-mode): Allow whitespace after keyword in paragraph-separate * send-pr.sh (MAIL_AGENT): Use /usr/lib/sendmail rather than /bin/mail (ORIGINATOR): remove $TEMP when done (die): New function to massage buggy Sun sh (EXIT_STATUS): New variable to massage buggy Sun sh Don't parse To: and CC: headers any more Check for failure of MAIL_AGENT Tue Aug 24 16:57:13 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr:libdir): Use @'s, be const (send-pr::categories): Remove (send-pr:::categories): Add (buffer-local) (send-pr::category-alist): Add (send-pr:::site): Add (send-pr::set-categories): Support multiple sites (send-pr::sites): Don't update without arg (send-pr::pr-buffer): Add -name to end, fix refs to use buffer (send-pr::err-buffer): Ditto (send-pr:send-pr): Always use site name, only ask about erasing report if it's been modified. (send-pr::start-up): Check for errors from send-pr -P Don't kill random buffers Remove useless progn (gnats::completing-read-and-replace): Fix doc string (gnats::set-variable-from-shell): Change to get-var... Check for errors * send-pr.sh (GNATS_ROOT): Put definition on newline so configure can find it Ask user whether or not to send the PR even if it's valid Mon Aug 23 12:31:00 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats::releases): Use send-pr:default-release * send-pr.sh (LIBDIR): Try looking under GCC_EXEC_PREFIX for the gnats stuff if it's not in the right place Move up TMPDIR stuff so the ORIGINATOR stuff can use $TEMP Remove 'g' from COMMAND sed pattern Remove 'p' from options list * send-pr.input: Fix C-u M-x send-pr description Fri Aug 20 20:34:12 1993 Jason Merrill (jason@rtl.cygnus.com) * send-pr.sh: Add long options, add -h, remove -p and -r Thu Aug 19 14:59:24 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (gnats::push): Move from gnats-el.in * Makefile.in (send-pr.el): Subst in $(libdir) and $(GNATS_SITE) * send-pr-el.in (send-pr:default-site): Create (send-pr:send-pr): Ask for site name if arg (send-pr::start-up): Use site name if non-nil (send-pr::set-sites): Create list of known sites from listing of LIBDIR/gnats * send-pr.sh (ORIGINATOR): Remove ''s around ^$LOGNAME Redirect stderr from ypcat to /dev/null Use $TEMP as a temp file to avoid quoting problems * Makefile.in (send-pr): Subst in $(SUBMITTER) (stamp-gnats): Ditto * send-pr.sh (SUBMITTER): Get substed * send-pr-el.in (gnats::get-config): Trim newline from echo output rather than using non-portable -n switch (send-pr:submit-pr): Indicate when send-pr is done Wed Aug 18 15:14:22 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr-mode-map): Move setup into defvar Reorganize namespace (put some things under send-pr:, others under gnats:) (send-pr:start-up): Use mail-default-reply-to (send-pr:submit-pr): If in a Server buffer, do server-buffer-done rather than spawning another send-pr. (gnats::get-config): Add, use Juggle contents of send-pr.el and gnats.el to avoid duplication and name clashing (like with gnats-set-categories) (gnats::set-variable-from-shell): kill the buffer when done * send-pr.sh: Don't complain about $SUBMITTER if using -f Fix typos Tue Aug 17 19:31:27 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Don't loop if called from Emacs Mon Aug 16 14:59:29 1993 Jason Merrill (jason@deneb.cygnus.com) * Makefile.in (send-pr.el): Substitute in GNATS_ROOT * send-pr-el.in (send-pr-start-up): Set $GNATS_ROOT to GNATS-ROOT Add definition of GNATS-ROOT * send-pr.sh: Use GNATS_ROOT in the environment Fri Aug 13 12:00:16 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Fix grammar in send-pr template * install-sid.sh: Change grep -s to grep > /dev/null for greps that just don't shut up (i.e. POSIX) Tue Aug 10 13:25:35 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr-el.in (send-pr-mode): Change paragraph-separate and paragraph-start to include "^>[-A-Za-z]:" (PR 3166) Mon Aug 9 15:37:00 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Added >Fix: field (re PR 1310) If errors are found, allow user to edit PR again. Remove [ -z $FORCE ] since $FORCE appears nowhere else Add contents of CC: field to $GNATS_ADDR before sending (PR 2298) Wed Aug 4 20:33:50 1993 Jason Merrill (jason@deneb.cygnus.com) * send-pr.sh: Snarf configuration from GNATS_ROOT/gnats-adm/config if it exists. * install-sid.sh: Fixed startup so that calling with no arguments will print usage info and exit Added --version switch Thu Jul 22 17:00:14 1993 Jason Merrill (jason@wahini.cygnus.com) * Makefile.in (install-gnats-dist): now depends on `info' target, installs send-pr.info* rather than just send-pr.info Wed Jul 21 19:14:30 1993 Jason Merrill (jason@wahini.cygnus.com) * Makefile.in (install-gnats-dist): remove $(srcdir)/ before send-pr.info so other-dir installs work. Tue May 18 21:45:45 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) * Makefile.in: remove all traces of send_pr and install_cid Fri Apr 30 08:42:33 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (check, installcheck): New, empty, targets. Tue Apr 13 16:52:24 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (all-gnats): Add rule, same as install-norm; hack for now to make top-level builds work that don't pass GNATS=foo down because they don't need all of GNATS. Wed Apr 7 13:41:04 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh (ORGANIZATION): If they don't have an ORGANIZATION environment variable, then try for DEFAULT_ORGANIZATION, then $HOME/.organization, before going for their .signature. * Makefile.in (install-sid): Use `tmp-inst-sid' instead of `tmp-install-sid' to avoid filename length limits. (DEFAULT_ORGANIZATION): New variable. (send-pr): Substitute it. (stamp-gnats): Substitute DEFAULT_ORGANIZATION in. Tue Mar 30 16:00:01 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh (PRINT_INTERN): Add missing `$'. Mon Mar 29 16:46:22 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * install-sid.sh (traps): Add them in. Thu Mar 25 17:01:43 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh (ORIGINATOR): Look in the NIS maps if they've got them. In any case, strip off anything following a comma, since they might have phone nos or other info. Wed Mar 24 17:56:15 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) * Makefile.in: define MAKEINFO, define & use TEXI2DVI Fri Mar 19 17:44:01 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr-el.in (send-pr-start-up): Check that send-pr-mode worked (aka, running send-pr worked). (send-pr-mode): Make sure the category list was set. (gnats-set-variable-from-shell): Instead of using a temp buffer, refuse to continue if send-pr couldn't give us a valid categories list. This will change when the send-pr and gnats elisp stuff are rationalized properly. * send-pr.sh (editing the PR): Use EDIT, not EDITOR. (SUBMITTER unknown): Fix the message. Mon Mar 15 14:31:58 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh (FROM, REPLY_TO): Check for LOGNAME then USER. Sat Mar 6 15:26:37 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.elisp: Rename to send-pr-el.in. * Makefile.in: Do so throughout. * Makefile.in (clean): Also delete send-pr.elc. Thu Mar 4 11:35:29 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh (TMPDIR): Wrap with quotes in the test for it not being set. Thu Mar 4 09:58:31 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (install-info): New target. * Makefile.in (install): Ignore error from chown. Get categories file from $(srcdir). Wed Mar 3 07:43:07 1993 Ian Lance Taylor (ian@cygnus.com) * Makefile.in (send-pr.info): Added -I$(srcdir). Sat Feb 27 22:46:09 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install): Use $(GNATS). (install-norm): Most of the install rule. (install-gnats-dist): The rest of it. (install-tools): New rule, just run install-norm. (install-gnats): The default, run both install-norma nd install-gnats-dist. Wed Feb 24 17:19:57 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.in->send-pr.input: so it's not erased with make clean Tue Feb 23 15:40:14 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install): Change ownership of files installed to gnats. Tue Feb 23 15:30:01 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.texi: use send-pr.in * send-pr.in: New file (included by send-pr.texi and gnats.texi) Tue Feb 23 10:45:34 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install): Chown $(libdir)/gnats to gnats. Mon Feb 22 13:26:18 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install): Install send-pr.1. * Makefile.in (install): Drop in the things for gnats-dist. Mon Feb 22 01:45:16 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.man: semi-major cleanup effort.. now in beta Mon Feb 22 01:22:48 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * INSTALL: now in beta Sun Feb 21 23:25:49 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (install): Create the parent of lispdir first. Sun Feb 21 17:07:56 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.texi: more minor tweaking, added portability note * send-pr.man: ditto Sun Feb 21 16:11:08 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.texi: minor install cleanup * MANIFEST: New file. * INSTALL: New file. * README: Major revision. Sat Feb 20 23:47:02 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.texi: added new alias info Sat Feb 20 20:46:23 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * send-pr.sh: Set `From:' and `Reply-To:'. * Makefile.in (send-pr): Depend upon Makefile, to catch variable changes. (install-sid, send-pr.el, send-pr.1): Likewise. * install-sid.sh: Copy TMP into the send-pr script, so we don't break the link we made to send_pr. * send-pr.sh: Given an argument, send to the alias `foo-gnats'. * Makefile.in (clean): Also remove stamp-gnats. Sat Feb 20 19:15:00 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.texi: recent update, removed installation information and added a line regarding (autoload) for Emacs version * send-pr.info: same update Sat Feb 20 18:44:09 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Makefile.in (gnats-build): Changed to depend upon stamp-gnats. (stamp-gnats): New rule, with body of what was in gnats-build. Sat Feb 20 18:37:33 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) * send-pr.texi: added install information * send-pr.info: New file. Sat Feb 20 14:16:56 1993 Brendan Kehoe (brendan@lisa.cygnus.com) * Initial entry for GNATS 3.0. gnats-4.1.0/send-pr/INSTALL0000644000175000017500000000011707561211717015771 0ustar chewiechewie00000000000000See the GNATS manual, "Keeping Track", for detailed installation instructions. gnats-4.1.0/send-pr/Makefile.in0000644000175000017500000001232110207420663016776 0ustar chewiechewie00000000000000#!/usr/bin/make -f # @configure_input@ # # Makefile for GNU send-pr. # Copyright (C) 1993, 2001 Free Software Foundation, Inc. # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # Start of system configuration section. srcdir = @srcdir@ VPATH = @srcdir@ # The default release for this send-pr. DEFAULT_RELEASE = @DEFAULT_RELEASE@ # The default organization for this send-pr. DEFAULT_ORGANIZATION = @DEFAULT_ORGANIZATION@ # The submitter-id for your site. SUBMITTER = @SUBMITTER@ # Command line to display the passwd database PASSWD = @PASSWD@ # Is the mktemp command available? MKTEMP = @MKTEMP@ # What to install SEND_PR_INSTALL = install-norm SEND_PR_INSTALL_ARCH_DEP = install-norm-arch-dep CC = cc AR = ar AR_FLAGS = rc # Set RANLIB = echo if your system doesn't have or need ranlib. RANLIB = ranlib INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_PROGRAM@ CFLAGS = -g LDFLAGS = -g ECHON = @ECHON@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libexecdir = @libexecdir@ sysconfdir = @sysconfdir@ program_transform_name = datadir = @datadir@ lispdir = @lispdir@ mandir = @mandir@ man1dir = $(mandir)/man1 man2dir = $(mandir)/man2 man3dir = $(mandir)/man3 man4dir = $(mandir)/man4 man5dir = $(mandir)/man5 man6dir = $(mandir)/man6 man7dir = $(mandir)/man7 man8dir = $(mandir)/man8 man9dir = $(mandir)/man9 includedir = @includedir@ # End of system configuration section. VERSION = @PACKAGE_VERSION@ SHELL = /bin/sh #### System configurations, if any, are inserted here. DISTFILES= COPYING ChangeLog Makefile.in README configure.in \ install-sid.sh send-pr-el.in send-pr.man send-pr.texi fields.texi \ states.texi s-usage.texi categ.texi send-pr.sh send-pr.conf install-sid.man all: send-pr install-sid send-pr.1 install-sid.8 version.texi all-gnats: all all-tools: all install: $(SEND_PR_INSTALL) install-arch-dep: $(SEND_PR_INSTALL_ARCH_DEP) install-tools: install-norm install-tools-arch-dep: install-norm-arch-dep install-gnats: install-norm install-gnats-arch-dep: install-norm-arch-dep install-norm: install-norm-arch-indep install-norm-arch-dep install-norm-arch-indep: install-norm-arch-dep: all $(INSTALL_SCRIPT) send-pr $(DESTDIR)$(bindir)/send-pr $(INSTALL_SCRIPT) install-sid $(DESTDIR)$(bindir)/install-sid $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(man1dir)/ $(INSTALL_DATA) send-pr.1 $(DESTDIR)$(man1dir)/send-pr.1 $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(man8dir)/ $(INSTALL_DATA) install-sid.8 $(DESTDIR)$(man8dir)/install-sid.8 $(INSTALL_DATA) $(srcdir)/send-pr.conf $(DESTDIR)$(sysconfdir)/gnats/ uninstall: -rm -f $(DESTDIR)$(bindir)/send-pr $(DESTDIR)$(bindir)/install-sid -rm -f $(DESTDIR)$(sysconfdir)/gnats/send-pr.conf -rmdir $(DESTDIR)$(datadir)/gnats -rm -f $(DESTDIR)$(man1dir)/send-pr.1 -rm -f $(DESTDIR)$(man1dir)/install-sid.8 TAGS: info: dvi: version.texi: Makefile echo "@set VERSION $(VERSION)" > $@-t mv $@-t $@ send-pr.1: Makefile send-pr.man sed -e 's,xVERSIONx,$(VERSION),g' \ -e 's,xSYSCONFDIRx,$(sysconfdir),g' $(srcdir)/send-pr.man > $@-t mv $@-t $@ install-sid.8: Makefile install-sid.man sed -e 's,xVERSIONx,$(VERSION),g' \ -e 's,xSYSCONFDIRx,$(sysconfdir),g' $(srcdir)/install-sid.man > $@-t mv $@-t $@ # When building GNATS, this target is used to communicate information # known only to the GNATS configuration. gnats-build: stamp-gnats stamp-gnats: Makefile sed -e 's,^GNATS_USER =.*,GNATS_USER = $(GNATS_USER),' \ -e 's,^DEFAULT_RELEASE =.*,DEFAULT_RELEASE = $(DEFAULT_RELEASE),' \ -e 's%^DEFAULT_ORGANIZATION =.*%DEFAULT_ORGANIZATION = $(DEFAULT_ORGANIZATION)%' \ -e 's,^SUBMITTER =.*,SUBMITTER = $(SUBMITTER),' \ -e 's,^VERSION =.*,VERSION = $(VERSION),' \ -e 's,^MAIL_AGENT =.*,MAIL_AGENT = $(MAIL_AGENT),' \ -e 's,^SEND_PR_INSTALL =.*,SEND_PR_INSTALL = $(GNATS_INSTALL),' \ Makefile > Makefile.tmp \ && mv Makefile.tmp Makefile \ && : > $@ # Clean things up. clean: mostlyclean -rm -f send-pr install-sid send-pr.1 install-sid.8 stamp-gnats -rm -f *.dvi mostlyclean: -rm -f *.toc *.log *.vr *.fn *.cp *.tp *.ky *.pg *.cps *.aux distclean: clean -rm -f Makefile config.cache config.status config.log -rm -rf =* ./"#"* *~* -rm -f *.orig *.rej maintainer-clean realclean: distclean -rm -f version.texi -rm -f send-pr.??s # FIXME dist: echo need to do something for dist check: installcheck: # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: Makefile: $(srcdir)/Makefile.in $(SHELL) config.status; \ if [ -f ../gnats/Makefile ]; then cd ../gnats; $(MAKE) config-send-pr; fi gnats-4.1.0/send-pr/README0000644000175000017500000000364407561211717015630 0ustar chewiechewie00000000000000 send-pr - sends bug reports to a central support site `send-pr' is a tool for submitting support questions and software bug reports (Problem Reports, or PRs, as we call them). No piece of software is perfect, and software organizations understand this. `send-pr' is designed to allow users who have problems to submit reports of these problems to sites responsible for supporting the software in question, in a defined form which can be read by an electronically managed database. `send-pr' is part of a suite of programs known collectively as GNATS. GNATS consists of several programs which, used in concert, formulate and partially administer a database of Problem Reports, or PRs, at a central support site. A PR goes through several states in its lifetime; GNATS tracks the PR and all information associated with it through each state and finally acts as an archive for PRs which have been resolved. The same engine can be used to submit bugs to any number of support sites by setting up aliases for each of them; `send-pr' error-checks each PR as it is sent to be sure that the category specified matches a category supported by the site in question. `send-pr' invokes an editor on a problem report template (after trying to fill in some fields with reasonable default values). When you exit the editor, `send-pr' submits the completed form to the support site, either by speaking directly over the nwtwork to the support site GNATS server or by sending e-mail to the support site. At the support site, the PR is assigned a unique number and is stored in the GNATS database according to its category and customer-id. GNATS automatically replies with an acknowledgement, citing the category and the PR number. See the GNATS manual for detailed installation and usage information. Copyright (c) 1993, 2002, Free Software Foundation, Inc. See the file COPYING for copyright information concerning this distribution and all its components. gnats-4.1.0/send-pr/acinclude.m40000644000175000017500000000147007333062277017136 0ustar chewiechewie00000000000000define([AC_ECHON],dnl [echo checking for echo -n if test "`echo -n foo`" = foo ; then ECHON=bsd test -n "$verbose" && echo ' using echo -n' elif test "`echo 'foo\c'`" = foo ; then ECHON=sysv test -n "$verbose" && echo ' using echo ...\\c' else ECHON=none test -n "$verbose" && echo ' using plain echo' fi])dnl dnl define([AC_PASSWD],dnl [echo checking how to access passwd database PASSWD="cat /etc/passwd" if test -f /bin/domainname && test -n "`/bin/domainname`"; then if test -f /usr/bin/niscat && /usr/bin/niscat passwd.org_dir > /dev/null 2>&1; then PASSWD="/usr/bin/niscat passwd.org_dir" elif test -f /usr/bin/ypcat && /usr/bin/ypcat passwd > /dev/null 2>&1; then PASSWD="/usr/bin/ypcat passwd" fi fi test -n "$verbose" && echo " setting PASSWD to ${PASSWD}" AC_SUBST(PASSWD)dnl ])dnl gnats-4.1.0/send-pr/aclocal.m40000644000175000017500000010364510142012127016571 0ustar chewiechewie00000000000000dnl aclocal.m4t generated automatically by aclocal 1.4-p6 dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A dnl PARTICULAR PURPOSE. define([AC_ECHON],dnl [echo checking for echo -n if test "`echo -n foo`" = foo ; then ECHON=bsd test -n "$verbose" && echo ' using echo -n' elif test "`echo 'foo\c'`" = foo ; then ECHON=sysv test -n "$verbose" && echo ' using echo ...\\c' else ECHON=none test -n "$verbose" && echo ' using plain echo' fi])dnl dnl define([AC_PASSWD],dnl [echo checking how to access passwd database PASSWD="cat /etc/passwd" if test -f /bin/domainname && test -n "`/bin/domainname`"; then if test -f /usr/bin/niscat && /usr/bin/niscat passwd.org_dir > /dev/null 2>&1; then PASSWD="/usr/bin/niscat passwd.org_dir" elif test -f /usr/bin/ypcat && /usr/bin/ypcat passwd > /dev/null 2>&1; then PASSWD="/usr/bin/ypcat passwd" fi fi test -n "$verbose" && echo " setting PASSWD to ${PASSWD}" AC_SUBST(PASSWD)dnl ])dnl # lib-prefix.m4 serial 3 (gettext-0.13) dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/lib" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/lib"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/lib"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) # lib-link.m4 serial 4 (gettext-0.12) dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, dnl hardcode_direct, hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib$1-prefix], [ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib$1-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/lib" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then found_dir="$additional_libdir" found_so="$additional_libdir/lib$name.$shlibext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then found_dir="$dir" found_so="$dir/lib$name.$shlibext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */lib | */lib/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/lib"; then haveit= if test "X$additional_libdir" = "X/usr/local/lib"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) # lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) # serial 1 AC_DEFUN([AM_PATH_LISPDIR], [# If set to t, that means we are running in a shell under Emacs. # If you have an Emacs named "t", then use the full path. test "$EMACS" = t && EMACS= AC_PATH_PROGS(EMACS, emacs xemacs, no) if test $EMACS != "no"; then AC_MSG_CHECKING([where .elc files should go]) dnl Set default value lispdir="\$(datadir)/emacs/site-lisp" emacs_flavor=`echo "$EMACS" | sed -e 's,^.*/,,'` if test "x$prefix" = "xNONE"; then if test -d $ac_default_prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $ac_default_prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi else if test -d $prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi fi AC_MSG_RESULT($lispdir) fi AC_SUBST(lispdir)]) gnats-4.1.0/send-pr/configure0000744000175000017500000022636510147021631016650 0ustar chewiechewie00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for send-pr 4.1.0. # # Report bugs to . # # Copyright (C) 2003 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 Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='send-pr' PACKAGE_TARNAME='send-pr' PACKAGE_VERSION='4.1.0' PACKAGE_STRING='send-pr 4.1.0' PACKAGE_BUGREPORT='bug-gnats@gnu.org' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA DEFAULT_RELEASE DEFAULT_ORGANIZATION DEFAULT_MAIL_AGENT SUBMITTER ECHON EMACS lispdir PASSWD MKTEMP SENDMAIL LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # 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. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= 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 ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -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 | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$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 ;; -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 ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) 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 ;; -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=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 ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && 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'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac 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 echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 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 # 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 its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | 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 if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias # # 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 send-pr 4.1.0 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 \`..'] _ACEOF cat <<_ACEOF 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] --datadir=DIR read-only architecture-independent data [PREFIX/share] --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] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of send-pr 4.1.0:";; esac cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-organization=name Sets the default organization to NAME --with-submitter=name Sets the default submitter to NAME Report bugs to . _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style 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 elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd "$ac_popdir" done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF send-pr configure 4.1.0 generated by GNU Autoconf 2.59 Copyright (C) 2003 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 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by send-pr $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { 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` hostinfo = `(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=. echo "PATH: $as_dir" done } >&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_sep= 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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$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 ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >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 # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" 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. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 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 `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 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 { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`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. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } 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 # Check whether --with-organization or --without-organization was given. if test "${with_organization+set}" = set; then withval="$with_organization" fi; # Check whether --with-submitter or --without-submitter was given. if test "${with_submitter+set}" = set; then withval="$with_submitter" fi; 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 { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # 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. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&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_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 ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done 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. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$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' # If set to t, that means we are running in a shell under Emacs. # If you have an Emacs named "t", then use the full path. test "$EMACS" = t && EMACS= for ac_prog in emacs xemacs do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_EMACS+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $EMACS in [\\/]* | ?:[\\/]*) ac_cv_path_EMACS="$EMACS" # Let the user override the test with a path. ;; *) 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_EMACS="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi EMACS=$ac_cv_path_EMACS if test -n "$EMACS"; then echo "$as_me:$LINENO: result: $EMACS" >&5 echo "${ECHO_T}$EMACS" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$EMACS" && break done test -n "$EMACS" || EMACS="no" if test $EMACS != "no"; then echo "$as_me:$LINENO: checking where .elc files should go" >&5 echo $ECHO_N "checking where .elc files should go... $ECHO_C" >&6 lispdir="\$(datadir)/emacs/site-lisp" emacs_flavor=`echo "$EMACS" | sed -e 's,^.*/,,'` if test "x$prefix" = "xNONE"; then if test -d $ac_default_prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $ac_default_prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi else if test -d $prefix/share/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/share/$emacs_flavor/site-lisp" else if test -d $prefix/lib/$emacs_flavor/site-lisp; then lispdir="\$(prefix)/lib/$emacs_flavor/site-lisp" fi fi fi echo "$as_me:$LINENO: result: $lispdir" >&5 echo "${ECHO_T}$lispdir" >&6 fi echo checking for echo -n if test "`echo -n foo`" = foo ; then ECHON=bsd test -n "$verbose" && echo ' using echo -n' elif test "`echo 'foo\c'`" = foo ; then ECHON=sysv test -n "$verbose" && echo ' using echo ...\\c' else ECHON=none test -n "$verbose" && echo ' using plain echo' fi echo checking how to access passwd database PASSWD="cat /etc/passwd" if test -f /bin/domainname && test -n "`/bin/domainname`"; then if test -f /usr/bin/niscat && /usr/bin/niscat passwd.org_dir > /dev/null 2>&1; then PASSWD="/usr/bin/niscat passwd.org_dir" elif test -f /usr/bin/ypcat && /usr/bin/ypcat passwd > /dev/null 2>&1; then PASSWD="/usr/bin/ypcat passwd" fi fi test -n "$verbose" && echo " setting PASSWD to ${PASSWD}" # Extract the first word of "mktemp", so it can be a program name with args. set dummy mktemp; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_MKTEMP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$MKTEMP"; then ac_cv_prog_MKTEMP="$MKTEMP" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MKTEMP="yes" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_MKTEMP" && ac_cv_prog_MKTEMP="no" fi fi MKTEMP=$ac_cv_prog_MKTEMP if test -n "$MKTEMP"; then echo "$as_me:$LINENO: result: $MKTEMP" >&5 echo "${ECHO_T}$MKTEMP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi SUBMITTER=unknown DEFAULT_ORGANIZATION=unknown echo "$as_me:$LINENO: checking for --with-submitter" >&5 echo $ECHO_N "checking for --with-submitter... $ECHO_C" >&6 if test -n "$with_submitter" ; then echo "$as_me:$LINENO: result: $with_submitter" >&5 echo "${ECHO_T}$with_submitter" >&6 SUBMITTER="$with_submitter" else echo "$as_me:$LINENO: result: default to unknown" >&5 echo "${ECHO_T}default to unknown" >&6 fi echo "$as_me:$LINENO: checking for --with-organization" >&5 echo $ECHO_N "checking for --with-organization... $ECHO_C" >&6 if test -n "$with_organization" ; then echo "$as_me:$LINENO: result: $with_organization" >&5 echo "${ECHO_T}$with_organization" >&6 DEFAULT_ORGANIZATION="$with_organization" else echo "$as_me:$LINENO: result: default to unknown" >&5 echo "${ECHO_T}default to unknown" >&6 fi if test -f ${srcdir}/../release-info ; then DEFAULT_RELEASE=`. ${srcdir}/../release-info ; echo ${RELEASE_TAG}` else DEFAULT_RELEASE="gnats-${PACKAGE_VERSION}" fi DEFAULT_MAIL_AGENT=false # Extract the first word of "sendmail", so it can be a program name with args. set dummy sendmail; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_SENDMAIL+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $SENDMAIL in [\\/]* | ?:[\\/]*) ac_cv_path_SENDMAIL="$SENDMAIL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:/usr/lib:/usr/sbin:/usr/ucblib" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SENDMAIL="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi SENDMAIL=$ac_cv_path_SENDMAIL if test -n "$SENDMAIL"; then echo "$as_me:$LINENO: result: $SENDMAIL" >&5 echo "${ECHO_T}$SENDMAIL" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -n "$SENDMAIL" ; then DEFAULT_MAIL_AGENT="$SENDMAIL -oi -t" else echo "configure: error: sendmail binary not available" exit 1 fi if test "x$prefix" != xNONE; then GNATS_PREFIX=$prefix else GNATS_PREFIX=$ac_default_prefix fi # If the config file exists, it may have more recent info than send-pr if test -n "$verbose"; then echo " setting SUBMITTER to $SUBMITTER" echo " setting DEFAULT_RELEASE to $DEFAULT_RELEASE" echo " setting DEFAULT_ORGANIZATION to $DEFAULT_ORGANIZATION" echo " setting DEFAULT_MAIL_AGENT to $DEFAULT_MAIL_AGENT" fi ac_config_files="$ac_config_files Makefile:Makefile.in install-sid:install-sid.sh send-pr:send-pr.sh" 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, don't put newlines in cache variables' values. # 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. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *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 \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" 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}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ 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[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $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} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; 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 # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # 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 # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. 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 ;; 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 { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # 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 sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # 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'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by send-pr $as_me 4.1.0, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet 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 Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ send-pr config.status 4.1.0 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. 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=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; 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 if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile:Makefile.in" ;; "install-sid" ) CONFIG_FILES="$CONFIG_FILES install-sid:install-sid.sh" ;; "send-pr" ) CONFIG_FILES="$CONFIG_FILES send-pr:send-pr.sh" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; 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 fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@DEFAULT_RELEASE@,$DEFAULT_RELEASE,;t t s,@DEFAULT_ORGANIZATION@,$DEFAULT_ORGANIZATION,;t t s,@DEFAULT_MAIL_AGENT@,$DEFAULT_MAIL_AGENT,;t t s,@SUBMITTER@,$SUBMITTER,;t t s,@ECHON@,$ECHON,;t t s,@EMACS@,$EMACS,;t t s,@lispdir@,$lispdir,;t t s,@PASSWD@,$PASSWD,;t t s,@MKTEMP@,$MKTEMP,;t t s,@SENDMAIL@,$SENDMAIL,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac # 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. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;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,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # 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 || { (exit 1); exit 1; } fi gnats-4.1.0/send-pr/configure.in0000644000175000017500000000347010147021631017242 0ustar chewiechewie00000000000000AC_PREREQ(2.5) AC_INIT(send-pr,4.1.0,bug-gnats@gnu.org) AC_ARG_WITH(organization, [ --with-organization=name Sets the default organization to NAME]) AC_ARG_WITH(submitter, [ --with-submitter=name Sets the default submitter to NAME]) AC_PROG_INSTALL AC_SUBST(DEFAULT_RELEASE)dnl AC_SUBST(DEFAULT_ORGANIZATION)dnl AC_SUBST(DEFAULT_MAIL_AGENT)dnl AC_SUBST(SUBMITTER)dnl AC_SUBST(ECHON)dnl AM_PATH_LISPDIR AC_ECHON AC_PASSWD AC_CHECK_PROG(MKTEMP, mktemp, yes, no) SUBMITTER=unknown DEFAULT_ORGANIZATION=unknown AC_MSG_CHECKING(for --with-submitter) if test -n "$with_submitter" ; then AC_MSG_RESULT($with_submitter) SUBMITTER="$with_submitter" else AC_MSG_RESULT(default to unknown) fi AC_MSG_CHECKING(for --with-organization) if test -n "$with_organization" ; then AC_MSG_RESULT($with_organization) DEFAULT_ORGANIZATION="$with_organization" else AC_MSG_RESULT(default to unknown) fi if test -f ${srcdir}/../release-info ; then DEFAULT_RELEASE=`. ${srcdir}/../release-info ; echo ${RELEASE_TAG}` else DEFAULT_RELEASE="gnats-${PACKAGE_VERSION}" fi DEFAULT_MAIL_AGENT=false AC_PATH_PROG(SENDMAIL,sendmail,[],$PATH:/usr/lib:/usr/sbin:/usr/ucblib) if test -n "$SENDMAIL" ; then DEFAULT_MAIL_AGENT="$SENDMAIL -oi -t" else echo "configure: error: sendmail binary not available" exit 1 fi if test "x$prefix" != xNONE; then GNATS_PREFIX=$prefix else GNATS_PREFIX=$ac_default_prefix fi # If the config file exists, it may have more recent info than send-pr if test -n "$verbose"; then echo " setting SUBMITTER to $SUBMITTER" echo " setting DEFAULT_RELEASE to $DEFAULT_RELEASE" echo " setting DEFAULT_ORGANIZATION to $DEFAULT_ORGANIZATION" echo " setting DEFAULT_MAIL_AGENT to $DEFAULT_MAIL_AGENT" fi AC_CONFIG_FILES([Makefile:Makefile.in] [install-sid:install-sid.sh] [send-pr:send-pr.sh]) AC_OUTPUT gnats-4.1.0/send-pr/install-sid.man0000644000175000017500000000614610142016660017655 0ustar chewiechewie00000000000000.\" -*- nroff -*- .\" --------------------------------------------------------------------------- .\" man page for install-sid (by Chad Walstrom, chewie@wookimus.net) .\" .\" This file is part of GNU GNATS .\" Copyright 1992 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 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 Library General Public .\" License along with this program; if not, write to the Free .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA .\" .\" --------------------------------------------------------------------------- .nh .TH INSTALL-SID 8 xVERSIONx "November 2004" .SH NAME install-sid \- update SUBMITTER variable in site or personal config files. .SH SYNOPSIS .B install-sid .RS [\ \fB\-\-site\-config\ \fR\ ] .br [\ \fB\-\-help\fR\ |\ \fB\-h\fR\ ] [\ \fB\-\-version\fR\ |\ \fB\-V\fR\ ] .br .B SUBMITTER .ad b .hy 1 .SH DESCRIPTION \fBinstall-sid\fR replaces the SUBMITTER variable assignment in the \fBxSYSCONFDIRx/gnats/send-pr.conf\fR or \fB$HOME/.send-pr.conf\fR files with the SUBMITTER specified on the commandline. This variable is necessary to ensure that a PR is handled promptly. .LP If you do not have a unique submitter-id, execute the command: .TP .B send-pr --request-id .LP .SH OPTIONS .TP \fB\-\-site\-config Edit the site configuration file rather than the personal configuration file. .TP \fB\-\-version\fR,\ \fB\-V\fR Displays the version number of the program. .TP \fB\-\-help\fR,\ \fB\-h\fR Prints a brief usage message. .SH FILES xSYSCONFDIRx/gnats/send-pr.conf The \fBsend-pr\fR configuration file .br $HOME/.send-pr.conf User-specific \fBsend-pr\fR configuration file .br .ta \w'/tmp/pbad$$ 'u /tmp/p$$ copy of send-pr.conf used in editing session .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR send-pr (1). .SH AUTHORS Chad Walstrom. .SH COPYING Copyright (c) 2004 Free Software Foundation, Inc. .PP This manual 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. .PP This manual 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. .PP You should have received a copy of the GNU General Public License along with this manual; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA gnats-4.1.0/send-pr/install-sid.sh0000744000175000017500000000632510145307721017520 0ustar chewiechewie00000000000000#!/bin/sh # @configure_input@ # # Update the SUBMITTER variable in the site or personal send-pr config file # Copyright (C) 1993,2004 Free Software Foundation, Inc. # Contributed by Brendan Kehoe (brendan@cygnus.com), based on a # version written by Heinz G. Seidl (hgs@ide.com). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. VERSION="@PACKAGE_VERSION@" prefix="@prefix@" sysconfdir="@sysconfdir@" COMMAND=`echo $0 | sed -e 's,.*/,,g'` function usage() { cat << __EOF__ >&2 Usage: $COMMAND [OPTIONS] submitter-id OPTION DESCRIPTION --help This message --version Print version and exit --site-config Update the site configuration file $COMMAND updates the SUBMITTER variable with 'submitter-id' in the site or personal send-pr config file. You may need to have root permissions in order to update the site configuration file. This application requires the sed script to work. __EOF__ } # Is the mktemp command available? MKTEMP="@MKTEMP@" # TEMP: Temporary copy of the config file, to be edited by the user. if [ -z "$TMPDIR" ]; then TMPDIR=/tmp else if [ "`echo $TMPDIR | grep '/$'`" != "" ]; then TMPDIR="`echo $TMPDIR | sed -e 's,/$,,'`" fi fi if [ $MKTEMP = yes ]; then TEMP=`mktemp $TMPDIR/pXXXXXX` || exit 1 else TEMP=$TMPDIR/p$$ : > $TEMP || exit 1 fi if [ $# -eq 0 ]; then usage exit 1 fi # Default configuration file CONFIGFILE="$HOME/.send-pr.conf" # Leave this blank SUBMITTER= # Process the commandline while [ $# -gt 0 ]; do case "$1" in --site-config) CONFIGFILE="${sysconfdir}/gnats/send-pr.conf" ;; --version) echo $COMMAND version $VERSION ; exit 1 ;; -*) usage; exit 1 ;; *) SUBMITTER=$1 ;; esac shift done trap 'rm -f $TEMP ; exit 0' 0 trap 'echo "$COMMAND: Aborting ..."; rm -f $TEMP ; exit 1' 1 2 3 13 15 if [ `echo ${SUBMITTER}| \ sed -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` = "unknown" ] ; then echo "$COMMAND: SUBMITTER cannot be 'unknown'" >&2 exit 1 fi if [ ! -e $CONFIGFILE ] ; then echo "$COMMAND: No configuration file was found. Creating." >&2 cat << __EOF__ > $CONFIGFILE # Configuration file for send-pr # ** CREATED BY $COMMAND ** SUBMITTER="$SUBMITTER" __EOF__ if [ $? -ne 0 ] ; then echo "$COMMAND: Error in creating $CONFIGFILE" >&2 exit 1 fi else sed -e "s/^#\?SUBMITTER=.*/SUBMITTER=${SUBMITTER}/" $CONFIGFILE > $TEMP if ! ( grep $SUBMITTER $TEMP > /dev/null ) ; then exit 1 fi if ! ( cat $TEMP > $CONFIGFILE ) ; then echo "$COMMAND: Error in updating $CONFIGFILE" >&2 exit 1 fi fi echo "$COMMAND: \`$SUBMITTER' has been updated in $CONFIGFILE for send-pr" >&2 exit 0 gnats-4.1.0/send-pr/send-pr.conf0000644000175000017500000000430310142011735017143 0ustar chewiechewie00000000000000# -*-sh-*- # send-pr.conf -- override default values for send-pr # Copyright (C) 2004 Free Software Foundation, Inc. # # This file is part of GNU GNATS. # # 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., 59 Temple # Place, Suite 330, Boston, MA 02111-1307 USA # # This file is used to override the default values as they are found in the # send-pr shell script. You may place this file at # xSYSCONFDIRx/gnats/send-pr.conf or $HOME/.send-pr.conf. # ################################################################################ # Id of the submitting organization #DEFAULT_ORGANIZATION=fill_some_value_here # The site *receiving* the bug reports #GNATS_SITE=fill_some_value_here # The submitter-id for your site. #SUBMITTER=fill_some_value_here # By default send-pr connects directly to the database. However, it can be # configured to use an existing template file by setting the TEMPLATE variable # below to point to a PR template generated from "send-pr -P". #TEMPLATE="" # send-pr can use mail to submit PRs, instead of connecting to the database # directly. MAILPROG needs to point to a compatible mailer (sendmail will # work). If MAILPROG needs to have the address that the mail is being sent to # specified on the command line, it should be specified here as well (for # example, the command MAILPROG="mail bugs@foo.bar.com" should work). If # sendmail is used, this should be set to MAILPROG="/usr/lib/sendmail -oi -t" #MAILPROG="" # The address that PRs are sent to. Normally this can be left as "bugs"; # however, if using mail to submit PRs, this should be set to the address where # PRs should be sent. #MAILADDR="bugs" gnats-4.1.0/send-pr/send-pr.man0000644000175000017500000001631410142011743016775 0ustar chewiechewie00000000000000.\" -*- nroff -*- .\" --------------------------------------------------------------------------- .\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com) .\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com .\" .\" This file is part of the Problem Report Management System (GNATS) .\" Copyright 1992 Cygnus Support .\" .\" 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 Library General Public .\" License along with this program; if not, write to the Free .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA .\" .\" --------------------------------------------------------------------------- .nh .TH SEND-PR 1 xVERSIONx "November 2002" .SH NAME send-pr \- submit a GNATS Problem Report (PR) to a support site .SH SYNOPSIS .B send-pr .RS [\ \fB\-\-batch\ \fR|\fB\ \-b\fR\ ] .br [\ \fB\-\-database\fR\=\fIdatabase\fR\ |\ \fB\-d\fR\ \fIdatabase\fR\ ] .br [\ \fB\-\-file\fR\=\fIfile\fR\ |\ \fB\-f\fR\ \fIfile\fR\ ] .br [\ \fB\-\-print\fR\ |\ \fB\-p\fR\ ] .br [\ \fB\-\-request-id\fR\ ] .br [\ \fB\-\-severity\fR\=\fIseverity\fR\ |\ \fB\-s\fR\ \fIseverity\fR\ ] .br [\ \fB\-\-help\fR\ |\ \fB\-h\fR\ ] [\ \fB\-\-version\fR\ |\ \fB\-V\fR\ ] .ad b .hy 1 .SH DESCRIPTION \fBsend-pr\fR invokes an editor on a problem report template (after trying to fill in some fields with reasonable default values). When you exit the editor, \fBsend-pr\fR submits the completed form to the GNATS system at a central support site, either directly over the network to the GNATS server or by e-mail. At the support site, the PR is assigned a unique number and is stored in the GNATS database according to its category and submitter-id. GNATS automatically replies with an acknowledgement, citing the category and the PR number. .LP To ensure that a PR is handled promptly, it should contain your (unique) \fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the problem area. .LP The more precise your problem description and the more complete your information, the faster your support team can solve your problems. .LP Note: use \fBsend-pr\fR to submit problem reports rather than mailing them directly. Using both the template and \fBsend-pr\fR itself will help ensure that all necessary information will reach the support site. .SH OPTIONS .TP \fB\-b\fR,\ \fB\-\-batch Suppresses printing of most of the messages that \fBsend-pr\fR usually prints while running. .TP \fB\-d \fIdatabase\fR,\ \fB\-\-database=\fIdatabase\fR Specifies the database to which the PR is to be submitted; if no database is specified, the local database named \fBdefault\fR is assumed. This option overrides the database specified in the \fBGNATSDB\fR environment variable. .TP \fB\-f\ \fIfile\fR,\ \fB\-\-file=\fIfile\fR Specifies a file where a completed Problem Report or a PR template exists. \fBsend-pr\fR verifies that the contents of the file constitute a valid PR and asks the user whether the PR should be submitted directly or edited first. If the PR text is invalid, the user will be notified and given the option to edit it. If \fIfile\fR is set to `-', \fBsend-pr\fR reads from standard input. .TP \fB\-p\fR,\ \fB\-\-print Displays the PR template for the specified \fBdatabase\fR, or if the \fB-d\fR or \fB--database\fR options are not specified, print the template for the local database \fBdefault\fR. No PR is submitted when this option is used. .TP \fB\-\-request-id\fR Sends a request for a Submitter Id to the support site. .TP \fB\-s\ \fIseverity\fR,\ \fB\-\-severity=\fIseverity\fR Sets the initial value of the \fBSeverity\fR field to \fIseverity\fR. .TP \fB\-\-version\fR,\ \fB\-V\fR Displays the version number of the program. .TP \fB\-\-help\fR,\ \fB\-h\fR Prints a brief usage message. .SH ENVIRONMENT The environment variable .B EDITOR specifies the editor to invoke on the template. .br default: .B vi .SH "HOW TO FILL OUT A PROBLEM REPORT" Problem reports have to be in a particular form so that a program can easily manage them. Please remember the following guidelines: .IP \(bu 3m describe only .B one problem with each problem report. .IP \(bu 3m For follow-up mail, use the same subject line as the one in the automatic acknowledgent. It consists of category, PR number and the original synopsis line. This allows the support site to relate several mail messages to a particular PR and to record them automatically. .IP \(bu 3m Please try to be as accurate as possible in the subject and/or synopsis line. .IP \(bu 3m The subject and the synopsis line are not confidential. This is because open-bugs lists are compiled from them. Avoid confidential information there. .LP See the GNU .B Info file .B gnats.info or the document \fIKeeping Track: Managing Messages With GNATS\fR\ for detailed information on reporting problems. .SH FILES xSYSCONFDIRx/gnats/send-pr.conf The \fBsend-pr\fR configuration file .br $HOME/.send-pr.conf User-specific \fBsend-pr\fR configuration file .br .ta \w'/tmp/pbad$$ 'u /tmp/p$$ copy of PR used in editing session .br /tmp/pf$$ copy of empty PR form, for testing purposes .br /tmp/pbad$$ file for rejected PRs .SH EMACS USER INTERFACE An Emacs user interface for .B send-pr with completion of field values is part of the .B send-pr distribution (invoked with .BR "M-x send-pr" ). See the file .B gnats.info in the doc subdirectory of the distribution for configuration, installation and usage information, or see .I Keeping Track: Managing Messages With GNATS .SH INSTALLATION AND CONFIGURATION See .B gnats.info or .B INSTALL for installation instructions. .SH "SEE ALSO" .I Keeping Track: Managing Messages With GNATS (also installed as the GNU Info file .BR gnats.info ) .LP .BR databases (5), .BR dbconfig (5), .BR delete-pr (8), .BR edit-pr (1) .BR file-pr (8), .BR gen-index (8), .BR gnats (7), .BR gnatsd (8), .BR mkcat (8), .BR mkdb (8), .BR pr-edit (8), .BR query-pr (1), .BR queue-pr (8), .BR send-pr (1). .SH AUTHORS Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus Support), Yngve Svendsen. .SH COPYING Copyright (c) 1992, 1993, 2002, Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English. gnats-4.1.0/send-pr/send-pr.sh0000744000175000017500000003735510145307726016661 0ustar chewiechewie00000000000000#!/bin/sh # @configure_input@ # # Submit a problem report to a GNATS site. # Copyright (C) 2001, 2002 Milan Zamazal # Copyright (C) 1993, 2001 Free Software Foundation, Inc. # Contributed by Brendan Kehoe (brendan@cygnus.com), based on a # version written by Heinz G. Seidl (hgs@cygnus.com). # Further edited by Milan Zamazal (pdm@zamazal.org). # mktemp support by Yngve Svendsen (yngve.svendsen@clustra.com). # # This file is part of GNU GNATS. # # GNU GNATS 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. # # GNU GNATS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU GNATS; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ################################################################################ # Default values -- You may override these in your configuration file ################################################################################ # The version of this send-pr. VERSION="@PACKAGE_VERSION@" # The submitter-id for your site. SUBMITTER="@SUBMITTER@" # The place where our usual binaries live. prefix="@prefix@" exec_prefix="@exec_prefix@" bindir="@bindir@" sbindir="@bindir@" sysconfdir="@sysconfdir@" libexecdir="@libexecdir@/gnats" # The default release for this host. DEFAULT_RELEASE="@DEFAULT_RELEASE@" # The default organization. DEFAULT_ORGANIZATION="@DEFAULT_ORGANIZATION@" # How to read the passwd database. PASSWD="@PASSWD@" # Is the mktemp command available? MKTEMP="@MKTEMP@" ECHON=@ECHON@ # By default send-pr connects directly to the database. However, it # can be configured to use an existing template file by setting the # TEMPLATE variable below to point to a PR template generated from # "send-pr -P". TEMPLATE="" # send-pr can use mail to submit PRs, instead of connecting to the # database directly. MAILPROG needs to point to a compatible mailer # (sendmail will work). If MAILPROG needs to have the address that # the mail is being sent to specified on the command line, it should # be specified here as well (for example, the command # MAILPROG="mail bugs@foo.bar.com" # should work). If sendmail is used, this should be set to # MAILPROG="@DEFAULT_MAIL_AGENT@" MAILPROG="" # The address that PRs are sent to. Normally this can be left as "bugs"; # however, if using mail to submit PRs, this should be set to the address # where PRs should be sent. MAILADDR="bugs" # Configuration file to be read. It must be a shell script that can redefine # the variables above to fit a local configuration. It reads the system config # file first, then the personal config file. CONFIGFILES="@sysconfdir@/gnats/send-pr.conf ${HOME}/.send-pr.conf" for CONFIGFILE in ${CONFIGFILES}; do if [ -r ${CONFIGFILE} ]; then . ${CONFIGFILE} fi done # if [ -z "$TMPDIR" ]; then TMPDIR=/tmp else if [ "`echo $TMPDIR | grep '/$'`" != "" ]; then TMPDIR="`echo $TMPDIR | sed -e 's,/$,,'`" fi fi # TEMP: Temporary copy of the PR, to be edited by the user. # BAD: The PR will end up here if the user aborts. # REF: The 'reference' copy of the PR template, used to verify that the user # actually did edit the template. # FIXFIL: A sed script used to remove comments from the template before # processing. if [ $MKTEMP = yes ]; then TEMP=`mktemp $TMPDIR/pXXXXXX` || exit 1 BAD=`mktemp $TMPDIR/pbadXXXXXX` || exit 1 REF=`mktemp $TMPDIR/pfXXXXXX` || exit 1 FIXFIL=`mktemp $TMPDIR/fixXXXXXX` || exit 1 else TEMP=$TMPDIR/p$$ BAD=$TMPDIR/pbad$$ REF=$TMPDIR/pf$$ FIXFIL=$TMPDIR/fix$$ bad_temp=0 : > $TEMP || bad_temp=1 : > $BAD || bad_temp=1 : > $REF || bad_temp=1 : > $FIXFIL || bad_temp=1 if [ $bad_temp = 1 ]; then rm -f $TEMP $BAD $REF $FIXFIL exit 1; fi fi REMOVE_TEMP="rm -f $TEMP $BAD $REF" # find a user name if [ "$LOGNAME" = "" ]; then if [ "$USER" != "" ]; then LOGNAME="$USER" else LOGNAME="UNKNOWN" fi fi FROM="$LOGNAME" REPLYTO="${REPLY_TO:-${REPLYTO:-$LOGNAME}}" if [ "x$MAILPROG" != "x" ] then RESP_ALIAS="`query-pr --adm-field responsible --adm-key $LOGNAME --adm-subfield alias 2>/dev/null`" else RESP_ALIAS="" fi # Find out the name of the originator of this PR. if [ -n "$NAME" ]; then DEFAULT_ORIGINATOR="$NAME" elif [ -f $HOME/.fullname ]; then DEFAULT_ORIGINATOR="`sed -e '1q' $HOME/.fullname`" else # Must use temp file due to incompatibilities in quoting behavior # and to protect shell metacharacters in the expansion of $LOGNAME $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP if [ "x$RESP_ALIAS" != "x" ] then DEFAULT_ORIGINATOR="$RESP_ALIAS (`cat $TEMP`)" else DEFAULT_ORIGINATOR="$FROM (`cat $TEMP`)" fi rm -f $TEMP fi if [ -z "$ORGANIZATION" ] then ORGANIZATION="$DEFAULT_ORGANIZATION"; fi if [ -n "$ORGANIZATION" -a "x$ORGANIZATION" != "@DEFAULT_ORGANIZATION@" ]; then if [ `echo $ORGANIZATION | fgrep -c /` -gt 0 -a -f "$ORGANIZATION" ]; then ORGANIZATION="`cat $ORGANIZATION`" fi elif [ -f $HOME/.organization ]; then ORGANIZATION="`cat $HOME/.organization`" fi if [ "x$ORGANIZATION" = "@DEFAULT_ORGANIZATION@" ]; then cat <<__EOF__ It seems that send-pr is not installed with your organization set to a useful value. To fix this, you need to edit the configuration file $CONFIGFILE and fill in the organization with the correct value. __EOF__ ORGANIZATION=""; else DEFAULT_ORGANIZATION="$ORGANIZATION" fi 1>&2 # If they don't have a preferred editor set, then use if [ -z "$VISUAL" ]; then if [ -z "$EDITOR" ]; then EDIT=vi else EDIT="$EDITOR" fi else EDIT="$VISUAL" fi # Find out some information. SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \ ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""` # Our base command name. COMMAND=`echo $0 | sed -e 's,.*/,,'` USAGE="Usage: $COMMAND [OPTION]... -b --batch run without printing most messages -d --database DATABASE submit PR to DATABASE -f --file FILE read the PR template from FILE (\`-' for stdin) -p --print just print the template and exit --request-id send a request for a user id -s --severity SEVERITY PR severity -h --help display this help and exit -V --version output version information and exit " REMOVE= BATCH= DEFAULT_SEVERITY= if [ "$SYSTEM" != "" ] then DEFAULT_ENVIRONMENT="System: $SYSTEM " fi while [ $# -gt 0 ]; do case "$1" in -r) ;; # Ignore for backward compat. -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi shift ; IN_FILE="$1" if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then echo "$COMMAND: cannot read $IN_FILE" exit 1 fi ;; -b | --batch) BATCH=true ;; -d | --database) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi shift; GNATSDB="$1"; export GNATSDB ;; -s | --severity) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi shift ; DEFAULT_SEVERITY="$1" ;; -p | -P | --print) PRINT=true ;; --request-id) REQUEST_ID=true ;; -h | --help) echo "$USAGE"; exit 0 ;; -V | --version) echo "$VERSION"; exit 0 ;; -*) echo "$USAGE" ; exit 1 ;; *) echo "$USAGE" ; exit 1 ;; esac shift done if [ "x$SUBMITTER" = "x" ] then SUBMITTER="unknown" fi if [ "x$SUBMITTER" = "xunknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then cat << '__EOF__' It seems that send-pr is not installed with your unique submitter-id, or that "unknown" has been specified. You need to run: install-sid YOUR-SID where YOUR-SID is the identification code you received with `send-pr'. `send-pr' will automatically insert this value into the template field `>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net' for this value. If you do not know your id, run `send-pr --request-id' to get one from your support site. __EOF__ exit 1 fi # So the template generation code finds it. DEFAULT_SUBMITTERID=${SUBMITTER} # Catch some signals. ($xs kludge needed by Sun /bin/sh) xs=0 trap 'rm -f $REF $TEMP $FIXFIL; exit $xs' 0 trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP $FIXFIL; xs=1; exit' 1 3 13 15 if [ "x$PRINT" = "xtrue" ]; then FROM="" REPLYTO="" DEFAULT_ORIGINATOR="" DEFAULT_SUBMITTERID="" fi # If they told us to use a specific file, then do so. if [ -n "$IN_FILE" ]; then if [ "$IN_FILE" = "-" ]; then # The PR is coming from the standard input. cat > $TEMP else # Use the file they named. cat $IN_FILE > $TEMP fi else if [ -n "$TEMPLATE" -a -z "$PRINT_INTERN" ]; then # If their TEMPLATE points to a bogus entry, then bail. if [ ! -f "$TEMPLATE" -o ! -r "$TEMPLATE" -o ! -s "$TEMPLATE" ]; then echo "$COMMAND: can't seem to read your template file (\`$TEMPLATE'), ignoring TEMPLATE" sleep 1 PRINT_INTERN=bad_prform fi fi if [ -n "$TEMPLATE" -a -z "$PRINT_INTERN" ]; then sed "s//$FROM/;s//$REPLYTO/;s//$DEFAULT_ORIGINATOR/;s//$DEFAULT_SUBMITTERID/" < $TEMPLATE > $TEMP || ( echo "$COMMAND: could not copy $TEMPLATE" ; xs=1; exit ) else # Which genius thought of iterating through this loop twice, when the # cp command would suffice? for file in $TEMP ; do cat > $file << '__EOF__' SEND-PR: -*- send-pr -*- SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as SEND-PR: will all comments (text enclosed in `<' and `>'). SEND-PR: SEND-PR: Please consult the send-pr man page `send-pr(1)' or the Texinfo SEND-PR: manual if you are not sure how to fill out a problem report. SEND-PR: Note that the Synopsis field is mandatory. The Subject (for SEND-PR: the mail) will be made the same as Synopsis unless explicitly SEND-PR: changed. SEND-PR: SEND-PR: Choose from the following categories: SEND-PR: __EOF__ # Format the categories so they fit onto lines. CATEGORIES=`${bindir}/query-pr --valid-values Category`; l=`echo "$CATEGORIES" | \ awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } } END {print max + 1;}'` c=`expr 61 / $l` if [ $c -eq 0 ]; then c=1; fi echo "$CATEGORIES" | \ awk 'BEGIN {printf "SEND-PR: "; i = 0 } { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { printf "\nSEND-PR: " } } END { printf "\nSEND-PR:\n"; }' >> $file cat >> $file << __EOF__ To: $MAILADDR Subject: From: $FROM Reply-To: $REPLYTO X-send-pr-version: $VERSION __EOF__ # # Iterate through the list of input fields. fieldname is the # name of the field. fmtname is the formatted name of the field, # with >, : and extra spaces to cause the field contents to be # aligned. # ${bindir}/query-pr --list-input-fields | awk '{a[NR]=$1""; mnr = NR+1; len = length($1) + 2; if (mlen < len) mlen = len; } END { for (x = 1; x < mnr; x++) { b = ">"a[x]":"; printf ("%s %-"mlen"s&\n", a[x], b); } }' | while read fieldname fmtname do fmtname="`echo "$fmtname" | sed 's/[&]$//;'`" upname="`echo $fieldname | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;s/-//g;'`" # Grab the default value for this field. eval 'default_val="$DEFAULT_'${upname}'"' # What's stored in the field? type=`${bindir}/query-pr --field-type $fieldname | sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` case $type in enum) if [ "$default_val" != "" ] then desc=$default_val; else if [ "$fieldname" != "Category" ] then values=`${bindir}/query-pr --valid-values $fieldname | tr '\n' ' ' | sed 's/ *$//g; s/ / | /g;s/^/[ /;s/$/ ]/;'` valslen=`echo "$values" | wc -c` else values="choose from a category listed above" valslen=1; fi if [ "$valslen" -gt 160 ] then desc="<`${bindir}/query-pr --field-description $fieldname` (one line)>"; else desc="<${values} (one line)>"; fi dpat=`echo "$desc" | tr '\]\[*+^$|\()&/' '............'` echo "/^>${fieldname}:/ s/${dpat}//" >> $FIXFIL fi echo "${fmtname}${desc}" >> $file ;; multitext) if [ "$default_val" != "" ] then desc=" $default_val"; else desc=" <`${bindir}/query-pr --field-description $fieldname` (multiple lines)>"; dpat=`echo "$desc" | tr '\]\[*+^$|\()&/' '............'` echo "s/^${dpat}//" >> $FIXFIL fi echo "${fmtname}" >> $file; echo "$desc" >> $file; ;; *) if [ "$default_val" != "" ] then desc="${default_val}" else desc="<`${bindir}/query-pr --field-description $fieldname` (one line)>" dpat=`echo "$desc" | tr '\]\[*+^$|\()&/' '............'` echo "/^>${fieldname}:/ s/${dpat}//" >> $FIXFIL fi echo "${fmtname}${desc}" >> $file ;; esac done done fi if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then cat $TEMP xs=0; exit fi cp $TEMP $REF chmod u+w $TEMP if [ -z "$REQUEST_ID" ]; then eval $EDIT $TEMP else ed -s $TEMP << '__EOF__' /^Subject/s/^Subject:.*/Subject: request for a customer id/ /^>Category/s/^>Category:.*/>Category: send-pr/ w q __EOF__ fi if cmp -s $REF $TEMP ; then echo "$COMMAND: problem report not filled out, therefore not sent" xs=1; exit fi fi # TEMP is the PR that we are editing. When we're done, REF will contain # the final PR to be sent. while [ -z "$REQUEST_ID" ]; do CNT=0 # # Remove comments. # echo '/^SEND-PR:/d' >> $FIXFIL sed -f $FIXFIL $TEMP > $REF # REF now has the actual PR that we want to send. # # Check that synopsis is not empty. # if grep "^>Synopsis:[ ]*$" $REF > /dev/null then echo "$COMMAND: Synopsis must not be empty." CNT=`expr $CNT + 1` fi if [ "x$MAILPROG" = "x" ] then # Since we're not using mail, use pr-edit to check the PR. We can't # do much checking otherwise, sorry. $libexecdir/pr-edit --check-initial < $REF || CNT=`expr $CNT + 1` fi [ $CNT -gt 0 -a -z "$BATCH" ] && echo "Errors were found with the problem report." while true; do if [ -z "$BATCH" ]; then echo @ECHO_N@ "a)bort, e)dit or s)end? @ECHO_C@" read input else if [ $CNT -eq 0 ]; then input=s else input=a fi fi case "$input" in a*) if [ -z "$BATCH" ]; then echo "$COMMAND: the problem report remains in $BAD and is not sent." mv $TEMP $BAD else echo "$COMMAND: the problem report is not sent." fi xs=1; exit ;; e*) eval $EDIT $TEMP continue 2 ;; s*) break 2 ;; esac done done # # Make sure the mail has got a Subject. If not, use the same as # in Synopsis. # if grep '^Subject:[ ]*$' $REF > /dev/null then SYNOPSIS=`grep '^>Synopsis:' $REF | sed -e 's/^>Synopsis:[ ]*//'` ed -s $REF << __EOF__ /^Subject:/s/:.*\$/: $SYNOPSIS/ w q __EOF__ fi while : do if [ "x$MAILPROG" != "x" ] then # Use mail to send the PR. $MAILPROG < $REF; echo "$COMMAND: problem report mailed" xs=0; exit else if pr_num=`$libexecdir/pr-edit --submit --show-prnum < $REF` ; then echo "$COMMAND: problem report $pr_num filed" xs=0; exit else echo "$COMMAND: the problem report is not sent." fi fi while true do if [ -z "$BATCH" ]; then echo @ECHO_N@ "a)bort or s)end? @ECHO_C@" read input case "$input" in a*) break 2 ;; s*) break ;; esac else break 2; fi done done if [ -z "$BATCH" ]; then echo "$COMMAND: the problem report remains in $BAD and is not sent." mv $TEMP $BAD else echo "$COMMAND: the problem report is not sent." fi xs=1; exit; gnats-4.1.0/send-pr/version.texi0000600000175000017500000000002310212665130017271 0ustar chewiechewie00000000000000@set VERSION 4.1.0 gnats-4.1.0/texinfo/0000755000175000017500000000000010212665130015032 5ustar chewiechewie00000000000000gnats-4.1.0/texinfo/texinfo.tex0000644000175000017500000066463510207444131017254 0ustar chewiechewie00000000000000% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2004-04-07.08} % % Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software % Foundation, Inc. % % This texinfo.tex file is free software; you can redistribute it and/or % modify it under the terms of the GNU General Public License as % published by the Free Software Foundation; either version 2, or (at % your option) any later version. % % This texinfo.tex file is distributed in the hope that it will be % useful, but WITHOUT ANY WARRANTY; without even the implied warranty % of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU % General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this texinfo.tex file; see the file COPYING. If not, write % to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, % Boston, MA 02111-1307, USA. % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. (This has been our intent since Texinfo was invented.) % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://www.gnu.org/software/texinfo/ (the Texinfo home page), or % ftp://tug.org/tex/texinfo.tex % (and all CTAN mirrors, see http://www.ctan.org). % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} \message{Basics,} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexnoindent=\noindent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexplus=+ \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexstar=\* \let\ptext=\t % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % In some macros, we cannot use the `\? notation---the left quote is % in some cases the escape char. \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\questChar = `\? \chardef\semiChar = `\; \chardef\underChar = `\_ \chardef\spaceChar = `\ % \chardef\spacecat = 10 \def\spaceisspace{\catcode\spaceChar=\spacecat} % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt} % @| inserts a changebar to the left of the current line. It should % surround any changed text. This approach does *not* work if the % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). % \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode % % Append this vertical mode material after the current line in the output. \vadjust{% % We want to insert a rule with the height and depth of the current % leading; that is exactly what \strutbox is supposed to record. \vskip-\baselineskip % % \vadjust-items are inserted at the left edge of the type. So % the \llap here moves out into the left-hand margin. \llap{% % % For a thicker or thinner bar, change the `1pt'. \vrule height\baselineskip width1pt % % This is the space between the bar and the text. \hskip 12pt }% }% } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\undefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % For @cropmarks command. % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \escapechar = `\\ % use backslash in output files. \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingxxx.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 2\baselineskip \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \normalturnoffactive \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1 \unvbox#1 \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\next{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % We cannot use \next here, as it holds the macro to run; % thus we reuse \temp. \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \next. % (Similarily, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\next\expandafter{#1}} % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as enviroments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At runtime, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Evironment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty out of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} %% Simple single-character @ commands % @@ prints an @ % Kludge this until the fonts are right (grr). \def\@{{\tt\char64}} % This is turned off because it was never documented % and you can use @w{...} around a quote to suppress ligatures. %% Define @` and @' to be the same as ` and ' %% but suppressing ligatures. %\def\`{{`}} %\def\'{{'}} % Used to generate quoted braces. \def\mylbrace {{\tt\char123}} \def\myrbrace {{\tt\char125}} \let\{=\mylbrace \let\}=\myrbrace \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux file. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \c \let\dotaccent = \. \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \t \let\ubaraccent = \b \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ptexi \else\ifx\temp\jmacro \j \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=3000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% \kern-.15em \TeX } % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=3000 } % @! is an end-of-sentence bang. \def\!{!\spacefactor=3000 } % @? is an end-of-sentence query. \def\?{?\spacefactor=3000 } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox \prevdepth = \dimen1 \checkinserts } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in % Old definition--didn't work. %\parseargdef\need{\par % %% This method tries to make TeX break the page naturally %% if the depth of the box does not fit. %{\baselineskip=0pt% %\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak %\prevdepth=-1000pt %}} \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @include file insert text of that file as input. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable \def\temp{\input #1 }% \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\next\centerH \else \let\next\centerV \fi \next{\hfil \ignorespaces#1\unskip \hfil}% } \def\centerH#1{% {% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }% } \def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} % @sp n outputs n lines of vertical space \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment \def\comment{\begingroup \catcode`\^^M=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent{% \restorefirstparagraphindent \indent }% \gdef\noindent{% \restorefirstparagraphindent \noindent }% \global\everypar = {% \kern -\parindent \restorefirstparagraphindent }% } \gdef\restorefirstparagraphindent{% \global \let \indent = \ptexindent \global \let \noindent = \ptexnoindent \global \everypar = {}% } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode\underChar = \active \gdef\mathunderscore{% \catcode\underChar=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a \ character. % FYI, plain.tex uses \\ as a temporary control sequence (why?), but % this is not advertised and we don't care. Texinfo does not % otherwise define @\. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \tex \mathunderscore \let\\ = \mathbackslash \mathactive $\finishmath } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus } } % @bullet and @minus need the same treatment as @math, just above. \def\bullet{$\ptexbullet$} \def\minus{$-$} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in a typewriter % font as three actual period characters. % \def\dots{% \leavevmode \hbox to 1.5em{% \hskip 0pt plus 0.25fil .\hfil.\hfil.% \hskip 0pt plus 0.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=3000 } % @comma{} is so commas can be inserted into text without messing up % Texinfo's parsing. % \let\comma = , % @refill is a no-op. \let\refill=\relax % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as \undefined, % borrowed from ifpdf.sty. \ifx\pdfoutput\undefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % \ifpdf \input pdfcolor \pdfcatalog{/PageMode /UseOutlines}% \def\dopdfimage#1#2#3{% \def\imagewidth{#2}% \def\imageheight{#3}% % without \immediate, pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifx\empty\imagewidth\else width \imagewidth \fi \ifx\empty\imageheight\else height \imageheight \fi \ifnum\pdftexversion<13 #1.pdf% \else {#1.pdf}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code in a section title % aren't expanded. \atdummies \normalturnoffactive \pdfdest name{#1} xyz% }} \def\pdfmkpgn#1{#1} \let\linkcolor = \Blue % was Cyan, but that seems light? \def\endlink{\Black\pdfendlink} % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node % text, which might be empty if this toc entry had no % corresponding node. #4 is the page number. % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worthwhile, since most documents are normally structured. \def\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}\fi % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{#1}% } % \def\pdfmakeoutlines{% \begingroup % Thanh's hack / proper braces in bookmarks \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace % % Read toc silently, to get counts of subentries for \pdfoutline. \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \let\thissecnum\empty \let\thissubsecnum\empty }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \let\thissubsecnum\empty }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \let\thischapnum\empty \let\thissecnum\empty \let\thissubsecnum\empty % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \input \jobname.toc % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % xx to do this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Right % now, I guess we'll just let the pdf reader have its way. \indexnofonts \turnoffactive \input \jobname.toc \endgroup } % \def\makelinks #1,{% \def\params{#1}\def\E{END}% \ifx\params\E \let\nextmakelinks=\relax \else \let\nextmakelinks=\makelinks \ifnum\lnkcount>0,\fi \picknum{#1}% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{\the\pgn}}% \linkcolor #1% \advance\lnkcount by 1% \endlink \fi \nextmakelinks } \def\picknum#1{\expandafter\pn#1} \def\pn#1{% \def\p{#1}% \ifx\p\lbrace \let\nextpn=\ppn \else \let\nextpn=\ppnn \def\first{#1} \fi \nextpn } \def\ppn#1{\pgn=#1\gobble} \def\ppnn{\pgn=\first} \def\pdfmklnk#1{\lnkcount=0\makelinks #1,END,} \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \ifx\p\space\else\addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \fi \nextsp} \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi \def\pdfurl#1{% \begingroup \normalturnoffactive\def\@{@}% \makevalueexpandable \leavevmode\Red \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \linkcolor #1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\linkcolor = \relax \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % Default leading. \newdimen\textleading \textleading = 13.2pt % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % \def\setleading#1{% \normalbaselineskip = #1\relax \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % Set the font macro #1 to the font named #2, adding on the % specified font prefix (normally `cm'). % #3 is the font's design size, #4 is a scale factor \def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\undefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} %where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Text fonts (11.2pt, magstep1). \newcount\mainmagstep \ifx\bigger\relax % not really supported. \mainmagstep=\magstep1 \setfont\textrm\rmshape{12}{1000} \setfont\texttt\ttshape{12}{1000} \else \mainmagstep=\magstephalf \setfont\textrm\rmshape{10}{\mainmagstep} \setfont\texttt\ttshape{10}{\mainmagstep} \fi \setfont\textbf\bfshape{10}{\mainmagstep} \setfont\textit\itshape{10}{\mainmagstep} \setfont\textsl\slshape{10}{\mainmagstep} \setfont\textsf\sfshape{10}{\mainmagstep} \setfont\textsc\scshape{10}{\mainmagstep} \setfont\textttsl\ttslshape{10}{\mainmagstep} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1} \setfont\deftt\ttshape{10}{\magstep1} \setfont\defttsl\ttslshape{10}{\magstep1} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \setfont\smallrm\rmshape{9}{1000} \setfont\smalltt\ttshape{9}{1000} \setfont\smallbf\bfshape{10}{900} \setfont\smallit\itshape{9}{1000} \setfont\smallsl\slshape{9}{1000} \setfont\smallsf\sfshape{9}{1000} \setfont\smallsc\scshape{10}{900} \setfont\smallttsl\ttslshape{10}{900} \font\smalli=cmmi9 \font\smallsy=cmsy9 % Fonts for small examples (8pt). \setfont\smallerrm\rmshape{8}{1000} \setfont\smallertt\ttshape{8}{1000} \setfont\smallerbf\bfshape{10}{800} \setfont\smallerit\itshape{8}{1000} \setfont\smallersl\slshape{8}{1000} \setfont\smallersf\sfshape{8}{1000} \setfont\smallersc\scshape{10}{800} \setfont\smallerttsl\ttslshape{10}{800} \font\smalleri=cmmi8 \font\smallersy=cmsy8 % Fonts for title page (20.4pt): \setfont\titlerm\rmbshape{12}{\magstep3} \setfont\titleit\itbshape{10}{\magstep4} \setfont\titlesl\slbshape{10}{\magstep4} \setfont\titlett\ttbshape{12}{\magstep3} \setfont\titlettsl\ttslshape{10}{\magstep4} \setfont\titlesf\sfbshape{17}{\magstep1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\authorrm{\secrm} \def\authortt{\sectt} % Chapter (and unnumbered) fonts (17.28pt). \setfont\chaprm\rmbshape{12}{\magstep2} \setfont\chapit\itbshape{10}{\magstep3} \setfont\chapsl\slbshape{10}{\magstep3} \setfont\chaptt\ttbshape{12}{\magstep2} \setfont\chapttsl\ttslshape{10}{\magstep3} \setfont\chapsf\sfbshape{17}{1000} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 % Section fonts (14.4pt). \setfont\secrm\rmbshape{12}{\magstep1} \setfont\secit\itbshape{10}{\magstep2} \setfont\secsl\slbshape{10}{\magstep2} \setfont\sectt\ttbshape{12}{\magstep1} \setfont\secttsl\ttslshape{10}{\magstep2} \setfont\secsf\sfbshape{12}{\magstep1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 % Subsection fonts (13.15pt). \setfont\ssecrm\rmbshape{12}{\magstephalf} \setfont\ssecit\itbshape{10}{1315} \setfont\ssecsl\slbshape{10}{1315} \setfont\ssectt\ttbshape{12}{\magstephalf} \setfont\ssecttsl\ttslshape{10}{1315} \setfont\ssecsf\sfbshape{12}{\magstephalf} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 % Reduced fonts for @acro in text (10pt). \setfont\reducedrm\rmshape{10}{1000} \setfont\reducedtt\ttshape{10}{1000} \setfont\reducedbf\bfshape{10}{1000} \setfont\reducedit\itshape{10}{1000} \setfont\reducedsl\slshape{10}{1000} \setfont\reducedsf\sfshape{10}{1000} \setfont\reducedsc\scshape{10}{1000} \setfont\reducedttsl\ttslshape{10}{1000} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used in % the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \def\titlefonts{% \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy \let\tenttsl=\titlettsl \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{25pt}} \def\titlefont#1{{\titlefonts\rm #1}} \def\chapfonts{% \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl \def\lsize{sec}\def\lllsize{text}% \resetmathfonts \setleading{19pt}} \def\secfonts{% \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % % I wish the USA used A4 paper. % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \textfonts \rm % Define these so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000} \setfont\shortcontbf\bfshape{10}{\magstep1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000} \setfont\shortconttt\ttshape{12}{1000} %% Add scribe-like font environments, plus @l for inline lisp (usually sans %% serif) and @ii for TeX italic % \smartitalic{ARG} outputs arg in italics, followed by an italic correction % unless the following character is such as not to need one. \def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else \ptexslash\fi\fi\fi} \def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} \def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally uses \ttsl. % @var is set to this for defun arguments. \def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitalicx} \let\i=\smartitalic \let\var=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic \def\b#1{{\bf #1}} \let\strong=\b % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\frenchspacing{% \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m } \catcode`@=\other \def\t#1{% {\tt \rawbackslash \frenchspacing #1}% \null } \def\samp#1{`\tclose{#1}'\null} \setfont\keyrm\rmshape{8}{1000} \font\keysy=cmsy9 \def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% \vbox{\hrule\kern-0.4pt \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% \kern-0.4pt\hrule}% \kern-.06em\raise0.4pt\hbox{\angleright}}}} % The old definition, with no lozenge: %\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} \def\ctrl #1{{\tt \rawbackslash \hat}#1} % @file, @option are the same as @samp. \let\file=\samp \let\option=\samp % @code is a modification of @t, % which makes spaces the same size as normal in the surrounding text. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \frenchspacing #1% }% \null } % We *must* turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. % -- rms. { \catcode`\-=\active \catcode`\_=\active % \global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex } } \def\realdash{-} \def\codedash{-\discretionary{}{}{}} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } \def\codex #1{\tclose{#1}\endgroup} % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\arg{#1}% \ifx\arg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\arg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\arg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle option `\arg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct.' \kbdinputstyle distinct \def\xkey{\key} \def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\look}}\fi \else{\tclose{\kbdfont\look}}\fi} % For @indicateurl, @env, @command quotes seem unnecessary, so use \code. \let\indicateurl=\code \let\env=\code \let\command=\code % @uref (abbreviation for `urlref') takes an optional (comma-separated) % second argument specifying the text to display and an optional third % arg as text to display instead of (rather than in addition to) the url % itself. First (mandatory) arg is the url. Perhaps eventually put in % a hypertex \special here. % \def\uref#1{\douref #1,,,\finish} \def\douref#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} \def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } % @pounds{} is a sterling sign, which is in the CM italic font. % \def\pounds{{\it\$}} % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % Do an implicit @contents or @shortcontents after @end titlepage if the % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. % \newif\ifsetcontentsaftertitlepage \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue \newif\ifsetshortcontentsaftertitlepage \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue \parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % If they want short, they certainly want long too. \ifsetshortcontentsaftertitlepage \shortcontents \contents \global\let\shortcontents = \relax \global\let\contents = \relax \fi % \ifsetcontentsaftertitlepage \contents \global\let\contents = \relax \global\let\shortcontents = \relax \fi } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } %%% Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines \let\tt=\authortt} \parseargdef\title{% \checkenv\titlepage \leftline{\titlefonts\rm #1} % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\authorfont \leftline{#1}}% \fi } %%% Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\pageheight by -\baselineskip \global\advance\vsize by -\baselineskip } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \def\headings #1 {\csname HEADINGS#1\endcsname} \def\HEADINGSoff{% \global\evenheadline={\hfil} \global\evenfootline={\hfil} \global\oddheadline={\hfil} \global\oddfootline={\hfil}} \HEADINGSoff % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\undefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. (Unfortunately % we can't prevent a possible page break at the following % \baselineskip glue.) However, if what follows is an environment % such as @example, there will be no \parskip glue; then % the negative vskip we just would cause the example and the item to % crash together. So we use this bizarre value of 10001 as a signal % to \aboveenvbreak to insert \parskip glue after all. % (Possibly there are other commands that could be followed by % @example which need the same treatment, but not section titles; or % maybe section titles are the only special case and they should be % penalty 10001...) \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablex } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablex } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablex } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi \def\itemcontents{#1}% % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% \vadjust{\penalty 1200}}% not good to break after first line of item. \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. % Assignments have to be global since we are inside the implicit group % of an alignment entry. Note that \everycr resets \everytab. \def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}% % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we encounter the problem it was intended to solve again. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. \let\item\crcr % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% test to see if user has set \multitablelinespace. % If so, do nothing. If not, give it an appropriate dimension based on % current baselineskip. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 %% strut to put in table in case some entry doesn't have descenders, %% to keep lines equally spaced \let\multistrut = \strut \else %% FIXME: what is \box0 supposed to be? \gdef\multistrut{\vrule height\multitablelinespace depth\dp0 width0pt\relax} \fi %% Test to see if parskip is larger than space between lines of %% table. If not, do nothing. %% If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore {#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the string `ifinfo'. % % Define a command to find the next `@end #1', which must be on a line % by itself. \long\def\doignoretext##1^^M@end #1{\doignoretextyyy##1^^M@#1\_STOP_}% % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \obeylines % \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. \def\enddoignore{\endgroup\ignorespaces} % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\- = \active \catcode`\_ = \active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\realdash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get special treatment of `@end ifset,' call \makeond and the redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within \newindex. {\catcode`\@=11 \gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} % \newindex {foo} defines an index named foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \undefined % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname\donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \def\indexdummies{% \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % Need these in case \tex is in effect and \{ is a \delimiter again. % But can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. \let\{ = \mylbrace \let\} = \myrbrace % % \definedummyword defines \#1 as \realbackslash #1\space, thus % effectively preventing its expansion. This is used only for control % words, not control letters, because the \space would be incorrect % for control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword##1{% \expandafter\def\csname ##1\endcsname{\realbackslash ##1\space}% }% \def\definedummyletter##1{% \expandafter\def\csname ##1\endcsname{\realbackslash ##1}% }% % % Do the redefinitions. \commondummies } % For the aux file, @ is the escape character. So we want to redefine % everything using @ instead of \realbackslash. When everything uses % @, this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % (See comments in \indexdummies.) \def\definedummyword##1{% \expandafter\def\csname ##1\endcsname{@##1\space}% }% \def\definedummyletter##1{% \expandafter\def\csname ##1\endcsname{@##1}% }% % % Do the redefinitions. \commondummies } % Called from \indexdummies and \atdummies. \definedummyword and % \definedummyletter must be defined first. % \def\commondummies{% % \normalturnoffactive % \commondummiesnofonts % \definedummyletter{_}% % % Non-English letters. \definedummyword{AA}% \definedummyword{AE}% \definedummyword{L}% \definedummyword{OE}% \definedummyword{O}% \definedummyword{aa}% \definedummyword{ae}% \definedummyword{l}% \definedummyword{oe}% \definedummyword{o}% \definedummyword{ss}% \definedummyword{exclamdown}% \definedummyword{questiondown}% \definedummyword{ordf}% \definedummyword{ordm}% % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword{bf}% \definedummyword{gtr}% \definedummyword{hat}% \definedummyword{less}% \definedummyword{sf}% \definedummyword{sl}% \definedummyword{tclose}% \definedummyword{tt}% % \definedummyword{LaTeX}% \definedummyword{TeX}% % % Assorted special characters. \definedummyword{bullet}% \definedummyword{copyright}% \definedummyword{registeredsymbol}% \definedummyword{dots}% \definedummyword{enddots}% \definedummyword{equiv}% \definedummyword{error}% \definedummyword{expansion}% \definedummyword{minus}% \definedummyword{pounds}% \definedummyword{point}% \definedummyword{print}% \definedummyword{result}% % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable % % Normal spaces, not active ones. \unsepspaces % % No macro expansion. \turnoffmacros } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % % Better have this without active chars. { \catcode`\~=\other \gdef\commondummiesnofonts{% % Control letters and accents. \definedummyletter{!}% \definedummyletter{"}% \definedummyletter{'}% \definedummyletter{*}% \definedummyletter{,}% \definedummyletter{.}% \definedummyletter{/}% \definedummyletter{:}% \definedummyletter{=}% \definedummyletter{?}% \definedummyletter{^}% \definedummyletter{`}% \definedummyletter{~}% \definedummyword{u}% \definedummyword{v}% \definedummyword{H}% \definedummyword{dotaccent}% \definedummyword{ringaccent}% \definedummyword{tieaccent}% \definedummyword{ubaraccent}% \definedummyword{udotaccent}% \definedummyword{dotless}% % % Texinfo font commands. \definedummyword{b}% \definedummyword{i}% \definedummyword{r}% \definedummyword{sc}% \definedummyword{t}% % % Commands that take arguments. \definedummyword{acronym}% \definedummyword{cite}% \definedummyword{code}% \definedummyword{command}% \definedummyword{dfn}% \definedummyword{emph}% \definedummyword{env}% \definedummyword{file}% \definedummyword{kbd}% \definedummyword{key}% \definedummyword{math}% \definedummyword{option}% \definedummyword{samp}% \definedummyword{strong}% \definedummyword{tie}% \definedummyword{uref}% \definedummyword{url}% \definedummyword{var}% \definedummyword{verb}% \definedummyword{w}% } } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% \def\definedummyword##1{% \expandafter\let\csname ##1\endcsname\asis }% % We can just ignore the accent commands and other control letters. \def\definedummyletter##1{% \expandafter\def\csname ##1\endcsname{}% }% % \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% % how to handle braces? \def\_{\normalunderscore}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\aa{aa}% \def\ae{ae}% \def\l{l}% \def\oe{oe}% \def\o{o}% \def\ss{ss}% \def\exclamdown{!}% \def\questiondown{?}% \def\ordf{a}% \def\ordm{o}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\bullet{bullet}% \def\copyright{copyright}% \def\registeredsymbol{R}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\expansion{==>}% \def\minus{-}% \def\pounds{pounds}% \def\point{.}% \def\print{-|}% \def\result{=>}% } \let\indexbackslash=0 %overridden during \printindex. \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \ifvmode \dosubindsanitize \else \dosubindwrite \fi }% \fi } % Write the entry in \toks0 to the index file: % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \escapechar=`\\ \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % Take care of unwanted page breaks: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write will make \lastskip zero. The result is that sequences % like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % % ..., ready, GO: % \def\dosubindsanitize{% % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \skip0 = \lastskip \edef\lastskipmacro{\the\lastskip}% \count255 = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\skip0 glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\skip0 \fi % \dosubindwrite % \ifx\lastskipmacro\zeroskipmacro % if \lastskip was zero, perhaps the last item was a % penalty, and perhaps it was >=10000, e.g., a \nobreak. % In that case, we want to re-insert the penalty; since we % just inserted a non-discardable item, any following glue % (such as a \parskip) would be a breakpoint. For example: % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\count255>9999 \nobreak \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\skip0 \fi } % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 11 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \penalty -300 % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus .5\baselineskip \leftline{\secbf #1}% \vskip .33\baselineskip plus .1\baselineskip % % Do our best not to break after the initial. \nobreak }} % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this frozes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \def\tempa{{\rm }}% \def\tempb{#1}% \edef\tempc{\tempa}% \edef\tempd{\tempb}% \ifx\tempc\tempd \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like \dotfill except takes at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% } % % All done with double columns. \def\enddoublecolumns{% \output = {% % Split the last of the double-column material. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % \unnumberedno is an oxymoron, of course. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines this as the name of the chapter. % page headings and footings can use it. @section does likewise. % However, they are not reliable, because we don't use marks. \def\thischapter{} \def\thissection{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achive this, remember the "biggest" unnum. sec. we are currently in: \chardef\unmlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unmlevel \chardef\unmlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unmlevel \def\headtype{U}% \else \chardef\unmlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % \message{\putwordChapter\space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % \def\appendixnum{\putwordAppendix\space \appendixletter}% \message{\appendixnum}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } \outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } \outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. \outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } \outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading % NOTE on use of \vbox for chapter headings, section headings, and such: % 1) We use \vbox rather than the earlier \line to permit % overlong headings to fold. % 2) \hyphenpenalty is set to 10000 because hyphenation in a % heading is obnoxious; this forbids it. % 3) Likewise, headings look best if no \parindent is used, and % if justification is not attempted. Hence \raggedright. \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\raggedright \rm #1\hfill}}% \bigskip \par\penalty 200\relax \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. %%% Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} %%% Define plain chapter starts, and page on/off switching for it % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip \def\chapbreak{\dobreak \chapheadingskip {-4000}} \def\chappager{\par\vfill\supereject} \def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% \pchapsepmacro {% \chapfonts \rm % % Have to define \thissection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\thissection{#1}% \gdef\thischaptername{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \def\thischapter{#1}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \xdef\thischapter{}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% % We don't substitute the actual chapter name into \thischapter % because we don't want its macros evaluated now. And we don't % use \thissection because that changes with each section. % \xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\raggedright \rm #1\hfill}}\bigskip \par\nobreak } \def\chfopen #1#2{\chapoddpage {\chapfonts \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% \par\penalty 5000 % } \def\centerchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt \hfill {\rm #1}\hfill}}\bigskip \par\nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\sectionheading#1#2#3#4{% {% % Switch to the right set of fonts. \csname #2fonts\endcsname \rm % % Insert space above the heading. \csname #2headingbreak\endcsname % % Only insert the space after the number if we have a section number. \def\sectionlevel{#2}% \def\temptype{#3}% % \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\thissection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \thissection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\thissection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\thissection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chfplain. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chfplain. \donoderef{#3}% % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) \vskip-\parskip % % This \nobreak is purely so the last item on the list is a \penalty % of 10000. This is so other code, for instance \parsebodycommon, can % check for and avoid allowing breakpoints. Otherwise, it would % insert a valid breakpoint between: % @section sec-whatever % @deffn def-whatever \nobreak } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks \toks0 = {#2}% \toks2 = \expandafter{\lastnode}% \edef\temp{\write\tocfile{\realbackslash #1entry{\the\toks0}{#3}% {\the\toks2}{\noexpand\folio}}}% \temp \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \def\thischapter{}% \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 % We can't do this, because then an actual ^ in a section % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % Normal (long) toc. \def\contents{% \startcontents{\putwordTOC}% \openin 1 \jobname.toc \ifeof 1 \else \input \jobname.toc \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \jobname.toc \ifeof 1 \else \input \jobname.toc \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, it should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\tentt \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @tex ... @end tex escapes into raw Tex temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain tex @ character. \envdef\tex{% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \escapechar=`\\ % \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\*=\ptexstar \let\t=\ptext % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} \let\afterenvbreak = \aboveenvbreak % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing=\comment \vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of \def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt \parindent = 0pt \emergencystretch = 0pt % don't try to avoid overfull boxes % @cartouche defines \nonarrowing to inhibit narrowing % at next level down. \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \fi \let\exdent=\nofillexdent } % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it by one command: \def\makedispenv #1#2{ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two synonyms: \def\maketwodispenvs #1#2#3{ \makedispenv{#1}{#3} \makedispenv{#2}{#3} } % @lisp: indented, narrowed, typewriter font; @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvs {lisp}{example}{% \nonfillstart \tt \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenv {display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenv{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill \gobble } \let\Eflushright = \afterenvbreak % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \envdef\quotation{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \advance\rightskip by \lispnarrowing \exdentamount = \lispnarrowing \let\nonarrowing = \relax \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\undefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % [Knuth] pp. 380,381,391 % Disable Spanish ligatures ?` and !` of \tt font \begingroup \catcode`\`=\active\gdef`{\relax\lq} \endgroup % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \catcode`\`=\active \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % \def\starttabbox{\setbox0=\hbox\bgroup} \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen0=\wd0 % the width so far, or since the previous tab \divide\dimen0 by\tabw \multiply\dimen0 by\tabw % compute previous multiple of \tabw \advance\dimen0 by\tabw % advance to next multiple of \tabw \wd0=\dimen0 \box0 \starttabbox }% } \endgroup \def\setupverbatim{% \nonfillstart \advance\leftskip by -\defbodyindent % Easiest (and conventionally used) font for verbatim \tt \def\par{\leavevmode\egroup\box0\endgraf}% \catcode`\`=\active \tabexpand % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. Many commands won't be % allowed in this context, but that's ok. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is very desirable. % \def\copying{\begingroup % Define a command to swallow text until we reach `@end copying'. % \ is the escape char in this texinfo.tex file, so it is the % delimiter for the command; @ will be the escape char when we read % it, but that doesn't matter. \long\def\docopying##1\end copying{\gdef\copyingtext{##1}\enddocopying}% % % We must preserve ^^M's in the input file; see \insertcopying below. \catcode`\^^M = \active \docopying } % What we do to finish off the copying text. % \def\enddocopying{\endgroup\ignorespaces} % @insertcopying. Here we must play games with ^^M's. On the one hand, % we need them to delimit commands such as `@end quotation', so they % must be active. On the other hand, we certainly don't want every % end-of-line to be a \par, as would happen with the normal active % definition of ^^M. On the third hand, two ^^M's in a row should still % generate a \par. % % Our approach is to make ^^M insert a space and a penalty1 normally; % then it can also check if \lastpenalty=1. If it does, then manually % do \par. % % This messes up the normal definitions of @c[omment], so we redefine % it. Similarly for @ignore. (These commands are used in the gcc % manual for man page generation.) % % Seems pretty fragile, most line-oriented commands will presumably % fail, but for the limited use of getting the copying text (which % should be quite simple) inserted, we can hope it's ok. % {\catcode`\^^M=\active % \gdef\insertcopying{\begingroup % \parindent = 0pt % looks wrong on title page \def^^M{% \ifnum \lastpenalty=1 % \par % \else % \space \penalty 1 % \fi % }% % % Fix @c[omment] for catcode 13 ^^M's. \def\c##1^^M{\ignorespaces}% \let\comment = \c % % % Don't bother jumping through all the hoops that \doignore does, it % would be very hard since the catcodes are already set. \long\def\ignore##1\end ignore{\ignorespaces}% % \copyingtext % \endgroup}% } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check for penalty 10002 (inserted by % \defargscommonending) instead of 10000, since the sectioning % commands insert a \penalty10000, and we don't want to allow a break % between a section heading and a defun. \ifnum\lastpenalty=10002 \penalty2000 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil \endgraf \nobreak\vskip -\parskip \penalty 10002 % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remainnig is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } %%% Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } %%% Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } %%% Type: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % How we'll format the type name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % (plain.tex says that \dimen1 should be used only as global.) \parshape 2 0in \dimen0 \defargsindent \dimen2 % % Put the type name to the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% return value type \ifx\temp\empty\else \tclose{\temp} \fi #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. Let's try @var for that. \let\var=\ttslanted #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } \def\badparencount{% \errmessage{Unbalanced parentheses in @def}% \global\parencount=0 } \def\badbrackcount{% \errmessage{Unbalanced square braces in @def}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\undefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1\endinput}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \def\scanmacro#1{% \begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % Undo catcode changes of \startcontents and \doprintindex \catcode`\@=0 \catcode`\\=\other \escapechar=`\@ % ... and \example \spaceisspace % % Append \endinput to make sure that TeX does not see the ending newline. % % I've verified that it is necessary both for e-TeX and for ordinary TeX % --kasal, 29nov03 \scantokens{#1\endinput}% \endgroup } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? \def\macrolist{} % List of all defined macros in the form % \do\macro1\do\macro2... % Utility routines. % This does \let #1 = #2, except with \csnames. \def\cslet#1#2{% \expandafter\expandafter \expandafter\let \expandafter\expandafter \csname#1\endcsname \csname#2\endcsname} % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \. % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. \def\macrobodyctxt{% \catcode`\~=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\+=\other \catcode`\{=\other \catcode`\}=\other \catcode`\@=\other \catcode`\^^M=\other \usembodybackslash} \def\macroargctxt{% \catcode`\~=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\+=\other \catcode`\@=\other \catcode`\\=\other} % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0% \else \expandafter\parsemargdef \argl;% \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% % Add the macroname to \macrolist \toks0 = \expandafter{\macrolist\do}% \xdef\macrolist{\the\toks0 \expandafter\noexpand\csname\the\macname\endcsname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\do\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx#1\relax % remove this \else \noexpand\do \noexpand #1% \fi } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname #1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.blah for each blah % in the params list, to be ##N where N is the position in that list. % That gets used by \mbodybackslash (above). % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. \def\parsemargdef#1;{\paramno=0\def\paramlist{}% \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1% \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% % This defines the macro itself. There are six cases: recursive and % nonrecursive macros of zero, one, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \fi \fi} \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg) \def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \expandafter\parsearg \fi \next} % We mant to disable all macros during \shipout so that they are not % expanded by \write. \def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}% \edef\next{\macrolist}\expandafter\endgroup\next} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Just make them active and then expand them all to nothing. \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \thissection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \atdummies % preserve commands, but don't expand them \turnoffactive \otherbackslash \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\thissection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \writexrdef{pg}{\folio}% will be written later, during \shipout }% \fi } % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces \def\printedmanual{\ignorespaces #5}% \def\printedrefname{\ignorespaces #3}% \setbox1=\hbox{\printedmanual\unskip}% \setbox0=\hbox{\printedrefname\unskip}% \ifdim \wd0 = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax % Use the node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Use the actual chapter/section title appear inside % the square brackets. Use the real section title if we have it. \ifdim \wd1 > 0pt % It is in another manual, so we don't have it. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf \leavevmode \getfilename{#4}% {\turnoffactive \otherbackslash \ifnum\filenamelength>0 \startlink attr{/Border [0 0 0]}% goto file{\the\filename.pdf} name{#1}% \else \startlink attr{/Border [0 0 0]}% goto name{\pdfmkpgn{#1}}% \fi }% \linkcolor \fi % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \otherbackslash \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd0 = 0pt \refx{#1-snt}% \else \printedrefname \fi % % if the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd1 > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not % insert empty discretionaries after hyphens, which means that it will % not find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, this % is a loss. Therefore, we give the text of the node name again, so it % is as if TeX is seeing it for the first time. \ifdim \wd1 > 0pt \putwordsection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% \else % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive \otherbackslash % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via a macro so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \otherbackslash \putwordpage\tie\refx{#1-pg}{}% \fi \fi \endlink \endgroup} % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. % If its value is nonempty, SUFFIX is output afterward. % \def\refx#1#2{% {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs \message{\linenumber Undefined cross reference `#1'.}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% \expandafter\gdef\csname XR#1\endcsname{#2}% remember this xref value. % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR#1\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0{#1}}% \fi } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readauxfile \global\havexrefstrue \fi \closein 1 } \def\readauxfile{\begingroup \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {% \count 1=128 \def\loop{% \catcode\count 1=\other \advance\count 1 by 1 \ifnum \count 1<256 \loop \fi }% }% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 % \input \jobname.aux \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\pagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut \futurelet\next\fo@t } }%end \catcode `\@=11 % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarily, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from ftp://tug.org/tex/epsf.tex.} % \def\image#1{% \ifx\epsfbox\undefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing this stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names % If the image is by itself, center it. \ifvmode \imagevmodetrue \nobreak\bigskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \line\bgroup\hss \fi % % Output the image. \ifpdf \dopdfimage{#1}{#2}{#3}% \else % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \fi % \ifimagevmode \hss \egroup \bigbreak \fi % space after the image \endgroup} % @float FLOATTYPE,LOC ... @end float for displayed figures, tables, etc. % We don't actually implement floating yet, we just plop the float "here". % But it seemed the best name for the future. % \envparseargdef\float{\dofloat #1,,,\finish} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \thissection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\thissection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline\thiscaption \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \atdummies \turnoffactive \otherbackslash \immediate\write\auxfile{@xrdef{\floatlabel-lof}{% \floatident \ifx\thisshortcaption\empty \ifx\thiscaption\empty \else : \thiscaption \fi \else : \thisshortcaption \fi }}% }% \fi % % Space below caption, if we printed anything. \ifx\printedsomething\empty \else \vskip\parskip \fi \egroup % end of \vtop \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \newtoks\appendtomacroAtoks \newtoks\appendtomacroBtoks \def\appendtomacro#1#2{% \appendtomacroAtoks = \expandafter{#1}% \appendtomacroBtoks = {#2}% \edef#1{\the\appendtomacroAtoks \the\appendtomacroBtoks}% } % @caption, @shortcaption are easy. % \long\def\caption#1{\checkenv\float \def\thiscaption{#1}} \def\shortcaption#1{\checkenv\float \def\thisshortcaption{#1}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \thissection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % and i18n. % @documentlanguage is usually given very early, just after % @setfilename. If done too late, it may not override everything % properly. Single argument is the language abbreviation. % It would be nice if we could set up a hyphenation file here. % \parseargdef\documentlanguage{% \tex % read txi-??.tex file in plain TeX. % Read the file if it exists. \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \input txi-#1.tex \fi \closein 1 \endgroup } \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? In the current directory should work if nowhere else does.} % @documentencoding should change something in TeX eventually, most % likely, but for now just recognize it. \let\documentencoding = \comment % Page size parameters. % \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be so finicky about underfull hboxes, either. \hbadness = 2000 % Following George Bush, just get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; 3) voffset; % 4) hoffset; 5) binding offset; 6) topskip; 7) physical page height; 8) % physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \pageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \pagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{46\baselineskip}{6in}% {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.5 (or so) format. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {\voffset}{.25in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{51\baselineskip}{160mm} {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1 \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \catcode`\~=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\+=\other \catcode`\$=\other \def\normaldoublequote{"} \def\normaltilde{~} \def\normalcaret{^} \def\normalunderscore{_} \def\normalverticalbar{|} \def\normalless{<} \def\normalgreater{>} \def\normalplus{+} \def\normaldollar{$}%$ font-lock fix % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. {\catcode`\\=\active @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} } % \realbackslash is an actual character `\' with catcode other. {\catcode`\\=\other @gdef@realbackslash{\}} % \normalbackslash outputs one backslash in fixed width font. \def\normalbackslash{{\tt\backslashcurfont}} \catcode`\\=\active % Used sometimes to turn off (effectively) the active characters % even after parsing them. @def@turnoffactive{% @let"=@normaldoublequote @let\=@realbackslash @let~=@normaltilde @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let<=@normalless @let>=@normalgreater @let+=@normalplus @let$=@normaldollar %$ font-lock fix @unsepspaces } % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. (Thus, \ is not expandable when this is in % effect.) % @def@normalturnoffactive{@turnoffactive @let\=@normalbackslash} % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\{ in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also back turn on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These look ok in all fonts, so just make them not special. @catcode`@& = @other @catcode`@# = @other @catcode`@% = @other @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore