Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial seed of IDLWAVE v4.10

  • Loading branch information...
commit c8115d3b0a0d76fee855858ed56c78ca6bb311cd 0 parents
jdsmith authored
286 CHANGES
@@ -0,0 +1,286 @@
+This is the CHANGES file of the IDLWAVE distribution, version VERSIONTAG
+
+The file covers only the changes for Revision 3.0 and later. Earlier
+changes are documented in the (obsolete) files idl.el and
+idl-shell.el, available at idlwave.org.
+
+Revision 4.10
+=============
+ - New maintainer: J.D. Smith <jdsmith@astro.cornell.edu>
+ - Compatible with IDL v5.5's new breakpoint listing
+ format, along with the older format.
+ - Updated routine info for new routines and new keywords to
+ existing routines, taken from the `What's New' document shipped
+ with the IDL v5.5 release.
+ - Updated online help text, from the `What's New' document.
+ - The get_rinfo script can now take a `fixup' file for adding
+ updated help and routine info material.
+ - New frame creation handled better with quick shell (idlwave-shell
+ 'quick).
+ - A few updates for better Emacs 21 compatibility.
+
+Revision 4.9
+============
+ - Idle time is used to automatically initialize the routine info.
+ See new variable `idlwave-init-rinfo-when-idle-after'.
+ - When using the mouse to print variables an expressions, you now
+ can also drag over a region to define the expression to print.
+ - Before doing file name completion in the shell, the Emacs working
+ directory is switched to the current IDL working directory.
+ - The IDL procedure "BEEP" works again in the IDLWAVE Shell.
+ - Fixed display problem with multiple frames.
+ - In places where completion defaults to *keywords*, you can force
+ function name completion with a C-u prefix to M-TAB.
+ - Some bugs fixed.
+
+Revision 4.8
+============
+ - The shell preserves the command history between sessions. See
+ new variables `idlwave-shell-command-history-file' and
+ `idlwave-shell-save-command-history'.
+ - New variable `idlwave-indent-to-open-paren' which can be used to
+ turn off deep indentation of continuation lines. Example:
+ x = function_a(function_b(function_c( a, b, $
+ d, c)))
+ - The library catalog can be updated with a background job so that
+ you can continue to work while it runs.
+ - A double prefix argument to `idlwave-shell-print' evaluates
+ and prints the current region as an expression.
+ - When the IDL process under the shell exits, it runs
+ `idlwave-shell-sentinel-hook'.
+ - Fixed bug with deleting last window on IDL exit.
+ - Fixed bug (exponential regexp) with parsing Liam Gumley's routine
+ headers.
+
+Revision 4.7
+============
+ - New way to define key bindings for debugging commands
+ See variable `idlwave-shell-debug-modifiers'.
+ - Variable `idlwave-shell-activate-alt-keybindings' obsolete.
+ - Tutorial added to the documentation.
+ - Bugfix with !PATH query under Solaris (Craig Markwardt)
+
+Revision 4.6
+============
+ - Shell window more like xterm:
+ - show as much output as possible
+ - up and down arrows do history stuff (see new variable
+ idlwave-shell-arrows-do-history).
+ - Routine info and help files updated to IDL 5.4
+ - Support for the new IDL statements (SWITCH, BREAK, CONTINUE)
+ - Bugfix for shell printing of identifiers with `!' and `.'
+ - File name completion in strings in buffers, similar to the shell.
+ - Fixed file name completion with a dash in file names.
+ - Font-lock enhancements in structure definitions: Structure name
+ and tag names.
+ - END is replaced by ENDIF etc already when indenting a line with TAB.
+ - Fixed bug with parsing of routine definition if comment lines are
+ scallered between continuation lines.
+ - `idlwave-close-block' and `idlwave-abbrev-change-case'
+ interaction bug fixed.
+ - Routine info and source lookup switch to INIT automatically when
+ the cursor is in keyword section of an OBJ_NEW call.
+ - Fixed BUG with getting system variable info from the Shell under
+ IDL5.2 and earlier. Used to produce a compilation error, now
+ just silently fails.
+
+
+Revision 4.5
+============
+ - Bug fixed with structure parsing in CLASS__define procedures.
+
+Revision 4.4
+============
+ - IDLWAVE understands inheritance in all important contexts.
+ - Completion of system variables and their tags.
+ - Completion of class structure tags on "self" variables.
+
+Revision 4.3
+============
+ - The IDL procedure "BEEP" works in the IDLWAVE Shell
+ - Fixed bug with dedicated shell frame display under Emacs
+ (patch from Stein Vidar Hagfors Haugan <shaugan@esa.nascom.nasa.gov>)
+
+Revision 4.2
+============
+ - Fixed bug with context-help when at end-of-buffer.
+ - Ambiguous kwd abbrev and non-existent in online help kwd
+ now ring the bell.
+ - Toggling the toolbar causes a redraw-frame on Emacs (21 only).
+ - Allow for space between a function and `('.
+ - Forcing completion type with prefix arg to M-TAB fixed in the shell.
+ - Fixed bug when exiting shell with *idl* as the only window.
+ - The class of object "self" is assumed of be the current routines class.
+
+Revision 4.1
+============
+ - Fixed bug in which unresolved routines could shadow catalog entries.
+ - Fixed the incorrect installation instructions in README.hlp.
+ - Online help for non-system stuff makes use of the DocLib file header.
+ - Abbreviated keywords are treated correctly for online help.
+ - Source files displayed as online help can be fontified
+ (off by default, see variable `idlwave-help-fontify-source-code').
+ - Multiple definitions of a routine in one file count as shadowing.
+ - Facility to send single characters to interact with GET_KBRD (see manual)
+ - The shell defines a system variable !IDLWAVE_VERSION, which can
+ be used by a program to detect if it is running under Emacs or not.
+ - More efficient way of querying the shell for routine info.
+ - Fixed bug in get_rinfo -> 10 mode keywords recognized.
+ - Fixed bug with translation of help topics.
+ - Fixed bug for completion context after continuation lines.
+ - Fixed bug with Keyword insertion after `(' from Routine Info Window.
+
+Revision 4.0
+============
+ - Fast and accurate IDL online help. Two additional files need to
+ be installed, they are not part of the standard distribution.
+ Help is triggered with `M-?', and by clicking with mouse-3 on
+ items in the Routine Info buffer or in *Completions*.
+ - Global IDL namespace analysis to produce a list of routines
+ with definitions in several files.
+ - Clicking on a keyword in the routine-info buffer inserts
+ the keyword in the buffer from which `C-c ?' was called.
+ - More intelligent completion in OBJ_NEW calls.
+ - Class completion after PRO and FUNCTION.
+ - Abbrev expansion in the shell.
+ - `idlwave-pad-keywords' can also have a value `keep'.
+ - `idlwave-scan-all-buffers-for-routine-info' can also have value
+ `current' to scan only the current buffer but no other buffers.
+
+Revision 3.15
+=============
+ - Printing expressions while execution is halted can now also
+ access all levels on the calling stack.
+ - Padding of long operators (like `->') is now possible. The
+ object arrow `->' has been added to the defaults - when
+ `idlwave-do-actions' is non-nil, `->' will have at least one
+ space before and after it.
+ - Code templates now respect settings of `idlwave-abbrev-change-case'
+ and `idlwave-reserved-word-upcase'.
+ - Fixed bug with `idlwave-pad-keywords' in procedure method calls.
+ - Fontification of keyword parameters works with embedded comments.
+
+Revision 3.13
+=============
+ - Minor cleanup.
+
+Revision 3.12
+=============
+ - 3 files had to be renamed, in order to get IDLWAVE included in the
+ Emacs distribution:
+ - idlwave-shell.el -> idlw-shell.el
+ - idlwave-rinfo.el -> idlw-rinfo.el
+ - idlwave-toolbar.el -> idlw-toolbar.el
+ When installing this version, make sure to remove the old
+ idlwave-*.el files and update the autoload for `idlwave-shell'.
+
+Revision 3.11
+=============
+ - Final cleanup before installing in the Emacs and XEmacs distributions.
+
+Revision 3.10
+=============
+ - Fixed bug with `idlwave-shell-automatic-start'.
+ - Fixed bug with the info files.
+
+Revision 3.9
+============
+ - Exiting the shell does not kill the *idl* buffer.
+ - Shell prompt pattern allows single whitespace before "IDL>"
+
+Revision 3.8
+============
+ - Library scan implemented for Windows and MacOS. On these systems
+ the search path need to be given in `idlwave-library-path'.
+ - *Completions* window disappears after successful completion.
+ - Fixed library scan bug with keywords in continuations line.
+
+Revision 3.7
+============
+ - Completion of Object methods finalized.
+ - Exiting the IDLWAVE shell now kills all associated buffers and
+ the dedicated frame (if applicable).
+ - Documentation finalized. The printed documentation is 24 pages.
+ Available online in Emacs (info), as postscript and HTML.
+
+Revision 3.6
+============
+ - You can make IDLWAVE prescan library files for routine info.
+
+Revision 3.5
+============
+ - Completion and Routine Info display now also work for object
+ methods.
+ - Completion and Routine Info display available in the IDLWAVE Shell.
+ - Debugging Toolbar adapted for Emacs 21.
+ - First draft of TeXInfo documentation.
+ - Fixed bug with END expansion in CASE lists.
+
+Revision 3.4
+============
+ - Fixed bug in Makefile with install-tags
+ - Fixed bug in with concat in XEmacs 21.x
+ - Enforced FSF coding standards, to prepare for installation in
+ main Emacs distributions.
+
+Revision 3.3
+============
+ - `C-c ?' displays the calling sequence and keyword parameters of a
+ routine. Works for most builtin IDL routines, the routines you
+ are currently editing, and the compiled routines in the idlwave-shell.
+ - `M-tab' completes procedure names, function names and keyword
+ parameters in the buffer.
+ - New source file idlwave-rinfo.el contains the code for these new
+ functions.
+
+Revision 3.2
+============
+ - The cleanup after the idl process finishes is now reliable and gets
+ called exactly once.
+ - Toolbar code moved to a separate source file.
+ - Fixed bug with `display-buffer' in Emacs 19.
+
+Revision 3.0
+============
+ File idlwave.el
+ ---------------
+ - New maintainer Carsten Dominik <dominik@strw.leidenuniv.nl>
+ - Renamed mode and all variables and functions. The new prefix is
+ `idlwave-' instead of `idl-'. This was necessary to evade a name
+ clash with the idl-mode defined in `cc-mode.el' which is part of
+ X/Emacs 20 distributions.
+ - Added Customize support.
+ - New commands `idlwave-beginning-of-block' and `idlwave-end-of-block'.
+ - New command `idlwave-close-block'.
+ - The type of END at the end of the block is checked.
+ - Font-lock enhancements. Multi-level fontification based on the
+ value of `font-lock-maximum-decoration'. Reunified the different
+ expressions for Emacs and XEmacs.
+ - `idlwave-show-begin' check the correctness of the END statement.
+ - `idlwave-surround' exception for `->'.
+ - Better listing of abbreviations with `idlwave-list-abbrevs'.
+ - Some general cleanup of the code. Menu reorganized.
+ - Both imenu (Emacs) and func-menu (XEmacs) are now supported.
+ - Dropped support for Emacs 18 and hilit19.el.
+ - Rewrite of the docstring for the Mode. Made more compact, to
+ make more people read it. Too long parts moved to the Commentary.
+ - Revision number jumps to 3.0 to synchronize with idlwave-shell.el.
+
+ File idlwave-shell.el
+ ---------------------
+ - New maintainer Carsten Dominik <dominik@strw.leidenuniv.nl>
+ - Renamed mode and all functions and variables to use `idlwave-' instead
+ of `idl-' prefix. This was necessary to avoid a name clash with
+ `idl-mode' which is defined in cc-mode.el.
+ - Made the stop-line-overlay work for XEmacs as well. Changed the
+ associated face to 'highlight.
+ - Breakpoint lines are highlighted with a glyph or a special face.
+ - Debugging toolbar under XEmacs.
+ - To get a special frame for the shell buffer, set the variable
+ `idlwave-shell-use-dedicated-frame' to t, or call `idlwave-shell'
+ with a prefix arg. The hook suggested for in Revision 2.4 for
+ the same purpose probably still works, but is no longer recommended.
+ - Changed the default `idlwave-shell-use-truename' to nil, since we ensure
+ now internally to not visit the same file twice under different names.
+ - Menu reorganized.
+ - Implemented a number of new commands. Check the "Debug" menu.
339 COPYING
@@ -0,0 +1,339 @@
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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.
191 INSTALL
@@ -0,0 +1,191 @@
+This is the INSTALL file of the IDLWAVE distribution, version VERSIONTAG
+
+IDLWAVE has been developed and tested on Emacs 20.4 and XEmacs 21.1.
+
+If you are using XEmacs 21, you probably want to install the XEmacs
+plugin package for idlwave which is available via the usual package
+management process. You can then skip items (1)--(3) of this guide
+and continue directly with item (4).
+
+If you are using Emacs 21, IDLWAVE is installed. You can then skip
+items (1)--(3) of this guide and continue directly with item (4).
+
+
+0. THE FAST ROAD
+================
+
+On a typical UNIX system, installation goes as easy as:
+
+Get these following files:
+
+http://idlwave.org/download/idlwave.tar.gz
+http://idlwave.org/download/idlwave-help.tar.gz
+
+Put them in /tmp (or anywhere), then do (as root):
+
+ % tar xzvf idlwave.tar.gz
+ % cd idlwave-version
+ % tar xzvf ../idlwave-help.tar.gz
+ % make
+ % make install-all
+
+where "version" is something like 4.10. This by default puts idlwave in
+/usr/local/share/emacs/site-lisp/, which is a fine place. It also puts
+the help files in /usr/local/etc, which is also fine.
+
+Then add to .emacs or to a site equivalent of it:
+
+ (autoload 'idlwave-mode "idlwave" "IDLWAVE Mode" t)
+ (autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t)
+ (setq auto-mode-alist
+ (cons '("\\.pro\\'" . idlwave-mode) auto-mode-alist))
+ (setq idlwave-help-directory "/usr/local/etc")
+
+The rest of this file is just an extensive destription of these steps,
+with eplanation of the options you have and how to change the defaults.
+
+
+1. SELECTING A DIRECTORY TO INSTALL THE FILES
+=============================================
+
+In order to install Emacs Lisp files, you need access to a directory
+which will be searched by Emacs for these files.
+
+- If you are installing IDLWAVE for all users on the system, then you
+ should use the "..../emacs/site-lisp" directory.
+
+- If you want to install the package just for yourself, make a
+ directory to contain your private lisp files, for example
+ "~/lib/emacs/lisp". Then tell Emacs to look also into this directory
+ by putting the following line into your .emacs file.
+
+ (setq load-path (cons "~/lib/emacs/lisp" load-path))
+
+
+2a. INSTALLATION BY HAND
+========================
+
+In order to install IDLWAVE by hand, put the files `idlwave.el',
+`idlw-rinfo.el', `idlw-shell.el', and `idlw-toolbar.el' into
+the chosen load-path directory and byte-compile them (from within
+Emacs, execute `M-x byte-compile-file' followed by the name of the
+Lisp files). You can ignore the warnings produced by the byte
+compiler.
+
+Copy the info file `idlwave' into the directory where Emacs info files
+are kept and add an entry to the `dir' file.
+
+2b. INSTALLATION USING MAKE
+===========================
+
+In order to install IDLWAVE with the make utility, edit the header of
+the file `Makefile'. You need to specify the Lisp installation
+directory and the directory where the Info files are installed. Also,
+check the name of the Emacs executable (usually either `emacs' or
+`xemacs').
+
+Then, type
+
+ make
+ make install
+ make install-info
+
+to compile and install the code and the info file.
+
+
+3. SETTING UP EMACS TO USE IDLWAVE
+==================================
+
+Copy the following lines into your .emacs file:
+
+(autoload 'idlwave-mode "idlwave" "IDLWAVE Mode" t)
+(autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t)
+(setq auto-mode-alist (cons '("\\.pro\\'" . idlwave-mode) auto-mode-alist))
+
+
+4. INITIALIZING FONT-LOCK
+=========================
+
+If you are using global-font-lock-mode, fontification of IDLWAVE
+buffers will be automatic. If not, add the following to .emacs:
+
+ (add-hook 'idlwave-mode-hook 'turn-on-font-lock)
+
+The level of colorization can be controlled with the variable
+`font-lock-maximum-decoration'.
+
+
+5. ARE YOU UPGRADING FROM THE OLD `idl.el' FILE?
+================================================
+
+If you have any customization for the older `idl-mode' in your .emacs
+file, you need to do the following:
+a) Change all variable and function prefixes from `idl-' to `idlwave-'.
+b) Remove the now invalid `autoload' and `auto-mode-alist'
+ forms pointing to the `idl.el' and `idl-shell.el' files.
+c) If you did use the hook recommended in earlier versions to get
+ a separate frame for the IDL shell, remove that hook again.
+ Instead, set the variable `idlwave-shell-use-dedicated-frame' with
+ (setq idlwave-shell-use-dedicated-frame t)
+d) The key sequence `M-TAB' no longer inserts a TAB character, but (as
+ in many other Emacs modes) does completion. Inserting a TAB is now
+ bound to `C-TAB'.
+
+6. YOU ARE DONE
+===============
+
+IDLWAVE has online documentation in Info format. To view this
+information, use `M-x idlwave-info' or follow the Menu entry in the
+IDLWAVE menu. You can also convert the documentation into Postscript
+with `make ps' and into HTML with `make html'.
+
+-------------------------------------------------------------------------
+
+7. INSTALLING ONLINE HELP
+=========================
+
+If you want IDLWAVE to display online help about IDL routines, you
+need an ASCII version of the IDL documentation and a file with
+pointers to the topics in the documentation. You can download the
+files from the IDLWAVE website.
+
+ INSTALL BY HAND
+ ---------------
+ Unpack the `idlwave-help.tar.gz' file and copy the files
+ `idlw-help.el' and `idlw-help.txt' into an arbitrary directory.
+ Byte-compile `idlw-help.el'.
+
+ INSTALL USING MAKE
+ ------------------
+ Unpack `idlwave-help.tar.gz' into the same directory where also the
+ IDLWAVE distribution is located. Edit the header of the IDLWAVE
+ Makefile to make sure the variable "helpdir" is set correctly.
+ Then, type:
+
+ make install-help
+
+Now all you have to do is to tell IDLWAVE where these files are
+located with
+
+ (setq idlwave-help-directory "/path/to/help/files/")
+
+in your .emacs file. For a system-wide installation, you can instead
+set the environment variable IDLWAVE_HELP_DIRECTORY.
+
+
+8. SCANNING THE LOCAL IDL LIBRARY
+=================================
+
+If you would like to use routine information and completion for
+modules in the local and your private IDL library, the library has to
+be scanned. Set the variable `idlwave-libinfo-file' to the absolute
+name of a file in which to store the extracted information. The
+default is "~/idlcat.el". Then from within Emacs, start the IDLWAVE
+shell with `M-x idlwave-shell'.
+Execute `M-x idlwave-create-libinfo-file' and follow the instructions.
+
+This final point (scanning the library to produce a catalog file)
+should be done by individual users in order to make sure their private
+libraries will be included as well. I could support separate catalogs
+for shared and private libraries, but currently this is not the case.
+
254 Makefile
@@ -0,0 +1,254 @@
+# Makefile - for the IDLWAVE distribution.
+#
+# Maintainer: J.D. Smith <jdsmith@astro.cornell.edu>
+# Version: VERSIONTAG
+#
+# To install IDLWAVE, (optionally) edit the Makefile, type `make',
+# then `make install', or `make install-all' (to include full info
+# help files).
+
+##----------------------------------------------------------------------
+## YOU MUST EDIT THE FOLLOWING LINES
+##----------------------------------------------------------------------
+
+# Prefix of installation path for Info and Lisp files
+prefix=/usr/local
+
+# Where info files go.
+infodir = $(prefix)/info
+
+# Where local lisp files go.
+lispdir = $(prefix)/share/emacs/site-lisp
+
+# Where would you like to install the help files?
+# Don't forget to configure the Emacs variable `idlwave-help-directory'
+# It must also point to the directory where help files are installed.
+helpdir = $(prefix)/etc
+
+# Name of your emacs binary
+EMACS=emacs
+
+##----------------------------------------------------------------------
+## YOU MAY NEED TO EDIT THESE (PROBABLY NOT...)
+##----------------------------------------------------------------------
+
+# Using emacs in batch mode.
+BATCH=$(EMACS) -batch -q -l lpath.el
+
+# Specify the byte-compiler for compiling .el files
+ELC= $(BATCH) -f batch-byte-compile
+
+# How to make a dvi file from a texinfo file
+TEXI2DVI = texi2dvi
+
+# How to create directories
+MKDIR = mkdir -p
+
+# How to make a postscript file from a dvi file
+DVIPS = dvips
+
+# How to create the info files from the texinfo file
+MAKEINFO = makeinfo
+
+# How to create the HTML file
+TEXI2HTML = texi2html -monolithic -number
+
+# How to create the PDF fil
+
+TEXI2PDF = texi2pdf
+
+# How to move the byte compiled files to their destination.
+MV = mv
+
+# How to copy the lisp files to their destination.
+CP = cp -p
+
+##----------------------------------------------------------------------
+## BELOW THIS LINE ON YOUR OWN RISK!
+##----------------------------------------------------------------------
+
+# The following variables need to be defined by the maintainer
+LISPFILES = idlwave.el idlw-shell.el idlw-rinfo.el idlw-toolbar.el
+LISPFILES1 = $(LISPFILES) idlw-help.el
+ELCFILES = $(LISPFILES:.el=.elc)
+TEXIFILES = idlwave.texi
+INFOFILES = idlwave idlwave-1 idlwave-2 idlwave-3
+RINFOFILES = idlw-help.el idlw-help.txt idlw-rinfo.el
+HELPFILES = idlw-help.el idlw-help.txt
+DLDIR = /home2/www/html/idlwave/download
+HTMLDIR = /home2/www/html/idlwave/
+
+# An alternative installation point
+#MY_INFODIR = /home/strw/dominik/lib/emacs/info
+#MY_LISPDIR = /home/strw/dominik/lib/emacs/lisp
+
+.SUFFIXES: .el .elc .texi
+SHELL = /bin/sh
+
+DISTFILES= README INSTALL CHANGES ChangeLog COPYING Makefile\
+ $(LISPFILES) $(TEXIFILES) $(INFOFILES) lpath.el\
+ idltags get_rinfo helpcode help55fixup.txt tutorial.pro\
+ idlw-complete-structtag.el
+
+WEBDISTFILES= idlwave.ps idlwave.pdf idlwave.html CHANGES
+HELPDISTFILES= README.hlp $(HELPFILES)
+
+XEMACSDISTFILES= CHANGES $(LISPFILES) $(TEXIFILES) Makefile.xemacs-package \
+ package-info.in
+
+EMACSDISTFILES= $(LISPFILES) $(TEXIFILES) ChangeLog
+
+DOWNGRADEFILES= README.downgrade idlw-rinfo.el idlw-help.el idlw-help.txt
+
+all: lisp
+
+install: install-lisp
+
+install-all: install-lisp install-info install-help
+
+lisp: $(LISPFILES)
+ $(ELC) $(LISPFILES)
+
+compile: $(LISPFILES)
+ $(ELC) $(LISPFILES)
+
+info: $(INFOFILES)
+
+
+dvi: idlwave.dvi
+
+view:
+ xdvi idlwave.dvi&
+
+ps: idlwave.ps
+
+ps2: idlwave.ps
+ psnup -2 idlwave.ps>idlwave.ps2
+
+html: idlwave.html
+
+pdf: idlwave.pdf
+
+install-lisp:
+ if [ ! -d $(lispdir) ]; then $(MKDIR) $(lispdir); else true; fi ;
+ $(CP) $(LISPFILES) $(lispdir)
+ $(CP) $(ELCFILES) $(lispdir)
+
+install-info:
+ if [ ! -d $(infodir) ]; then $(MKDIR) $(infodir); else true; fi ;
+ $(CP) $(INFOFILES) $(infodir)
+
+install-help:
+ @[ -f idlw-help.el -a -f idlw-help.txt ] || { echo "Help package missing. download from idlwave.org and install here."; exit 1; }
+ $(ELC) idlw-help.el
+ if [ ! -d $(helpdir) ]; then $(MKDIR) $(helpdir); else true; fi ;
+ $(CP) $(HELPFILES) idlw-help.elc $(helpdir)
+
+$(INFOFILES): $(TEXIFILES)
+ $(MAKEINFO) idlwave.texi
+
+idlwave.dvi: idlwave.texi
+ $(TEXI2DVI) idlwave.texi
+
+idlwave.ps: idlwave.dvi
+ $(DVIPS) -o idlwave.ps idlwave.dvi
+
+idlwave.html: idlwave.texi
+ $(TEXI2HTML) idlwave.texi
+
+idlwave.pdf: idlwave.texi
+ $(TEXI2PDF) idlwave.texi
+
+rinfo: rinfo55
+
+rinfo53:
+ ./get_rinfo53 -txt -emacs -path pdf53 -idl idl_5.3
+
+rinfo54:
+ ./get_rinfo54 -txt -emacs -path pdf54 -idl idl_5.4
+
+rinfo55: $(RINFOFILES)
+
+$(RINFOFILES): get_rinfo
+ ./get_rinfo -fixup help55fixup.txt -txt -emacs -path pdf55 -idl idl_5.5
+
+dgkit:
+ @if [ "X$(IDL)" = "X" ]; then echo "*** No IDL tag ***"; exit 1; fi
+ make rinfo$(IDL)
+ gtar zcvf idlwave-downgrade-for-idl$(IDL).tar.gz $(DOWNGRADEFILES)
+
+NUTSHELL: idlwave.texi
+ makeinfo --no-headers idlwave.texi|perl NUTSHELL.pl>NUTSHELL
+
+wcompile:
+ xemacs -batch -q -l lpath-warn.el -f batch-byte-compile $(LISPFILES1)
+
+xcompile:
+ xemacs -batch -q -l lpath-warn.el -f batch-byte-compile $(LISPFILES1)
+
+ecompile:
+ emacs -batch -q -l lpath-warn.el -f batch-byte-compile $(LISPFILES1)
+
+ccompile:
+ xemacs -batch -q -l lpath-compatible.el -f batch-byte-compile $(LISPFILES1)
+
+#myinstall: $(LISPFILES) $(ELCFILES) $(INFOFILES)
+# if [ ! -d $(MY_LISPDIR) ]; then mkdir $(MY_LISPDIR); else true; fi ;
+# $(CP) $(LISPFILES) $(MY_LISPDIR)
+# $(CP) $(ELCFILES) $(MY_LISPDIR)
+# if [ ! -d $(MY_INFODIR) ]; then mkdir $(MY_INFODIR); else true; fi ;
+# $(CP) $(INFOFILES) $(MY_INFODIR)
+
+distfile:
+ @if [ "X$(TAG)" = "X" ]; then echo "*** No tag ***"; exit 1; fi
+# make rinfo
+ rm -rf idlwave-$(TAG)
+ mkdir idlwave-$(TAG)
+ cp -p $(DISTFILES) idlwave-$(TAG)/
+ perl -pi -e 's/\sVERSIONTAG\b/ $(TAG)/' idlwave-$(TAG)/*
+ tar czvf idlwave-$(TAG).tar.gz idlwave-$(TAG)
+ tar czvf idlwave-$(TAG)-help.tar.gz $(HELPDISTFILES)
+ rm -rf idlwave-$(TAG)
+
+dist: $(WEBDISTFILES)
+ make distfile TAG=$(TAG)
+ cp -p idlwave-$(TAG).tar.gz $(DLDIR)
+ cp -p idlwave-$(TAG)-help.tar.gz $(DLDIR)
+ (cd $(DLDIR); ln -sf idlwave-$(TAG).tar.gz idlwave.tar.gz)
+ (cd $(DLDIR); ln -sf idlwave-$(TAG)-help.tar.gz idlwave-help.tar.gz)
+ (cd $(DLDIR); ln -sf idlwave-$(TAG).tar.gz idlwave-alpha.tar.gz)
+ cp -f $(WEBDISTFILES) $(HTMLDIR)
+ perl -pi -e 's/\sVERSIONTAG\b/ $(TAG)/' $(HTMLDIR)/CHANGES
+
+alphadist: $(WEBDISTFILES)
+ make distfile TAG=$(TAG)
+ cp idlwave-$(TAG).tar.gz $(DLDIR)
+ cp idlwave-$(TAG)-help.tar.gz $(DLDIR)
+ cp CHANGES $(HTMLDIR)
+ perl -pi -e 's/\sVERSIONTAG\b/ $(TAG)/' $(HTMLDIR)/CHANGES
+ (cd $(DLDIR); ln -sf idlwave-$(TAG).tar.gz idlwave-alpha.tar.gz)
+ (cd $(DLDIR); ln -sf idlwave-$(TAG)-help.tar.gz idlwave-help-alpha.tar.gz)
+
+clean:
+ rm -f $(ELCFILES)
+ rm -f *~
+ rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.pg *.pgs
+ rm -f *.toc *.tp *.tps *.vr *.vrs *.log *.html *.ps
+
+veryclean:
+ rm -f $(ELCFILES)
+ rm -f *~ idlwave idlwave-[1-9]
+ rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.pg *.pgs
+ rm -f *.toc *.tp *.tps *.vr *.vrs *.log *.html *.ps
+
+
+linkelc:
+ rm -f ../lisp/idlw*.elc
+ (cd ../lisp;ln -s ../idlwave/idlw*.elc .)
+
+unlinkelc:
+ rm -f ../lisp/idlw*.elc
+ rm -f *.elc
+
+.el.elc:
+ $(ELC) $<
57 README
@@ -0,0 +1,57 @@
+This is the README file of the IDLWAVE distribution, version VERSIONTAG
+
+IDLWAVE is the successor to Chris Chase's idl.el and idl-shell.el.
+
+ ****************************************************************************
+ ****************************************************************************
+ ** **
+ ** Note that the entire package has been renamed. The prefix **
+ ** of all functions and variables is now `idlwave-' instead of `idl-'. **
+ ** This was necessary in order to make this mode work with X/Emacs 20. **
+ ** So it is now **
+ ** **
+ ** idlwave-mode instead of idl-mode **
+ ** idlwave-shell instead of idl-shell **
+ ** idlwave-mode-hook instead of idl-mode-hook **
+ ** ... etc ... **
+ ** **
+ ** If you have any local settings for idl-mode, these settings will **
+ ** have to be adapted. See the INSTALL file for details. **
+ ** **
+ ****************************************************************************
+ ****************************************************************************
+
+Your kit should contain the following files:
+
+README This file
+INSTALL A brief installation guide
+CHANGES The package history
+ChangeLog Detailed list of changes to the code
+COPYING The GNU General Public License
+Makefile The Makefile to compile and install IDLWAVE
+lpath.el A file needed to compile the lisp files
+
+idlwave.el The Lisp code for idlwave-mode
+idlw-rinfo.el The Lisp constant for routine-info
+idlw-shell.el The Lisp code for idlwave-shell-mode
+idlw-toolbar.el The Lisp code for the toolbar.
+
+idlwave.texi The TeX-Info documentation source
+idlwave \
+idlwave-1 > The Info files (the documentation in Info format)
+idlwave-2 /
+idlwave-3 /
+
+idltags A Perl program to produce IDL TAGS files
+get_rinfo A Perl program to scan the IDL documentation and
+ produce several files needed by IDLWAVE.
+helpcode Lispcode used by get_rinfo to build idlw-help.el
+
+tutorial.pro Buggy source code for the tutorial. See the
+ `Getting Started' section in the manual.
+
+The most recent version of IDLWAVE is available at
+
+ http://idlwave.org
+
+
26 README.hlp
@@ -0,0 +1,26 @@
+This is the README file for the IDLWAVE online help files.
+
+This distribution contains the following files:
+
+idlw-help.txt An ASCII version of several IDL manuals
+idlw-help.el A file with Lisp code and pointers to the topics
+ in `idlw-help.txt'.
+
+Please install these two files anywhere on your system and tell
+IDLWAVE where to find them. You can do this by adding the following
+line to to your Emacs configuration:
+
+ (setq idlwave-help-path "/path/to/idlwave/helpfiles/")
+
+Alternatively, set the environment variable IDLWAVE_HELP_DIRECTORY.
+
+Byte-compiling the file `idlw-help.el' will make online help even
+faster.
+
+The IDL documentation is copyright by Research Systems, Inc. This
+ASCII version can be distributed for the purpose of supporting the
+Emacs IDLWAVE mode. Please see the file `idlw-help.txt' for the
+original copyright notice by RSI.
+
+The code in `idlw-help.el' is distributed under the terms of the GNU
+General Public License.
2,448 get_rinfo
@@ -0,0 +1,2448 @@
+#!/usr/bin/perl
+
+# Program to extract the information from the IDL manuals and IDL to
+# support IDLWAVE.
+# (c) 1999, 2000 Carsten Dominik <dominik@astro.uva.nl>
+# (c) 2001 J.D. Smith <jdsmith@alum.mit.edu>
+#
+# Needs the PDF documentation files distributed with IDL 5.4 or later.
+#
+# Uses `pdftotext' by Derek B. Noonburg in order to convert the PDF
+# files to ASCII.
+#
+# Talks to the local version of IDL in order to get additional information.
+#
+# Call this program from the command line like this:
+#
+# get_rinfo --path path/to/pdffiles/ --idl /path/to/idl/executable
+#
+# This will convert the PDF files to ASCII, extract routine information,
+# talk to IDL and write the following files which are needed by IDLWAVE:
+#
+# idlw-rinfo.el: Routine information for completion etc.
+# idlw-help.txt: ASCII version of the IDL documantation
+# idlw-help.el: Supporting code and pointers to topics in idlw-help.txt.
+
+# The full manpage of this program is available with "perldoc get_rinfo".
+
+# Commentary:
+# ===========
+#
+# IDL currently contains more than 1200 functions, procedures and object
+# methods with more than 5000 keywords. In order to support writing IDL
+# programs, the IDLWAVE mode uses a list of routines and keywords. RSI
+# does not provide such a list in machine-readable form. Therefore this
+# program embarks on the task to extract the necessary information from
+# available sources - the IDL manuals which are supplied by RSI in PDF
+# format. GET_RINFO works by looking for the "Syntax" sections and
+# extracting information from there.
+#
+# Note that this program depends strongly upon the standards for writing
+# documentation that are used by RSI. So it is only as robust as these
+# standards are. For example, the syntax descriptions changed considerably
+# between IDL 5.2 and IDL 5.3, and I had to rewrite :-(
+#
+# The program extracts information from manuals written by humans (the
+# documentation department at RSI). Naturally, such documents are not
+# always complete, consistent or free of typos. As a result of this, the
+# list of routines and keywords extracted from the manuals will not be
+# perfect. In order to cover for incorrect or inconsistent "Syntax"
+# entries in the manual, get_rinfo contains a number of special matchers
+# which detect specific entries and try to correct. See the definition of
+# %specials in the BEGIN block. When a new version of IDL is released,
+# the actions of these special matchers needs to be checked, because the
+# involved syntax entries may have changed.
+#
+# Please contact the maintainer if you find any inconsistencies between
+# the routine information supplied by IDLWAVE, and the IDL documentation.
+#
+# Get_rinfo also produces an ASCII version of the IDL documentation
+# and a topics file which can be used to display full online help for
+# system routines. See the IDLWAVE documentation for details.
+#
+# Acknowledgement:
+# ================
+#
+# Without Perl, the task of reverse-engineering thousands of pages of
+# documentation would have been impossible. With Perl, it only takes a
+# small program like this. Thanks to Larry Wall and the Perl community.
+#
+# Thanks to Mark Goosman from RSI for granting me permission to
+# extract and distribute routine information from the IDL manual,
+# and to distribute an ASCII version of the manuals for online help.
+#
+# Maintainer Information:
+# =======================
+# When a new version of IDL is published, the following things might need
+# work in order to make the result of this program as good as possible.
+# To find the corresponding places in the file, search for "UPDATE".
+#
+# 1. UPDATE: Files
+# -------------
+# The names of the PDF files to be scanned for routine info and/or
+# to be included into the online help file. RSI might have renamed
+# or added or removed files.
+#
+# 2. UPDATE: Manual sections
+# -----------------------
+# Each Routine description has many sections. The list can be extended
+# when necessary - the better the list, the more accurate the parsing.
+#
+# 3. UPDATE: Special matchers
+# ------------------------
+# The %specials hash contains all the special matchers which fix unusual
+# or incorrect routine descriptions. They change the entry so that the
+# parser does the right thing, or they add entries to special arrays.
+# The first thing to do with a new version is to run get_rinfo with
+# the -debug flag. Part of the output will be a list of all special
+# matchers, with additional info how often the matcher matches, and
+# if it did its actions correctly. Matchers which no longer match
+# should be checked. Matchers which match, but do not act may be due
+# to the fact that RSI fixed that particular entry.
+# It is also possible that new special matchers have to be written for
+# new entries - you need to check what is new in this version and if
+# it is processed correctly.
+# Read the documentation just before the definition of the %specials hash
+# to find out how such a matcher must behave.
+#
+# 4. UPDATE: Statement regexp
+# ------------------------
+# This is also a special matcher which makes sure that no routine
+# info is produced by the syntax entries for IDL language
+# constructs. As RSI adds new statements (as COMPILE_OPT in
+# version 5.3 or SWITCH/BREAK/CONTINUE in version 5.4), this regexp
+# must be extended to match the new statements as well.
+#
+# 5. UPDATE: Graphics Keywords Routines
+# ----------------------------------
+# Routines that should have links to the GRAPHICS KEYWORDS section,
+# because some of their keywords are described there. For many but
+# not all routines, this can be detected automatically by looking
+# for "Graphics Keywords" in the syntax entry. This list is a
+# backup to make sure also those routines which do not have this
+# magic cookie will get theirs links set.
+#
+# 5. UPDATE: Multi-Threading routines
+# --------------------------------
+# Routines that should have links to the MULTI-THREADING keywords,
+# as described in teh documentation for routine CPU, because of
+# their keywords are described there. As of IDL v5.5, these
+# keywords were not covered in the main documentation, and instead
+# were added using a fixup file. Future version of IDL should
+# include links such as "Multi-threading keywords", analogous to
+# "Graphics Keywords", but can still be listed as backup.
+#
+# 6. UPDATE: Special help topics
+# ---------------------------
+# Some words which can show up in IDL source code have special help topics
+# associated with them. This Lisp association list links downcase
+# versions of these words to the appropriate topics. Even if word and
+# topic are the same, it must be mentioned here in order to trigger
+# help on this word. If the word at point is not in this list, IDLWAVE
+# checks for the local routine call and supplies help.
+#
+# 7. UPDATE: Group appendix topics
+# -----------------------------
+# Here we group some appendix topics to a single large topic.
+# The hash %group_topics associates the first topic in the group
+# with the first topic which is no longer part of the group.
+# The refguide.txt file needs to be checked if these borders are
+# correct. Remember that GET_RINFO makes a topic of (almost) all lines
+# which are not indented.
+#
+# It is certainly a good idea to look at a diff between the old and
+# the new `idlw-rinfo.el' file. Comparing this with the "What's New"
+# section from RSI should give hints where get_rinfo may have to be
+# adapted.
+# For more detailed info, run `get_rinfo' with the `-debug' flag and
+# check the resulting files get_rinfo.cpl, get_rinfo.rej, and
+# get_rinfo.log.
+#
+#============================================================================
+
+require 5.004;
+
+# UPDATE: Files
+# -------------
+# Set the default list of files to be scanned for routine info
+# These are the files which contain "Syntax" descriptions.
+@rifiles = ("refguide.pdf","sdf.pdf","datamine.pdf","edg.pdf","obsolete.pdf",
+ "whatsnew55.pdf");
+
+# Set the list of files which will be used for fast online help.
+# More or less the same files as above, but you can leave out
+# long files which have only one or two Syntax entries, like
+# edg.pdf or insight.pdf. Leaving them out makes the help file smaller.
+@olhfiles = ("refguide.pdf","sdf.pdf","datamine.pdf","obsolete.pdf",
+ "whatsnew55.pdf");
+
+# Parse command line options and make file names
+use Getopt::Long;
+GetOptions("-debug" => \$debug,
+ "-path=s" => \$path,
+ "-idl=s" => \$idl,
+ "-emacs" => \$emacs,
+ "-nohelp" => \$nohelp,
+ "-nowrap" => \$nowrap,
+ "-txt" => \$usetxt,
+ "-maketxt" => \$maketxt,
+ "-xname=s" => \$ignore_name_re,
+ "-xclass=s" => \$ignore_class_re,
+ "-fixup=s" => \$fixup)
+ or usage();
+
+if (@ARGV) {
+ # File names are on the command line
+ print STDERR "Unrecognized command line args: @ARGV\n";
+ exit(1);
+}
+
+$idl = $idl || "idl";
+
+# Compute the base names of file names
+@ribases = map {file_basename($_)} @rifiles;
+@olhbases = map {file_basename($_)} @olhfiles;
+
+# We must scan all files - thus combine the lists
+@files = make_unique( (@rifiles,@olhfiles) );
+
+# Compressed file extensions and decompressors
+%compress = (".gz" => "gunzip -c",
+ ".bz2" => "bunzip2 -c",
+ ".Z" => "zcat");
+
+# Establish default output file names
+$rinfofile = "idlw-rinfo.el";
+$helpfile = "idlw-help.txt";
+$topicsfile = "idlw-help.el";
+
+# Establish default for the wrap width
+$wrapwidth = 65;
+
+# The program which converts pdf to text
+$pdftotext = "pdftotext";
+
+# Check the path
+$path ||= ".";
+die "Invalid path $path\n" unless !$path || -d $path;
+
+if ($maketxt) {
+ warn "Only converting pdf to ascii\n";
+ foreach $file (@files) {
+ convert_pdf_to_text($path,$file);
+ }
+ exit(0);
+}
+
+if ($usetxt) {
+ # Look for txt files instead of pdf files
+ @files = map {textname($_)} @files;
+}
+
+# Check if the files exist. If not, try compression suffixes.
+foreach $file (@files) {
+ $file = find_file($path,$file);
+}
+
+%routines = ();
+
+# Open the REJECT and LOG files file for debugging information
+if ($debug) {
+ open REJECT, ">get_rinfo.rej" or die "Cannot write to get_rinfo.rej\n";
+ open COMPLAIN,">get_rinfo.cpl" or die "Cannot write to get_rinfo.cpl\n";
+ open LOG, ">get_rinfo.log" or die "Cannot write to get_rinfo.log\n";
+}
+
+# Do this here so help files can
+open_help_file() unless $nohelp;
+
+# Open the lisp file for output
+open RINFO,">$rinfofile" or die "Cannot open $rinfofile for write\n";
+
+read_fixup() if $fixup;
+
+# Scan the different files
+foreach $file (@files) {
+
+ $file_basename = file_basename($file);
+ $isri = grep {/^$file_basename$/} @ribases;
+ $isolh = grep {/^$file_basename$/} @olhbases;
+
+ # Read the file into a string, and make a second copy
+ $text = read_manual_file($path,$file);
+
+ # Find the version number
+ if ($text =~ /IDL\s+Version\s+(\d+\.\d+)/) {
+ $version = $1;
+ $idlversion = $version if $version > $idlversion;
+ }
+
+ # Remove Table of Contents and Index.
+ $text =~ s/^.*\nContents\s+[^\n]*\n\n\f\n\n//s;
+ $text =~ s/\f\s+\nIndex.*$//s;
+
+ # Remove headers and footers and newpage stuff. We remove the line
+ # with ^L, at least 2 lines before and after it, and any additional
+ # empty lines around it. Regular expressions rule!
+ $text =~ s/\n+.*\n.*\n *\f *\n.*\n.*\n+/\n/gm;
+
+ # Collapse multiple empty lines
+ $text =~ s/(^\s*\n){3,}/\n\n/mg;
+
+ # Split the string at "Syntax", to seperate the modules.
+ # This seems to be more robust than splitting at the section titles
+ # (which would be more correct), because sometimes the section title
+ # contains not only the routine name but extra stuff, for example
+ # `(VMS only)'. In this way, the part of the description before the
+ # "Syntax" paragraph becomes part of the string for the preceeding
+ # routine. However, this information is not used, so we can live
+ # with this problem.
+ @modules = split(/(?=^ *Syntax *$)/im,$text);
+ printf STDERR " %4d locations\n", $#modules;
+ $files_string .= sprintf(";; %6d syntax entries in file %s\n",
+ $#modules,$file);
+
+ if ($file =~ /datamine/i && $#modules == 0) {
+ # Unsuccessful datamine scan - add 5.2 entries by hand
+ # FIXME: This should only be necessary in IDL 5.3
+ local $debug = 1;
+ diag("Scanning $file did not produce any entries\n");
+ add_datamine_entries();
+ }
+ if ($file =~ /insight/i && $#modules == 0) {
+ # Unsuccessful insight scan - add 5.2 entries by hand
+ # FIXME: This should only be necessary in IDL 5.3
+ local $debug = 1;
+ diag("Scanning $file did not produce any entries\n");
+ add_insight_entries();
+ }
+
+ # UPDATE: Manual sections
+ # -----------------------
+ # The sections of each routine description that we know of and want to
+ # use. There might be more. This listing should be as complete as
+ # possible, mainly in order to have the "Syntax" section terminated
+ # where it should.
+ %sections = ("Syntax" => "call",
+ "Arguments" => "args",
+ "Return [vV]alue" => "return",
+ "Keywords?" => "kwds",
+ "Examples?" => "examples",
+ "Using [a-zA-Z0-9_]+" => "using",
+ "See Also" => "see",
+ "Graphics Keywords Accepted" => "graphics");
+
+ # Make a regexp matching these, making sure to save everything.
+ $section_re = ("(?=^ *(?:" . join('|',keys %sections) . ") *\$)");
+
+ SYNTAX:
+ foreach $txt (@modules) {
+ # Special check -- add fixup system variables if need be
+ if ($fixup && exists $fix{sysvars} && $txt=~/^System Variables\s*$/mi &&
+ !$fix{sysvars}{matched}) {
+ $fix{sysvars}{matched}=1;
+ # Insert the system variables just after the heading.
+ my $heading_off=length($`)+length($&);
+ my $rest=$';
+ # Add in all the sysvars, either as update, or not.
+ diag("Adding system variable: \n ".join(",",keys %{$fix{sysvars}}).
+ "\n");
+ foreach $sysvar (sort keys %{$fix{sysvars}}) {
+ next unless $sysvar=~/^\!/;
+ diag("Matching sysvar: $sysvar\n");
+ if ($rest=~/^\s*\Q$sysvar\E\s*$/m) {
+ my $sysv_off=length($`)+length($&);
+ @last=split(/(?:\n)/,$`);
+ @last=@last[$#last-10..$#last];
+ diag("$sysvar: Matched past: $&\n".join("\n",@last)."\n");
+ (my $ws)=substr($rest,$sysv_off)=~/\n+( +)/;
+ fixup_whitespace(\$fix{sysvars}{$sysvar},$ws);
+ substr($txt,$heading_off+$sysv_off,0)="\n$fix{sysvars}{$sysvar}";
+ } else { #Just stick it in after the "System Variables" heading.
+ substr($txt,$heading_off,0)=
+ " $sysvar\n$fix{sysvars}{$sysvar}\n";
+ }
+ $rest=substr($txt,$heading_off);
+ }
+ }
+
+ next SYNTAX unless $txt =~ /\A *Syntax/;
+ # Split into the standard sections
+ @parts = split(/$section_re/mo,$txt);
+ %parts = %region = ();
+ my $offset=0;
+ foreach $part (@parts) {
+ SECTION:
+ foreach $re (keys %sections) {
+ if ($part =~ /^ *$re *$/mi) {
+ $parts{$sections{$re}} = $part;
+ # save the byte offset into $txt and length for each section
+ $region{$sections{$re}} = [$offset,length($part)];
+ last SECTION;
+ }
+ }
+ $offset+=length($part);
+ }
+
+ # Clear a few variables which are used by deeper routines to return stuff
+ @rejects = ();
+ @complains = ();
+ @enter = ();
+
+ # Look at the Syntax section and get the info
+ # -------------------------------------------
+
+ $syntax = $parts{call};
+
+ # It would be good to have a better way to determine where the
+ # Syntax section ends. Looking at a change in indentation is a
+ # possibility, but since the indentation can change from page to
+ # page, it is not safe to actually use it.
+
+ # Apply the special matchers
+ &try_specials();
+
+ # See if there are reasons to reject or complain about this entry
+ if (@rejects) {
+ # Reject
+ $n_rejections += scalar(@rejects);
+ reject($parts{call},$file,@rejects);
+ next SYNTAX;
+ }
+ if (@complains) {
+ # Keep, but complain
+ $n_complains += scalar(@complains);
+ complain($parts{call},$file,@complains);
+ }
+
+ # Try to parse the entry
+ unless (parse_syntax($syntax)) {
+ # Make a note that this section could not be parsed and move on
+ # to the next syntax entry.
+ reject($parts{call},$file,("Could not be parsed"));
+ next SYNTAX;
+ }
+
+ # Make the cases correct.
+ if ($class) {
+ $class = case_name("class",$class);
+ $name = case_name("method",$name);
+ } else {
+ $name = case_name("routine",$name);
+ }
+
+ my $fname=make_full_name($class,$name);
+
+ # If the special matchers have not set @enter, do it here
+ $enter[0] = [$name,$type,$class,$call] unless @enter;
+
+ # See if any fix-ups match for this routine.
+ if ($fixup && exists $fix{$fname}) {
+ $fix{$fname}{matched}=1;
+ #Just put any notes at the beginning of the syntax entry.
+ if (exists $fix{$fname}{notes}) {
+ diag("FIXUP: $fname (notes)\n");
+ if (exists $parts{call}) {
+ $parts{call}="\n$fix{$fname}{notes}\n\n$parts{call}";
+ } else {
+ diag("Nowhere to put fixup notes for $fname.\n");
+ }
+ }
+
+ # Add keywords to keyword list, and parsed syntax
+ if (exists $fix{$fname}{kwds}) {
+ push @kwds,map(uc,keys %{$fix{$fname}{kwds}});
+ if (exists $parts{call}) {
+ $keylist="[, ".join("] [, ",map(uc,keys %{$fix{$fname}{kwds}}))."]";
+ # dumb approach: look for other keywords to put it with
+ $parts{call}=~
+ s~(\[[^/\]]*/[^\]]*\] | # [ /KEY ]
+ \[[^=\]]*=[^\]]*\]) # [ KEY=`val' ]
+ ~$keylist $1~sx ||
+ $parts{call}=~s/(${fname}\s*[,\(].*?)(\)|$)/$1$keylist$2/mi;
+ }
+ }
+
+ # Modify syntax section of help, and calling sequence(s)
+ if (exists $fix{$fname}{args} and exists $parts{call}) {
+ foreach $arg (sort keys %{$fix{$fname}{args}}) {
+ # Don't add it if it's already there...
+ # Watch our for args like Di, standing for D1 ... DN
+ (my $matcharg=$arg)=~s/([A-Z])i$/$1[0-9]/;
+ next if $enter[0][3]=~/(,|\() *$matcharg/i;
+ # Add arguments to the pre-built calling sequence...
+ foreach $a (@enter) {
+ diag("Adding to calling sequence\n<$$a[3]\n");
+ $$a[3]=~s/(\)|$)/,$arg$1/m;
+ diag(">$$a[3]\n");
+ }
+ # and to the help text itself, up front
+ $parts{call}=~s/($fname\s*[\(,]?)/$1$arg,/i;
+ }
+ }
+
+ # Modify specific keyword/argument help documentation sections
+ foreach $type (qw(kwds args)) {
+ next unless exists $fix{$fname}{$type};
+ diag("FIXUP: $fname (".scalar(keys %{$fix{$fname}{$type}}).
+ " $type -- ".join(",",keys(%{$fix{$fname}{$type}})).")\n");
+ foreach $keyarg (sort keys %{$fix{$fname}{$type}}) {
+ if (exists $parts{$type}) {
+ diag("Adding to $type in existing part\n");
+ diag("Checking for arg/key doc section: $keyarg (re: ^[ \t]*${keyarg}[ \t]*\$)\n");
+ ## See if documentation for the keyword/argument exists already....
+ if ($parts{$type}=~/^[ \t]*${keyarg}[ \t]*$/m) {
+ # Just prepend the new information to the existing section.
+ my $insertion_point=length($`)+length($&);
+ (my $ws)=($'=~m/\n+( +)/);
+ fixup_whitespace(\$fix{$fname}{$type}{$keyarg},$ws);
+ diag("Prepending to existing $type section\n");
+ substr($parts{$type},$insertion_point,0)=
+ "\n$fix{$fname}{$type}{$keyarg}";
+ } else {
+ ## It's a whole new entry.. add it first, after any heading.
+ diag("Adding entire new $keyarg section\n");
+ if ($parts{$type}=~
+ /^ *(?:Keywords?|Arguments) *$/m) {
+ my $insertion_point=length($`)+length($&);
+ (my $ws)=($'=~m/\n+( +)/);
+ diag("Adding using ==>$ws<==\n");
+ fixup_whitespace(\$fix{$fname}{$type}{$keyarg},$ws);
+ substr($parts{$type},$insertion_point,0)=
+ "\n$ws$keyarg\n$fix{$fname}{$type}{$keyarg}";
+ }
+ }
+ } else { # No such section part exists: make one up, with this entry.
+ diag("No $type section: making one.\n");
+ if (exists $parts{call}) {
+ $parts{call}.="\n ".($type eq "kwds"?"Keywords":"Arguments").
+ "\n $keyarg\n$fix{$fname}{$type}{$keyarg}\n\n";
+ }
+ }
+ }
+ }
+
+ # Update the actual raw text itself, if need be
+ my $extraoff=0;
+ foreach $part (sort {$region{$a}[0]<=>$region{$b}[0]}
+ qw(call args kwds)) {
+ next unless exists $parts{$part};
+ if (length($parts{$part})>$region{$part}[1]) {
+ substr($txt,$extraoff+$region{$part}[0],$region{$part}[1])=
+ $parts{$part};
+ $extraoff+=length($parts{$part}) - $region{$part}[1];
+ }
+ }
+ }
+
+ check_special_keywords($class,$name);
+
+ # Write a message for debugging output
+ diag(sprintf("%-20s %-15s %-20s with %3d keywords\n",
+ $type,$class,$name,scalar(@kwds)));
+
+ # Store the stuff.
+ foreach $a (@enter) {
+ my $name = $$a[0];
+ my $class = $$a[2];
+ my $type = $$a[1];
+ if ($ignore_name_re && $name =~ /$ignore_name_re/o) {
+ diag("Ignoring name $name because of -xname option\n");
+ $ignore_name_cnt++;
+ next;
+ }
+ if ($ignore_class_re && $class =~ /$ignore_class_re/o) {
+ diag("Ignoring name $name because of -xclass option\n");
+ $ignore_class_cnt++;
+ next;
+ }
+ # Store only if this is a routine info scan file
+ if ($isri) {
+ push @{$e{$class}{$type}{$name}{kwds}},@kwds;
+ push @{$e{$class}{$type}{$name}{Get}},@getkwds;
+ push @{$e{$class}{$type}{$name}{Set}},@setkwds;
+ $e{$class}{$type}{$name}{call} = $$a[3];
+ }
+ if ($has_special_keywords{Graphics}) {
+ push @{$extra_keyword_topics{lc($name)}},"graphics keywords";
+ }
+
+ # The threading keywords are documented in the CPU procedure.
+ if ($has_special_keywords{MultiThreading}) {
+ push @{$extra_keyword_topics{lc($name)}},"cpu";
+ # FIXME: When the threaded-routines are finally documented,
+ # the following will be unnecessary.
+ push @{$e{$class}{$type}{$name}{kwds}},
+ qw(TPOOL_MAX_ELTS TPOOL_MIN_ELTS TPOOL_NTHREADS);
+ }
+ }
+ } continue { # Always write the help text, even if skipped.
+ write_help($txt) if $isolh && !$nohelp;
+ }
+}
+close_help_file();
+write_topics_file() unless $nohelp;
+
+# We have all the information now in one huge array. A few things
+# still need to be fixed...
+
+# 1. The IDL manual lists for object methods GetProperty and
+# SetProperty only an incomplete list of keywords. Additional
+# keywords are documented under "Init" with a "Get" or "Set"
+# marker. These were collected during scan - here we put them into
+# the right space.
+
+foreach $class (keys %e) {
+ foreach $what ("Get","Set") {
+ $pname = case_name("method",$what."Property");
+ $iname = case_name("method","Init");
+ if (defined $e{$class}{fun}{$iname} && @{$e{$class}{fun}{$iname}{$what}}) {
+ push @{$e{$class}{pro}{$pname}{kwds}},@{$e{$class}{fun}{$iname}{$what}};
+ }
+ }
+}
+
+# 2. It is possible that some special matcher put in a request to add keywords
+# of one routine to another. Since now we know all keywords and all
+# routines, we can do so.
+
+foreach $add (@add_keywords) {
+ my ($name1,$type1,$class1,$name2,$type2,$class2,$nokeysref) = @$add[0..6];
+ my %nokeys = ();
+ foreach (@$nokeysref) {$nokeys{$_}++;}
+ my @kwds = @{$e{$class2}{$type2}{$name2}{kwds}};
+ foreach (@kwds) {
+ push @{$e{$class1}{$type1}{$name1}{kwds}},$_ unless $nokeys{$_};
+ }
+}
+
+# 3. Cleanup the keyword lists: make case correct, uniquify, and sort.
+foreach $class (keys %e) {
+ foreach $type ("pro","fun") {
+ foreach $name (keys %{$e{$class}{$type}}) {
+ @{$e{$class}{$type}{$name}{kwds}} =
+ fix_keywords(@{$e{$class}{$type}{$name}{kwds}});
+ }
+ }
+}
+
+# Make the Lisp reader strings and count the routines and keywords
+foreach $class (keys %e) {
+ foreach $type ("pro","fun") {
+ foreach $name (keys %{$e{$class}{$type}}) {
+ $n_routines_total++;
+ $call = $e{$class}{$type}{$name}{call};
+ $book = $e{$class}{$type}{$name}{book};
+ @kwds = @{$e{$class}{$type}{$name}{kwds}};
+ $n_keywords_total += scalar(@kwds);
+ $routines{$class}{$type}{$name} =
+ make_lisp_reader_string($name,$type,$class,$call,$book,@kwds);
+ }
+ }
+}
+
+# Write the lisp file
+# Also write some statistics to STDERR
+write_rinfo_header();
+print RINFO "(defconst idlwave-system-routines\n";
+print RINFO " '(\n";
+printf STDERR "\n Nr Class Npro Nfun Ntot Nkwd\n";
+printf STDERR "-------------------------------------------\n";
+$classcnt = -1;
+foreach $class (sort ignoring_case keys %routines) {
+ $npro = scalar(keys %{$routines{$class}{"pro"}});
+ $nfun = scalar(keys %{$routines{$class}{"fun"}});
+ $nkwd = 0;
+ foreach $type ("pro","fun") {
+ foreach $name (keys %{$e{$class}{$type}}) {
+ $nkwd += scalar @{$e{$class}{$type}{$name}{kwds}}
+ }
+ }
+ $nprotot += $npro;
+ $nfuntot += $nfun;
+ $nclass++;
+ printf STDERR "%3d %-17s %4d %4d %4d %5d\n",
+ ++$classcnt,$class,$npro,$nfun,$npro+$nfun,$nkwd;
+ foreach $type ("pro","fun") {
+ foreach $module (sort ignoring_case keys %{$routines{$class}{$type}}) {
+ $entry = $routines{$class}{$type}{$module};
+ print RINFO " $entry\n";
+ }
+ }
+}
+
+print STDERR "-" x 43,"\n";
+printf STDERR "Total %4d %4d %5d %5d\n",
+ $nprotot,$nfuntot,$nprotot+$nfuntot,$n_keywords_total;
+printf STDERR "Routines ignored due to -xname: %4d\n",$ignore_name_cnt
+ if $ignore_name_re;
+printf STDERR "Routines ignored due to -xclass: %4d\n",$ignore_class_cnt
+ if $ignore_class_re;
+print RINFO <<EOF;
+ )
+ "$n_routines_total builtin routines with $n_keywords_total keywords for IDL version $idlversion.")
+EOF
+
+talk_to_idl();
+write_sysvar_info();
+write_classtag_info();
+write_rinfo_footer();
+close RINFO;
+
+printf STDERR "Wrote file $rinfofile (%4d kBytes)\n", (-s $rinfofile)/1000.;
+
+# Print information about how often each special matcher matched.
+# Will only be visible in debugging mode.
+diag("SPECIAL MATCHERS: [m]atched, [s]uccess, [f]ailed---------------------\n");
+foreach $key (sort ignoring_case keys %specials) {
+ diag(sprintf("Special matcher %-35s m:s:f %3d %3d %3d\n",
+ $key,$special_matcnt{$key},$special_actcnt{$key},
+ $special_matcnt{$key}-$special_actcnt{$key}));
+}
+diag(sprintf("\nProblematic entries: %d rejected, %d complains.\n",$n_rejections,$n_complains));
+
+if ($fixup) {
+ diag("\nFIXUP RESULTS:\n".("="x60)."\n");
+ foreach $name (sort keys %fix) {
+ unless ($fix{$name}{matched}) {
+ diag(" No FIXUP match found for $name\n")
+ } else {
+# diag(" FIXED $name\n");
+ $fixcnt++
+ }
+ }
+ diag(sprintf(" Fixed %d/%d\n",$fixcnt,scalar(keys %fix)));
+}
+
+
+# ==========================================================================
+# ==========================================================================
+#
+# The subroutines
+
+sub usage {
+ # Print usage information
+ print STDERR <<EOF;
+usage: get_rinfo [-txt] [-debug] [-nowrap] [-emacs] [-path DIR]
+ [-fixup FIXUP_FILE] [-xname REGEXP] [-xclass REGEXP]
+ [-idl /path/to/idl]
+
+ get_rinfo -maketxt [-path DIR]
+EOF
+ exit(1);
+}
+
+sub diag {
+ # Write diagnosis to STDERR and to the LOG file if we are debugging.
+ my $msg = @_[0];
+ if ($debug) {
+ print STDERR $msg;
+ print LOG $msg;
+ }
+}
+
+sub reject {
+ # Write a message to the reject file.
+ my($string,$file,@reasons) = @_;
+ if ($debug) {
+ print REJECT (("-" x 100) . "\n") x 2;
+ print REJECT "File: $file\n";
+ foreach $reason (@reasons) {
+ print REJECT "Reason: $reason\n";
+ }
+ print REJECT (("- " x 30) . "\n");
+ print REJECT $string;
+ }
+}
+
+sub complain {
+ # Write a message to the reject file.
+ my($string,$file,@reasons) = @_;
+ if ($debug) {
+ print COMPLAIN (("-" x 100) . "\n") x 2;
+ print COMPLAIN "File: $file\n";
+ foreach $reason (@reasons) {
+ print COMPLAIN "Reason: $reason\n";
+ }
+ print COMPLAIN (("- " x 30) . "\n");
+ print COMPLAIN $string;
+ }
+}
+
+sub find_file {
+ # Find the file or a compressed version of it.
+ my($path,$file) = @_;
+ my $fullname = "$path/$file";
+ return $file if -e $fullname;
+ foreach $ext (keys %compress) {
+ if (-e $fullname.$ext) {
+ warn "Only found compressed ($ext) version of $file\n";
+ return $file.$ext;
+ }
+ }
+ die "No such file $file\n";
+}
+
+sub convert_pdf_to_text {
+ # Call pdftotext to convert a file.
+ my ($path,$file) = @_;
+ my $fullname = "$path/$file";
+ unless (-e $fullname) {
+ warn "No such file $fullname\n";
+ return 0;
+ }
+ print STDERR "Converting to ASCII: $fullname...\n";
+ system("$pdftotext $fullname") == 0
+ or warn "$pdftotext $fullname failed: $?\n";
+}
+
+sub read_manual_file {
+ # Return the entire manual file as a string.
+ my ($path,$name) = @_;
+ my $file = "$path/$name";
+ my $ext = ($file =~ m|(\.[^\./]+)$|)[0];
+ my $cmd;
+ my $decomp = $compress{$ext} || "cat";
+ local $/;
+
+ if ($file =~ m|\.txt\b[^/]*$|) {
+ $cmd = "$decomp $file|";
+ open IN,$cmd or die "Cannot read $file\n";
+ } elsif ($file =~ m|\.pdf\b[^/]*$|) {
+ if ($decomp eq "cat") {
+ $cmd = "$pdftotext $file -|";
+ open IN,$cmd or die "Cannot read $file\n";
+ } else {
+ die "Cannot read compressed pdf file $file\n";
+ }
+ } else {
+ die "Something is wrong here with $file.\n";
+ }
+
+ printf STDERR "Scanning file %-20s",$file."...";
+
+ # Put everything in one big string and return the string
+ undef $/;
+ $txt=scalar(<IN>);
+ close IN;
+ if ($? != 0) {die "Conversion process `$cmd' failed\n"}
+ $txt;
+}
+
+sub fix_keywords {
+ # Fix the case of keywords, sort and uniquify the list.
+ my @a;
+ @a = map { case_name("keyword",$_) } @_;
+ @a = make_unique(@a);
+ @a = sort ignoring_case @a;
+ @a;
+}
+
+sub case_name {
+ # Return $name in a unique case.
+ # The first time this function gets called, the default casification
+ # is determined and stored. Later calls with same or different case only
+ # return this initial value.
+ my ($type,$name) = @_;
+ my $lcname = lc($name);
+ if ($debug) {
+ $origcase{$type}{$lcname} = $name unless defined $origcase{$type}{$lcname};
+ if (defined $origcase{$type}{$lcname} &&
+ $name ne $origcase{$type}{$lcname}) {
+ diag("CASECHANGE $type: old $origcase{$type}{$lcname}, new $name\n");
+ }
+ }
+
+ if (defined $casedname{$type}{$lcname}) {
+ return $casedname{$type}{$lcname};
+ } else {
+ my $casedname;
+ if ($type eq "class" || $type eq "method") {
+ $casedname = $name;
+ } else {
+ $casedname = uc($name)
+ }
+ return $casedname{$type}{$lcname} = $casedname;
+ }
+}
+
+sub check_special_keywords {
+ my ($class,$name) = @_;
+ my $fullname = uc(make_full_name($class,$name));
+ foreach $special (keys %routines_with_special_keywords) {
+ if ( scalar(grep(/^$name$/,@{$routines_with_special_keywords{$special}}))
+ && !$has_special_keywords{$special}) {
+ $has_special_keywords{$special} = 1;
+ complain($parts{call},$file,
+ ("$special Keywords not linked to $special Keywords Section"))
+ }
+ }
+}
+
+sub make_full_name {
+ my ($class,$name) = @_;
+ ($class ? "$class" . "::" : "") . $name
+}
+
+sub make_unique {
+ # make an array unique.
+ my @new;
+ my %seen;
+ foreach (@_) {
+ push @new,$_ unless $seen{$_}++;
+ }
+ @new;
+}
+
+# for case-insensitive sorting..
+sub ignoring_case {lc($a) cmp lc($b)}
+
+sub textname {
+ # replace the pdf extension with .txt
+ my ($file) = @_;
+ $file =~ s/\.pdf$/.txt/;
+ $file;
+}
+
+sub file_basename {
+ # return the basename of a file
+ my $file = @_[0];
+ $file =~ s/\..*//;
+ $file;
+}
+
+sub balanced_parens {
+ # Check if all parenthesis are balanced
+ my $string = $_[0];
+ $string =~ tr/()[]{}//cd;
+ 1 while $string =~ s/\(\)|\[\]|\{\}//g;
+ $string eq "";
+}
+
+sub close_open_parens {
+ # Add all necessary closing parenthesis to the end if a string
+ my $rtn = $_[0];
+ my $string = $_[0];
+ $string =~ tr/()[]{}//cd;
+ 1 while $string =~ s/\(\)|\[\]|\{\}//g;
+ my $close = reverse($string);
+ $close =~ tr/([{/)]}/;
+ $rtn . $close;
+}
+
+sub make_lisp_reader_string {
+ # Make a string which will be correctly interpreted by the Emacs Lisp reader
+ # as a lisp list containing all needed information about a routine.
+ my ($name,$type,$class,$call,$book,@keywords) = @_;
+ my $entry;
+
+ # In the calling sequence we want `%s' instead of name and class.
+ # The calling sequence will later be used as format string to make
+ # a calling sequence with the correct version of class and name.
+ $call =~ s/^result/Result/;
+ if ($class) {
+ $call =~ s/(\[)($class)(:+)(\])($name)\b/$1%s$3$4%s$6/i;
+ } else {
+ $call =~ s/\b$name\b/%s/i;
+ }
+
+ # Now we make the string which can be parsed by the Lisp reader
+ # It looks like this:
+ # ("NAME" TYPE "CLASS" (system) "CALLING SEQUENCE" ("KWD1" "KWD2"...))
+ $entry = sprintf('(%-24s %3s %-19s', '"'.$name.'"', $type,
+ ($class eq "" ? "nil" : "\"$class\""));
+ $entry .= " (system) \"$call\"";
+ if (@keywords) {
+ $entry .= ' (("' . join('") ("',@keywords) . '"))';
+ } else {
+ $entry .= " nil";
+ }
+ $entry .= ')';
+
+ # Return the entry
+ $entry;
+}
+
+sub read_fixup {
+ # Read in fix-up file, add routines, with extra notes, arguments,
+ # and keywords, for inclusion into RInfo, Help, etc.
+ local $/;
+ undef $/;
+ my %types=("Notes"=>"notes", "Keywords" => "kwds", "Arguments"=>"args");
+ open FIXUP, "<$fixup" or die "Can't open fixup file $fixup.";
+ my ($null, %routines,%parts,%subparts);
+
+ ($null,%routines)=split(/^([A-Z][0-9A-Za-z:_ ]*\w)/m,<FIXUP>);
+ foreach $routine (keys %routines) {
+ # Handle System variables specially
+ if ($routine=~/System\s*Variables?/i) {
+ ($null,%parts)=split(/^ {5,}(\![A-Z0-9_]+)\s*$/m,$routines{$routine});
+ foreach (keys %parts) {
+ trim_and_mark_fixup(\$parts{$_});
+ $fix{sysvars}{$_}=$parts{$_};
+ }
+ next;
+ }
+
+ # Split entry into its parts
+ ($null,%parts)=split(/^ {2,}(Keywords|Arguments|Notes)\s*$/m,
+ $routines{$routine});
+ foreach $part (keys %parts) {
+ next unless exists $types{$part}; # Keep only known section types
+ if ($part eq "Notes") {
+ trim_and_mark_fixup(\$parts{$part});
+ $fix{$routine}{$types{$part}}=$parts{$part};
+ next;
+ }
+ # Separate each keyword or argument.
+ ($null,%subparts)=split(/^ {5,}([A-Za-z_0-9]+)\s*$/m,$parts{$part});
+ foreach (keys %subparts) {
+ trim_and_mark_fixup(\$subparts{$_});
+ $fix{$routine}{$types{$part}}{$_}=$subparts{$_};
+ }
+ }
+ }
+}
+
+# Fixup whitespace to fit in with existing region
+sub fixup_whitespace {
+ my ($txtref,$ws)=@_;
+ my @ws=($$txtref=~/^( +)/mg);
+ my $minws=9999;
+ map {$minws=length($_) if length($_)<$minws} @ws;
+ my $diff=length($ws)-$minws;
+ return if $diff==0;
+ if($diff>0) { #Add whitespace
+ my $newws=" "x$diff;
+ $$txtref=~s/^/$newws/mg;
+ } else {
+ $diff=-$diff;
+ $$txtref=~s/^ {$diff}//mg;
+ }
+}
+
+# Trim leading newlines, final whitespace, and wrap in <NEW></NEW>
+sub trim_and_mark_fixup {
+ my $txtref=shift;
+ $$txtref=~s/^\n+//s;
+ $$txtref=~s/\s+$//s;
+ $$txtref=~s/^( *)/$1<NEW>/;
+ $$txtref.="</NEW>";
+}
+
+sub try_specials {
+ # Try if any of the special matchers in %specials matches the current
+ # entry.
+ my($key,$sub);
+ foreach (keys %has_special_keywords) { $has_special_keywords{$_} = 0; }
+ SPECIAL:
+ foreach $key (sort keys %specials) {
+ $sub = $specials{$key};
+ $act = 0;
+ $rtn = &$sub();
+ if ($rtn) {
+ $special_matcnt{$key}++;
+ $special_actcnt{$key}++ if $act;
+ diag("Special $key matched. Count is $special_matcnt{$key}, $special_actcnt{$key}\n");
+ next SPECIAL if $rtn == 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+# UPDATE: Special matchers
+# ------------------------
+# The BEGIN block sets the array which contains special matchers. The
+# hash keys are just strings identifying the matcher. The values are
+# anonymous subroutines which work on the global variable $syntax
+# which contains the full syntax entry. To fix a problem, the matcher
+# may change the $syntax variable.
+# The return value of a matcher must be 0, 1, or 2
+# 0: The matcher did not match the entry.
+# 1: The matcher matched, but further matchers should be tried.
+# 2: The matcher did match and no further matchers should be tried.
+
+# Matching should mean that the matcher found the entry it was supposed to
+# find. When the entry is successfully changed, the matcher should also set
+# the variable $act. As typos get fixed by RSI, some matchers will still
+# match but not act - a sign that they can be removed from the %specials list.
+
+# Matchers of buggy entries should also push onto the @complains array
+# an explanation why the matched entry is buggy. The result can later
+# be mailed to RSI to make them fix the problem.
+
+# Some entries describe actually several routines, for example PRINT/PRINTF.
+# The matcher must then place entries into the @enter array for each routine.
+# Also in this case it will be necessary to tell the online help system
+# that help for this routine is under a different topic - this is done
+# with the @name_translations array - see the examples.
+
+# Finally, some routines do not list all the keywords, but just say
+# "accepts all keywords accepted by PLOT" or so. See the SURFACE matcher
+# for an example how to tell the system to add the corresponding keywords
+# to the routine description as well.
+
+# When this program is being run with the -d flag, at the end a list
+# will be shown which matcher was used how often.
+BEGIN {
+
+ # The following function prefixes the names of special matchers with
+ # numbers, to make sure they are called in the same sequence as
+ # specified here.
+ $cnt = 0;
+ sub sname {sprintf("%03d %s",++$cnt,$_[0])}
+
+ # The hash with the matchers
+ %specials =
+ (
+
+ # ------------------------------------------------------------------
+ # Some typos which occur globally in many entries ------------------
+ # ------------------------------------------------------------------
+
+ sname("DASH") =>
+ sub {
+ if ($syntax =~ /\255/) {
+ # A wrong character is being used as the dash.
+ $act = ($syntax =~ s/\255/-/g);
+ @complains,"Character \\255 used as dash (which is \\045)";
+ 1;
+ } else {0}
+ },
+
+ sname("UNBANACED PARENTHESIS") =>
+ sub {
+ if (! balanced_parens($syntax)) {
+ # A parenthesis is missing in the Syntax entry
+ push @complains, "Unbalanced parenthesis";
+ 1;
+ } else {0}
+ },
+
+ # ------------------------------------------------------------------
+ # The explanation of what the "Syntax" entry is must be rejected ---
+ # ------------------------------------------------------------------
+
+ sname("SYNTAX") =>
+ sub {
+ if ($syntax =~ /Syntax\s*The\s*syntax\s*section/i) {
+ # Ignore when Syntax is used to explain itself
+ $syntax = "";
+ $act = 1;
+ } else {0}
+ },
+
+ # ------------------------------------------------------------------
+ # C Functions ------------------------------------------------------
+ # ------------------------------------------------------------------
+
+ sname("C FUNCTION") =>
+ sub {
+ if ($syntax =~ /\A\s*Syntax\s*
+ (int |
+ char |
+ void |
+ IDL_MEMINT |
+ IDL_FUN_RET |
+ IDL_VPTR |
+ Client
+ )\b
+ /x) {
+ push @rejects, "Seems to be a C routine";
+ $syntax = "";
+ $act = 2;
+ } else {0}
+ },
+
+ # ------------------------------------------------------------------
+ # IDL statements ---------------------------------------------------
+ # ------------------------------------------------------------------
+
+ # UPDATE: Statement regexp
+ sname("IDL STATEMENT") =>
+ sub {
+ if ($syntax =~ /\A\s*Syntax\s+
+ (BEGIN \s+ statements |
+ CASE \s+ expression |
+ SWITCH \s+ expression |
+ BREAK \s+ |
+ CONTINUE \s+ |
+ COMMON \s+ Block_name |
+ COMPILE_OPT \s+ |
+ FORWARD_FUNCTION \s+ |
+ FOR \s+ variable |
+ FUNCTION \s+ Function_Name |
+ GOTO \s* , \s+ label |
+ IF \s+ expression |
+ PRO \s+ Procedure_Name |
+ REPEAT \s+ statement |
+ WHILE \s+ expression)
+ /ix) {
+ # Ignore
+ $syntax = "";
+ push @rejects, "IDL control stucture.";
+ $act = 2;
+ } else {0}
+ },
+
+ # ------------------------------------------------------------------
+ # Executive statements ---------------------------------------------
+ # ------------------------------------------------------------------
+
+ sname("IDL EXECUTIVE COMMAND") =>
+ sub {
+ if ($syntax =~ /\A *Syntax\s*\.[A-Z]+/) {
+ # Command starts with a dot. Ignore it.
+ $syntax = "";
+ push @rejects, "IDL executive command.";
+ $act = 2;
+ } else {0}
+ },
+
+ # ------------------------------------------------------------------
+ # Entries which must produce several rinfo list entries ------------
+ # ------------------------------------------------------------------
+
+ sname("CALL_METHOD") =>
+ sub {
+ if ($syntax =~ /CALL_METHOD.*\bor\b.*CALL_METHOD/s) {
+ # Can be called as function or method - make 2 entries.
+ $enter[0] = ["CALL_METHOD","pro","","CALL_METHOD, Name, ObjRef, [, P1, ..., Pn]"];
+ $enter[1] = ["CALL_METHOD","fun","","Result = CALL_METHOD, Name, ObjRef, [, P1, ..., Pn]"];
+ $act = 1;
+ } else {0}
+ },
+
+ sname("OPEN") =>
+ sub {
+ if ($syntax =~ /OPENR.*OPENW.*OPENU/s) {
+ # Make this 3 separate entries
+ $enter[0] = ["OPENR","pro","","OPENR, Unit, File [, Record_Length]"];
+ $enter[1] = ["OPENW","pro","","OPENW, Unit, File [, Record_Length]"];
+ $enter[2] = ["OPENU","pro","","OPENU, Unit, File [, Record_Length]"];
+ $name_translations{OPENR} = "OPEN";
+ $name_translations{OPENW} = "OPEN";
+ $name_translations{OPENU} = "OPEN";
+ $override_name="OPEN";
+ $act = 1;
+ } else {0}
+ },
+
+ sname("READ") =>
+ sub {
+ if ($syntax =~ /Syntax\s*READ, \[Prompt/si) {
+ # Make this 2 separate entries
+ $syntax =~ s/^[ \t]*READ,.*?\n//m;
+ $syntax =~ s/^[ \t]*READF,.*?\n/m/;
+ $enter[0] = ["READ","pro","","READ, [Prompt,] Var1, ..., Varn"];
+ $enter[1] = ["READF","pro","","READF, [Prompt,] Var1, ..., Varn"];
+ $name_translations{READ} = "READ/READF";
+ $name_translations{READF} = "READ/READF";
+ $act = 1;
+ } else {0}
+ },
+
+ sname("PRINT") =>
+ sub {
+ if ($syntax =~ /Syntax\s*PRINT \[, Expr/si) {
+ # Make this two separate entries
+ $syntax =~ s/^[ \t]*PRINT .*?\n//m;
+ $syntax =~ s/^[ \t]*PRINTF .*?\n/m/;
+ $enter[0] = ["PRINT","pro","","PRINT [, Expr1, ..., Exprn]"];
+ $enter[1] = ["PRINTF","pro","","PRINTF [, Unit, Expr1, ..., Exprn]"];
+ $name_translations{PRINT} = "PRINT/PRINTF";
+ $name_translations{PRINTF} = "PRINT/PRINTF";
+ $act = 1;
+ } else {0}
+ },
+
+ # ------------------------------------------------------------------
+ # INIT and CLEANUP -------------------------------------------------
+ # ------------------------------------------------------------------
+
+ sname("INIT & OBJ_NEW") =>
+ sub {
+ if ($syntax =~ /.*Init.*\bor\b.*OBJ_NEW\b/s) {
+ # Mention only "Init", not OBJ_NEW in calling sequence
+ $act = ($syntax =~ s/\bor\b.*OBJ_NEW.*subclass.*?\)//s);
+ push @complains,"Most syntax entries for INIT methods list OBJ_NEW before INIT";
+ 1;
+ } else {0}
+ },
+
+ sname("OBJ_NEW & INIT") =>
+ sub {
+ if ($syntax =~ /\s*Syntax.*OBJ_NEW(.*)\bor\s*(Result\b.*Init.*)/si) {
+ # Mention only "Init", not OBJ_NEW in calling sequence
+ $syntax = "$2 $1"; # space needed to make line indented
+ $syntax =~ s/\([^\)]*in\s+a\s+subclass[^\)]*Init[^\)]*\)//i;
+ $syntax =~ s/Note[\sa-zA-Z.]*brevity\.//i;
+ $syntax =~ s/\n[ \t\n]*\n/\n/;
+ $act = 1;
+ } else {0}
+ },
+
+ sname("INIT MISSING") =>
+ sub {
+# if ($syntax =~ /OBJ_NEW\(\s*[\`\']([a-zA-Z0-9_]+)[\`\'](.*)\(Only\s+in\s+a\s+sub/) { #`)
+ if ($syntax =~ /OBJ_NEW\(\s*[\`\']([a-zA-Z0-9_]+)[\`\'](.*?)(\(Only\s+in\s+a\s+sub|\))/s) { #`)
+ my $class = $1;
+ my $args = $2;
+ $args =~ s/^(\s*\[\s*),/$1/;
+ $syntax = "Result = Obj -> [${class}::]Init($args)";
+ push @complains,"INIT calling sequence missing";
+ $act = 1;
+ } else {0}
+ },
+
+ sname("OBJ_DESTROY & CLEANUP") =>
+ sub {
+ if ($syntax =~ /\s*Syntax.*OBJ_DESTROY,\s*Obj\s+or\s*(.*)/si) {
+ # Mention only "Cleanup" in calling sequence, not OBJ_DESTROY
+ $syntax = $1;
+ $syntax =~ s/\(\s*in\s+a\s+subclass[^)]*Cleanup[^)]*\)//i;
+ $act = 1;
+ } else {0}
+ },
+
+ sname("CLEANUP & OBJ_DESTROY") =>
+ sub {
+ if ($syntax =~ /.*Cleanup.*\bor\b.*OBJ_DESTROY\b/si) {
+ # Mention only "Cleanup" in calling sequence, not OBJ_DESTROY
+ push @complains,"Most syntax entries for CLEANUP methods list OBJ_DESTROY before CLEANUP";
+ $act = ($syntax =~ s/\bor\b.*OBJ_DESTROY.*subclass.*?\)//s);
+ 1;
+ } else {0}
+ },
+