diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..e69de29b diff --git a/BUGS b/BUGS new file mode 100644 index 00000000..2c3ecae1 --- /dev/null +++ b/BUGS @@ -0,0 +1,15 @@ + +- versao 0.9 usa fits2jpeg proprio, mas o uts-www ainda inclui o antigo + +- filtro e foco: ao trocar o filtro, o controlador deve procurar qual a configuracao de foco adequado, focar, testar (configuravel), e se nao houver configuracao de foco, deve preparar uma e salvar no banco de configuracoes + +- configuracoes: necessário.. e muito... + + +- FITS headers + + +- controle de temperatura +- controle de eixos individuais +- NSEW control + diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..5b6e7c66 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + 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) + + 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) year 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. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..e69de29b diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..e69de29b diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..60e04734 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,45 @@ +include $(top_srcdir)/rules.make + +SUBDIRS = src contrib + +EXTRA_DIST = rules.make + +#install-exec-hook: + +# @echo "Creating UTS services..." + +# @if [ @UTS_DISTRO@ = "suse" ]; then \ +# /sbin/insserv spmd; \ +# /sbin/insserv secd; \ +# /sbin/insserv camd; \ +# /sbin/insserv teld; \ +# /sbin/insserv sbigcam; \ +# fi; + +# @if [ @UTS_DISTRO@ = "redhat" ]; then \ +# /sbin/chkconfig --del sbigcam; /sbin/chkconfig --add sbigcam; /sbin/chkconfig --level 345 sbigcam on; \ +# /sbin/chkconfig --del spmd; /sbin/chkconfig --add spmd; /sbin/chkconfig --level 345 spmd on; \ +# /sbin/chkconfig --del secd; /sbin/chkconfig --add secd; /sbin/chkconfig --level 345 secd on; \ +# /sbin/chkconfig --del camd; /sbin/chkconfig --add camd; /sbin/chkconfig --level 345 camd on; \ +# /sbin/chkconfig --del teld; /sbin/chkconfig --add teld; /sbin/chkconfig --level 345 teld on; \ +# fi; + +# @if [ @UTS_DISTRO@ = "debian" ]; then \ +# /usr/sbin/update-rc.d sbigcam defaults 90; \ +# /usr/sbin/update-rc.d spmd defaults 91; \ +# /usr/sbin/update-rc.d secd defaults 92; \ +# /usr/sbin/update-rc.d teld defaults 93; \ +# /usr/sbin/update-rc.d camd defaults 94; \ +# fi; + +# @if [ ! -d /var/log/uts ]; then \ +# @echo "Creating log directory... ( /var/log/uts )"; \ +# mkdir /var/log/uts; \ +# fi; + +# @if [ -x @PYTHON@ ]; then \ +# cd $(top_srcdir)/src/python; \ +# @PYTHON@ setup.py build; \ +# @PYTHON@ setup.py install; \ +# cd $(top_srcdir); \ +# fi; diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..d36447af --- /dev/null +++ b/README @@ -0,0 +1,7 @@ + +sh autogen.sh +./configure --prefix=/usr +make +make install + +(make install deve ser rodado como root) diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000..f8b0c11f --- /dev/null +++ b/SConstruct @@ -0,0 +1,22 @@ +#! /usr/bin/python + +# +# Main Sconscruct file for UTS +# +# Copyright(c) 2006 - P. Henrique Silva +# + +env = Environment() + +Export('env') + +SConscript('src/base/SConscript') +SConscript('src/sec/SConscript') + +SConscript('src/instruments/cam/SConscript') +SConscript('src/instruments/tel/SConscript') +SConscript('src/instruments/order/SConscript') + +SConscript('src/tools/client/SConscript') + + diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..0c7fea3b --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,35 @@ +# UTS_CHECK_DISTRO + +AC_DEFUN([UTS_CHECK_DISTRO], [ + + AC_MSG_CHECKING([which distro we are running on]) + + if test -a /etc/SuSE-release; then + + distro=suse + initconfig=/etc/sysconfig + + elif test -a /etc/redhat-release; then + + distro=redhat + initconfig=/etc/sysconfig + + + elif test -a /etc/debian_version; then + + distro=debian + initconfig=/etc/default + + else + distro=suse + fi + + AC_SUBST([UTS_DISTRO], $distro) + AC_SUBST([UTS_INITCONFIG_DIR], $initconfig) + + AC_MSG_RESULT([$distro]) + +]) + + + diff --git a/autogen.sh b/autogen.sh new file mode 100644 index 00000000..a3a4e8a1 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,21 @@ + +which aclocal > /dev/null || "You don't have aclocal in your PATH." + +echo -n "Running "; +aclocal --version | grep aclocal +aclocal + +echo -n "Running "; +autoheader --version | grep autoheader +autoheader + +echo -n "Running "; +autoconf --version | grep autoconf +autoconf + +echo -n "Running "; +automake --version | grep automake +automake -a + +echo "Now, run ./configure, then, make and make install." + diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..89011fdc --- /dev/null +++ b/configure.ac @@ -0,0 +1,97 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([uts], [1.0RC1], [henrique@astro.ufsc.br] ) +AC_CONFIG_SRCDIR([src/sec/main.c]) +AM_INIT_AUTOMAKE + +AC_DEFINE([PROGRAM_URL], ["http://www.astro.ufsc.br/"], [ ]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_RANLIB + +# Python stuff +AM_PATH_PYTHON + +# which distro? +UTS_CHECK_DISTRO + +# Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([fcntl.h limits.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/socket.h sys/time.h termios.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_CONST +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM + +# Checks for library functions. +AC_FUNC_ERROR_AT_LINE +AC_REPLACE_FNMATCH +AC_FUNC_FORK +AC_FUNC_MALLOC +AC_FUNC_SELECT_ARGTYPES +AC_TYPE_SIGNAL +AC_CHECK_FUNCS([alarm floor memset pow select sqrt strcasecmp strchr strncasecmp strrchr]) + +# Checks for libraries. +AC_CHECK_LIB([m], [sin], [AC_DEFINE([HAVE_LM], [1], [Have C Math Library])]) +AC_CHECK_LIB([jpeg], [jpeg_set_quality], [AC_DEFINE([HAVE_JPEG], [1], [Have libjpeg])]) + +# outputs +AM_CONFIG_HEADER([config.h]) +AC_CONFIG_FILES([ + Makefile + src/Makefile + + src/drivers/Makefile + src/drivers/camfits.fake/Makefile + src/drivers/camfits.st4/Makefile + src/drivers/camfits.st7/Makefile + src/drivers/telgo.fake/Makefile + src/drivers/telgo.lx200/Makefile + src/drivers/telgo.paramount/Makefile + src/drivers/weather.wx200/Makefile + + src/sec/Makefile + + src/tools/Makefile + src/tools/client/Makefile + + src/config/Makefile + src/config/initscripts/Makefile + src/config/initscripts/redhat/Makefile + src/config/initscripts/redhat/uts + src/config/initscripts/suse/Makefile + src/config/initscripts/suse/uts + src/config/initscripts/debian/Makefile + src/config/initscripts/debian/uts + + src/python/Makefile + src/python/uts/Makefile + src/python/uts/core/Makefile + src/python/uts/instruments/Makefile + src/python/uts/interfaces/Makefile + + contrib/Makefile + contrib/bin/Makefile + contrib/bin/sbig_load_lpt + contrib/bin/sbig_load_usb + contrib/bin/sbig_load_usb_suse + contrib/fits2jpeg/Makefile + contrib/lib/Makefile]) + +AC_OUTPUT + + diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 00000000..a2c4cede --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = bin lib fits2jpeg + +EXTRA_DIST = include + diff --git a/contrib/bin/Makefile.am b/contrib/bin/Makefile.am new file mode 100644 index 00000000..5207ecd8 --- /dev/null +++ b/contrib/bin/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/rules.make + +dist_bin_SCRIPTS = Spm spmtable \ + sbig_load_usb sbig_load_usb_suse sbig_load_lpt \ + sbig_unload_lpt sbig_unload_usb diff --git a/contrib/bin/Spm b/contrib/bin/Spm new file mode 100755 index 00000000..d1dffdfc Binary files /dev/null and b/contrib/bin/Spm differ diff --git a/contrib/bin/sbig_load_lpt.in b/contrib/bin/sbig_load_lpt.in new file mode 100644 index 00000000..b317a2a7 --- /dev/null +++ b/contrib/bin/sbig_load_lpt.in @@ -0,0 +1,32 @@ +#!/bin/sh +#==================================================================== +# Insert 'sbiglptmod' module. +# This script was modified from A.Rubini: Linux Device Drivers, 1998 +# Written by: Jan Soldan +#==================================================================== +modules_path=@prefix@/lib +lpt_module="sbiglptmod" +lpt_device="sbiglpt" +#==================================================================== +# Character kernel driver: sbiglptmod +#==================================================================== +# remove old nodes +rm -f /dev/${lpt_device}[0-2] + +# insert new lpt module, use -f option +/sbin/insmod -f ${modules_path}/${lpt_module}.o || exit 1 + +# find free major number +major=`awk "\\$2==\"$lpt_device\" {print \\$1}" /proc/devices` + +# create new nodes for the three lpt devices +mknod /dev/${lpt_device}0 c $major 0 +mknod /dev/${lpt_device}1 c $major 1 +mknod /dev/${lpt_device}2 c $major 2 + +#set appropriate permissions +chmod 666 /dev/${lpt_device}[0-2] +#==================================================================== + + + diff --git a/contrib/bin/sbig_load_usb.in b/contrib/bin/sbig_load_usb.in new file mode 100644 index 00000000..0004fe73 --- /dev/null +++ b/contrib/bin/sbig_load_usb.in @@ -0,0 +1,37 @@ +#!/bin/sh +#==================================================================== +# Insert 'sbigusbmod' modules. +# This script was modified from A.Rubini: Linux Device Drivers, 1998 +# Written by: Jan Soldan +#==================================================================== +modules_path=@prefix@/lib +usb_module="sbigusbmod" +usb_device="sbigusb" + +SBIG_USB_MINOR_BASE=192 + +SBIG_USB_MINOR_0=192 +SBIG_USB_MINOR_1=193 +SBIG_USB_MINOR_2=194 +SBIG_USB_MINOR_3=195 +#==================================================================== +# USB kernel driver: sbigusbmod +#==================================================================== +# remove old nodes +rm -f /dev/${usb_device}[0-3] + +# insert new usb module, use -f option +/sbin/insmod -f ${modules_path}/${usb_module}.o || exit 1 + +# create new nodes for the three devices +mknod /dev/${usb_device}0 c 180 ${SBIG_USB_MINOR_0} +mknod /dev/${usb_device}1 c 180 ${SBIG_USB_MINOR_1} +mknod /dev/${usb_device}2 c 180 ${SBIG_USB_MINOR_2} +mknod /dev/${usb_device}3 c 180 ${SBIG_USB_MINOR_3} + +#set appropriate permissions +chmod 666 /dev/${usb_device}[0-3] +#==================================================================== + + + diff --git a/contrib/bin/sbig_load_usb_suse.in b/contrib/bin/sbig_load_usb_suse.in new file mode 100644 index 00000000..b4925abd --- /dev/null +++ b/contrib/bin/sbig_load_usb_suse.in @@ -0,0 +1,37 @@ +#!/bin/sh +#==================================================================== +# Insert 'sbigusbmod' modules. +# This script was modified from A.Rubini: Linux Device Drivers, 1998 +# Written by: Jan Soldan +#==================================================================== +modules_path=@prefix@/lib +usb_module="sbigusbmod_2_6" +usb_device="sbigusb" + +SBIG_USB_MINOR_BASE=192 + +SBIG_USB_MINOR_0=192 +SBIG_USB_MINOR_1=193 +SBIG_USB_MINOR_2=194 +SBIG_USB_MINOR_3=195 +#==================================================================== +# USB kernel driver: sbigusbmod +#==================================================================== +# remove old nodes +rm -f /dev/${usb_device}[0-3] + +# insert new usb module, use -f option +/sbin/insmod -f ${modules_path}/${usb_module}.ko || exit 1 + +# create new nodes for the three devices +mknod /dev/${usb_device}0 c 180 ${SBIG_USB_MINOR_0} +mknod /dev/${usb_device}1 c 180 ${SBIG_USB_MINOR_1} +mknod /dev/${usb_device}2 c 180 ${SBIG_USB_MINOR_2} +mknod /dev/${usb_device}3 c 180 ${SBIG_USB_MINOR_3} + +#set appropriate permissions +chmod 666 /dev/${usb_device}[0-3] +#==================================================================== + + + diff --git a/contrib/bin/sbig_unload_lpt b/contrib/bin/sbig_unload_lpt new file mode 100644 index 00000000..7268ef58 --- /dev/null +++ b/contrib/bin/sbig_unload_lpt @@ -0,0 +1,16 @@ +#!/bin/sh +#==================================================================== +# Remove 'sbiglptmod' module. +# Written by: Jan Soldan +#==================================================================== +lpt_module="sbiglptmod" +lpt_device="sbiglpt" +#==================================================================== +# Character kernel driver: sbiglptdrv +#==================================================================== +/sbin/rmmod ${lpt_module} + +# remove all three nodes +rm -f /dev/${lpt_device}[0-2] +#==================================================================== + diff --git a/contrib/bin/sbig_unload_usb b/contrib/bin/sbig_unload_usb new file mode 100644 index 00000000..82e79ae7 --- /dev/null +++ b/contrib/bin/sbig_unload_usb @@ -0,0 +1,17 @@ +#!/bin/sh +#==================================================================== +# Remove 'sbigusbmod' modules. +# Written by: Jan Soldan +#==================================================================== +usb_module="sbigusbmod" +usb_device="sbigusb" +#==================================================================== +# USB kernel driver: sbigusbdrv +#==================================================================== +/sbin/rmmod ${usb_module} + +# remove all three nodes +rm -f /dev/${usb_device}[0-3] +#==================================================================== + + diff --git a/contrib/bin/spmtable b/contrib/bin/spmtable new file mode 100755 index 00000000..e5686080 Binary files /dev/null and b/contrib/bin/spmtable differ diff --git a/contrib/fits2jpeg/FITS2jpeg.c b/contrib/fits2jpeg/FITS2jpeg.c new file mode 100644 index 00000000..b5e412dc --- /dev/null +++ b/contrib/fits2jpeg/FITS2jpeg.c @@ -0,0 +1,390 @@ +/*-----------------------------------------------------------------------*/ +/* Copyright (C) 1996 */ +/* Associated Universities, Inc. Washington DC, USA. */ +/* 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 Massachusetts Ave, Cambridge, */ +/* MA 02139, USA. */ +/* */ +/* Correspondence concerning FITS2jpeg should be addressed as follows: */ +/* Internet email: bcotton@nrao.edu. */ +/* Postal address: William Cotton */ +/* National Radio Astronomy Observatory */ +/* 520 Edgemont Road */ +/* Charlottesville, VA 22903-2475 USA */ +/*-----------------------------------------------------------------------*/ +#include "jpegsubs.h" +#include "fitsio.h" +#include +#include +#include +#include +#include + +/* global variables */ +char *infile; /* input FITS file name */ +char *outfile; /* output jpeg file name */ +float *DataArray=NULL; /* image data as 1-D array */ +float fblank; /* undefined pixel value */ +float vmax,vmin; /* Max. and Min. values to be displayed */ +int NonLinear; /* if true then nonlinear transfer fn. */ +int quality; /* jpeg quality factor [1-100] */ +int GotMaxMin; /* if true then already have max/min to display */ +int naxis; /* number of axes */ +long inaxes[7]; /* dimensions of axes */ +fitsfile *fptr; /* cfitsio i/o file pointer */ + +/* internal prototypes */ +void jpgfin (int argc, char **argv, int *ierr); +void Usage(void); +void jpegim (int *ierr); +void gethed (int *ierr); +void gtinfo (int *ierr); +void getdat (int *ierr); +int get_histogram_region(float* img, int size, float start, float end, int* startValue, int* endValue); +/*----------------------------------------------------------------------- */ +/* Program to convert a FITS image to a jpeg file */ +/*----------------------------------------------------------------------- */ +int main ( int argc, char **argv ) +{ + int iret; +/* Startup */ + jpgfin (argc, argv, &iret); + if (iret!=0) return iret; +/* Convert to jpeg */ + jpegim(&iret); + return iret; +} /* end of main */ + +void jpgfin (int argc, char **argv, int *ierr) +/*----------------------------------------------------------------------- */ +/* Parse control info from command line */ +/* Input: */ +/* argc Number of arguments from command line */ +/* argv Array of strings from command line */ +/* Output: */ +/* ierr Error code: 0 => ok */ +/* infile FITS file name */ +/* NonLinear True if nonlinear function desired. */ +/* vmax, vmin Max and min values(image units) to be displayed */ +/*----------------------------------------------------------------------- */ +{ + int ax; + char *arg; + +/* copyright to get it into the executable */ +char *copyright="Copyright 1996 NRAO/AUI"; + + /* Set undefined value */ + fblank = 1.234567e25; + vmax = fblank; + vmin = fblank; + infile = NULL; + outfile = NULL; + NonLinear = 0; + quality = 100; + + if (argc<=1) Usage(); /* must have arguments */ +/* parse command line */ + for (ax=1; ax ok */ +/*----------------------------------------------------------------------- */ +{ + int iptr, nrow, lrow, irow, i, iln, nx, ny, donon, lname; + + *ierr = 0; +/* Open */ + if ( fits_open_file(&fptr, infile, READONLY, ierr) ) { + fprintf(stderr,"ERROR opening input FITS file %s \n", infile); + *ierr = 1; + return; + } +/* Get header information */ + gethed (ierr); + if (*ierr!=0) { + fprintf(stderr,"ERROR getting FITS file header info \n"); + return; + } +/* Read FITS image */ + getdat (ierr); + if (*ierr!=0) { + fprintf(stderr,"ERROR getting image pixel values \n"); + return; + } +/* Close FITS file */ + fits_close_file (fptr, ierr); +/* Initialize output */ + nx = inaxes[0]; + ny = inaxes[1]; + jpgini (outfile, nx, ny, vmax, vmin, NonLinear, quality, ierr); + if (*ierr!=0) { + fprintf(stderr,"error %d initializing jpeg output \n", + *ierr); + return; + } + +/* Write, loop over image */ +/* write backwards to get right side up */ + lrow = inaxes[0]; + nrow = inaxes[1]; + iptr = (nrow-1) * lrow; + irow = nrow; + for (i=0;i ok */ +/*----------------------------------------------------------------------- */ +{ + int bitpix, simple, extend, maxdim=7; + long pcount, gcount; + + fits_read_imghdr (fptr, maxdim, &simple, &bitpix, &naxis, inaxes, + &pcount, &gcount, &extend, ierr); + if (*ierr!=0) { + fprintf(stderr,"fits_read_imghdr error %d reading FITS header \n", *ierr); + return; + } +/* Max/min if necessary */ + gtinfo (ierr); + if (*ierr!=0) { + fprintf(stderr,"gtinfo error %d reading FITS header \n", *ierr); + return; + } +} /* end gethed */ + +void gtinfo (int *ierr) +/*----------------------------------------------------------------------- */ +/* Read FITS header info from INUNIT and save in common */ +/* Inputs in common: */ +/* fptr Input FITS fitsio unit number */ +/* GotMaxMin If true already have Max and Min values */ +/* Output: */ +/* ierr Error code: 0 => ok */ +/* Output in common: */ +/* vmax Maximum image value */ +/* vmin Minimum image value */ +/* GotMaxMin If true already have Max and Min values */ +/*----------------------------------------------------------------------- */ +{ + char commnt[81]; + float tmax=0.0, tmin=0.0; + int GotMax=0, GotMin=0; +/* Read keyword values */ + fits_read_key_flt (fptr, "DATAMAX", &tmax, commnt, ierr); + GotMax = (*ierr==0); + if (*ierr==202) *ierr = 0; + fits_read_key_flt (fptr, "DATAMIN", &tmin, commnt, ierr); + GotMin = (*ierr==0); + if (*ierr==202) *ierr = 0; + if (*ierr!=0) { + fprintf(stderr,"ERROR reading input FITS header \n"); + return; + } + if (GotMaxMin) { +/* Don't put vmax,vmin outside */ +/* of actual range */ + if (GotMin && (vmintmax)) vmax = tmax; + } + else if (GotMin && GotMax) { + GotMaxMin = 1; + vmax = tmax; + vmin = tmin; + } +*ierr = 0; /* OK */ +} /* end gtinfo */ + +void getdat (int *ierr) +/*----------------------------------------------------------------------- */ +/* Read FITS file and determine max. and min. values */ +/* Inputs in common: */ +/* fptr Input FITS fitsio unit number */ +/* Output: */ +/* ierr I Error code: 0 => ok */ +/* Output in common: */ +/* vmax Maximum image value */ +/* vmin Minimum image value */ +/* GotMaxMin If true already have Max and Min values */ +/*----------------------------------------------------------------------- */ +{ + long size,incs[7]={1,1,1,1,1,1,1},blc[7]={1,1,1,1,1,1,1},trc[7]; + int group=0, i, anyf; + float tmax,tmin; + int s_max, s_min; + +/* How big is the array? */ + size = inaxes[0]; + size = size * inaxes[1]; +/* allocate floating array */ + if (DataArray) free(DataArray); /* free any old allocations */ + DataArray = (float*)malloc(sizeof(float)*size); + if (!DataArray) { /* cannot allocate */ + fprintf(stderr,"Cannot allocate memory for image array \n"); + *ierr = 1; + return; + } +/* Take all of image */ + trc[0] = inaxes[0]; + trc[1] = inaxes[1]; +/* but only first plane */ + for (i=2;itmax) tmax = DataArray[i]; */ +/* if (DataArray[i]tmax) vmax = tmax; */ +/* } */ +/* else { /\* set to full range *\/ */ +/* GotMaxMin = 1; */ +/* vmax = tmax; */ +/* vmin = tmin; */ +/* } */ +} /* end getdat */ + +int get_histogram_region(float* img, int size, float start, float end, int* startValue, int* endValue) { + + int startTarget, endTarget; + int default_max = (2<<15) -1; + int sum = 0; + int i; + int* histo = (int *)calloc(default_max, sizeof(int)); + + startTarget = (start/100) * size; + endTarget = (end/100) * size; + + for (i = 0; i < size; i++) { + histo[(int)truncf(img[i])]++; + } + +/* printf("%d %f %f %d %d\n", size, start, end, startTarget, endTarget); */ + +/* for (i = 0; i < default_max; i++) { */ +/* printf("%d\n", histo[i]); */ +/* } */ + + for (i = 0; i < default_max; i++) { + + sum += histo[i]; + + if ( (sum < startTarget) && (startTarget < (sum + histo[i+1])) ) + *startValue = i; + + if ( (sum < endTarget) && (endTarget < (sum + histo[i+1])) ) + *endValue = i; + + } + + return 1; + +} diff --git a/contrib/fits2jpeg/LICENSE b/contrib/fits2jpeg/LICENSE new file mode 100644 index 00000000..48f57956 --- /dev/null +++ b/contrib/fits2jpeg/LICENSE @@ -0,0 +1,343 @@ + 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 + + 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. + diff --git a/contrib/fits2jpeg/Makefile.am b/contrib/fits2jpeg/Makefile.am new file mode 100644 index 00000000..741bed95 --- /dev/null +++ b/contrib/fits2jpeg/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = fits2jpeg + +fits2jpeg_SOURCES = FITS2jpeg.c jpegsubs.c jpegsubs.h +fits2jpeg_LDADD = -lm -lcfitsio -ljpeg diff --git a/contrib/fits2jpeg/jpegsubs.c b/contrib/fits2jpeg/jpegsubs.c new file mode 100644 index 00000000..1533ea1a --- /dev/null +++ b/contrib/fits2jpeg/jpegsubs.c @@ -0,0 +1,216 @@ +/*--------------------------------------------------------------------*/ +/*; Copyright (C) 1996 */ +/*; Associated Universities, Inc. Washington DC, USA. */ +/*; */ +/*; 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 Massachusetts Ave, Cambridge, */ +/*; MA 02139, USA. */ +/*; */ +/*; Correspondence should be addressed as follows: */ +/*; Internet email: bcotton@nrao.edu. */ +/*; Postal address: William Cotton */ +/*; National Radio Astronomy Observatory */ +/*; 520 Edgemont Road */ +/*; Charlottesville, VA 22903-2475 USA */ +/*--------------------------------------------------------------------*/ +#include "jpegsubs.h" + +/* JPEG compress routines */ + +/* global values for jpeg I/O; allows 1 at a time */ +int nx, ny; /* size of image */ +int nonlinear; /* if true use nonlinear mapping */ +float vmax, vmin; /* max and min unscaled values */ +char *name=NULL; /* name of output jpeg file */ +JSAMPROW idata=NULL; /* buffer for scaled version of row */ +FILE *outfile=NULL; /* output jpeg stream pointer */ +struct jpeg_compress_struct cinfo; /* jpeg compress structure */ +struct jpeg_error_mgr jerr; /* jpeg error handler structure */ +JSAMPROW row_pointer[1]; /* pointer to a single row */ + + +void jpgini (char *iname, int inx, int iny, float ivmax, float ivmin, + int nonLin, int quality, int *ierr) +/*--------------------------------------------------------------------*/ +/* Initializes i/o to jpeg output routines */ +/* Inputs: */ +/* iname Name of output file */ +/* ilname Length of name */ +/* inx number of columns in image */ +/* iny Number of rows in image */ +/* ivmax Maximum image value (values larger get this value) */ +/* ivmin Minimum image value (values smaller get this value) */ +/* nonLin if > 0.0 use non linear function */ +/* quality jpeg quality factor [1-100] */ +/* Output: */ +/* ierr 0.0 => OK */ +/*--------------------------------------------------------------------*/ +{ + int lname, i; + + /* get values */ + nx = inx; + ny = iny; + lname = strlen(iname); + vmax = ivmax; + vmin = ivmin; + nonlinear = nonLin; + + /* file name */ + if (name) free(name); + name = (char*)malloc(lname+1); + if (name == NULL) { + fprintf(stderr, "can't allocate file name"); + *ierr = 1; /* set error return */ + return; /* failed */ + } + for (i=0;i100) quality = 100; + jpeg_set_quality (&cinfo, quality, TRUE); /* set quality factor */ + + /* initialize compression */ + jpeg_start_compress(&cinfo, TRUE); + + *ierr = 0; /* OK */ +} /* end of jpgini */ + +void jpgwri (float *data, float blank, int *ierr) +/*--------------------------------------------------------------------*/ +/* Write row of a jpeg image, floating values scaled and converted */ +/* as specified to jpgini. Grayscale only. */ +/* Only does gray scale at present */ +/* Pure black reserved for blanked pixels. */ +/* Inputs: */ +/* data floating values */ +/* blank value of undefined pixel */ +/* Output: */ +/* ierr 0.0 => OK */ +/*--------------------------------------------------------------------*/ +{ + int i, icol, maxcolor=255; + float val, irange, c1, c2; + double arg; + + /* scaling parameters */ + /* + irange = vmax - vmin; + if (fabs(irange)<1.0e-25) + irange = 1.0; + else + irange = 1.0 / irange; + + c1 = (maxcolor - 1.0) * irange; + c2 = vmin * c1 - 0.5; + */ + + // get vmax and vmin from image histogram + + if(nonlinear) { + c1 = maxcolor / log10(vmax - vmin + 1.0); + } else { + c1 = maxcolor / (vmax - vmin + 1.0); + } + + /* convert row */ + for (i=0;ivmax) val=vmax; + if (nonlinear) {/* nonlinear */ + icol = log10(val - vmin + 1) * c1; + //arg = ((val-vmin) * irange); + //icol = 0.5 + ((maxcolor-1.0) * log10(arg)); + } + else /* Linear */ + icol = (val - vmin + 1) * c1; + //icol = c1 * val - c2; + + if (icol<1) icol = 1; /* minimum color = 1 */ + if (icol>=maxcolor) icol = maxcolor-1; + idata[i] = GETJSAMPLE(icol); + } + } /* end loop over row pixels */ + + row_pointer[0] = (JSAMPROW)idata; /* set row pointer */ + + /* compress/write row */ + jpeg_write_scanlines(&cinfo, row_pointer, 1); + + *ierr = 0; /* OK */ +} /* end of jpgwri */ + +void jpgclo (int *ierr) +/*--------------------------------------------------------------------*/ +/* Close/flush i/o to jpeg image file */ +/* Output: */ +/* ierr 0.0 => OK */ +/*--------------------------------------------------------------------*/ +{ + /* finish compression/ flush output */ + jpeg_finish_compress(&cinfo); + + /* close output file */ + if (outfile) fclose(outfile); + outfile = NULL; + + jpeg_destroy_compress(&cinfo); /* delete jpeg structures */ + + /* delete file structures: file name */ + if (name) free(name); + /* row buffer */ + if (idata) free(idata); + + *ierr = 0; /* OK */ +} /* end of jpgclo */ + diff --git a/contrib/fits2jpeg/jpegsubs.h b/contrib/fits2jpeg/jpegsubs.h new file mode 100644 index 00000000..41f0e733 --- /dev/null +++ b/contrib/fits2jpeg/jpegsubs.h @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------*/ +/*; Copyright (C) 1996 */ +/*; Associated Universities, Inc. Washington DC, USA. */ +/*; */ +/*; 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 Massachusetts Ave, Cambridge, */ +/*; MA 02139, USA. */ +/*; */ +/*; Correspondence should be addressed as follows: */ +/*; Internet email: bcotton@nrao.edu. */ +/*; Postal address: William Cotton */ +/*; National Radio Astronomy Observatory */ +/*; 520 Edgemont Road */ +/*; Charlottesville, VA 22903-2475 USA */ +/*--------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include "jpeglib.h" +#ifndef JPEGSUBS_H +#define JPEGSUBS_H + +/* includes for JPEG routines */ + +/* initialize jpeg output file */ +void jpgini (char *name, int nx, int ny, float vmax, float vmin, + int nonLin, int quality, int *ierr); +/* write row in jpeg image */ +void jpgwri (float *data, float blank, int *ierr); +/* close jpeg image */ +void jpgclo (int *ierr); + +#endif /* JPEGSUBS_H */ diff --git a/contrib/include/Makefile.am b/contrib/include/Makefile.am new file mode 100644 index 00000000..05eac403 --- /dev/null +++ b/contrib/include/Makefile.am @@ -0,0 +1,3 @@ +EXTRA_DIST = sbigcam.h drvrsmem.h fitsio.h rdcolor.h setproto.h xstdlib.h \ + csbigimg.h fitsio2.h longnam.h sbigudrv.h sockets.h xtdio.h + diff --git a/contrib/include/csbigcam.h b/contrib/include/csbigcam.h new file mode 100644 index 00000000..264f8aea --- /dev/null +++ b/contrib/include/csbigcam.h @@ -0,0 +1,113 @@ +/* + + csbigcam.h - Contains the interface to the csbigcam + camera class + + 1. This software (c)2004 Santa Barbara Instrument Group. + 2. This free software is provided as an example of how + to communicate with SBIG cameras. It is provided AS-IS + without any guarantees by SBIG of suitability for a + particular purpose and without any guarantee to be + bug-free. If you use it you agree to these terms and + agree to do so at your own risk. + 3. Any distribution of this source code to include these + terms. + +*/ +#ifndef _CSBIGCAM_ +#define _CSBIGCAM_ + +#ifndef _PARDRV_ + #include "sbigudrv.h" +#endif + +#ifndef _CSBIGIMG_ + #include "csbigimg.h" +#endif + +#include +using namespace std; + +typedef enum {RELAY_XPLUS, RELAY_XMINUS, RELAY_YPLUS, RELAY_YMINUS } CAMERA_RELAY; +typedef enum {SBDF_LIGHT_ONLY, SBDF_DARK_ONLY, SBDF_DARK_ALSO } SBIG_DARK_FRAME; + +class CSBIGCam { +private: + PAR_ERROR m_eLastError; + PAR_COMMAND m_eLastCommand; + short m_nDrvHandle; + CAMERA_TYPE m_eCameraType; + CCD_REQUEST m_eActiveCCD; + double m_dExposureTime; + unsigned short m_uReadoutMode; + ABG_STATE7 m_eABGState; + +public: + // Constructors/Destructors + CSBIGCam(); + CSBIGCam(OpenDeviceParams odp); + CSBIGCam(SBIG_DEVICE_TYPE dev); + ~CSBIGCam(); + void Init(); + + // Error Reporting Routines + PAR_ERROR GetError(); + string GetErrorString(); + string GetErrorString(PAR_ERROR err); + PAR_COMMAND GetCommand(); + + // Accessor Functions + double GetExposureTime(void) { return m_dExposureTime; } + void SetExposureTime(double exp) { m_dExposureTime = exp; } + CCD_REQUEST GetActiveCCD(void) { return m_eActiveCCD; } + void SetActiveCCD(CCD_REQUEST ccd) { m_eActiveCCD = ccd; } + unsigned short GetReadoutMode(void) { return m_uReadoutMode; } + void SetReadoutMode(unsigned short rm) { m_uReadoutMode = rm; } + CAMERA_TYPE GetCameraType(void) { return m_eCameraType; } + ABG_STATE7 GetABGState(void) { return m_eABGState; } + void SetABGState(ABG_STATE7 abgState) { m_eABGState = abgState; } + + // Driver/Device Routines + PAR_ERROR OpenDriver(); + PAR_ERROR CloseDriver(); + PAR_ERROR OpenDevice(OpenDeviceParams odp); + PAR_ERROR CloseDevice(); + PAR_ERROR GetDriverInfo(DRIVER_REQUEST request, GetDriverInfoResults0 &gdir); + + // High-Level Exposure Related Commands + PAR_ERROR GrabImage(CSBIGImg *pImg, SBIG_DARK_FRAME dark); + + // Low-Level Exposure Related Commands + PAR_ERROR StartExposure(SHUTTER_COMMAND shutterState); + PAR_ERROR EndExposure(void); + PAR_ERROR IsExposureComplete(MY_LOGICAL &complete); + PAR_ERROR StartReadout(StartReadoutParams srp); + PAR_ERROR EndReadout(void); + PAR_ERROR ReadoutLine(ReadoutLineParams rlp, MY_LOGICAL darkSubtract, unsigned short *dest); + PAR_ERROR DumpLines(unsigned short noLines); + + //Temperature Related Commands + PAR_ERROR GetCCDTemperature(double &ccdTemp); + PAR_ERROR SetTemperatureRegulation(MY_LOGICAL enable, double setpoint); + PAR_ERROR QueryTemperatureStatus(MY_LOGICAL &enabled, double &ccdTemp, + double &setpointTemp, double &percentTE); + + // Control Related Commands + PAR_ERROR ActivateRelay(CAMERA_RELAY relay, double time); + PAR_ERROR AOTipTilt(AOTipTiltParams attp); + PAR_ERROR CFWCommand(CFWParams cfwp, CFWResults &cfwr); + + // General Purpose Commands + PAR_ERROR EstablishLink(void); + string GetCameraTypeString(void); + + // Utility functions + MY_LOGICAL CheckLink(void); + unsigned short DegreesCToAD(double degC, MY_LOGICAL ccd = TRUE); + double ADToDegreesC(unsigned short ad, MY_LOGICAL ccd = TRUE); + + // Allows access directly to driver + PAR_ERROR SBIGUnivDrvCommand(short command, void *Params, void *Results); +}; + +#endif /* #ifndef _CSBIGCAM_ */ diff --git a/contrib/include/csbigimg.h b/contrib/include/csbigimg.h new file mode 100644 index 00000000..3d7bf720 --- /dev/null +++ b/contrib/include/csbigimg.h @@ -0,0 +1,157 @@ +/* + + csbigimg.h - Contains the definition of the interface to + the SBIG Image Class + + 1. This software (c)2004 Santa Barbara Instrument Group. + 2. This free software is provided as an example of how + to communicate with SBIG cameras. It is provided AS-IS + without any guarantees by SBIG of suitability for a + particular purpose and without any guarantee to be + bug-free. If you use it you agree to these terms and + agree to do so at your own risk. + 3. Any distribution of this source code to include these + terms. + +*/ +#ifndef _CSBIGIMG_ +#define _CSBIGIMG_ + +#ifndef _PARDRV_ + #include "sbigudrv.h" +#endif + +#include +#include +using namespace std; + +/* + + Exposure State Field Defines + +*/ +#define ES_ABG_MASK 0x0003 +#define ES_ABG_UNKNOWN 0x0000 +#define ES_ABG_LOW 0x0001 +#define ES_ABG_CLOCKED 0x0002 +#define ES_ABG_MID 0x0003 + +#define ES_ABG_RATE_MASK 0x00C0 +#define ES_ABG_RATE_FIXED 0x0000 +#define ES_ABG_RATE_LOW 0x0040 +#define ES_ABG_RATE_MED 0x0080 +#define ES_ABG_RATE_HI 0x00C0 + +#define ES_DCS_MASK 0x000c +#define ES_DCS_UNKNOWN 0x0000 +#define ES_DCS_ENABLED 0x0004 +#define ES_DCS_DISABLED 0x0008 + +#define ES_DCR_MASK 0x0030 +#define ES_DCR_UNKNOWN 0x0000 +#define ES_DCR_ENABLED 0x0010 +#define ES_DCR_DISABLED 0x0020 + +#define ES_AUTOBIAS_MASK 0x0100 +#define ES_AUTOBIAS_ENABLED 0x0100 +#define ES_AUTOBIAS_DISABLED 0x0000 + + +typedef enum { SBIF_COMPRESSED, SBIF_UNCOMPRESSED } SBIG_IMAGE_FORMAT; +typedef enum {SBFE_NO_ERROR, SBFE_OPEN_ERROR, SBRE_CLOSE_ERROR, SBFE_READ_ERROR, SBFE_WRITE_ERROR, + SBFE_FORMAT_ERROR, SBFE_MEMORY_ERROR } SBIG_FILE_ERROR; + +class CSBIGImg { +private: + int m_nHeight, m_nWidth; // image size in pixels + unsigned short *m_pImage; // pointer to image data + time_t m_imageStartTime; // time that light exposure started + double m_dCCDTemperature; // CCD Temp at start of exposure + double m_dExposureTime; // Exposure time in seconds + double m_dTrackExposure; // Exposure when tracking + double m_dEachExposure; // Snapshot time in seconds + double m_dFocalLength; // Lens/Telescope Focal Length in inches + double m_dApertureArea; // Lens/Telescope Aperture Are in Sq-Inches + double m_dResponseFactor; // Magnitude Calibration Factor + double m_dPixelHeight, m_dPixelWidth; // Pixel Dimensions in mm + double m_dEGain; // Electronic Gain, e-/ADU + unsigned short m_uBackground, m_uRange; // Display Background and Range + unsigned short m_uNumberExposures; // Number of exposures co-added + unsigned short m_uSaturationLevel; // Pixels at this level are saturated + unsigned short m_uPedestal; // Image Pedestal + unsigned short m_uExposureState; // Exposure State + unsigned short m_uReadoutMode; // Camera Readout Mode use to acquire image + string m_cImageNote; // Note attached to image + string m_cObserver; // Observer name + string m_cHistory; // Image History string of modification chars + string m_cFilter; // Filter name imaged through + string m_cSoftware; // Software App Name and Version + string m_cCameraModel; // Model of camera used to acquire image + +public: + /* Constructors/Destructor */ + CSBIGImg(); + CSBIGImg(int height, int width); + ~CSBIGImg(); + void Init(); + + /* Accessor Functions */ + int GetHeight() {return m_nHeight;} + int GetWidth() {return m_nWidth;} + unsigned short *GetImagePointer() {return m_pImage;} + void SetImageStartTime(time_t startTime){m_imageStartTime = startTime;} + time_t GetImageStartTime(void) {return m_imageStartTime;} + void SetCCDTemperature(double temp) {m_dCCDTemperature = temp;} + double GetCCDTemperature(void) {return m_dCCDTemperature;} + void SetExposureTime(double exp) {m_dExposureTime = exp;} + double GetExposureTime(void) {return m_dExposureTime;} + void SetEachExposure(double exp) {m_dEachExposure = exp;} + double GetEachExposure(void) {return m_dEachExposure;} + void SetFocalLength(double fl) {m_dFocalLength = fl;} + double GetFocalLength(void) {return m_dFocalLength;} + void SetApertureArea(double ap) {m_dApertureArea = ap;} + double GetApertureArea(void) {return m_dApertureArea;} + void SetResponseFactor(double resp) {m_dResponseFactor = resp;} + double GetResponseFactor(void) {return m_dResponseFactor;} + void SetPixelHeight(double ht) {m_dPixelHeight = ht;} + double GetPixelHeight(void) {return m_dPixelHeight;} + void SetPixelWidth(double wd) {m_dPixelWidth = wd;} + double GetPixelWidth(void) {return m_dPixelWidth;} + void SetEGain(double gn) {m_dEGain = gn;} + double GetEGain(void) {return m_dEGain;} + void SetBackground(unsigned short back) {m_uBackground = back;} + unsigned short GetBackground(void) {return m_uBackground;} + void SetRange(unsigned short range) {m_uRange = range;} + unsigned short GetRange(void) {return m_uRange;} + void SetSaturationLevel(unsigned short sat) {m_uSaturationLevel = sat;} + unsigned short GetSaturationLevel(void) {return m_uSaturationLevel;} + void SetNumberExposures(unsigned short no) {m_uNumberExposures = no;} + unsigned short GetNumberExposures(void) {return m_uNumberExposures;} + void SetTrackExposure(double exp) {m_dTrackExposure = exp;} + double GetTrackExposure(void) {return m_dTrackExposure;} + void SetReadoutMode(unsigned short rm) {m_uReadoutMode = rm;} + unsigned short GetReadoutMode(void) {return m_uReadoutMode;} + void SetPedestal(unsigned short ped) {m_uPedestal = ped;} + unsigned short GetPedestal(void) {return m_uPedestal;} + void SetExposureState(unsigned short es) {m_uExposureState = es;} + unsigned short GetExposureState(void) {return m_uExposureState;} + void SetImageNote(string str) {m_cImageNote = str;} + string GetImageNote(void) {return m_cImageNote;} + void SetObserver(string str) {m_cObserver = str;} + string GetObserver(void) {return m_cObserver;} + void SetHistory(string str) {m_cHistory = str;} + string GetHistory(void) {return m_cHistory;} + void SetCameraModel(string str) {m_cCameraModel = str;} + string GetCameraModel(void) {return m_cCameraModel;} + + /* File IO Routines */ + SBIG_FILE_ERROR SaveImage(const char *pFullPath, SBIG_IMAGE_FORMAT fmt); + + /* Utility Functions */ + MY_LOGICAL AllocateImageBuffer(int height, int width); + void CreateSBIGHeader(char *pHeader, MY_LOGICAL isCompressed); + int CompressSBIGData(unsigned char *pCmpData, int imgRow); + void IntelCopyBytes(unsigned char *pRevData, int imgRow); +}; + +#endif /* #ifndef _CSBIGIMG_ */ diff --git a/contrib/include/drvrsmem.h b/contrib/include/drvrsmem.h new file mode 100644 index 00000000..0e3953b3 --- /dev/null +++ b/contrib/include/drvrsmem.h @@ -0,0 +1,178 @@ +/* S H A R E D M E M O R Y D R I V E R + ======================================= + + by Jerzy.Borkowski@obs.unige.ch + +09-Mar-98 : initial version 1.0 released +23-Mar-98 : shared_malloc now accepts new handle as an argument +*/ + + +#include /* this is necessary for Solaris/Linux */ +#include +#include + +#ifdef _AIX +#include +#else +#include +#endif + + /* configuration parameters */ + +#define SHARED_MAXSEG (16) /* maximum number of shared memory blocks */ + +#define SHARED_KEYBASE (14011963) /* base for shared memory keys, may be overriden by getenv */ +#define SHARED_FDNAME ("/tmp/.shmem-lockfile") /* template for lock file name */ + +#define SHARED_ENV_KEYBASE ("SHMEM_LIB_KEYBASE") /* name of environment variable */ +#define SHARED_ENV_MAXSEG ("SHMEM_LIB_MAXSEG") /* name of environment variable */ + + /* useful constants */ + +#define SHARED_RDONLY (0) /* flag for shared_(un)lock, lock for read */ +#define SHARED_RDWRITE (1) /* flag for shared_(un)lock, lock for write */ +#define SHARED_WAIT (0) /* flag for shared_lock, block if cannot lock immediate */ +#define SHARED_NOWAIT (2) /* flag for shared_lock, fail if cannot lock immediate */ +#define SHARED_NOLOCK (0x100) /* flag for shared_validate function */ + +#define SHARED_RESIZE (4) /* flag for shared_malloc, object is resizeable */ +#define SHARED_PERSIST (8) /* flag for shared_malloc, object is not deleted after last proc detaches */ + +#define SHARED_INVALID (-1) /* invalid handle for semaphore/shared memory */ + +#define SHARED_EMPTY (0) /* entries for shared_used table */ +#define SHARED_USED (1) + +#define SHARED_GRANUL (16384) /* granularity of shared_malloc allocation = phys page size, system dependent */ + + + + /* checkpoints in shared memory segments - might be omitted */ + +#define SHARED_ID_0 ('J') /* first byte of identifier in BLKHEAD */ +#define SHARED_ID_1 ('B') /* second byte of identifier in BLKHEAD */ + +#define BLOCK_REG (0) /* value for tflag member of BLKHEAD */ +#define BLOCK_SHARED (1) /* value for tflag member of BLKHEAD */ + + /* generic error codes */ + +#define SHARED_OK (0) + +#define SHARED_ERR_MIN_IDX SHARED_BADARG +#define SHARED_ERR_MAX_IDX SHARED_NORESIZE + + +#define DAL_SHM_FREE (0) +#define DAL_SHM_USED (1) + +#define DAL_SHM_ID0 ('D') +#define DAL_SHM_ID1 ('S') +#define DAL_SHM_ID2 ('M') + +#define DAL_SHM_SEGHEAD_ID (0x19630114) + + + + /* data types */ + +/* BLKHEAD object is placed at the beginning of every memory segment (both + shared and regular) to allow automatic recognition of segments type */ + +typedef union + { struct BLKHEADstruct + { char ID[2]; /* ID = 'JB', just as a checkpoint */ + char tflag; /* is it shared memory or regular one ? */ + int handle; /* this is not necessary, used only for non-resizeable objects via ptr */ + } s; + double d; /* for proper alignment on every machine */ + } BLKHEAD; + +typedef void *SHARED_P; /* generic type of shared memory pointer */ + +typedef struct SHARED_GTABstruct /* data type used in global table */ + { int sem; /* access semaphore (1 field): process count */ + int semkey; /* key value used to generate semaphore handle */ + int key; /* key value used to generate shared memory handle (realloc changes it) */ + int handle; /* handle of shared memory segment */ + int size; /* size of shared memory segment */ + int nprocdebug; /* attached proc counter, helps remove zombie segments */ + char attr; /* attributes of shared memory object */ + } SHARED_GTAB; + +typedef struct SHARED_LTABstruct /* data type used in local table */ + { BLKHEAD *p; /* pointer to segment (may be null) */ + int tcnt; /* number of threads in this process attached to segment */ + int lkcnt; /* >=0 <- number of read locks, -1 - write lock */ + long seekpos; /* current pointer position, read/write/seek operations change it */ + } SHARED_LTAB; + + + /* system dependent definitions */ + +#ifndef HAVE_FLOCK_T +typedef struct flock flock_t; +#define HAVE_FLOCK_T +#endif + +#ifndef HAVE_UNION_SEMUN +union semun + { int val; + struct semid_ds *buf; + unsigned short *array; + }; +#define HAVE_UNION_SEMUN +#endif + + +typedef struct DAL_SHM_SEGHEAD_STRUCT DAL_SHM_SEGHEAD; + +struct DAL_SHM_SEGHEAD_STRUCT + { int ID; /* ID for debugging */ + int h; /* handle of sh. mem */ + int size; /* size of data area */ + int nodeidx; /* offset of root object (node struct typically) */ + }; + + /* API routines */ + +#ifdef __cplusplus +extern "C" { +#endif + +void shared_cleanup(void); /* must be called at exit/abort */ +int shared_init(int debug_msgs); /* must be called before any other shared memory routine */ +int shared_recover(int id); /* try to recover dormant segment(s) after applic crash */ +int shared_malloc(long size, int mode, int newhandle); /* allocate n-bytes of shared memory */ +int shared_attach(int idx); /* attach to segment given index to table */ +int shared_free(int idx); /* release shared memory */ +SHARED_P shared_lock(int idx, int mode); /* lock segment for reading */ +SHARED_P shared_realloc(int idx, long newsize); /* reallocate n-bytes of shared memory (ON LOCKED SEGMENT ONLY) */ +int shared_size(int idx); /* get size of attached shared memory segment (ON LOCKED SEGMENT ONLY) */ +int shared_attr(int idx); /* get attributes of attached shared memory segment (ON LOCKED SEGMENT ONLY) */ +int shared_set_attr(int idx, int newattr); /* set attributes of attached shared memory segment (ON LOCKED SEGMENT ONLY) */ +int shared_unlock(int idx); /* unlock segment (ON LOCKED SEGMENT ONLY) */ +int shared_set_debug(int debug_msgs); /* set/reset debug mode */ +int shared_set_createmode(int mode); /* set/reset debug mode */ +int shared_list(int id); /* list segment(s) */ +int shared_uncond_delete(int id); /* uncondintionally delete (NOWAIT operation) segment(s) */ + +int smem_init(void); +int smem_shutdown(void); +int smem_setoptions(int options); +int smem_getoptions(int *options); +int smem_getversion(int *version); +int smem_open(char *filename, int rwmode, int *driverhandle); +int smem_create(char *filename, int *driverhandle); +int smem_close(int driverhandle); +int smem_remove(char *filename); +int smem_size(int driverhandle, OFF_T *size); +int smem_flush(int driverhandle); +int smem_seek(int driverhandle, OFF_T offset); +int smem_read(int driverhandle, void *buffer, long nbytes); +int smem_write(int driverhandle, void *buffer, long nbytes); + +#ifdef __cplusplus +} +#endif diff --git a/contrib/include/fitsio.h b/contrib/include/fitsio.h new file mode 100644 index 00000000..332664fe --- /dev/null +++ b/contrib/include/fitsio.h @@ -0,0 +1,1557 @@ +/* Version Info: This file is distributed with version 2.490 of CFITSIO */ + +/* The FITSIO software was written by William Pence at the High Energy */ +/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */ +/* Goddard Space Flight Center. */ +/* + +Copyright (Unpublished--all rights reserved under the copyright laws of +the United States), U.S. Government as represented by the Administrator +of the National Aeronautics and Space Administration. No copyright is +claimed in the United States under Title 17, U.S. Code. + +Permission to freely use, copy, modify, and distribute this software +and its documentation without fee is hereby granted, provided that this +copyright notice and disclaimer of warranty appears in all copies. + +DISCLAIMER: + +THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, +EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, +ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE +DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE +SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY +DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY +CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, +CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY +PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED +FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR +SERVICES PROVIDED HEREUNDER." + +*/ + +#ifndef _FITSIO_H +#define _FITSIO_H + +#include + +#if defined(linux) || defined(__APPLE__) +# include /* apparently needed on debian linux systems */ +#endif /* to define off_t */ + +#include /* apparently needed to define size_t with gcc 2.8.1 */ +#include /* needed for LLONG_MAX and INT64_MAX definitions */ + +/* Define the datatype for variables which store file offset values. */ +/* The new 'off_t' datatype should be used for this purpose, but some */ +/* older compilers do not recognize this type, in which case we use 'long' */ +/* instead. Note that _OFF_T is defined (or not) in stdio.h depending */ +/* on whether _LARGEFILE_SOURCE is defined in sys/feature_tests.h */ +/* (at least on Solaris platforms using cc) */ + +/* Debian systems require the 2nd test, below, */ +/* i.e, "(defined(linux) && defined(__off_t_defined))" */ +#if defined(_OFF_T) || (defined(linux) && defined(__off_t_defined)) || defined(_MIPS_SZLONG) || defined(__APPLE__) || defined(_AIX) +# define OFF_T off_t +#else +# define OFF_T long +#endif + +/* typedef the 'LONGLONG' data type to the intrinsice 8-byte integer type */ + +#if defined(HAVE_LONGLONG) || defined(__APPLE__) + typedef long long LONGLONG; +# ifndef HAVE_LONGLONG +# define HAVE_LONGLONG 1 +# endif +#elif defined(_MSC_VER) /* Windows PCs; Visual C++, but not Borland C++ */ + typedef __int64 LONGLONG; +# ifndef HAVE_LONGLONG +# define HAVE_LONGLONG 1 +# endif +#else + typedef long LONGLONG; /* intrinsic 8-byte integer not supported */ +#endif + +/* The following exclusion if __CINT__ is defined is needed for ROOT */ +#ifndef __CINT__ +#include "longnam.h" +#endif + +/* global variables */ + +#define FLEN_FILENAME 1025 /* max length of a filename */ +#define FLEN_KEYWORD 72 /* max length of a keyword (HIERARCH convention) */ +#define FLEN_CARD 81 /* length of a FITS header card */ +#define FLEN_VALUE 71 /* max length of a keyword value string */ +#define FLEN_COMMENT 73 /* max length of a keyword comment string */ +#define FLEN_ERRMSG 81 /* max length of a FITSIO error message */ +#define FLEN_STATUS 31 /* max length of a FITSIO status text string */ + +#define TBIT 1 /* codes for FITS table data types */ +#define TBYTE 11 +#define TSBYTE 12 +#define TLOGICAL 14 +#define TSTRING 16 +#define TUSHORT 20 +#define TSHORT 21 +#define TUINT 30 +#define TINT 31 +#define TULONG 40 +#define TLONG 41 +#define TINT32BIT 41 /* used when returning datatype of a column */ +#define TFLOAT 42 +#define TLONGLONG 81 +#define TDOUBLE 82 +#define TCOMPLEX 83 +#define TDBLCOMPLEX 163 + +#define TYP_STRUC_KEY 10 +#define TYP_CMPRS_KEY 20 +#define TYP_SCAL_KEY 30 +#define TYP_NULL_KEY 40 +#define TYP_DIM_KEY 50 +#define TYP_RANG_KEY 60 +#define TYP_UNIT_KEY 70 +#define TYP_DISP_KEY 80 +#define TYP_HDUID_KEY 90 +#define TYP_CKSUM_KEY 100 +#define TYP_WCS_KEY 110 +#define TYP_REFSYS_KEY 120 +#define TYP_COMM_KEY 130 +#define TYP_CONT_KEY 140 +#define TYP_USER_KEY 150 + + +#define INT32BIT int /* 32-bit integer datatype. Currently this */ + /* datatype is an 'int' on all useful platforms */ + /* however, it is possible that that are cases */ + /* where 'int' is a 2-byte integer, in which case */ + /* INT32BIT would need to be defined as 'long'. */ + +#define BYTE_IMG 8 /* BITPIX code values for FITS image types */ +#define SHORT_IMG 16 +#define LONG_IMG 32 +#define LONGLONG_IMG 64 +#define FLOAT_IMG -32 +#define DOUBLE_IMG -64 + /* The following 2 codes are not true FITS */ + /* datatypes; these codes are only used internally */ + /* within cfitsio to make it easier for users */ + /* to deal with unsigned integers. */ +#define SBYTE_IMG 10 +#define USHORT_IMG 20 +#define ULONG_IMG 40 + +#define IMAGE_HDU 0 /* Primary Array or IMAGE HDU */ +#define ASCII_TBL 1 /* ASCII table HDU */ +#define BINARY_TBL 2 /* Binary table HDU */ +#define ANY_HDU -1 /* matches any HDU type */ + +#define READONLY 0 /* options when opening a file */ +#define READWRITE 1 + +/* adopt a hopefully obscure number to use as a null value flag */ +/* could be problems if the FITS files contain data with these values */ +#define FLOATNULLVALUE -9.11912E-36F +#define DOUBLENULLVALUE -9.1191291391491E-36 + +/* Image compression algorithm types */ +#define MAX_COMPRESS_DIM 6 +#define RICE_1 11 +#define GZIP_1 21 +#define PLIO_1 31 +#define HCOMPRESS_1 41 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define CASESEN 1 /* do case-sensitive string match */ +#define CASEINSEN 0 /* do case-insensitive string match */ + +#define GT_ID_ALL_URI 0 /* hierarchical grouping parameters */ +#define GT_ID_REF 1 +#define GT_ID_POS 2 +#define GT_ID_ALL 3 +#define GT_ID_REF_URI 11 +#define GT_ID_POS_URI 12 + +#define OPT_RM_GPT 0 +#define OPT_RM_ENTRY 1 +#define OPT_RM_MBR 2 +#define OPT_RM_ALL 3 + +#define OPT_GCP_GPT 0 +#define OPT_GCP_MBR 1 +#define OPT_GCP_ALL 2 + +#define OPT_MCP_ADD 0 +#define OPT_MCP_NADD 1 +#define OPT_MCP_REPL 2 +#define OPT_MCP_MOV 3 + +#define OPT_MRG_COPY 0 +#define OPT_MRG_MOV 1 + +#define OPT_CMT_MBR 1 +#define OPT_CMT_MBR_DEL 11 + +typedef struct /* structure used to store table column information */ +{ + char ttype[70]; /* column name = FITS TTYPEn keyword; */ + long tbcol; /* offset in row to first byte of each column */ + int tdatatype; /* datatype code of each column */ + OFF_T trepeat; /* repeat count of column; number of elements */ + double tscale; /* FITS TSCALn linear scaling factor */ + double tzero; /* FITS TZEROn linear scaling zero point */ + long tnull; /* FITS null value for int image or binary table cols */ + char strnull[20]; /* FITS null value string for ASCII table columns */ + char tform[10]; /* FITS tform keyword value */ + long twidth; /* width of each ASCII table column */ +}tcolumn; + +#define VALIDSTRUC 555 /* magic value used to identify if structure is valid */ + +typedef struct /* structure used to store basic FITS file information */ +{ + int filehandle; /* handle returned by the file open function */ + int driver; /* defines which set of I/O drivers should be used */ + int open_count; /* number of opened 'fitsfiles' using this structure */ + char *filename; /* file name */ + int validcode; /* magic value used to verify that structure is valid */ + OFF_T filesize; /* current size of the physical disk file in bytes */ + OFF_T logfilesize; /* logical size of file, including unflushed buffers */ + int lasthdu; /* is this the last HDU in the file? 0 = no, else yes */ + OFF_T bytepos; /* current logical I/O pointer position in file */ + OFF_T io_pos; /* current I/O pointer position in the physical file */ + int curbuf; /* number of I/O buffer currently in use */ + int curhdu; /* current HDU number; 0 = primary array */ + int hdutype; /* 0 = primary array, 1 = ASCII table, 2 = binary table */ + int writemode; /* 0 = readonly, 1 = readwrite */ + int maxhdu; /* highest numbered HDU known to exist in the file */ + int MAXHDU; /* dynamically allocated dimension of headstart array */ + OFF_T *headstart; /* byte offset in file to start of each HDU */ + OFF_T headend; /* byte offest in file to end of the current HDU header */ + OFF_T nextkey; /* byte offset in file to beginning of next keyword */ + OFF_T datastart;/* byte offset in file to start of the current data unit */ + int tfield; /* number of fields in the table (primary array has 2 */ + long origrows; /* original number of rows (value of NAXIS2 keyword) */ + long numrows; /* number of rows in the table (dynamically updated) */ + OFF_T rowlength; /* length of a table row or image size (bytes) */ + tcolumn *tableptr; /* pointer to the table structure */ + OFF_T heapstart; /* heap start byte relative to start of data unit */ + long heapsize; /* size of the heap, in bytes */ + + /* the following elements are related to compressed images */ + int request_compress_type; /* requested image compression algorithm */ + long request_tilesize[MAX_COMPRESS_DIM]; /* requested tiling size */ + int request_rice_nbits; /* requested noise bit parameter value */ + + int compressimg; /* 1 if HDU contains a compressed image, else 0 */ + char zcmptype[12]; /* compression type string */ + int compress_type; /* type of compression algorithm */ + int zbitpix; /* FITS data type of image (BITPIX) */ + int zndim; /* dimension of image */ + long znaxis[MAX_COMPRESS_DIM]; /* length of each axis */ + long tilesize[MAX_COMPRESS_DIM]; /* size of compression tiles */ + long maxtilelen; /* max number of pixels in each image tile */ + long maxelem; /* maximum length of variable length arrays */ + + int cn_compressed; /* column number for COMPRESSED_DATA column */ + int cn_uncompressed; /* column number for UNCOMPRESSED_DATA column */ + int cn_zscale; /* column number for ZSCALE column */ + int cn_zzero; /* column number for ZZERO column */ + int cn_zblank; /* column number for the ZBLANK column */ + + double zscale; /* scaling value, if same for all tiles */ + double zzero; /* zero pt, if same for all tiles */ + double cn_bscale; /* value of the BSCALE keyword in header */ + double cn_bzero; /* value of the BZERO keyword in header */ + int zblank; /* value for null pixels, if not a column */ + + int rice_blocksize; /* first compression parameter */ + int rice_nbits; /* second compression parameter */ +} FITSfile; + +typedef struct /* structure used to store basic HDU information */ +{ + int HDUposition; /* HDU position in file; 0 = first HDU */ + FITSfile *Fptr; /* pointer to FITS file structure */ +}fitsfile; + +typedef struct /* structure for the iterator function column information */ +{ + /* elements required as input to fits_iterate_data: */ + + fitsfile *fptr; /* pointer to the HDU containing the column */ + int colnum; /* column number in the table (use name if < 1) */ + char colname[70]; /* name (= TTYPEn value) of the column (optional) */ + int datatype; /* output datatype (converted if necessary */ + int iotype; /* = InputCol, InputOutputCol, or OutputCol */ + + /* output elements that may be useful for the work function: */ + + void *array; /* pointer to the array (and the null value) */ + long repeat; /* binary table vector repeat value */ + long tlmin; /* legal minimum data value */ + long tlmax; /* legal maximum data value */ + char tunit[70]; /* physical unit string */ + char tdisp[70]; /* suggested display format */ + +} iteratorCol; + +#define InputCol 0 /* flag for input only iterator column */ +#define InputOutputCol 1 /* flag for input and output iterator column */ +#define OutputCol 2 /* flag for output only iterator column */ + +/* error status codes */ + +#define SKIP_TABLE -104 /* move to 1st image when opening file */ +#define SKIP_IMAGE -103 /* move to 1st table when opening file */ +#define SKIP_NULL_PRIMARY -102 /* skip null primary array when opening file */ +#define USE_MEM_BUFF -101 /* use memory buffer when opening file */ +#define OVERFLOW_ERR -11 /* overflow during datatype conversion */ +#define PREPEND_PRIMARY -9 /* used in ffiimg to insert new primary array */ +#define SAME_FILE 101 /* input and output files are the same */ +#define TOO_MANY_FILES 103 /* tried to open too many FITS files */ +#define FILE_NOT_OPENED 104 /* could not open the named file */ +#define FILE_NOT_CREATED 105 /* could not create the named file */ +#define WRITE_ERROR 106 /* error writing to FITS file */ +#define END_OF_FILE 107 /* tried to move past end of file */ +#define READ_ERROR 108 /* error reading from FITS file */ +#define FILE_NOT_CLOSED 110 /* could not close the file */ +#define ARRAY_TOO_BIG 111 /* array dimensions exceed internal limit */ +#define READONLY_FILE 112 /* Cannot write to readonly file */ +#define MEMORY_ALLOCATION 113 /* Could not allocate memory */ +#define BAD_FILEPTR 114 /* invalid fitsfile pointer */ +#define NULL_INPUT_PTR 115 /* NULL input pointer to routine */ +#define SEEK_ERROR 116 /* error seeking position in file */ + +#define BAD_URL_PREFIX 121 /* invalid URL prefix on file name */ +#define TOO_MANY_DRIVERS 122 /* tried to register too many IO drivers */ +#define DRIVER_INIT_FAILED 123 /* driver initialization failed */ +#define NO_MATCHING_DRIVER 124 /* matching driver is not registered */ +#define URL_PARSE_ERROR 125 /* failed to parse input file URL */ +#define RANGE_PARSE_ERROR 126 /* failed to parse input file URL */ + +#define SHARED_ERRBASE (150) +#define SHARED_BADARG (SHARED_ERRBASE + 1) +#define SHARED_NULPTR (SHARED_ERRBASE + 2) +#define SHARED_TABFULL (SHARED_ERRBASE + 3) +#define SHARED_NOTINIT (SHARED_ERRBASE + 4) +#define SHARED_IPCERR (SHARED_ERRBASE + 5) +#define SHARED_NOMEM (SHARED_ERRBASE + 6) +#define SHARED_AGAIN (SHARED_ERRBASE + 7) +#define SHARED_NOFILE (SHARED_ERRBASE + 8) +#define SHARED_NORESIZE (SHARED_ERRBASE + 9) + +#define HEADER_NOT_EMPTY 201 /* header already contains keywords */ +#define KEY_NO_EXIST 202 /* keyword not found in header */ +#define KEY_OUT_BOUNDS 203 /* keyword record number is out of bounds */ +#define VALUE_UNDEFINED 204 /* keyword value field is blank */ +#define NO_QUOTE 205 /* string is missing the closing quote */ +#define BAD_KEYCHAR 207 /* illegal character in keyword name or card */ +#define BAD_ORDER 208 /* required keywords out of order */ +#define NOT_POS_INT 209 /* keyword value is not a positive integer */ +#define NO_END 210 /* couldn't find END keyword */ +#define BAD_BITPIX 211 /* illegal BITPIX keyword value*/ +#define BAD_NAXIS 212 /* illegal NAXIS keyword value */ +#define BAD_NAXES 213 /* illegal NAXISn keyword value */ +#define BAD_PCOUNT 214 /* illegal PCOUNT keyword value */ +#define BAD_GCOUNT 215 /* illegal GCOUNT keyword value */ +#define BAD_TFIELDS 216 /* illegal TFIELDS keyword value */ +#define NEG_WIDTH 217 /* negative table row size */ +#define NEG_ROWS 218 /* negative number of rows in table */ +#define COL_NOT_FOUND 219 /* column with this name not found in table */ +#define BAD_SIMPLE 220 /* illegal value of SIMPLE keyword */ +#define NO_SIMPLE 221 /* Primary array doesn't start with SIMPLE */ +#define NO_BITPIX 222 /* Second keyword not BITPIX */ +#define NO_NAXIS 223 /* Third keyword not NAXIS */ +#define NO_NAXES 224 /* Couldn't find all the NAXISn keywords */ +#define NO_XTENSION 225 /* HDU doesn't start with XTENSION keyword */ +#define NOT_ATABLE 226 /* the CHDU is not an ASCII table extension */ +#define NOT_BTABLE 227 /* the CHDU is not a binary table extension */ +#define NO_PCOUNT 228 /* couldn't find PCOUNT keyword */ +#define NO_GCOUNT 229 /* couldn't find GCOUNT keyword */ +#define NO_TFIELDS 230 /* couldn't find TFIELDS keyword */ +#define NO_TBCOL 231 /* couldn't find TBCOLn keyword */ +#define NO_TFORM 232 /* couldn't find TFORMn keyword */ +#define NOT_IMAGE 233 /* the CHDU is not an IMAGE extension */ +#define BAD_TBCOL 234 /* TBCOLn keyword value < 0 or > rowlength */ +#define NOT_TABLE 235 /* the CHDU is not a table */ +#define COL_TOO_WIDE 236 /* column is too wide to fit in table */ +#define COL_NOT_UNIQUE 237 /* more than 1 column name matches template */ +#define BAD_ROW_WIDTH 241 /* sum of column widths not = NAXIS1 */ +#define UNKNOWN_EXT 251 /* unrecognizable FITS extension type */ +#define UNKNOWN_REC 252 /* unrecognizable FITS record */ +#define END_JUNK 253 /* END keyword is not blank */ +#define BAD_HEADER_FILL 254 /* Header fill area not blank */ +#define BAD_DATA_FILL 255 /* Data fill area not blank or zero */ +#define BAD_TFORM 261 /* illegal TFORM format code */ +#define BAD_TFORM_DTYPE 262 /* unrecognizable TFORM datatype code */ +#define BAD_TDIM 263 /* illegal TDIMn keyword value */ +#define BAD_HEAP_PTR 264 /* invalid BINTABLE heap address */ + +#define BAD_HDU_NUM 301 /* HDU number < 1 or > MAXHDU */ +#define BAD_COL_NUM 302 /* column number < 1 or > tfields */ +#define NEG_FILE_POS 304 /* tried to move before beginning of file */ +#define NEG_BYTES 306 /* tried to read or write negative bytes */ +#define BAD_ROW_NUM 307 /* illegal starting row number in table */ +#define BAD_ELEM_NUM 308 /* illegal starting element number in vector */ +#define NOT_ASCII_COL 309 /* this is not an ASCII string column */ +#define NOT_LOGICAL_COL 310 /* this is not a logical datatype column */ +#define BAD_ATABLE_FORMAT 311 /* ASCII table column has wrong format */ +#define BAD_BTABLE_FORMAT 312 /* Binary table column has wrong format */ +#define NO_NULL 314 /* null value has not been defined */ +#define NOT_VARI_LEN 317 /* this is not a variable length column */ +#define BAD_DIMEN 320 /* illegal number of dimensions in array */ +#define BAD_PIX_NUM 321 /* first pixel number greater than last pixel */ +#define ZERO_SCALE 322 /* illegal BSCALE or TSCALn keyword = 0 */ +#define NEG_AXIS 323 /* illegal axis length < 1 */ + +#define NOT_GROUP_TABLE 340 +#define HDU_ALREADY_MEMBER 341 +#define MEMBER_NOT_FOUND 342 +#define GROUP_NOT_FOUND 343 +#define BAD_GROUP_ID 344 +#define TOO_MANY_HDUS_TRACKED 345 +#define HDU_ALREADY_TRACKED 346 +#define BAD_OPTION 347 +#define IDENTICAL_POINTERS 348 +#define BAD_GROUP_ATTACH 349 +#define BAD_GROUP_DETACH 350 + +#define BAD_I2C 401 /* bad int to formatted string conversion */ +#define BAD_F2C 402 /* bad float to formatted string conversion */ +#define BAD_INTKEY 403 /* can't interprete keyword value as integer */ +#define BAD_LOGICALKEY 404 /* can't interprete keyword value as logical */ +#define BAD_FLOATKEY 405 /* can't interprete keyword value as float */ +#define BAD_DOUBLEKEY 406 /* can't interprete keyword value as double */ +#define BAD_C2I 407 /* bad formatted string to int conversion */ +#define BAD_C2F 408 /* bad formatted string to float conversion */ +#define BAD_C2D 409 /* bad formatted string to double conversion */ +#define BAD_DATATYPE 410 /* bad keyword datatype code */ +#define BAD_DECIM 411 /* bad number of decimal places specified */ +#define NUM_OVERFLOW 412 /* overflow during datatype conversion */ + +# define DATA_COMPRESSION_ERR 413 /* error in imcompress routines */ +# define DATA_DECOMPRESSION_ERR 414 /* error in imcompress routines */ +# define NO_COMPRESSED_TILE 415 /* compressed tile doesn't exist */ + +#define BAD_DATE 420 /* error in date or time conversion */ + +#define PARSE_SYNTAX_ERR 431 /* syntax error in parser expression */ +#define PARSE_BAD_TYPE 432 /* expression did not evaluate to desired type */ +#define PARSE_LRG_VECTOR 433 /* vector result too large to return in array */ +#define PARSE_NO_OUTPUT 434 /* data parser failed not sent an out column */ +#define PARSE_BAD_COL 435 /* bad data encounter while parsing column */ +#define PARSE_BAD_OUTPUT 436 /* Output file not of proper type */ + +#define ANGLE_TOO_BIG 501 /* celestial angle too large for projection */ +#define BAD_WCS_VAL 502 /* bad celestial coordinate or pixel value */ +#define WCS_ERROR 503 /* error in celestial coordinate calculation */ +#define BAD_WCS_PROJ 504 /* unsupported type of celestial projection */ +#define NO_WCS_KEY 505 /* celestial coordinate keywords not found */ +#define APPROX_WCS_KEY 506 /* approximate WCS keywords were calculated */ + +#define NO_CLOSE_ERROR 999 /* special value used internally to switch off */ + /* the error message from ffclos and ffchdu */ + +/*------- following error codes are used in the grparser.c file -----------*/ +#define NGP_ERRBASE (360) /* base chosen so not to interfere with CFITSIO */ +#define NGP_OK (0) +#define NGP_NO_MEMORY (NGP_ERRBASE + 0) /* malloc failed */ +#define NGP_READ_ERR (NGP_ERRBASE + 1) /* read error from file */ +#define NGP_NUL_PTR (NGP_ERRBASE + 2) /* null pointer passed as argument */ +#define NGP_EMPTY_CURLINE (NGP_ERRBASE + 3) /* line read seems to be empty */ +#define NGP_UNREAD_QUEUE_FULL (NGP_ERRBASE + 4) /* cannot unread more then 1 line (or single line twice) */ +#define NGP_INC_NESTING (NGP_ERRBASE + 5) /* too deep include file nesting (inf. loop ?) */ +#define NGP_ERR_FOPEN (NGP_ERRBASE + 6) /* fopen() failed, cannot open file */ +#define NGP_EOF (NGP_ERRBASE + 7) /* end of file encountered */ +#define NGP_BAD_ARG (NGP_ERRBASE + 8) /* bad arguments passed */ +#define NGP_TOKEN_NOT_EXPECT (NGP_ERRBASE + 9) /* token not expected here */ + +/* The following exclusion if __CINT__ is defined is needed for ROOT */ +#ifndef __CINT__ +/* the following 3 lines are needed to support C++ compilers */ +#ifdef __cplusplus +extern "C" { +#endif +#endif + +/*---------------- FITS file URL parsing routines -------------*/ +int fits_get_token(char **ptr, char *delimiter, char *token, int *isanumber); +char *fits_split_names(char *list); +int ffiurl(char *url, char *urltype, char *infile, + char *outfile, char *extspec, char *rowfilter, + char *binspec, char *colspec, int *status); +int ffrtnm(char *url, char *rootname, int *status); +int ffexts(char *extspec, int *extnum, char *extname, int *extvers, + int *hdutype, char *colname, char *rowexpress, int *status); +int ffextn(char *url, int *extension_num, int *status); +int ffurlt(fitsfile *fptr, char *urlType, int *status); +int ffbins(char *binspec, int *imagetype, int *haxis, + char colname[4][FLEN_VALUE], double *minin, + double *maxin, double *binsizein, + char minname[4][FLEN_VALUE], char maxname[4][FLEN_VALUE], + char binname[4][FLEN_VALUE], double *weight, char *wtname, + int *recip, int *status); +int ffbinr(char **binspec, char *colname, double *minin, + double *maxin, double *binsizein, char *minname, + char *maxname, char *binname, int *status); +int ffimport_file( char *filename, char **contents, int *status ); +int ffrwrg( char *rowlist, long maxrows, int maxranges, int *numranges, + long *minrow, long *maxrow, int *status); + +/*---------------- FITS file I/O routines -------------*/ +int ffomem(fitsfile **fptr, const char *name, int mode, void **buffptr, + size_t *buffsize, size_t deltasize, + void *(*mem_realloc)(void *p, size_t newsize), + int *status); +int ffopen(fitsfile **fptr, const char *filename, int iomode, int *status); +int ffdopn(fitsfile **fptr, const char *filename, int iomode, int *status); +int fftopn(fitsfile **fptr, const char *filename, int iomode, int *status); +int ffiopn(fitsfile **fptr, const char *filename, int iomode, int *status); +int ffreopen(fitsfile *openfptr, fitsfile **newfptr, int *status); +int ffinit(fitsfile **fptr, const char *filename, int *status); +int ffimem(fitsfile **fptr, void **buffptr, + size_t *buffsize, size_t deltasize, + void *(*mem_realloc)(void *p, size_t newsize), + int *status); +int fftplt(fitsfile **fptr, const char *filename, const char *tempname, + int *status); +int ffflus(fitsfile *fptr, int *status); +int ffflsh(fitsfile *fptr, int clearbuf, int *status); +int ffclos(fitsfile *fptr, int *status); +int ffdelt(fitsfile *fptr, int *status); +int ffflnm(fitsfile *fptr, char *filename, int *status); +int ffflmd(fitsfile *fptr, int *filemode, int *status); + +/*---------------- utility routines -------------*/ +float ffvers(float *version); +void ffupch(char *string); +void ffgerr(int status, char *errtext); +void ffpmsg(const char *err_message); +void ffpmrk(void); +int ffgmsg(char *err_message); +void ffcmsg(void); +void ffcmrk(void); +void ffrprt(FILE *stream, int status); +void ffcmps(char *templt, char *colname, int casesen, int *match, + int *exact); +int fftkey(char *keyword, int *status); +int fftrec(char *card, int *status); +int ffnchk(fitsfile *fptr, int *status); +int ffkeyn(char *keyroot, int value, char *keyname, int *status); +int ffnkey(int value, char *keyroot, char *keyname, int *status); +int ffgkcl(char *card); +int ffdtyp(char *cval, char *dtype, int *status); +int ffpsvc(char *card, char *value, char *comm, int *status); +int ffgknm(char *card, char *name, int *length, int *status); +int ffgthd(char *tmplt, char *card, int *hdtype, int *status); +int ffasfm(char *tform, int *datacode, long *width, int *decim, int *status); +int ffbnfm(char *tform, int *datacode, long *repeat, long *width, int *status); +int ffgabc(int tfields, char **tform, int space, long *rowlen, long *tbcol, + int *status); +int fits_get_section_range(char **ptr,long *secmin,long *secmax,long *incre, + int *status); + +/*----------------- write single keywords --------------*/ +int ffpky(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status); +int ffprec(fitsfile *fptr, const char *card, int *status); +int ffpcom(fitsfile *fptr, const char *comm, int *status); +int ffpunt(fitsfile *fptr, char *keyname, char *unit, int *status); +int ffphis(fitsfile *fptr, const char *history, int *status); +int ffpdat(fitsfile *fptr, int *status); +int ffgstm(char *timestr, int *timeref, int *status); +int ffgsdt(int *day, int *month, int *year, int *status); +int ffdt2s(int year, int month, int day, char *datestr, int *status); +int fftm2s(int year, int month, int day, int hour, int minute, double second, + int decimals, char *datestr, int *status); +int ffs2dt(char *datestr, int *year, int *month, int *day, int *status); +int ffs2tm(char *datestr, int *year, int *month, int *day, int *hour, + int *minute, double *second, int *status); +int ffpkyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffpkys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffpkls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffplsw(fitsfile *fptr, int *status); +int ffpkyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffpkyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffpkyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffpkye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffpkyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffpkyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffpkyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffpkym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffpkfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffpkfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffpkyt(fitsfile *fptr, char *keyname, long intval, double frac, char *comm, + int *status); +int ffptdm( fitsfile *fptr, int colnum, int naxis, long naxes[], int *status); + +/*----------------- write array of keywords --------------*/ +int ffpkns(fitsfile *fptr, char *keyroot, int nstart, int nkey, char *value[], + char *comm[], int *status); +int ffpknl(fitsfile *fptr, char *keyroot, int nstart, int nkey, int *value, + char *comm[], int *status); +int ffpknj(fitsfile *fptr, char *keyroot, int nstart, int nkey, long *value, + char *comm[], int *status); +int ffpknf(fitsfile *fptr, char *keyroot, int nstart, int nkey, float *value, + int decim, char *comm[], int *status); +int ffpkne(fitsfile *fptr, char *keyroot, int nstart, int nkey, float *value, + int decim, char *comm[], int *status); +int ffpkng(fitsfile *fptr, char *keyroot, int nstart, int nkey, double *value, + int decim, char *comm[], int *status); +int ffpknd(fitsfile *fptr, char *keyroot, int nstart, int nkey, double *value, + int decim, char *comm[], int *status); +int ffcpky(fitsfile *infptr,fitsfile *outfptr,int incol,int outcol, + char *rootname, int *status); + +/*----------------- write required header keywords --------------*/ +int ffphps( fitsfile *fptr, int bitpix, int naxis, long naxes[], int *status); +int ffphpr( fitsfile *fptr, int simple, int bitpix, int naxis, long naxes[], + long pcount, long gcount, int extend, int *status); +int ffphtb(fitsfile *fptr, long naxis1, long naxis2, int tfields, char **ttype, + long *tbcol, char **tform, char **tunit, char *extname, int *status); +int ffphbn(fitsfile *fptr, long naxis2, int tfields, char **ttype, + char **tform, char **tunit, char *extname, long pcount, int *status); + +/*----------------- write template keywords --------------*/ +int ffpktp(fitsfile *fptr, const char *filename, int *status); + +/*------------------ get header information --------------*/ +int ffghsp(fitsfile *fptr, int *nexist, int *nmore, int *status); +int ffghps(fitsfile *fptr, int *nexist, int *position, int *status); + +/*------------------ move position in header -------------*/ +int ffmaky(fitsfile *fptr, int nrec, int *status); +int ffmrky(fitsfile *fptr, int nrec, int *status); + +/*------------------ read single keywords -----------------*/ +int ffgnxk(fitsfile *fptr, char **inclist, int ninc, char **exclist, + int nexc, char *card, int *status); +int ffgrec(fitsfile *fptr, int nrec, char *card, int *status); +int ffgcrd(fitsfile *fptr, char *keyname, char *card, int *status); +int ffgunt(fitsfile *fptr, char *keyname, char *unit, int *status); +int ffgkyn(fitsfile *fptr, int nkey, char *keyname, char *keyval, char *comm, + int *status); +int ffgkey(fitsfile *fptr, char *keyname, char *keyval, char *comm, + int *status); + +int ffgky( fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status); +int ffgkys(fitsfile *fptr, char *keyname, char *value, char *comm, int *status); +int ffgkls(fitsfile *fptr, char *keyname, char **value, char *comm, int *status) +; +int ffgkyl(fitsfile *fptr, char *keyname, int *value, char *comm, int *status); +int ffgkyj(fitsfile *fptr, char *keyname, long *value, char *comm, int *status); +int ffgkye(fitsfile *fptr, char *keyname, float *value, char *comm,int *status); +int ffgkyd(fitsfile *fptr, char *keyname, double *value,char *comm,int *status); +int ffgkyc(fitsfile *fptr, char *keyname, float *value, char *comm,int *status); +int ffgkym(fitsfile *fptr, char *keyname, double *value,char *comm,int *status); +int ffgkyt(fitsfile *fptr, char *keyname, long *ivalue, double *dvalue, + char *comm, int *status); +int ffgtdm(fitsfile *fptr, int colnum, int maxdim, int *naxis, long naxes[], + int *status); +int ffdtdm(fitsfile *fptr, char *tdimstr, int colnum, int maxdim, + int *naxis, long naxes[], int *status); + +/*------------------ read array of keywords -----------------*/ +int ffgkns(fitsfile *fptr, char *keyname, int nstart, int nmax, char *value[], + int *nfound, int *status); +int ffgknl(fitsfile *fptr, char *keyname, int nstart, int nmax, int *value, + int *nfound, int *status); +int ffgknj(fitsfile *fptr, char *keyname, int nstart, int nmax, long *value, + int *nfound, int *status); +int ffgkne(fitsfile *fptr, char *keyname, int nstart, int nmax, float *value, + int *nfound, int *status); +int ffgknd(fitsfile *fptr, char *keyname, int nstart, int nmax, double *value, + int *nfound, int *status); +int ffh2st(fitsfile *fptr, char **header, int *status); +int ffhdr2str( fitsfile *fptr, int exclude_comm, char **exclist, + int nexc, char **header, int *nkeys, int *status); + +/*----------------- read required header keywords --------------*/ +int ffghpr(fitsfile *fptr, int maxdim, int *simple, int *bitpix, int *naxis, + long naxes[], long *pcount, long *gcount, int *extend, int *status); + +int ffghtb(fitsfile *fptr,int maxfield, long *naxis1, long *naxis2, + int *tfields, char **ttype, long *tbcol, char **tform, char **tunit, + char *extname, int *status); + +int ffghbn(fitsfile *fptr, int maxfield, long *naxis2, int *tfields, + char **ttype, char **tform, char **tunit, char *extname, + long *pcount, int *status); + +/*--------------------- update keywords ---------------*/ +int ffuky(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status); +int ffucrd(fitsfile *fptr, char *keyname, char *card, int *status); +int ffukyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffukys(fitsfile *fptr, char *keyname, char *value, char *comm, int *status); +int ffukls(fitsfile *fptr, char *keyname, char *value, char *comm, int *status); +int ffukyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffukyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffukyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffukye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffukyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffukyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffukyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffukym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffukfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffukfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); + +/*--------------------- modify keywords ---------------*/ +int ffmrec(fitsfile *fptr, int nkey, char *card, int *status); +int ffmcrd(fitsfile *fptr, char *keyname, char *card, int *status); +int ffmnam(fitsfile *fptr, char *oldname, char *newname, int *status); +int ffmcom(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffmkyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffmkys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffmkls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffmkyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffmkyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffmkyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffmkye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffmkyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffmkyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffmkyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffmkym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffmkfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffmkfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); + +/*--------------------- insert keywords ---------------*/ +int ffirec(fitsfile *fptr, int nkey, char *card, int *status); +int ffikey(fitsfile *fptr, char *card, int *status); +int ffikyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffikys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffikls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffikyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffikyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffikyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffikye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffikyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffikyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffikyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffikym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffikfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffikfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); + +/*--------------------- delete keywords ---------------*/ +int ffdkey(fitsfile *fptr, char *keyname, int *status); +int ffdrec(fitsfile *fptr, int keypos, int *status); + +/*--------------------- get HDU information -------------*/ +int ffghdn(fitsfile *fptr, int *chdunum); +int ffghdt(fitsfile *fptr, int *exttype, int *status); +int ffghad(fitsfile *fptr, long *headstart, long *datastart, long *dataend, + int *status); +int ffghof(fitsfile *fptr, OFF_T *headstart, OFF_T *datastart, OFF_T *dataend, + int *status); +int ffgipr(fitsfile *fptr, int maxaxis, int *imgtype, int *naxis, + long *naxes, int *status); +int ffgidt(fitsfile *fptr, int *imgtype, int *status); +int ffgiet(fitsfile *fptr, int *imgtype, int *status); +int ffgidm(fitsfile *fptr, int *naxis, int *status); +int ffgisz(fitsfile *fptr, int nlen, long *naxes, int *status); + +/*--------------------- HDU operations -------------*/ +int ffmahd(fitsfile *fptr, int hdunum, int *exttype, int *status); +int ffmrhd(fitsfile *fptr, int hdumov, int *exttype, int *status); +int ffmnhd(fitsfile *fptr, int exttype, char *hduname, int hduvers, + int *status); +int ffthdu(fitsfile *fptr, int *nhdu, int *status); +int ffcrhd(fitsfile *fptr, int *status); +int ffcrim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status); +int ffcrtb(fitsfile *fptr, int tbltype, long naxis2, int tfields, char **ttype, + char **tform, char **tunit, char *extname, int *status); +int ffiimg(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status); +int ffitab(fitsfile *fptr, long naxis1, long naxis2, int tfields, char **ttype, + long *tbcol, char **tform, char **tunit, char *extname, int *status); +int ffibin(fitsfile *fptr,long naxis2, int tfields, char **ttype, char **tform, + char **tunit, char *extname, long pcount, int *status); +int ffrsim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status); +int ffdhdu(fitsfile *fptr, int *hdutype, int *status); +int ffcopy(fitsfile *infptr, fitsfile *outfptr, int morekeys, int *status); +int ffcpfl(fitsfile *infptr, fitsfile *outfptr, int prev, int cur, int follow, + int *status); +int ffcphd(fitsfile *infptr, fitsfile *outfptr, int *status); +int ffcpdt(fitsfile *infptr, fitsfile *outfptr, int *status); +int ffchfl(fitsfile *fptr, int *status); +int ffcdfl(fitsfile *fptr, int *status); + +int ffrdef(fitsfile *fptr, int *status); +int ffhdef(fitsfile *fptr, int morekeys, int *status); +int ffpthp(fitsfile *fptr, long theap, int *status); + +int ffcsum(fitsfile *fptr, long nrec, unsigned long *sum, int *status); +void ffesum(unsigned long sum, int complm, char *ascii); +unsigned long ffdsum(char *ascii, int complm, unsigned long *sum); +int ffpcks(fitsfile *fptr, int *status); +int ffupck(fitsfile *fptr, int *status); +int ffvcks(fitsfile *fptr, int *datastatus, int *hdustatus, int *status); +int ffgcks(fitsfile *fptr, unsigned long *datasum, unsigned long *hdusum, + int *status); + +/*--------------------- define scaling or null values -------------*/ +int ffpscl(fitsfile *fptr, double scale, double zero, int *status); +int ffpnul(fitsfile *fptr, long nulvalue, int *status); +int fftscl(fitsfile *fptr, int colnum, double scale, double zero, int *status); +int fftnul(fitsfile *fptr, int colnum, long nulvalue, int *status); +int ffsnul(fitsfile *fptr, int colnum, char *nulstring, int *status); + +/*--------------------- get column information -------------*/ +int ffgcno(fitsfile *fptr, int casesen, char *templt, int *colnum, + int *status); +int ffgcnn(fitsfile *fptr, int casesen, char *templt, char *colname, + int *colnum, int *status); + +int ffgtcl(fitsfile *fptr, int colnum, int *typecode, long *repeat, + long *width, int *status); +int ffeqty(fitsfile *fptr, int colnum, int *typecode, long *repeat, + long *width, int *status); +int ffgncl(fitsfile *fptr, int *ncols, int *status); +int ffgnrw(fitsfile *fptr, long *nrows, int *status); +int ffgacl(fitsfile *fptr, int colnum, char *ttype, long *tbcol, + char *tunit, char *tform, double *tscal, double *tzero, + char *tnull, char *tdisp, int *status); +int ffgbcl(fitsfile *fptr, int colnum, char *ttype, char *tunit, + char *dtype, long *repeat, double *tscal, double *tzero, + long *tnull, char *tdisp, int *status); +int ffgrsz(fitsfile *fptr, long *nrows, int *status); +int ffgcdw(fitsfile *fptr, int colnum, int *width, int *status); + +/*--------------------- read primary array or image elements -------------*/ +int ffgpxv(fitsfile *fptr, int datatype, long *firstpix, long nelem, + void *nulval, void *array, int *anynul, int *status); +int ffgpxf(fitsfile *fptr, int datatype, long *firstpix, long nelem, + void *array, char *nullarray, int *anynul, int *status); +int ffgsv(fitsfile *fptr, int datatype, long *blc, long *trc, long *inc, + void *nulval, void *array, int *anynul, int *status); +int ffgpv(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *nulval, void *array, int *anynul, int *status); +int ffgpf(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, char *nullarray, int *anynul, int *status); +int ffgpvb(fitsfile *fptr, long group, long firstelem, long nelem, unsigned + char nulval, unsigned char *array, int *anynul, int *status); +int ffgpvsb(fitsfile *fptr, long group, long firstelem, long nelem, signed + char nulval, signed char *array, int *anynul, int *status); +int ffgpvui(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned short nulval, unsigned short *array, int *anynul, + int *status); +int ffgpvi(fitsfile *fptr, long group, long firstelem, long nelem, + short nulval, short *array, int *anynul, int *status); +int ffgpvuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long nulval, unsigned long *array, int *anynul, + int *status); +int ffgpvj(fitsfile *fptr, long group, long firstelem, long nelem, + long nulval, long *array, int *anynul, int *status); +int ffgpvjj(fitsfile *fptr, long group, long firstelem, long nelem, + LONGLONG nulval, LONGLONG *array, int *anynul, int *status); +int ffgpvuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int nulval, unsigned int *array, int *anynul, int *status); +int ffgpvk(fitsfile *fptr, long group, long firstelem, long nelem, + int nulval, int *array, int *anynul, int *status); +int ffgpve(fitsfile *fptr, long group, long firstelem, long nelem, + float nulval, float *array, int *anynul, int *status); +int ffgpvd(fitsfile *fptr, long group, long firstelem, long nelem, + double nulval, double *array, int *anynul, int *status); + +int ffgpfb(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned char *array, char *nularray, int *anynul, int *status); +int ffgpfsb(fitsfile *fptr, long group, long firstelem, long nelem, + signed char *array, char *nularray, int *anynul, int *status); +int ffgpfui(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned short *array, char *nularray, int *anynul, int *status); +int ffgpfi(fitsfile *fptr, long group, long firstelem, long nelem, + short *array, char *nularray, int *anynul, int *status); +int ffgpfuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long *array, char *nularray, int *anynul, int *status); +int ffgpfj(fitsfile *fptr, long group, long firstelem, long nelem, + long *array, char *nularray, int *anynul, int *status); +int ffgpfjj(fitsfile *fptr, long group, long firstelem, long nelem, + LONGLONG *array, char *nularray, int *anynul, int *status); +int ffgpfuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int *array, char *nularray, int *anynul, int *status); +int ffgpfk(fitsfile *fptr, long group, long firstelem, long nelem, + int *array, char *nularray, int *anynul, int *status); +int ffgpfe(fitsfile *fptr, long group, long firstelem, long nelem, + float *array, char *nularray, int *anynul, int *status); +int ffgpfd(fitsfile *fptr, long group, long firstelem, long nelem, + double *array, char *nularray, int *anynul, int *status); + +int ffg2db(fitsfile *fptr, long group, unsigned char nulval, long ncols, + long naxis1, long naxis2, unsigned char *array, + int *anynul, int *status); +int ffg2dsb(fitsfile *fptr, long group, signed char nulval, long ncols, + long naxis1, long naxis2, signed char *array, + int *anynul, int *status); +int ffg2dui(fitsfile *fptr, long group, unsigned short nulval, long ncols, + long naxis1, long naxis2, unsigned short *array, + int *anynul, int *status); +int ffg2di(fitsfile *fptr, long group, short nulval, long ncols, + long naxis1, long naxis2, short *array, + int *anynul, int *status); +int ffg2duj(fitsfile *fptr, long group, unsigned long nulval, long ncols, + long naxis1, long naxis2, unsigned long *array, + int *anynul, int *status); +int ffg2dj(fitsfile *fptr, long group, long nulval, long ncols, + long naxis1, long naxis2, long *array, + int *anynul, int *status); +int ffg2djj(fitsfile *fptr, long group, LONGLONG nulval, long ncols, + long naxis1, long naxis2, LONGLONG *array, + int *anynul, int *status); +int ffg2duk(fitsfile *fptr, long group, unsigned int nulval, long ncols, + long naxis1, long naxis2, unsigned int *array, + int *anynul, int *status); +int ffg2dk(fitsfile *fptr, long group, int nulval, long ncols, + long naxis1, long naxis2, int *array, + int *anynul, int *status); +int ffg2de(fitsfile *fptr, long group, float nulval, long ncols, + long naxis1, long naxis2, float *array, + int *anynul, int *status); +int ffg2dd(fitsfile *fptr, long group, double nulval, long ncols, + long naxis1, long naxis2, double *array, + int *anynul, int *status); + +int ffg3db(fitsfile *fptr, long group, unsigned char nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned char *array, int *anynul, int *status); +int ffg3dsb(fitsfile *fptr, long group, signed char nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + signed char *array, int *anynul, int *status); +int ffg3dui(fitsfile *fptr, long group, unsigned short nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned short *array, int *anynul, int *status); +int ffg3di(fitsfile *fptr, long group, short nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + short *array, int *anynul, int *status); +int ffg3duj(fitsfile *fptr, long group, unsigned long nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned long *array, int *anynul, int *status); +int ffg3dj(fitsfile *fptr, long group, long nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + long *array, int *anynul, int *status); +int ffg3djj(fitsfile *fptr, long group, LONGLONG nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + LONGLONG *array, int *anynul, int *status); +int ffg3duk(fitsfile *fptr, long group, unsigned int nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned int *array, int *anynul, int *status); +int ffg3dk(fitsfile *fptr, long group, int nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + int *array, int *anynul, int *status); +int ffg3de(fitsfile *fptr, long group, float nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + float *array, int *anynul, int *status); +int ffg3dd(fitsfile *fptr, long group, double nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + double *array, int *anynul, int *status); + +int ffgsvb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned char nulval, unsigned char *array, + int *anynul, int *status); +int ffgsvsb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, signed char nulval, signed char *array, + int *anynul, int *status); +int ffgsvui(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned short nulval, unsigned short *array, + int *anynul, int *status); +int ffgsvi(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, short nulval, short *array, int *anynul, int *status); +int ffgsvuj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned long nulval, unsigned long *array, + int *anynul, int *status); +int ffgsvj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, long nulval, long *array, int *anynul, int *status); +int ffgsvjj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, LONGLONG nulval, LONGLONG *array, int *anynul, + int *status); +int ffgsvuk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned int nulval, unsigned int *array, + int *anynul, int *status); +int ffgsvk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, int nulval, int *array, int *anynul, int *status); +int ffgsve(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, float nulval, float *array, int *anynul, int *status); +int ffgsvd(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, double nulval, double *array, int *anynul, + int *status); + +int ffgsfb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned char *array, char *flagval, + int *anynul, int *status); +int ffgsfsb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, signed char *array, char *flagval, + int *anynul, int *status); +int ffgsfui(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned short *array, char *flagval, int *anynul, + int *status); +int ffgsfi(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, short *array, char *flagval, int *anynul, int *status); +int ffgsfuj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned long *array, char *flagval, int *anynul, + int *status); +int ffgsfj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, long *array, char *flagval, int *anynul, int *status); +int ffgsfjj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, LONGLONG *array, char *flagval, int *anynul, + int *status); +int ffgsfuk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned int *array, char *flagval, int *anynul, + int *status); +int ffgsfk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, int *array, char *flagval, int *anynul, int *status); +int ffgsfe(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, float *array, char *flagval, int *anynul, int *status); +int ffgsfd(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, double *array, char *flagval, int *anynul, + int *status); + +int ffggpb(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned char *array, int *status); +int ffggpsb(fitsfile *fptr, long group, long firstelem, long nelem, + signed char *array, int *status); +int ffggpui(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned short *array, int *status); +int ffggpi(fitsfile *fptr, long group, long firstelem, long nelem, + short *array, int *status); +int ffggpuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long *array, int *status); +int ffggpj(fitsfile *fptr, long group, long firstelem, long nelem, + long *array, int *status); +int ffggpjj(fitsfile *fptr, long group, long firstelem, long nelem, + LONGLONG *array, int *status); +int ffggpuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int *array, int *status); +int ffggpk(fitsfile *fptr, long group, long firstelem, long nelem, + int *array, int *status); +int ffggpe(fitsfile *fptr, long group, long firstelem, long nelem, + float *array, int *status); +int ffggpd(fitsfile *fptr, long group, long firstelem, long nelem, + double *array, int *status); + +/*--------------------- read column elements -------------*/ +int ffgcv( fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *nulval, void *array, int *anynul, + int *status); +int ffgcf( fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, char *nullarray, + int *anynul, int *status); +int ffgcvs(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *nulval, char **array, int *anynul, int *status); +int ffgcl (fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *array, int *status); +int ffgcvl (fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char nulval, char *array, int *anynul, int *status); +int ffgcvb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned char nulval, unsigned char *array, + int *anynul, int *status); +int ffgcvsb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, signed char nulval, signed char *array, + int *anynul, int *status); +int ffgcvui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short nulval, unsigned short *array, + int *anynul, int *status); +int ffgcvi(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short nulval, short *array, int *anynul, int *status); +int ffgcvuj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long nulval, unsigned long *array, int *anynul, + int *status); +int ffgcvj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long nulval, long *array, int *anynul, int *status); +int ffgcvjj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, LONGLONG nulval, LONGLONG *array, int *anynul, + int *status); +int ffgcvuk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int nulval, unsigned int *array, int *anynul, + int *status); +int ffgcvk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int nulval, int *array, int *anynul, int *status); +int ffgcve(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float nulval, float *array, int *anynul, int *status); +int ffgcvd(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double nulval, double *array, int *anynul, int *status); +int ffgcvc(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float nulval, float *array, int *anynul, int *status); +int ffgcvm(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double nulval, double *array, int *anynul, int *status); +int ffgcx(fitsfile *fptr, int colnum, long firstrow, long firstbit, + long nbits, char *larray, int *status); +int ffgcxui(fitsfile *fptr, int colnum, long firstrow, long nrows, + long firstbit, int nbits, unsigned short *array, int *status); +int ffgcxuk(fitsfile *fptr, int colnum, long firstrow, long nrows, + long firstbit, int nbits, unsigned int *array, int *status); + +int ffgcfs(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, char **array, char *nularray, int *anynul, int *status); +int ffgcfl(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, char *array, char *nularray, int *anynul, int *status); +int ffgcfb(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, unsigned char *array, char *nularray, int *anynul, int *status); +int ffgcfsb(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, signed char *array, char *nularray, int *anynul, int *status); +int ffgcfui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short *array, char *nularray, int *anynul, + int *status); +int ffgcfi(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short *array, char *nularray, int *anynul, int *status); +int ffgcfuj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long *array, char *nularray, int *anynul, + int *status); +int ffgcfj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long *array, char *nularray, int *anynul, int *status); +int ffgcfjj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, LONGLONG *array, char *nularray, int *anynul, int *status); +int ffgcfuk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int *array, char *nularray, int *anynul, + int *status); +int ffgcfk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *array, char *nularray, int *anynul, int *status); +int ffgcfe(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, char *nularray, int *anynul, int *status); +int ffgcfd(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, char *nularray, int *anynul, int *status); +int ffgcfc(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, char *nularray, int *anynul, int *status); +int ffgcfm(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, char *nularray, int *anynul, int *status); + +int ffgdes(fitsfile *fptr, int colnum, long rownum, long *length, + long *heapaddr, int *status); + +int ffgdess(fitsfile *fptr, int colnum, long firstrow, long nrows, long *length, + long *heapaddr, int *status); + +int fftheap(fitsfile *fptr, long *heapsize, long *unused, long *overlap, + int *valid, int *status); +int ffcmph(fitsfile *fptr, int *status); + +int ffgtbb(fitsfile *fptr, long firstrow, long firstchar, long nchars, + unsigned char *values, int *status); + +/*------------ write primary array or image elements -------------*/ +int ffppx(fitsfile *fptr, int datatype, long *firstpix, long nelem, + void *array, int *status); +int ffppxn(fitsfile *fptr, int datatype, long *firstpix, long nelem, + void *array, void *nulval, int *status); +int ffppr(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, int *status); +int ffpprb(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned char *array, int *status); +int ffpprsb(fitsfile *fptr, long group, long firstelem, + long nelem, signed char *array, int *status); +int ffpprui(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned short *array, int *status); +int ffppri(fitsfile *fptr, long group, long firstelem, + long nelem, short *array, int *status); +int ffppruj(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned long *array, int *status); +int ffpprj(fitsfile *fptr, long group, long firstelem, + long nelem, long *array, int *status); +int ffppruk(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned int *array, int *status); +int ffpprk(fitsfile *fptr, long group, long firstelem, + long nelem, int *array, int *status); +int ffppre(fitsfile *fptr, long group, long firstelem, + long nelem, float *array, int *status); +int ffpprd(fitsfile *fptr, long group, long firstelem, + long nelem, double *array, int *status); +int ffpprjj(fitsfile *fptr, long group, long firstelem, + long nelem, LONGLONG *array, int *status); + +int ffppru(fitsfile *fptr, long group, long firstelem, long nelem, + int *status); +int ffpprn(fitsfile *fptr, long firstelem, long nelem, int *status); + +int ffppn(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, void *nulval, int *status); +int ffppnb(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned char *array, unsigned char nulval, int *status); +int ffppnsb(fitsfile *fptr, long group, long firstelem, long nelem, + signed char *array, signed char nulval, int *status); +int ffppnui(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned short *array, unsigned short nulval, + int *status); +int ffppni(fitsfile *fptr, long group, long firstelem, + long nelem, short *array, short nulval, int *status); +int ffppnj(fitsfile *fptr, long group, long firstelem, + long nelem, long *array, long nulval, int *status); +int ffppnuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long *array, unsigned long nulval, int *status); +int ffppnuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int *array, unsigned int nulval, int *status); +int ffppnk(fitsfile *fptr, long group, long firstelem, + long nelem, int *array, int nulval, int *status); +int ffppne(fitsfile *fptr, long group, long firstelem, + long nelem, float *array, float nulval, int *status); +int ffppnd(fitsfile *fptr, long group, long firstelem, + long nelem, double *array, double nulval, int *status); +int ffppnjj(fitsfile *fptr, long group, long firstelem, + long nelem, LONGLONG *array, long nulval, int *status); + +int ffp2db(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned char *array, int *status); +int ffp2dsb(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, signed char *array, int *status); +int ffp2dui(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned short *array, int *status); +int ffp2di(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, short *array, int *status); +int ffp2duj(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned long *array, int *status); +int ffp2dj(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, long *array, int *status); +int ffp2duk(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned int *array, int *status); +int ffp2dk(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, int *array, int *status); +int ffp2de(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, float *array, int *status); +int ffp2dd(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, double *array, int *status); +int ffp2djj(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, LONGLONG *array, int *status); + +int ffp3db(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned char *array, int *status); +int ffp3dsb(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, signed char *array, int *status); +int ffp3dui(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned short *array, int *status); +int ffp3di(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, short *array, int *status); +int ffp3duj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned long *array, int *status); +int ffp3dj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, long *array, int *status); +int ffp3duk(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned int *array, int *status); +int ffp3dk(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, int *array, int *status); +int ffp3de(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, float *array, int *status); +int ffp3dd(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, double *array, int *status); +int ffp3djj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, LONGLONG *array, int *status); + +int ffpss(fitsfile *fptr, int datatype, + long *fpixel, long *lpixel, void *array, int *status); +int ffpssb(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned char *array, int *status); +int ffpsssb(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, signed char *array, int *status); +int ffpssui(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned short *array, int *status); +int ffpssi(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, short *array, int *status); +int ffpssuj(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned long *array, int *status); +int ffpssj(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, long *array, int *status); +int ffpssuk(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned int *array, int *status); +int ffpssk(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, int *array, int *status); +int ffpsse(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, float *array, int *status); +int ffpssd(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, double *array, int *status); +int ffpssjj(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, LONGLONG *array, int *status); + +int ffpgpb(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned char *array, int *status); +int ffpgpsb(fitsfile *fptr, long group, long firstelem, + long nelem, signed char *array, int *status); +int ffpgpui(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned short *array, int *status); +int ffpgpi(fitsfile *fptr, long group, long firstelem, + long nelem, short *array, int *status); +int ffpgpuj(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned long *array, int *status); +int ffpgpj(fitsfile *fptr, long group, long firstelem, + long nelem, long *array, int *status); +int ffpgpuk(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned int *array, int *status); +int ffpgpk(fitsfile *fptr, long group, long firstelem, + long nelem, int *array, int *status); +int ffpgpe(fitsfile *fptr, long group, long firstelem, + long nelem, float *array, int *status); +int ffpgpd(fitsfile *fptr, long group, long firstelem, + long nelem, double *array, int *status); +int ffpgpjj(fitsfile *fptr, long group, long firstelem, + long nelem, LONGLONG *array, int *status); + +/*--------------------- iterator functions -------------*/ +int fits_iter_set_by_name(iteratorCol *col, fitsfile *fptr, char *colname, + int datatype, int iotype); +int fits_iter_set_by_num(iteratorCol *col, fitsfile *fptr, int colnum, + int datatype, int iotype); +int fits_iter_set_file(iteratorCol *col, fitsfile *fptr); +int fits_iter_set_colname(iteratorCol *col, char *colname); +int fits_iter_set_colnum(iteratorCol *col, int colnum); +int fits_iter_set_datatype(iteratorCol *col, int datatype); +int fits_iter_set_iotype(iteratorCol *col, int iotype); + +fitsfile * fits_iter_get_file(iteratorCol *col); +char * fits_iter_get_colname(iteratorCol *col); +int fits_iter_get_colnum(iteratorCol *col); +int fits_iter_get_datatype(iteratorCol *col); +int fits_iter_get_iotype(iteratorCol *col); +void * fits_iter_get_array(iteratorCol *col); +long fits_iter_get_tlmin(iteratorCol *col); +long fits_iter_get_tlmax(iteratorCol *col); +long fits_iter_get_repeat(iteratorCol *col); +char * fits_iter_get_tunit(iteratorCol *col); +char * fits_iter_get_tdisp(iteratorCol *col); + +int ffiter(int ncols, iteratorCol *data, long offset, long nPerLoop, + int (*workFn)( long totaln, long offset, long firstn, + long nvalues, int narrays, iteratorCol *data, void *userPointer), + void *userPointer, int *status); + +/*--------------------- write column elements -------------*/ +int ffpcl(fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, int *status); +int ffpcls(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char **array, int *status); +int ffpcll(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *array, int *status); +int ffpclb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned char *array, int *status); +int ffpclsb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, signed char *array, int *status); +int ffpclui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short *array, int *status); +int ffpcli(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short *array, int *status); +int ffpcluj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long *array, int *status); +int ffpclj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long *array, int *status); +int ffpcluk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int *array, int *status); +int ffpclk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *array, int *status); +int ffpcle(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, int *status); +int ffpcld(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, int *status); +int ffpclc(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, int *status); +int ffpclm(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, int *status); +int ffpclu(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *status); +int ffpclx(fitsfile *fptr, int colnum, long frow, long fbit, long nbit, + char *larray, int *status); +int ffpcljj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, LONGLONG *array, int *status); + +int ffpcn(fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, void *nulval, int *status); +int ffpcns( fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char **array, char *nulvalue, int *status); +int ffpcnl( fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *array, char nulvalue, int *status); +int ffpcnb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned char *array, unsigned char nulvalue, + int *status); +int ffpcnsb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, signed char *array, signed char nulvalue, + int *status); +int ffpcnui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short *array, unsigned short nulvalue, + int *status); +int ffpcni(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short *array, short nulvalue, int *status); +int ffpcnuj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long *array, unsigned long nulvalue, + int *status); +int ffpcnj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long *array, long nulvalue, int *status); +int ffpcnuk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int *array, unsigned int nulvalue, + int *status); +int ffpcnk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *array, int nulvalue, int *status); +int ffpcne(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, float nulvalue, int *status); +int ffpcnd(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, double nulvalue, int *status); +int ffpcnjj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, LONGLONG *array, LONGLONG nulvalue, int *status); + +int ffpdes(fitsfile *fptr, int colnum, long rownum, long length, + long heapaddr, int *status); + +int ffptbb(fitsfile *fptr, long firstrow, long firstchar, long nchars, + unsigned char *values, int *status); + +int ffirow(fitsfile *fptr, long firstrow, long nrows, int *status); +int ffdrow(fitsfile *fptr, long firstrow, long nrows, int *status); +int ffdrrg(fitsfile *fptr, char *ranges, int *status); +int ffdrws(fitsfile *fptr, long *rownum, long nrows, int *status); +int fficol(fitsfile *fptr, int numcol, char *ttype, char *tform, int *status); +int fficls(fitsfile *fptr, int firstcol, int ncols, char **ttype, + char **tform, int *status); +int ffmvec(fitsfile *fptr, int colnum, long newveclen, int *status); +int ffdcol(fitsfile *fptr, int numcol, int *status); +int ffcpcl(fitsfile *infptr, fitsfile *outfptr, int incol, int outcol, + int create_col, int *status); + +/*--------------------- WCS Utilities ------------------*/ +int ffgics(fitsfile *fptr, double *xrval, double *yrval, double *xrpix, + double *yrpix, double *xinc, double *yinc, double *rot, + char *type, int *status); +int ffgtcs(fitsfile *fptr, int xcol, int ycol, double *xrval, + double *yrval, double *xrpix, double *yrpix, double *xinc, + double *yinc, double *rot, char *type, int *status); +int ffwldp(double xpix, double ypix, double xref, double yref, + double xrefpix, double yrefpix, double xinc, double yinc, + double rot, char *type, double *xpos, double *ypos, int *status); +int ffxypx(double xpos, double ypos, double xref, double yref, + double xrefpix, double yrefpix, double xinc, double yinc, + double rot, char *type, double *xpix, double *ypix, int *status); + +/* WCS support routines (provide interface to Doug Mink's WCS library */ +int ffgiwcs(fitsfile *fptr, char **header, int *status); +int ffgtwcs(fitsfile *fptr, int xcol, int ycol, char **header, int *status); + +/*--------------------- lexical parsing routines ------------------*/ +int fftexp( fitsfile *fptr, char *expr, int maxdim, + int *datatype, long *nelem, int *naxis, + long *naxes, int *status ); + +int fffrow( fitsfile *infptr, char *expr, + long firstrow, long nrows, + long *n_good_rows, char *row_status, int *status); + +int ffffrw( fitsfile *fptr, char *expr, long *rownum, int *status); + +int fffrwc( fitsfile *fptr, char *expr, char *timeCol, + char *parCol, char *valCol, long ntimes, + double *times, char *time_status, int *status ); + +int ffsrow( fitsfile *infptr, fitsfile *outfptr, char *expr, + int *status); + +int ffcrow( fitsfile *fptr, int datatype, char *expr, + long firstrow, long nelements, void *nulval, + void *array, int *anynul, int *status ); + +int ffcalc_rng( fitsfile *infptr, char *expr, fitsfile *outfptr, + char *parName, char *parInfo, int nRngs, + long *start, long *end, int *status ); + +int ffcalc( fitsfile *infptr, char *expr, fitsfile *outfptr, + char *parName, char *parInfo, int *status ); + + /* ffhist is not really intended as a user-callable routine */ + /* but it may be useful for some specialized applications */ + +int ffhist(fitsfile **fptr, char *outfile, int imagetype, int naxis, + char colname[4][FLEN_VALUE], + double *minin, double *maxin, double *binsizein, + char minname[4][FLEN_VALUE], char maxname[4][FLEN_VALUE], + char binname[4][FLEN_VALUE], + double weightin, char wtcol[FLEN_VALUE], + int recip, char *rowselect, int *status); + +int fits_select_image_section(fitsfile **fptr, char *outfile, + char *imagesection, int *status); +int fits_select_section( fitsfile *infptr, fitsfile *outfptr, + char *imagesection, int *status); + +/*--------------------- grouping routines ------------------*/ + +int ffgtcr(fitsfile *fptr, char *grpname, int grouptype, int *status); +int ffgtis(fitsfile *fptr, char *grpname, int grouptype, int *status); +int ffgtch(fitsfile *gfptr, int grouptype, int *status); +int ffgtrm(fitsfile *gfptr, int rmopt, int *status); +int ffgtcp(fitsfile *infptr, fitsfile *outfptr, int cpopt, int *status); +int ffgtmg(fitsfile *infptr, fitsfile *outfptr, int mgopt, int *status); +int ffgtcm(fitsfile *gfptr, int cmopt, int *status); +int ffgtvf(fitsfile *gfptr, long *firstfailed, int *status); +int ffgtop(fitsfile *mfptr,int group,fitsfile **gfptr,int *status); +int ffgtam(fitsfile *gfptr, fitsfile *mfptr, int hdupos, int *status); +int ffgtnm(fitsfile *gfptr, long *nmembers, int *status); +int ffgmng(fitsfile *mfptr, long *nmembers, int *status); +int ffgmop(fitsfile *gfptr, long member, fitsfile **mfptr, int *status); +int ffgmcp(fitsfile *gfptr, fitsfile *mfptr, long member, int cpopt, + int *status); +int ffgmtf(fitsfile *infptr, fitsfile *outfptr, long member, int tfopt, + int *status); +int ffgmrm(fitsfile *fptr, long member, int rmopt, int *status); + +/*--------------------- group template parser routines ------------------*/ + +int fits_execute_template(fitsfile *ff, char *ngp_template, int *status); + +/*--------------------- image compression routines ------------------*/ + +int fits_set_compression_type(fitsfile *fptr, int ctype, int *status); +int fits_set_tile_dim(fitsfile *fptr, int ndim, long *dims, int *status); +int fits_set_noise_bits(fitsfile *fptr, int noisebits, int *status); + +int fits_get_compression_type(fitsfile *fptr, int *ctype, int *status); +int fits_get_tile_dim(fitsfile *fptr, int ndim, long *dims, int *status); +int fits_get_noise_bits(fitsfile *fptr, int *noisebits, int *status); + +int fits_compress_img(fitsfile *infptr, fitsfile *outfptr, int compress_type, + long *tilesize, int parm1, int parm2, int *status); +int fits_is_compressed_image(fitsfile *fptr, int *status); +int fits_decompress_img (fitsfile *infptr, fitsfile *outfptr, int *status); + +/* The following exclusion if __CINT__ is defined is needed for ROOT */ +#ifndef __CINT__ +#ifdef __cplusplus +} +#endif +#endif + +#endif + diff --git a/contrib/include/fitsio2.h b/contrib/include/fitsio2.h new file mode 100644 index 00000000..b1f8023c --- /dev/null +++ b/contrib/include/fitsio2.h @@ -0,0 +1,1109 @@ +#ifndef _FITSIO2_H +#define _FITSIO2_H + +#include "fitsio.h" + +/* Setting SUPPORT_64_BIT_INTEGERS to 1 will enable CFITSIO to read */ +/* and write images with BITPIX = 64 and binary table columns with */ +/* TFORMn = 'K'. Otherwise, setting SUPPORT_64_BIT_INTEGERS to 0 */ +/* will cause CFITSIO to not recognize these non-standard 64-bit */ +/* FITS datatypes. */ + +#define SUPPORT_64BIT_INTEGERS 1 + +/* + If REPLACE_LINKS is defined, then whenever CFITSIO fails to open + a file with write access because it is a soft link to a file that + only has read access, then CFITSIO will attempt to replace + the link with a local copy of the file, with write access. This + feature was originally added to support the ftools in the Hera + environment, where many of the user's data file are soft links. +*/ +#if defined(BUILD_HERA) +#define REPLACE_LINKS 1 +#endif + +#define USE_LARGE_VALUE -99 /* flag used when writing images */ + +#define DBUFFSIZE 28800 /* size of data buffer in bytes */ + +#define NIOBUF 40 /* number of IO buffers to create */ + /* !! Significantly increasing NIOBUF may degrade performance !! */ +#define NMAXFILES 300 /* maximum number of FITS files that can be opened */ + /* CFITSIO will allocate (NMAXFILES * 80) bytes of memory */ + +#define IOBUFLEN 2880 /* size in bytes of each IO buffer (DONT CHANGE!) */ +#define MINDIRECT 8640 /* minimum size for direct reads and writes */ + /* MINDIRECT must have a value >= 8640 */ + +#define NATIVE 0 /* a generic machine that uses IEEE formats */ +#define ULTRIX 1 +#define ALPHA_OSF 2 +#define VAXVMS 3 +#define ALPHAVMS 4 +#define IBMPC 5 +#define CRAY 6 +#define PC64BIT 7 + +#define GFLOAT 1 +#define IEEEFLOAT 2 + +/* the following are used to determine what type machine we are running on */ + +/* the following block determines the size of longs on SGI IRIX machines */ +#if defined(_MIPS_SZLONG) +# if _MIPS_SZLONG == 32 +# define LONGSIZE 32 +# elif _MIPS_SZLONG == 64 +# define LONGSIZE 64 +# else +# error "can't handle long size given by _MIPS_SZLONG" +# endif +#endif + +#if defined(vax) && defined(VMS) + +#define MACHINE VAXVMS +#define BYTESWAPPED TRUE + +#elif defined(__alpha) && defined(__VMS) + +#if (__D_FLOAT == TRUE) + +/* this float option is the same as for VAX/VMS machines. */ +#define MACHINE VAXVMS +#define BYTESWAPPED TRUE + +#elif (__G_FLOAT == TRUE) + +/* G_FLOAT is the default for ALPHA VMS systems */ +#define MACHINE ALPHAVMS +#define BYTESWAPPED TRUE +#define FLOATTYPE GFLOAT + +#elif (__IEEE_FLOAT == TRUE) + +#define MACHINE ALPHAVMS +#define BYTESWAPPED TRUE +#define FLOATTYPE IEEEFLOAT + +#endif + +#elif defined(__alpha) && ( defined(__unix__) || defined(__NetBSD__) ) + +#define MACHINE ALPHA_OSF +#define BYTESWAPPED TRUE +#define LONGSIZE 64 + +#elif defined(ultrix) && defined(unix) + +#define MACHINE ULTRIX +#define BYTESWAPPED TRUE + +#elif defined(__sparcv9) + +/* SUN Solaris7 in 64-bit mode */ +#define BYTESWAPPED FALSE +#define MACHINE NATIVE +#define LONGSIZE 64 + +#elif defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) + +/* IBM PC */ +#define MACHINE IBMPC +#define BYTESWAPPED TRUE + +#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) + +/* IBM PC running DOS or Windows */ +#define MACHINE IBMPC +#define BYTESWAPPED TRUE + +#elif defined(_NI_mswin_) || defined(__EMX__) + +/* LabWindows/CVI with Windows, or PC runnin OS/2 */ +#define MACHINE IBMPC +#define BYTESWAPPED TRUE + +#elif defined(__ia64__) || defined(__x86_64__) + +/* Intel itanium 64-bit PC, or AMD opteron 64-bit PC */ +#define BYTESWAPPED TRUE +#define MACHINE PC64BIT +#define LONGSIZE 64 + +#else + +/* assume machine uses the same IEEE formats as used in FITS files */ +#define MACHINE NATIVE +#define BYTESWAPPED FALSE + +#endif + +/* assume longs are 4 bytes long, unless previously set otherwise */ +#ifndef LONGSIZE +#define LONGSIZE 32 +#endif + +#define IGNORE_EOF 1 +#define REPORT_EOF 0 +#define DATA_UNDEFINED -1 +#define NULL_UNDEFINED 1234554321 +#define ASCII_NULL_UNDEFINED 1 /* indicate no defined null value */ + +#define maxvalue(A,B) ((A) > (B) ? (A) : (B)) +#define minvalue(A,B) ((A) < (B) ? (A) : (B)) + +/* faster string comparison macros */ +#define FSTRCMP(a,b) ((a)[0]<(b)[0]? -1:(a)[0]>(b)[0]?1:strcmp((a),(b))) +#define FSTRNCMP(a,b,n) ((a)[0]<(b)[0]?-1:(a)[0]>(b)[0]?1:strncmp((a),(b),(n))) + +#if defined(__VMS) || defined(VMS) + +#define FNANMASK 0xFFFF /* mask all bits */ +#define DNANMASK 0xFFFF /* mask all bits */ + +#else + +#define FNANMASK 0x7F80 /* mask bits 1 - 8; all set on NaNs */ + /* all 0 on underflow or 0. */ + +#define DNANMASK 0x7FF0 /* mask bits 1 - 11; all set on NaNs */ + /* all 0 on underflow or 0. */ + +#endif + +#if MACHINE == CRAY + /* + Cray machines: the large negative integer corresponds + to the 3 most sig digits set to 1. If these + 3 bits are set in a floating point number (64 bits), then it represents + a reserved value (i.e., a NaN) + */ +#define fnan(L) ( (L) >= 0xE000000000000000 ? 1 : 0) ) + +#else + /* these functions work for both big and little endian machines */ + /* that use the IEEE floating point format for internal numbers */ + + /* These functions tests whether the float value is a reserved IEEE */ + /* value such as a Not-a-Number (NaN), or underflow, overflow, or */ + /* infinity. The functions returns 1 if the value is a NaN, overflow */ + /* or infinity; it returns 2 if the value is an denormalized underflow */ + /* value; otherwise it returns 0. fnan tests floats, dnan tests doubles */ + +#define fnan(L) \ + ( (L & FNANMASK) == FNANMASK ? 1 : (L & FNANMASK) == 0 ? 2 : 0) + +#define dnan(L) \ + ( (L & DNANMASK) == DNANMASK ? 1 : (L & DNANMASK) == 0 ? 2 : 0) + +#endif + +#define DSCHAR_MAX 127.49 /* max double value that fits in an signed char */ +#define DSCHAR_MIN -128.49 /* min double value that fits in an signed char */ +#define DUCHAR_MAX 255.49 /* max double value that fits in an unsigned char */ +#define DUCHAR_MIN -0.49 /* min double value that fits in an unsigned char */ +#define DUSHRT_MAX 65535.49 /* max double value that fits in a unsigned short*/ +#define DUSHRT_MIN -0.49 /* min double value that fits in an unsigned short */ +#define DSHRT_MAX 32767.49 /* max double value that fits in a short */ +#define DSHRT_MIN -32768.49 /* min double value that fits in a short */ + +#if LONGSIZE == 32 +# define DLONG_MAX 2147483647.49 /* max double value that fits in a long */ +# define DLONG_MIN -2147483648.49 /* min double value that fits in a long */ +# define DULONG_MAX 4294967295.49 /* max double that fits in a unsigned long */ +#else +# define DLONG_MAX 9.2233720368547752E18 /* max double value long */ +# define DLONG_MIN -9.2233720368547752E18 /* min double value long */ +# define DULONG_MAX 1.84467440737095504E19 /* max double value ulong */ +#endif + +#define DULONG_MIN -0.49 /* min double value that fits in an unsigned long */ +#define DLONGLONG_MAX 9.2233720368547752E18 /* max double value longlong */ +#define DLONGLONG_MIN -9.2233720368547752E18 /* min double value longlong */ +#define DUINT_MAX 4294967295.49 /* max dbl that fits in a unsigned 4-byte int */ +#define DUINT_MIN -0.49 /* min dbl that fits in an unsigned 4-byte int */ +#define DINT_MAX 2147483647.49 /* max double value that fits in a 4-byte int */ +#define DINT_MIN -2147483648.49 /* min double value that fits in a 4-byte int */ + +#ifndef UINT32_MAX +#define UINT32_MAX 4294967295U /* max unsigned 32-bit integer */ +#endif +#ifndef INT32_MAX +#define INT32_MAX 2147483647 /* max 32-bit integer */ +#endif +#ifndef INT32_MIN +#define INT32_MIN (-INT32_MAX -1) /* min 32-bit integer */ +#endif + +#ifndef LONGLONG_MAX + +#ifdef LLONG_MAX +#define LONGLONG_MAX LLONG_MAX +#define LONGLONG_MIN LLONG_MIN + +#elif defined(INT64_MAX) +#define LONGLONG_MAX INT64_MAX +#define LONGLONG_MIN INT64_MIN + +#elif (LONGSIZE == 64) || defined(HAVE_LONGLONG) +#define LONGLONG_MAX 9223372036854775807L /* max 64-bit integer */ +#define LONGLONG_MIN (-LONGLONG_MAX -1L) /* min 64-bit integer */ + +#else +/* define a default value, even if it is never used */ +#define LONGLONG_MAX LONG_MAX +#define LONGLONG_MIN LONG_MIN +#endif +#endif /* end of ndef LONGLONG_MAX section */ + + +#define COMPRESS_NULL_VALUE -2147483647 + +int ffmkky(char *keyname, char *keyval, char *comm, char *card, int *status); +int ffgnky(fitsfile *fptr, char *card, int *status); +void ffcfmt(char *tform, char *cform); +void ffcdsp(char *tform, char *cform); +void ffswap2(short *values, long nvalues); +void ffswap4(INT32BIT *values, long nvalues); +void ffswap8(double *values, long nvalues); +int ffi2c(long ival, char *cval, int *status); +int ffl2c(int lval, char *cval, int *status); +int ffs2c(char *instr, char *outstr, int *status); +int ffr2f(float fval, int decim, char *cval, int *status); +int ffr2e(float fval, int decim, char *cval, int *status); +int ffd2f(double dval, int decim, char *cval, int *status); +int ffd2e(double dval, int decim, char *cval, int *status); +int ffc2ii(char *cval, long *ival, int *status); +int ffc2ll(char *cval, int *lval, int *status); +int ffc2rr(char *cval, float *fval, int *status); +int ffc2dd(char *cval, double *dval, int *status); +int ffc2x(char *cval, char *dtype, long *ival, int *lval, char *sval, + double *dval, int *status); +int ffc2s(char *instr, char *outstr, int *status); +int ffc2i(char *cval, long *ival, int *status); +int ffc2r(char *cval, float *fval, int *status); +int ffc2d(char *cval, double *dval, int *status); +int ffc2l(char *cval, int *lval, int *status); +void ffxmsg(int action, char *err_message); +int ffgcnt(fitsfile *fptr, char *value, int *status); +int ffgtkn(fitsfile *fptr, int numkey, char *keyname, long *value, int *status); +int fftkyn(fitsfile *fptr, int numkey, char *keyname, char *value, int *status); +int ffgphd(fitsfile *fptr, int maxdim, int *simple, int *bitpix, int *naxis, + long naxes[], long *pcount, long *gcount, int *extend, double *bscale, + double *bzero, long *blank, int *nspace, int *status); +int ffgttb(fitsfile *fptr, long *rowlen, long *nrows, long *pcount, + long *tfield, int *status); + +int ffmkey(fitsfile *fptr, char *card, int *status); + +int ffmbyt(fitsfile *fptr, OFF_T bytpos, int ignore_err, int *status); +int ffgbyt(fitsfile *fptr, long nbytes, void *buffer, int *status); +int ffpbyt(fitsfile *fptr, long nbytes, void *buffer, int *status); +int ffgbytoff(fitsfile *fptr, long gsize, long ngroups, long offset, + void *buffer, int *status); +int ffpbytoff(fitsfile *fptr, long gsize, long ngroups, long offset, + void *buffer, int *status); +int ffldrc(fitsfile *fptr, long record, int err_mode, int *status); +int ffwhbf(fitsfile *fptr, int *nbuff); +int ffbfeof(fitsfile *fptr, int *status); +int ffbfwt(int nbuff, int *status); +int fits_get_num_files(void); +int ffpxsz(int datatype); + +int ffourl(char *url, char *urltype, char *outfile, char *tmplfile, + char *compspec, int *status); +int ffparsecompspec(fitsfile *fptr, char *compspec, int *status); +int ffoptplt(fitsfile *fptr, const char *tempname, int *status); +int fits_is_this_a_copy(char *urltype); +int fits_store_Fptr(FITSfile *Fptr, int *status); +int fits_clear_Fptr(FITSfile *Fptr, int *status); +int fits_already_open(fitsfile **fptr, char *url, + char *urltype, char *infile, char *extspec, char *rowfilter, + char *binspec, char *colspec, int mode,int *isopen, int *status); +int ffedit_columns(fitsfile **fptr, char *outfile, char *expr, int *status); +int fits_get_col_minmax(fitsfile *fptr, int colnum, float *datamin, + float *datamax, int *status); +int ffwritehisto(long totaln, long offset, long firstn, long nvalues, + int narrays, iteratorCol *imagepars, void *userPointer); +int ffcalchist(long totalrows, long offset, long firstrow, long nrows, + int ncols, iteratorCol *colpars, void *userPointer); +int fits_copy_image_cell(fitsfile **fptr, char *outfile, char *colname, + long rownum, int *status); +int fits_copy_image_keywords(fitsfile *infptr, fitsfile *outfptr, int *status); +int ffrhdu(fitsfile *fptr, int *hdutype, int *status); +int ffpinit(fitsfile *fptr, int *status); +int ffainit(fitsfile *fptr, int *status); +int ffbinit(fitsfile *fptr, int *status); +int ffchdu(fitsfile *fptr, int *status); +int ffwend(fitsfile *fptr, int *status); +int ffpdfl(fitsfile *fptr, int *status); +int ffuptf(fitsfile *fptr, int *status); + +int ffdblk(fitsfile *fptr, long nblocks, int *status); +int ffgext(fitsfile *fptr, int moveto, int *exttype, int *status); +int ffgtbc(fitsfile *fptr, long *totalwidth, int *status); +int ffgtbp(fitsfile *fptr, char *name, char *value, int *status); +int ffiblk(fitsfile *fptr, long nblock, int headdata, int *status); +int ffshft(fitsfile *fptr, OFF_T firstbyte, OFF_T nbytes, OFF_T nshift, + int *status); + +int ffgcpr(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, int writemode, double *scale, double *zero, char *tform, + long *twidth, int *tcode, int *maxelem, OFF_T *startpos, + OFF_T *elemnum, long *incre, OFF_T *repeat, OFF_T *rowlen, + int *hdutype, long *tnull, char *snull, int *status); + +int ffflushx(FITSfile *fptr); +int ffseek(FITSfile *fptr, OFF_T position); +int ffread(FITSfile *fptr, long nbytes, void *buffer, + int *status); +int ffwrite(FITSfile *fptr, long nbytes, void *buffer, + int *status); +int fftrun(fitsfile *fptr, OFF_T filesize, int *status); + +int ffgcll(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, long + nelem, int nultyp, char nulval, char *array, char *nularray, + int *anynul, int *status); +int ffgcls(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int nultyp, char *nulval, + char **array, char *nularray, int *anynul, int *status); +int ffgcls2(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int nultyp, char *nulval, + char **array, char *nularray, int *anynul, int *status); +int ffgclb(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, unsigned char nulval, + unsigned char *array, char *nularray, int *anynul, int *status); +int ffgclsb(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, signed char nulval, + signed char *array, char *nularray, int *anynul, int *status); +int ffgclui(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, unsigned short nulval, + unsigned short *array, char *nularray, int *anynul, int *status); +int ffgcli(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, short nulval, + short *array, char *nularray, int *anynul, int *status); +int ffgcluj(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, unsigned long nulval, + unsigned long *array, char *nularray, int *anynul, int *status); +int ffgcljj(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, LONGLONG nulval, + LONGLONG *array, char *nularray, int *anynul, int *status); +int ffgclj(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, long nulval, long *array, + char *nularray, int *anynul, int *status); +int ffgcluk(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, unsigned int nulval, + unsigned int *array, char *nularray, int *anynul, int *status); +int ffgclk(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, int nulval, int *array, + char *nularray, int *anynul, int *status); +int ffgcle(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, float nulval, float *array, + char *nularray, int *anynul, int *status); +int ffgcld(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, + long nelem, long elemincre, int nultyp, double nulval, + double *array, char *nularray, int *anynul, int *status); + +int ffpi1b(fitsfile *fptr, long nelem, long incre, unsigned char *buffer, + int *status); +int ffpi2b(fitsfile *fptr, long nelem, long incre, short *buffer, int *status); +int ffpi4b(fitsfile *fptr, long nelem, long incre, INT32BIT *buffer, + int *status); +int ffpi8b(fitsfile *fptr, long nelem, long incre, long *buffer, int *status); +int ffpr4b(fitsfile *fptr, long nelem, long incre, float *buffer, int *status); +int ffpr8b(fitsfile *fptr, long nelem, long incre, double *buffer, int *status); + +int ffgi1b(fitsfile *fptr, OFF_T pos, long nelem, long incre, + unsigned char *buffer, int *status); +int ffgi2b(fitsfile *fptr, OFF_T pos, long nelem, long incre, short *buffer, + int *status); +int ffgi4b(fitsfile *fptr, OFF_T pos, long nelem, long incre, INT32BIT *buffer, + int *status); +int ffgi8b(fitsfile *fptr, OFF_T pos, long nelem, long incre, long *buffer, + int *status); +int ffgr4b(fitsfile *fptr, OFF_T pos, long nelem, long incre, float *buffer, + int *status); +int ffgr8b(fitsfile *fptr, OFF_T pos, long nelem, long incre, double *buffer, + int *status); + +int ffcins(fitsfile *fptr, long naxis1, long naxis2, long nbytes, + long bytepos, int *status); +int ffcdel(fitsfile *fptr, long naxis1, long naxis2, long nbytes, + long bytepos, int *status); +int ffkshf(fitsfile *fptr, int firstcol, int tfields, int nshift, int *status); + +int fffi1i1(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, unsigned char nullval, char + *nullarray, int *anynull, unsigned char *output, int *status); +int fffi2i1(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, unsigned char nullval, char *nullarray, + int *anynull, unsigned char *output, int *status); +int fffi4i1(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, unsigned char nullval, char *nullarray, + int *anynull, unsigned char *output, int *status); +int fffi8i1(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, unsigned char nullval, char *nullarray, + int *anynull, unsigned char *output, int *status); +int fffr4i1(float *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char nullval, char *nullarray, + int *anynull, unsigned char *output, int *status); +int fffr8i1(double *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char nullval, char *nullarray, + int *anynull, unsigned char *output, int *status); +int fffstri1(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + unsigned char nullval, char *nullarray, int *anynull, + unsigned char *output, int *status); + +int fffi1s1(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, signed char nullval, char + *nullarray, int *anynull, signed char *output, int *status); +int fffi2s1(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, signed char nullval, char *nullarray, + int *anynull, signed char *output, int *status); +int fffi4s1(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, signed char nullval, char *nullarray, + int *anynull, signed char *output, int *status); +int fffi8s1(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, signed char nullval, char *nullarray, + int *anynull, signed char *output, int *status); +int fffr4s1(float *input, long ntodo, double scale, double zero, + int nullcheck, signed char nullval, char *nullarray, + int *anynull, signed char *output, int *status); +int fffr8s1(double *input, long ntodo, double scale, double zero, + int nullcheck, signed char nullval, char *nullarray, + int *anynull, signed char *output, int *status); +int fffstrs1(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + signed char nullval, char *nullarray, int *anynull, + signed char *output, int *status); + +int fffi1u2(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, unsigned short nullval, + char *nullarray, + int *anynull, unsigned short *output, int *status); +int fffi2u2(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, unsigned short nullval, char *nullarray, + int *anynull, unsigned short *output, int *status); +int fffi4u2(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, unsigned short nullval, char *nullarray, + int *anynull, unsigned short *output, int *status); +int fffi8u2(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, unsigned short nullval, char *nullarray, + int *anynull, unsigned short *output, int *status); +int fffr4u2(float *input, long ntodo, double scale, double zero, + int nullcheck, unsigned short nullval, char *nullarray, + int *anynull, unsigned short *output, int *status); +int fffr8u2(double *input, long ntodo, double scale, double zero, + int nullcheck, unsigned short nullval, char *nullarray, + int *anynull, unsigned short *output, int *status); +int fffstru2(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + unsigned short nullval, char *nullarray, int *anynull, + unsigned short *output, int *status); + +int fffi1i2(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, short nullval, char *nullarray, + int *anynull, short *output, int *status); +int fffi2i2(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, short nullval, char *nullarray, + int *anynull, short *output, int *status); +int fffi4i2(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, short nullval, char *nullarray, + int *anynull, short *output, int *status); +int fffi8i2(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, short nullval, char *nullarray, + int *anynull, short *output, int *status); +int fffr4i2(float *input, long ntodo, double scale, double zero, + int nullcheck, short nullval, char *nullarray, + int *anynull, short *output, int *status); +int fffr8i2(double *input, long ntodo, double scale, double zero, + int nullcheck, short nullval, char *nullarray, + int *anynull, short *output, int *status); +int fffstri2(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + short nullval, char *nullarray, int *anynull, short *output, + int *status); + +int fffi1u4(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, unsigned long nullval, + char *nullarray, + int *anynull, unsigned long *output, int *status); +int fffi2u4(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, unsigned long nullval, char *nullarray, + int *anynull, unsigned long *output, int *status); +int fffi4u4(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, unsigned long nullval, char *nullarray, + int *anynull, unsigned long *output, int *status); +int fffi8u4(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, unsigned long nullval, char *nullarray, + int *anynull, unsigned long *output, int *status); +int fffr4u4(float *input, long ntodo, double scale, double zero, + int nullcheck, unsigned long nullval, char *nullarray, + int *anynull, unsigned long *output, int *status); +int fffr8u4(double *input, long ntodo, double scale, double zero, + int nullcheck, unsigned long nullval, char *nullarray, + int *anynull, unsigned long *output, int *status); +int fffstru4(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + unsigned long nullval, char *nullarray, int *anynull, + unsigned long *output, int *status); + +int fffi1i4(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, long nullval, char *nullarray, + int *anynull, long *output, int *status); +int fffi2i4(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, long nullval, char *nullarray, + int *anynull, long *output, int *status); +int fffi4i4(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, long nullval, char *nullarray, + int *anynull, long *output, int *status); +int fffi8i4(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, long nullval, char *nullarray, + int *anynull, long *output, int *status); +int fffr4i4(float *input, long ntodo, double scale, double zero, + int nullcheck, long nullval, char *nullarray, + int *anynull, long *output, int *status); +int fffr8i4(double *input, long ntodo, double scale, double zero, + int nullcheck, long nullval, char *nullarray, + int *anynull, long *output, int *status); +int fffstri4(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + long nullval, char *nullarray, int *anynull, long *output, + int *status); + +int fffi1int(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, int nullval, char *nullarray, + int *anynull, int *output, int *status); +int fffi2int(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, int nullval, char *nullarray, + int *anynull, int *output, int *status); +int fffi4int(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, int nullval, char *nullarray, + int *anynull, int *output, int *status); +int fffi8int(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, int nullval, char *nullarray, + int *anynull, int *output, int *status); +int fffr4int(float *input, long ntodo, double scale, double zero, + int nullcheck, int nullval, char *nullarray, + int *anynull, int *output, int *status); +int fffr8int(double *input, long ntodo, double scale, double zero, + int nullcheck, int nullval, char *nullarray, + int *anynull, int *output, int *status); +int fffstrint(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + int nullval, char *nullarray, int *anynull, int *output, + int *status); + +int fffi1uint(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, unsigned int nullval, + char *nullarray, int *anynull, unsigned int *output, int *status); +int fffi2uint(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, unsigned int nullval, char *nullarray, + int *anynull, unsigned int *output, int *status); +int fffi4uint(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, unsigned int nullval, char *nullarray, + int *anynull, unsigned int *output, int *status); +int fffi8uint(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, unsigned int nullval, char *nullarray, + int *anynull, unsigned int *output, int *status); +int fffr4uint(float *input, long ntodo, double scale, double zero, + int nullcheck, unsigned int nullval, char *nullarray, + int *anynull, unsigned int *output, int *status); +int fffr8uint(double *input, long ntodo, double scale, double zero, + int nullcheck, unsigned int nullval, char *nullarray, + int *anynull, unsigned int *output, int *status); +int fffstruint(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + unsigned int nullval, char *nullarray, int *anynull, + unsigned int *output, int *status); + +int fffi1i8(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, LONGLONG nullval, + char *nullarray, int *anynull, LONGLONG *output, int *status); +int fffi2i8(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, LONGLONG nullval, char *nullarray, + int *anynull, LONGLONG *output, int *status); +int fffi4i8(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, LONGLONG nullval, char *nullarray, + int *anynull, LONGLONG *output, int *status); +int fffi8i8(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, LONGLONG tnull, LONGLONG nullval, char *nullarray, + int *anynull, LONGLONG *output, int *status); +int fffr4i8(float *input, long ntodo, double scale, double zero, + int nullcheck, LONGLONG nullval, char *nullarray, + int *anynull, LONGLONG *output, int *status); +int fffr8i8(double *input, long ntodo, double scale, double zero, + int nullcheck, LONGLONG nullval, char *nullarray, + int *anynull, LONGLONG *output, int *status); +int fffstri8(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + LONGLONG nullval, char *nullarray, int *anynull, LONGLONG *output, + int *status); + +int fffi1r4(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, float nullval, char *nullarray, + int *anynull, float *output, int *status); +int fffi2r4(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, float nullval, char *nullarray, + int *anynull, float *output, int *status); +int fffi4r4(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, float nullval, char *nullarray, + int *anynull, float *output, int *status); +int fffi8r4(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, float nullval, char *nullarray, + int *anynull, float *output, int *status); +int fffr4r4(float *input, long ntodo, double scale, double zero, + int nullcheck, float nullval, char *nullarray, + int *anynull, float *output, int *status); +int fffr8r4(double *input, long ntodo, double scale, double zero, + int nullcheck, float nullval, char *nullarray, + int *anynull, float *output, int *status); +int fffstrr4(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + float nullval, char *nullarray, int *anynull, float *output, + int *status); + +int fffi1r8(unsigned char *input, long ntodo, double scale, double zero, + int nullcheck, unsigned char tnull, double nullval, char *nullarray, + int *anynull, double *output, int *status); +int fffi2r8(short *input, long ntodo, double scale, double zero, + int nullcheck, short tnull, double nullval, char *nullarray, + int *anynull, double *output, int *status); +int fffi4r8(INT32BIT *input, long ntodo, double scale, double zero, + int nullcheck, INT32BIT tnull, double nullval, char *nullarray, + int *anynull, double *output, int *status); +int fffi8r8(LONGLONG *input, long ntodo, double scale, double zero, + int nullcheck, long tnull, double nullval, char *nullarray, + int *anynull, double *output, int *status); +int fffr4r8(float *input, long ntodo, double scale, double zero, + int nullcheck, double nullval, char *nullarray, + int *anynull, double *output, int *status); +int fffr8r8(double *input, long ntodo, double scale, double zero, + int nullcheck, double nullval, char *nullarray, + int *anynull, double *output, int *status); +int fffstrr8(char *input, long ntodo, double scale, double zero, + long twidth, double power, int nullcheck, char *snull, + double nullval, char *nullarray, int *anynull, double *output, + int *status); + +int ffi1fi1(unsigned char *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffs1fi1(signed char *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffu2fi1(unsigned short *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffi2fi1(short *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffu4fi1(unsigned long *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffi4fi1(long *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffi8fi1(LONGLONG *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffuintfi1(unsigned int *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffintfi1(int *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffr4fi1(float *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); +int ffr8fi1(double *array, long ntodo, double scale, double zero, + unsigned char *buffer, int *status); + +int ffi1fi2(unsigned char *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffs1fi2(signed char *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffu2fi2(unsigned short *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffi2fi2(short *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffu4fi2(unsigned long *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffi4fi2(long *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffi8fi2(LONGLONG *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffuintfi2(unsigned int *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffintfi2(int *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffr4fi2(float *array, long ntodo, double scale, double zero, + short *buffer, int *status); +int ffr8fi2(double *array, long ntodo, double scale, double zero, + short *buffer, int *status); + +int ffi1fi4(unsigned char *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffs1fi4(signed char *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffu2fi4(unsigned short *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffi2fi4(short *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffu4fi4(unsigned long *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffi4fi4(long *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffi8fi4(LONGLONG *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffuintfi4(unsigned int *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffintfi4(int *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffr4fi4(float *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); +int ffr8fi4(double *array, long ntodo, double scale, double zero, + INT32BIT *buffer, int *status); + +int fflongfi8(long *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffi8fi8(LONGLONG *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffi2fi8(short *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffi1fi8(unsigned char *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffs1fi8(signed char *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffr4fi8(float *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffr8fi8(double *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffintfi8(int *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffu2fi8(unsigned short *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffu4fi8(unsigned long *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); +int ffuintfi8(unsigned int *array, long ntodo, double scale, double zero, + LONGLONG *buffer, int *status); + +int ffi1fr4(unsigned char *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffs1fr4(signed char *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffu2fr4(unsigned short *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffi2fr4(short *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffu4fr4(unsigned long *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffi4fr4(long *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffi8fr4(LONGLONG *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffuintfr4(unsigned int *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffintfr4(int *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffr4fr4(float *array, long ntodo, double scale, double zero, + float *buffer, int *status); +int ffr8fr4(double *array, long ntodo, double scale, double zero, + float *buffer, int *status); + +int ffi1fr8(unsigned char *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffs1fr8(signed char *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffu2fr8(unsigned short *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffi2fr8(short *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffu4fr8(unsigned long *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffi4fr8(long *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffi8fr8(LONGLONG *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffuintfr8(unsigned int *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffintfr8(int *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffr4fr8(float *array, long ntodo, double scale, double zero, + double *buffer, int *status); +int ffr8fr8(double *array, long ntodo, double scale, double zero, + double *buffer, int *status); + +int ffi1fstr(unsigned char *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffs1fstr(signed char *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffu2fstr(unsigned short *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffi2fstr(short *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffu4fstr(unsigned long *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffi4fstr(long *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffi8fstr(LONGLONG *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffintfstr(int *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffuintfstr(unsigned int *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffr4fstr(float *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); +int ffr8fstr(double *input, long ntodo, double scale, double zero, + char *cform, long twidth, char *output, int *status); + +/* the following 4 routines are VMS macros used on VAX or Alpha VMS */ +void ieevpd(double *inarray, double *outarray, long *nvals); +void ieevud(double *inarray, double *outarray, long *nvals); +void ieevpr(float *inarray, float *outarray, long *nvals); +void ieevur(float *inarray, float *outarray, long *nvals); + +/* routines related to the lexical parser */ +int ffselect_table(fitsfile **fptr, char *outfile, char *expr, int *status); +int ffiprs( fitsfile *fptr, int compressed, char *expr, int maxdim, + int *datatype, long *nelem, int *naxis, long *naxes, + int *status ); +void ffcprs( void ); +int ffcvtn( int inputType, void *input, char *undef, long ntodo, + int outputType, void *nulval, void *output, + int *anynull, int *status ); +int parse_data( long totalrows, long offset, long firstrow, + long nrows, int nCols, iteratorCol *colData, + void *userPtr ); +int uncompress_hkdata( fitsfile *fptr, long ntimes, + double *times, int *status ); +int ffffrw_work( long totalrows, long offset, long firstrow, + long nrows, int nCols, iteratorCol *colData, + void *userPtr ); + + +/* image compression routines */ +int fits_write_compressed_img(fitsfile *fptr, + int datatype, long *fpixel, long *lpixel, + int nullcheck, void *array, void *nulval, + int *status); +int fits_write_compressed_pixels(fitsfile *fptr, + int datatype, OFF_T fpixel, long npixels, + int nullcheck, void *array, void *nulval, + int *status); +int fits_write_compressed_img_plane(fitsfile *fptr, int datatype, + int bytesperpixel, long nplane, long *firstcoord, long *lastcoord, + long *naxes, int nullcheck, + void *array, void *nullval, long *nread, int *status); + +int imcomp_init_table(fitsfile *outfptr, int compress_type, + int bitpix, int naxis,long *naxes,long *tilesize, + int rice_blocksize,int rice_nbits,int *status); +int imcomp_calc_max_elem (int comptype, int nx, int blocksize); +int imcomp_copy_imheader(fitsfile *infptr, fitsfile *outfptr, + int *status); +int imcomp_compress_image (fitsfile *infptr, fitsfile *outfptr, + int *status); +int imcomp_compress_tile (fitsfile *outfptr, long row, + int datatype, void *tiledata, long tilelen, int *status); + +/* image decompression routines */ + +int fits_read_compressed_img(fitsfile *fptr, + int datatype, long *fpixel,long *lpixel,long *inc, + int nullcheck, void *nulval, void *array, char *nullarray, + int *anynul, int *status); +int fits_read_compressed_pixels(fitsfile *fptr, + int datatype, OFF_T fpixel, long npixels, + int nullcheck, void *nulval, void *array, char *nullarray, + int *anynul, int *status); +int fits_read_compressed_img_plane(fitsfile *fptr, int datatype, + int bytesperpixel, long nplane, long *firstcoord, long *lastcoord, + long *inc, long *naxes, int nullcheck, void *nullval, + void *array, char *nullarray, int *anynul, long *nread, int *status); + +int imcomp_get_compressed_image_par(fitsfile *infptr, int *status); +int imcomp_decompress_tile (fitsfile *infptr, + int nrow, int tilesize, int datatype, int nullcheck, + void *nulval, void *buffer, char *bnullarray, int *anynul, + int *status); +int imcomp_copy_overlap (char *tile, int pixlen, int ndim, + long *tfpixel, long *tlpixel, char *bnullarray, char *image, + long *fpixel, long *lpixel, long *inc, int nullcheck, char *nullarray, + int *status); +int imcomp_merge_overlap (char *tile, int pixlen, int ndim, + long *tfpixel, long *tlpixel, char *bnullarray, char *image, + long *fpixel, long *lpixel, int nullcheck, int *status); + +int fits_quantize_float (float fdata[], int nx, float in_null_value, + int noise_bits, int idata[], double *bscale, double *bzero, + int *iminval, int *imaxval); +int fits_quantize_double (double fdata[], int nx, double in_null_value, + int noise_bits, int idata[], double *bscale, double *bzero, + int *iminval, int *imaxval); +int fits_rcomp(int a[], int nx, unsigned char *c, int clen,int nblock); +int fits_rdecomp (unsigned char *c, int clen, unsigned int array[], int nx, + int nblock); + +int pl_p2li (int *pxsrc, int xs, short *lldst, int npix); +int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix); + +/* general driver routines */ + +int urltype2driver(char *urltype, int *driver); +int fits_init_cfitsio(void); + +int fits_register_driver( char *prefix, + int (*init)(void), + int (*fitsshutdown)(void), + int (*setoptions)(int option), + int (*getoptions)(int *options), + int (*getversion)(int *version), + int (*checkfile) (char *urltype, char *infile, char *outfile), + int (*fitsopen)(char *filename, int rwmode, int *driverhandle), + int (*fitscreate)(char *filename, int *driverhandle), + int (*fitstruncate)(int driverhandle, OFF_T filesize), + int (*fitsclose)(int driverhandle), + int (*fremove)(char *filename), + int (*size)(int driverhandle, OFF_T *size), + int (*flush)(int driverhandle), + int (*seek)(int driverhandle, OFF_T offset), + int (*fitsread) (int driverhandle, void *buffer, long nbytes), + int (*fitswrite)(int driverhandle, void *buffer, long nbytes)); + +/* file driver I/O routines */ + +int file_init(void); +int file_setoptions(int options); +int file_getoptions(int *options); +int file_getversion(int *version); +int file_shutdown(void); +int file_checkfile(char *urltype, char *infile, char *outfile); +int file_open(char *filename, int rwmode, int *driverhandle); +int file_compress_open(char *filename, int rwmode, int *hdl); +int file_openfile(char *filename, int rwmode, FILE **diskfile); +int file_create(char *filename, int *driverhandle); +int file_truncate(int driverhandle, OFF_T filesize); +int file_size(int driverhandle, OFF_T *filesize); +int file_close(int driverhandle); +int file_remove(char *filename); +int file_flush(int driverhandle); +int file_seek(int driverhandle, OFF_T offset); +int file_read (int driverhandle, void *buffer, long nbytes); +int file_write(int driverhandle, void *buffer, long nbytes); +int file_is_compressed(char *filename); + +/* memory driver I/O routines */ + +int mem_init(void); +int mem_setoptions(int options); +int mem_getoptions(int *options); +int mem_getversion(int *version); +int mem_shutdown(void); +int mem_create(char *filename, int *handle); +int mem_create_comp(char *filename, int *handle); +int mem_openmem(void **buffptr, size_t *buffsize, size_t deltasize, + void *(*memrealloc)(void *p, size_t newsize), int *handle); +int mem_createmem(size_t memsize, int *handle); +int stdin_checkfile(char *urltype, char *infile, char *outfile); +int stdin_open(char *filename, int rwmode, int *handle); +int stdin2mem(int hd); +int stdin2file(int hd); +int stdout_close(int handle); +int mem_compress_openrw(char *filename, int rwmode, int *hdl); +int mem_compress_open(char *filename, int rwmode, int *hdl); +int mem_iraf_open(char *filename, int rwmode, int *hdl); +int mem_rawfile_open(char *filename, int rwmode, int *hdl); +int mem_size(int handle, OFF_T *filesize); +int mem_truncate(int handle, OFF_T filesize); +int mem_close_free(int handle); +int mem_close_keep(int handle); +int mem_close_comp(int handle); +int mem_seek(int handle, OFF_T offset); +int mem_read(int hdl, void *buffer, long nbytes); +int mem_write(int hdl, void *buffer, long nbytes); +int mem_uncompress2mem(char *filename, FILE *diskfile, int hdl); + +int iraf2mem(char *filename, char **buffptr, size_t *buffsize, + size_t *filesize, int *status); + +/* root driver I/O routines */ + +int root_init(void); +int root_setoptions(int options); +int root_getoptions(int *options); +int root_getversion(int *version); +int root_shutdown(void); +int root_open(char *filename, int rwmode, int *driverhandle); +int root_create(char *filename, int *driverhandle); +int root_close(int driverhandle); +int root_flush(int driverhandle); +int root_seek(int driverhandle, OFF_T offset); +int root_read (int driverhandle, void *buffer, long nbytes); +int root_write(int driverhandle, void *buffer, long nbytes); +int root_size(int handle, OFF_T *filesize); + +/* http driver I/O routines */ + +int http_checkfile(char *urltype, char *infile, char *outfile); +int http_open(char *filename, int rwmode, int *driverhandle); +int http_file_open(char *filename, int rwmode, int *driverhandle); +int http_compress_open(char *filename, int rwmode, int *driverhandle); + +/* ftp driver I/O routines */ + +int ftp_checkfile(char *urltype, char *infile, char *outfile); +int ftp_open(char *filename, int rwmode, int *driverhandle); +int ftp_file_open(char *filename, int rwmode, int *driverhandle); +int ftp_compress_open(char *filename, int rwmode, int *driverhandle); + + +int uncompress2mem(char *filename, FILE *diskfile, + char **buffptr, size_t *buffsize, + void *(*mem_realloc)(void *p, size_t newsize), + size_t *filesize, int *status); + +int uncompress2mem_from_mem( + char *inmemptr, + size_t inmemsize, + char **buffptr, + size_t *buffsize, + void *(*mem_realloc)(void *p, size_t newsize), + size_t *filesize, + int *status); + +int uncompress2file(char *filename, + FILE *indiskfile, + FILE *outdiskfile, + int *status); + +int compress2mem_from_mem( + char *inmemptr, + size_t inmemsize, + char **buffptr, + size_t *buffsize, + void *(*mem_realloc)(void *p, size_t newsize), + size_t *filesize, + int *status); + +int compress2file_from_mem( + char *inmemptr, + size_t inmemsize, + FILE *outdiskfile, + size_t *filesize, /* O - size of file, in bytes */ + int *status); + +/* ==================== SHARED MEMORY DRIVER SECTION ======================= */ + +#ifdef HAVE_SHMEM_SERVICES +#include "drvrsmem.h" +#endif + +/* ==================== END OF SHARED MEMORY DRIVER SECTION ================ */ + +#endif + + +#if defined(vms) || defined(__vms) || defined(WIN32) || defined(__WIN32__) || (defined(macintosh) && !defined(TARGET_API_MAC_CARBON)) + +/* ================================================================== */ +/* A hack for nonunix machines, which lack strcasecmp and strncasecmp */ +/* ================================================================== */ + +int strcasecmp (const char *s1, const char *s2 ); +int strncasecmp(const char *s1, const char *s2, size_t n); + +#endif diff --git a/contrib/include/longnam.h b/contrib/include/longnam.h new file mode 100644 index 00000000..4e34f2c2 --- /dev/null +++ b/contrib/include/longnam.h @@ -0,0 +1,535 @@ +#ifndef _LONGNAME_H +#define _LONGNAME_H + +#define fits_parse_input_url ffiurl +#define fits_parse_rootname ffrtnm +#define fits_parse_output_url ffourl +#define fits_parse_extspec ffexts +#define fits_parse_extnum ffextn +#define fits_parse_binspec ffbins +#define fits_parse_binrange ffbinr +#define fits_parse_range ffrwrg +#define fits_open_memfile ffomem +#define fits_open_file ffopen +#define fits_open_data ffdopn +#define fits_open_table fftopn +#define fits_open_image ffiopn +#define fits_reopen_file ffreopen +#define fits_create_file ffinit +#define fits_create_memfile ffimem +#define fits_create_template fftplt +#define fits_flush_file ffflus +#define fits_flush_buffer ffflsh +#define fits_close_file ffclos +#define fits_delete_file ffdelt +#define fits_file_name ffflnm +#define fits_file_mode ffflmd +#define fits_url_type ffurlt + +#define fits_get_version ffvers +#define fits_uppercase ffupch +#define fits_get_errstatus ffgerr +#define fits_write_errmsg ffpmsg +#define fits_write_errmark ffpmrk +#define fits_read_errmsg ffgmsg +#define fits_clear_errmsg ffcmsg +#define fits_clear_errmark ffcmrk +#define fits_report_error ffrprt +#define fits_compare_str ffcmps +#define fits_test_keyword fftkey +#define fits_test_record fftrec +#define fits_null_check ffnchk +#define fits_make_keyn ffkeyn +#define fits_make_nkey ffnkey +#define fits_get_keyclass ffgkcl +#define fits_get_keytype ffdtyp +#define fits_parse_value ffpsvc +#define fits_get_keyname ffgknm +#define fits_parse_template ffgthd +#define fits_ascii_tform ffasfm +#define fits_binary_tform ffbnfm +#define fits_get_tbcol ffgabc +#define fits_get_rowsize ffgrsz +#define fits_get_col_display_width ffgcdw + +#define fits_write_record ffprec +#define fits_write_key ffpky +#define fits_write_key_unit ffpunt +#define fits_write_comment ffpcom +#define fits_write_history ffphis +#define fits_write_date ffpdat +#define fits_get_system_time ffgstm +#define fits_get_system_date ffgsdt +#define fits_date2str ffdt2s +#define fits_time2str fftm2s +#define fits_str2date ffs2dt +#define fits_str2time ffs2tm +#define fits_write_key_longstr ffpkls +#define fits_write_key_longwarn ffplsw +#define fits_write_key_null ffpkyu +#define fits_write_key_str ffpkys +#define fits_write_key_log ffpkyl +#define fits_write_key_lng ffpkyj +#define fits_write_key_fixflt ffpkyf +#define fits_write_key_flt ffpkye +#define fits_write_key_fixdbl ffpkyg +#define fits_write_key_dbl ffpkyd +#define fits_write_key_fixcmp ffpkfc +#define fits_write_key_cmp ffpkyc +#define fits_write_key_fixdblcmp ffpkfm +#define fits_write_key_dblcmp ffpkym +#define fits_write_key_triple ffpkyt +#define fits_write_tdim ffptdm +#define fits_write_keys_str ffpkns +#define fits_write_keys_log ffpknl +#define fits_write_keys_lng ffpknj +#define fits_write_keys_fixflt ffpknf +#define fits_write_keys_flt ffpkne +#define fits_write_keys_fixdbl ffpkng +#define fits_write_keys_dbl ffpknd +#define fits_copy_key ffcpky +#define fits_write_imghdr ffphps +#define fits_write_grphdr ffphpr +#define fits_write_atblhdr ffphtb +#define fits_write_btblhdr ffphbn +#define fits_write_key_template ffpktp + +#define fits_get_hdrspace ffghsp +#define fits_get_hdrpos ffghps +#define fits_movabs_key ffmaky +#define fits_movrel_key ffmrky +#define fits_find_nextkey ffgnxk + +#define fits_read_record ffgrec +#define fits_read_card ffgcrd +#define fits_read_key_unit ffgunt +#define fits_read_keyn ffgkyn +#define fits_read_key ffgky +#define fits_read_keyword ffgkey +#define fits_read_key_str ffgkys +#define fits_read_key_log ffgkyl +#define fits_read_key_lng ffgkyj +#define fits_read_key_flt ffgkye +#define fits_read_key_dbl ffgkyd +#define fits_read_key_cmp ffgkyc +#define fits_read_key_dblcmp ffgkym +#define fits_read_key_triple ffgkyt +#define fits_read_key_longstr ffgkls +#define fits_read_tdim ffgtdm +#define fits_decode_tdim ffdtdm +#define fits_read_keys_str ffgkns +#define fits_read_keys_log ffgknl +#define fits_read_keys_lng ffgknj +#define fits_read_keys_flt ffgkne +#define fits_read_keys_dbl ffgknd +#define fits_read_imghdr ffghpr +#define fits_read_atblhdr ffghtb +#define fits_read_btblhdr ffghbn +#define fits_hdr2str ffhdr2str + +#define fits_update_card ffucrd +#define fits_update_key ffuky +#define fits_update_key_null ffukyu +#define fits_update_key_str ffukys +#define fits_update_key_longstr ffukls +#define fits_update_key_log ffukyl +#define fits_update_key_lng ffukyj +#define fits_update_key_fixflt ffukyf +#define fits_update_key_flt ffukye +#define fits_update_key_fixdbl ffukyg +#define fits_update_key_dbl ffukyd +#define fits_update_key_fixcmp ffukfc +#define fits_update_key_cmp ffukyc +#define fits_update_key_fixdblcmp ffukfm +#define fits_update_key_dblcmp ffukym + +#define fits_modify_record ffmrec +#define fits_modify_card ffmcrd +#define fits_modify_name ffmnam +#define fits_modify_comment ffmcom +#define fits_modify_key_null ffmkyu +#define fits_modify_key_str ffmkys +#define fits_modify_key_longstr ffmkls +#define fits_modify_key_log ffmkyl +#define fits_modify_key_lng ffmkyj +#define fits_modify_key_fixflt ffmkyf +#define fits_modify_key_flt ffmkye +#define fits_modify_key_fixdbl ffmkyg +#define fits_modify_key_dbl ffmkyd +#define fits_modify_key_fixcmp ffmkfc +#define fits_modify_key_cmp ffmkyc +#define fits_modify_key_fixdblcmp ffmkfm +#define fits_modify_key_dblcmp ffmkym + +#define fits_insert_record ffirec +#define fits_insert_card ffikey +#define fits_insert_key_null ffikyu +#define fits_insert_key_str ffikys +#define fits_insert_key_longstr ffikls +#define fits_insert_key_log ffikyl +#define fits_insert_key_lng ffikyj +#define fits_insert_key_fixflt ffikyf +#define fits_insert_key_flt ffikye +#define fits_insert_key_fixdbl ffikyg +#define fits_insert_key_dbl ffikyd +#define fits_insert_key_fixcmp ffikfc +#define fits_insert_key_cmp ffikyc +#define fits_insert_key_fixdblcmp ffikfm +#define fits_insert_key_dblcmp ffikym + +#define fits_delete_key ffdkey +#define fits_delete_record ffdrec +#define fits_get_hdu_num ffghdn +#define fits_get_hdu_type ffghdt +#define fits_get_hduaddr ffghad +#define fits_get_hduoff ffghof + +#define fits_get_img_param ffgipr +#define fits_get_img_type ffgidt +#define fits_get_img_equivtype ffgiet +#define fits_get_img_dim ffgidm +#define fits_get_img_size ffgisz + +#define fits_movabs_hdu ffmahd +#define fits_movrel_hdu ffmrhd +#define fits_movnam_hdu ffmnhd +#define fits_get_num_hdus ffthdu +#define fits_create_img ffcrim +#define fits_create_tbl ffcrtb +#define fits_create_hdu ffcrhd +#define fits_insert_img ffiimg +#define fits_insert_atbl ffitab +#define fits_insert_btbl ffibin +#define fits_resize_img ffrsim +#define fits_delete_hdu ffdhdu +#define fits_copy_hdu ffcopy +#define fits_copy_file ffcpfl +#define fits_copy_header ffcphd +#define fits_copy_data ffcpdt + +#define fits_set_hdustruc ffrdef +#define fits_set_hdrsize ffhdef +#define fits_write_theap ffpthp + +#define fits_encode_chksum ffesum +#define fits_decode_chksum ffdsum +#define fits_write_chksum ffpcks +#define fits_update_chksum ffupck +#define fits_verify_chksum ffvcks +#define fits_get_chksum ffgcks + +#define fits_set_bscale ffpscl +#define fits_set_tscale fftscl +#define fits_set_imgnull ffpnul +#define fits_set_btblnull fftnul +#define fits_set_atblnull ffsnul + +#define fits_get_colnum ffgcno +#define fits_get_colname ffgcnn +#define fits_get_coltype ffgtcl +#define fits_get_eqcoltype ffeqty +#define fits_get_num_rows ffgnrw +#define fits_get_num_cols ffgncl +#define fits_get_acolparms ffgacl +#define fits_get_bcolparms ffgbcl + +#define fits_iterate_data ffiter + +#define fits_read_grppar_byt ffggpb +#define fits_read_grppar_sbyt ffggpsb +#define fits_read_grppar_usht ffggpui +#define fits_read_grppar_ulng ffggpuj +#define fits_read_grppar_sht ffggpi +#define fits_read_grppar_lng ffggpj +#define fits_read_grppar_lnglng ffggpjj +#define fits_read_grppar_int ffggpk +#define fits_read_grppar_uint ffggpuk +#define fits_read_grppar_flt ffggpe +#define fits_read_grppar_dbl ffggpd + +#define fits_read_pix ffgpxv +#define fits_read_pixnull ffgpxf +#define fits_read_img ffgpv +#define fits_read_imgnull ffgpf +#define fits_read_img_byt ffgpvb +#define fits_read_img_sbyt ffgpvsb +#define fits_read_img_usht ffgpvui +#define fits_read_img_ulng ffgpvuj +#define fits_read_img_sht ffgpvi +#define fits_read_img_lng ffgpvj +#define fits_read_img_lnglng ffgpvjj +#define fits_read_img_uint ffgpvuk +#define fits_read_img_int ffgpvk +#define fits_read_img_flt ffgpve +#define fits_read_img_dbl ffgpvd + +#define fits_read_imgnull_byt ffgpfb +#define fits_read_imgnull_sbyt ffgpfsb +#define fits_read_imgnull_usht ffgpfui +#define fits_read_imgnull_ulng ffgpfuj +#define fits_read_imgnull_sht ffgpfi +#define fits_read_imgnull_lng ffgpfj +#define fits_read_imgnull_lnglng ffgpfjj +#define fits_read_imgnull_uint ffgpfuk +#define fits_read_imgnull_int ffgpfk +#define fits_read_imgnull_flt ffgpfe +#define fits_read_imgnull_dbl ffgpfd + +#define fits_read_2d_byt ffg2db +#define fits_read_2d_sbyt ffg2dsb +#define fits_read_2d_usht ffg2dui +#define fits_read_2d_ulng ffg2duj +#define fits_read_2d_sht ffg2di +#define fits_read_2d_lng ffg2dj +#define fits_read_2d_lnglng ffg2djj +#define fits_read_2d_uint ffg2duk +#define fits_read_2d_int ffg2dk +#define fits_read_2d_flt ffg2de +#define fits_read_2d_dbl ffg2dd + +#define fits_read_3d_byt ffg3db +#define fits_read_3d_sbyt ffg3dsb +#define fits_read_3d_usht ffg3dui +#define fits_read_3d_ulng ffg3duj +#define fits_read_3d_sht ffg3di +#define fits_read_3d_lng ffg3dj +#define fits_read_3d_lnglng ffg3djj +#define fits_read_3d_uint ffg3duk +#define fits_read_3d_int ffg3dk +#define fits_read_3d_flt ffg3de +#define fits_read_3d_dbl ffg3dd + +#define fits_read_subset ffgsv +#define fits_read_subset_byt ffgsvb +#define fits_read_subset_sbyt ffgsvsb +#define fits_read_subset_usht ffgsvui +#define fits_read_subset_ulng ffgsvuj +#define fits_read_subset_sht ffgsvi +#define fits_read_subset_lng ffgsvj +#define fits_read_subset_lnglng ffgsvjj +#define fits_read_subset_uint ffgsvuk +#define fits_read_subset_int ffgsvk +#define fits_read_subset_flt ffgsve +#define fits_read_subset_dbl ffgsvd + +#define fits_read_subsetnull_byt ffgsfb +#define fits_read_subsetnull_sbyt ffgsfsb +#define fits_read_subsetnull_usht ffgsfui +#define fits_read_subsetnull_ulng ffgsfuj +#define fits_read_subsetnull_sht ffgsfi +#define fits_read_subsetnull_lng ffgsfj +#define fits_read_subsetnull_lnglng ffgsfjj +#define fits_read_subsetnull_uint ffgsfuk +#define fits_read_subsetnull_int ffgsfk +#define fits_read_subsetnull_flt ffgsfe +#define fits_read_subsetnull_dbl ffgsfd + +#define fits_compress_img fits_comp_img +#define fits_decompress_img fits_decomp_img + +#define fits_read_col ffgcv +#define fits_read_colnull ffgcf +#define fits_read_col_str ffgcvs +#define fits_read_col_log ffgcvl +#define fits_read_col_byt ffgcvb +#define fits_read_col_sbyt ffgcvsb +#define fits_read_col_usht ffgcvui +#define fits_read_col_ulng ffgcvuj +#define fits_read_col_sht ffgcvi +#define fits_read_col_lng ffgcvj +#define fits_read_col_lnglng ffgcvjj +#define fits_read_col_uint ffgcvuk +#define fits_read_col_int ffgcvk +#define fits_read_col_flt ffgcve +#define fits_read_col_dbl ffgcvd +#define fits_read_col_cmp ffgcvc +#define fits_read_col_dblcmp ffgcvm +#define fits_read_col_bit ffgcx +#define fits_read_col_bit_usht ffgcxui +#define fits_read_col_bit_uint ffgcxuk + +#define fits_read_colnull_str ffgcfs +#define fits_read_colnull_log ffgcfl +#define fits_read_colnull_byt ffgcfb +#define fits_read_colnull_sbyt ffgcfsb +#define fits_read_colnull_usht ffgcfui +#define fits_read_colnull_ulng ffgcfuj +#define fits_read_colnull_sht ffgcfi +#define fits_read_colnull_lng ffgcfj +#define fits_read_colnull_lnglng ffgcfjj +#define fits_read_colnull_uint ffgcfuk +#define fits_read_colnull_int ffgcfk +#define fits_read_colnull_flt ffgcfe +#define fits_read_colnull_dbl ffgcfd +#define fits_read_colnull_cmp ffgcfc +#define fits_read_colnull_dblcmp ffgcfm + +#define fits_read_descript ffgdes +#define fits_read_descripts ffgdess +#define fits_read_tblbytes ffgtbb + +#define fits_write_grppar_byt ffpgpb +#define fits_write_grppar_sbyt ffpgpsb +#define fits_write_grppar_usht ffpgpui +#define fits_write_grppar_ulng ffpgpuj +#define fits_write_grppar_sht ffpgpi +#define fits_write_grppar_lng ffpgpj +#define fits_write_grppar_lnglng ffpgpjj +#define fits_write_grppar_uint ffpgpuk +#define fits_write_grppar_int ffpgpk +#define fits_write_grppar_flt ffpgpe +#define fits_write_grppar_dbl ffpgpd + +#define fits_write_pix ffppx +#define fits_write_pixnull ffppxn +#define fits_write_img ffppr +#define fits_write_img_byt ffpprb +#define fits_write_img_sbyt ffpprsb +#define fits_write_img_usht ffpprui +#define fits_write_img_ulng ffppruj +#define fits_write_img_sht ffppri +#define fits_write_img_lng ffpprj +#define fits_write_img_lnglng ffpprjj +#define fits_write_img_uint ffppruk +#define fits_write_img_int ffpprk +#define fits_write_img_flt ffppre +#define fits_write_img_dbl ffpprd + +#define fits_write_imgnull ffppn +#define fits_write_imgnull_byt ffppnb +#define fits_write_imgnull_sbyt ffppnsb +#define fits_write_imgnull_usht ffppnui +#define fits_write_imgnull_ulng ffppnuj +#define fits_write_imgnull_sht ffppni +#define fits_write_imgnull_lng ffppnj +#define fits_write_imgnull_lnglng ffppnjj +#define fits_write_imgnull_uint ffppnuk +#define fits_write_imgnull_int ffppnk +#define fits_write_imgnull_flt ffppne +#define fits_write_imgnull_dbl ffppnd + +#define fits_write_img_null ffppru +#define fits_write_null_img ffpprn + +#define fits_write_2d_byt ffp2db +#define fits_write_2d_sbyt ffp2dsb +#define fits_write_2d_usht ffp2dui +#define fits_write_2d_ulng ffp2duj +#define fits_write_2d_sht ffp2di +#define fits_write_2d_lng ffp2dj +#define fits_write_2d_lnglng ffp2djj +#define fits_write_2d_uint ffp2duk +#define fits_write_2d_int ffp2dk +#define fits_write_2d_flt ffp2de +#define fits_write_2d_dbl ffp2dd + +#define fits_write_3d_byt ffp3db +#define fits_write_3d_sbyt ffp3dsb +#define fits_write_3d_usht ffp3dui +#define fits_write_3d_ulng ffp3duj +#define fits_write_3d_sht ffp3di +#define fits_write_3d_lng ffp3dj +#define fits_write_3d_lnglng ffp3djj +#define fits_write_3d_uint ffp3duk +#define fits_write_3d_int ffp3dk +#define fits_write_3d_flt ffp3de +#define fits_write_3d_dbl ffp3dd + +#define fits_write_subset ffpss +#define fits_write_subset_byt ffpssb +#define fits_write_subset_sbyt ffpsssb +#define fits_write_subset_usht ffpssui +#define fits_write_subset_ulng ffpssuj +#define fits_write_subset_sht ffpssi +#define fits_write_subset_lng ffpssj +#define fits_write_subset_lnglng ffpssjj +#define fits_write_subset_uint ffpssuk +#define fits_write_subset_int ffpssk +#define fits_write_subset_flt ffpsse +#define fits_write_subset_dbl ffpssd + +#define fits_write_col ffpcl +#define fits_write_col_str ffpcls +#define fits_write_col_log ffpcll +#define fits_write_col_byt ffpclb +#define fits_write_col_sbyt ffpclsb +#define fits_write_col_usht ffpclui +#define fits_write_col_ulng ffpcluj +#define fits_write_col_sht ffpcli +#define fits_write_col_lng ffpclj +#define fits_write_col_lnglng ffpcljj +#define fits_write_col_uint ffpcluk +#define fits_write_col_int ffpclk +#define fits_write_col_flt ffpcle +#define fits_write_col_dbl ffpcld +#define fits_write_col_cmp ffpclc +#define fits_write_col_dblcmp ffpclm +#define fits_write_col_null ffpclu +#define fits_write_col_bit ffpclx + +#define fits_write_colnull ffpcn +#define fits_write_colnull_str ffpcns +#define fits_write_colnull_log ffpcnl +#define fits_write_colnull_byt ffpcnb +#define fits_write_colnull_sbyt ffpcnsb +#define fits_write_colnull_usht ffpcnui +#define fits_write_colnull_ulng ffpcnuj +#define fits_write_colnull_sht ffpcni +#define fits_write_colnull_lng ffpcnj +#define fits_write_colnull_lnglng ffpcnjj +#define fits_write_colnull_uint ffpcnuk +#define fits_write_colnull_int ffpcnk +#define fits_write_colnull_flt ffpcne +#define fits_write_colnull_dbl ffpcnd + +#define fits_write_descript ffpdes +#define fits_compress_heap ffcmph +#define fits_test_heap fftheap + +#define fits_write_tblbytes ffptbb +#define fits_insert_rows ffirow +#define fits_delete_rows ffdrow +#define fits_delete_rowrange ffdrrg +#define fits_delete_rowlist ffdrws +#define fits_insert_col fficol +#define fits_insert_cols fficls +#define fits_delete_col ffdcol +#define fits_copy_col ffcpcl +#define fits_modify_vector_len ffmvec + +#define fits_read_img_coord ffgics +#define fits_read_tbl_coord ffgtcs +#define fits_pix_to_world ffwldp +#define fits_world_to_pix ffxypx + +#define fits_get_image_wcs_keys ffgiwcs +#define fits_get_table_wcs_keys ffgtwcs + +#define fits_find_rows fffrow +#define fits_find_first_row ffffrw +#define fits_find_rows_cmp fffrwc +#define fits_select_rows ffsrow +#define fits_calc_rows ffcrow +#define fits_calculator ffcalc +#define fits_calculator_rng ffcalc_rng +#define fits_test_expr fftexp + +#define fits_create_group ffgtcr +#define fits_insert_group ffgtis +#define fits_change_group ffgtch +#define fits_remove_group ffgtrm +#define fits_copy_group ffgtcp +#define fits_merge_groups ffgtmg +#define fits_compact_group ffgtcm +#define fits_verify_group ffgtvf +#define fits_open_group ffgtop +#define fits_add_group_member ffgtam +#define fits_get_num_members ffgtnm + +#define fits_get_num_groups ffgmng +#define fits_open_member ffgmop +#define fits_copy_member ffgmcp +#define fits_transfer_member ffgmtf +#define fits_remove_member ffgmrm + +#endif diff --git a/contrib/include/rdcolor.h b/contrib/include/rdcolor.h new file mode 100644 index 00000000..0aa99593 --- /dev/null +++ b/contrib/include/rdcolor.h @@ -0,0 +1,89 @@ +/* color.h: this file specifies that all colors are actually pointers to + * color strings. It is expected that the function "rdcolor()" will + * be used to initialize the colors. "rdcolor()" examines a colorfile + * called "color.dat" for color strings: color ... where the ellipsis + * is the desired escape string. The default value of such color strings + * is set for a color ASCII monitor (8 colors) and the IDS Prism printer. + */ +#ifndef RDCOLOR_H +#define RDCOLOR_H + +#ifndef __GL_GL_H__ +extern char *BLACK; +extern char *RED; +extern char *GREEN; +extern char *YELLOW; +extern char *BLUE; +extern char *MAGENTA; +extern char *CYAN; +extern char *WHITE; +#endif + +extern char *RD_BLACK; /* same as BLACK */ +extern char *RD_RED; /* same as RED */ +extern char *RD_GREEN; /* same as GREEN */ +extern char *RD_YELLOW; /* same as YELLOW */ +extern char *RD_BLUE; /* same as BLUE */ +extern char *RD_MAGENTA; /* same as MAGENTA */ +extern char *RD_CYAN; /* same as CYAN */ +extern char *RD_WHITE; /* same as WHITE */ + +extern char *UBLACK; +extern char *URED; +extern char *UGREEN; +extern char *UYELLOW; +extern char *UBLUE; +extern char *UMAGENTA; +extern char *UCYAN; +extern char *UWHITE; +extern char *RVBLACK; +extern char *RVRED; +extern char *RVGREEN; +extern char *RVYELLOW; +extern char *RVBLUE; +extern char *RVMAGENTA; +extern char *RVCYAN; +extern char *RVWHITE; +#ifndef VIM__H +extern char *CLEAR; +#endif +extern char *BOLD; +extern char *NRML; +extern char *PYELLOW; +extern char *PRED; +extern char *PCYAN; +extern char *PBLACK; + +/* for rdcputs's benefit... */ +#define XBLACK "\255X0" +#define XRED "\255X1" +#define XGREEN "\255X2" +#define XYELLOW "\255X3" +#define XBLUE "\255X4" +#define XMAGENTA "\255X5" +#define XCYAN "\255X6" +#define XWHITE "\255X7" +#define XUBLACK "\255X8" +#define XURED "\255X9" +#define XUGREEN "\255X10" +#define XUYELLOW "\255X11" +#define XUBLUE "\255X12" +#define XUMAGENTA "\255X13" +#define XUCYAN "\255X14" +#define XUWHITE "\255X15" +#define XRVBLACK "\255X16" +#define XRVRED "\255X17" +#define XRVGREEN "\255X18" +#define XRVYELLOW "\255X19" +#define XRVBLUE "\255X20" +#define XRVMAGENTA "\255X21" +#define XRVCYAN "\255X22" +#define XRVWHITE "\255X23" +#define XBOLD "\255X24" +#define XNRML "\255X25" +#define XPYELLOW "\255X26" +#define XPRED "\255X27" +#define XPCYAN "\255X28" +#define XPBLACK "\255X29" +#define XCLEAR "\255X30" +#endif diff --git a/contrib/include/sbigudrv.h b/contrib/include/sbigudrv.h new file mode 100644 index 00000000..830faf4b --- /dev/null +++ b/contrib/include/sbigudrv.h @@ -0,0 +1,668 @@ +/* + + SBIGUDRV.H + + Contains the function prototypes and enumerated constants + for the Universal Parallel/USB/Ethernet driver. + + This supports the following devices: + + ST-7E/8E/9E/10E + ST-5C/237/237A (PixCel255/237) + ST-1K, ST-2K + ST-L Large Format Camera + ST-F Feather Camera + AO-7 + + Version 4.35 - December 10, 2003 + + (c)1995-2003 - Santa Barbara Instrument Group + +*/ +#ifndef _PARDRV_ +#define _PARDRV_ + +/* + + SBIG Specific Code + +*/ +#ifndef TARGET + #define ENV_WIN 1 /* Target for Windows environment */ + #define ENV_WINVXD 2 /* SBIG Use Only, Win 9X VXD */ + #define ENV_WINSYS 3 /* SBIG Use Only, Win NT SYS */ + #define ENV_ESRVJK 4 /* SBIG Use Only, Ethernet Remote */ + #define ENV_ESRVWIN 5 /* SBIG Use Only, Ethernet Remote */ + #define ENV_MACOSX 6 /* SBIG Use Only, Mac OSX */ + #define ENV_LINUX 7 /* SBIG Use Only, Linux */ + #define TARGET ENV_LINUX /* Set for your target */ +#endif + +/* + + Enumerated Constants + + Note that the various constants are declared here as enums + for ease of declaration but in the structures that use the + enums unsigned shorts are used to force the various + 16 and 32 bit compilers to use 16 bits. + +*/ + +/* + + Supported Camera Commands + + These are the commands supported by the driver. + They are prefixed by CC_ to designate them as + camera commands and avoid conflicts with other + enums. + + Some of the commands are marked as SBIG use only + and have been included to enhance testability + of the driver for SBIG. + +*/ +typedef enum { + /* + + General Use Commands + + */ + CC_NULL, + + /* 1 - 10 */ + CC_START_EXPOSURE=1, CC_END_EXPOSURE, CC_READOUT_LINE, + CC_DUMP_LINES, CC_SET_TEMPERATURE_REGULATION, + CC_QUERY_TEMPERATURE_STATUS, CC_ACTIVATE_RELAY, CC_PULSE_OUT, + CC_ESTABLISH_LINK, CC_GET_DRIVER_INFO, + + /* 11 - 20 */ + CC_GET_CCD_INFO, CC_QUERY_COMMAND_STATUS, CC_MISCELLANEOUS_CONTROL, + CC_READ_SUBTRACT_LINE, CC_UPDATE_CLOCK, CC_READ_OFFSET, + CC_OPEN_DRIVER, CC_CLOSE_DRIVER, + CC_TX_SERIAL_BYTES, CC_GET_SERIAL_STATUS, + + /* 21 - 30 */ + CC_AO_TIP_TILT, CC_AO_SET_FOCUS, CC_AO_DELAY, + CC_GET_TURBO_STATUS, CC_END_READOUT, CC_GET_US_TIMER, + CC_OPEN_DEVICE, CC_CLOSE_DEVICE, CC_SET_IRQL, CC_GET_IRQL, + + /* 31 - 40 */ + CC_GET_LINE, CC_GET_LINK_STATUS, CC_GET_DRIVER_HANDLE, + CC_SET_DRIVER_HANDLE, CC_START_READOUT, CC_GET_ERROR_STRING, + CC_SET_DRIVER_CONTROL, CC_GET_DRIVER_CONTROL, + CC_USB_AD_CONTROL, CC_QUERY_USB, + + /* 41 - 50 */ + CC_GET_PENTIUM_CYCLE_COUNT, CC_RW_USB_I2C, CC_CFW, CC_BIT_IO, + + /* + + SBIG Use Only Commands + + */ + CC_SEND_BLOCK=90, CC_SEND_BYTE, CC_GET_BYTE, CC_SEND_AD, + CC_GET_AD, CC_CLOCK_AD, CC_SYSTEM_TEST, + CC_GET_DRIVER_OPTIONS, CC_SET_DRIVER_OPTIONS, + CC_LAST_COMMAND} PAR_COMMAND; + +/* + + Return Error Codes + + These are the error codes returned by the driver + function. They are prefixed with CE_ to designate + them as camera errors. + +*/ +#ifndef CE_ERROR_BASE + #define CE_ERROR_BASE 1 +#endif + +typedef enum { + /* 0 - 10 */ + CE_NO_ERROR, CE_CAMERA_NOT_FOUND=CE_ERROR_BASE, + CE_EXPOSURE_IN_PROGRESS, CE_NO_EXPOSURE_IN_PROGRESS, + CE_UNKNOWN_COMMAND, CE_BAD_CAMERA_COMMAND, CE_BAD_PARAMETER, + CE_TX_TIMEOUT, CE_RX_TIMEOUT, CE_NAK_RECEIVED, CE_CAN_RECEIVED, + + /* 11 - 20 */ + CE_UNKNOWN_RESPONSE, CE_BAD_LENGTH, + CE_AD_TIMEOUT, CE_KBD_ESC, CE_CHECKSUM_ERROR, CE_EEPROM_ERROR, + CE_SHUTTER_ERROR, CE_UNKNOWN_CAMERA, + CE_DRIVER_NOT_FOUND, CE_DRIVER_NOT_OPEN, + + /* 21 - 30 */ + CE_DRIVER_NOT_CLOSED, CE_SHARE_ERROR, CE_TCE_NOT_FOUND, CE_AO_ERROR, + CE_ECP_ERROR, CE_MEMORY_ERROR, CE_DEVICE_NOT_FOUND, + CE_DEVICE_NOT_OPEN, CE_DEVICE_NOT_CLOSED, + CE_DEVICE_NOT_IMPLEMENTED, + + /* 31 - 40 */ + CE_DEVICE_DISABLED, CE_OS_ERROR, CE_SOCK_ERROR, CE_SERVER_NOT_FOUND, + CE_CFW_ERROR, CE_NEXT_ERROR} PAR_ERROR; + +/* + + Camera Command State Codes + + These are the return status codes for the Query + Command Status command. Theyt are prefixed with + CS_ to designate them as camera status. + +*/ +typedef enum { CS_IDLE, CS_IN_PROGRESS, CS_INTEGRATING, + CS_INTEGRATION_COMPLETE } PAR_COMMAND_STATUS; +#define CS_PULSE_IN_ACTIVE 0x8000 +#define CS_WAITING_FOR_TRIGGER 0x8000 + +/* + Misc. Enumerated Constants + + ABG_STATE7 - Passed to Start Exposure Command + MY_LOGICAL - General purpose type + DRIVER_REQUEST - Used with Get Driver Info command + CCD_REQUEST - Used with Imaging commands to specify CCD + CCD_INFO_REQUEST - Used with Get CCD Info Command + PORT - Used with Establish Link Command + CAMERA_TYPE - Returned by Establish Link and Get CCD Info commands + SHUTTER_COMMAND, SHUTTER_STATE7 - Used with Start Exposure + and Miscellaneous Control Commands + TEMPERATURE_REGULATION - Used with Enable Temperature Regulation + LED_STATE - Used with the Miscellaneous Control Command + FILTER_COMMAND, FILTER_STATE - Used with the Miscellaneous + Control Command + AD_SIZE, FILTER_TYPE - Used with the GetCCDInfo3 Command + AO_FOCUS_COMMAND - Used with the AO Set Focus Command + SBIG_DEVICE_TYPE - Used with Open Device Command + DRIVER_CONTROL_PARAMS - Used with Get/SetDriverControl Command + USB_AD_CONTROL_COMMAND - Used with UsbADControl Command + CFW_MODEL_SELECT, CFW_STATUS, CFW_ERROR - Used with CFW command + CFW_POSITION, CFW_GET_INFO_SELECT - Used with CFW Command + BIT_IO_OPERATION, BIT_IO_NMAE - Used with BitIO command + + +*/ +typedef enum { ABG_LOW7, ABG_CLK_LOW7, ABG_CLK_MED7, ABG_CLK_HI7 } ABG_STATE7; +typedef unsigned short MY_LOGICAL; +#define FALSE 0 +#define TRUE 1 +typedef enum { DRIVER_STD, DRIVER_EXTENDED, DRIVER_USB_LOADER } DRIVER_REQUEST; +typedef enum { CCD_IMAGING, CCD_TRACKING, CCD_EXT_TRACKING } CCD_REQUEST; +typedef enum { CCD_INFO_IMAGING, CCD_INFO_TRACKING, + CCD_INFO_EXTENDED, CCD_INFO_EXTENDED_5C, CCD_INFO_EXTENDED2_IMAGING, + CCD_INFO_EXTENDED2_TRACKING } CCD_INFO_REQUEST; +typedef enum { ABG_NOT_PRESENT, ABG_PRESENT } IMAGING_ABG; +typedef enum { BR_AUTO, BR_9600, BR_19K, BR_38K, BR_57K, BR_115K } PORT_RATE; +typedef enum { ST7_CAMERA=4, ST8_CAMERA, ST5C_CAMERA, TCE_CONTROLLER, + ST237_CAMERA, STK_CAMERA, ST9_CAMERA, STV_CAMERA, ST10_CAMERA, + ST1K_CAMERA, ST2K_CAMERA, STL_CAMERA, STF_CAMERA, NEXT_CAMERA, NO_CAMERA=0xFFFF } CAMERA_TYPE; +typedef enum { SC_LEAVE_SHUTTER, SC_OPEN_SHUTTER, SC_CLOSE_SHUTTER, + SC_INITIALIZE_SHUTTER, SC_OPEN_EXT_SHUTTER, SC_CLOSE_EXT_SHUTTER} SHUTTER_COMMAND; +typedef enum { SS_OPEN, SS_CLOSED, SS_OPENING, SS_CLOSING } SHUTTER_STATE7; +typedef enum { REGULATION_OFF, REGULATION_ON, + REGULATION_OVERRIDE, REGULATION_FREEZE, REGULATION_UNFREEZE, + REGULATION_ENABLE_AUTOFREEZE, REGULATION_DISABLE_AUTOFREEZE } TEMPERATURE_REGULATION; +#define REGULATION_FROZEN_MASK 0x8000 +typedef enum { LED_OFF, LED_ON, LED_BLINK_LOW, LED_BLINK_HIGH } LED_STATE; +typedef enum { FILTER_LEAVE, FILTER_SET_1, FILTER_SET_2, FILTER_SET_3, + FILTER_SET_4, FILTER_SET_5, FILTER_STOP, FILTER_INIT } FILTER_COMMAND; +typedef enum { FS_MOVING, FS_AT_1, FS_AT_2, FS_AT_3, + FS_AT_4, FS_AT_5, FS_UNKNOWN } FILTER_STATE; +typedef enum { AD_UNKNOWN, AD_12_BITS, AD_16_BITS } AD_SIZE; +typedef enum { FW_UNKNOWN, FW_EXTERNAL, FW_VANE, FW_FILTER_WHEEL } FILTER_TYPE; +typedef enum { AOF_HARD_CENTER, AOF_SOFT_CENTER, AOF_STEP_IN, + AOF_STEP_OUT } AO_FOCUS_COMMAND; +typedef enum { DEV_NONE, DEV_LPT1, DEV_LPT2, DEV_LPT3, + DEV_USB=0x7F00, DEV_ETH, DEV_USB1, DEV_USB2, DEV_USB3, DEV_USB4 } SBIG_DEVICE_TYPE; +typedef enum { DCP_USB_FIFO_ENABLE, DCP_CALL_JOURNAL_ENABLE, + DCP_IVTOH_RATIO, DCP_USB_FIFO_SIZE, DCP_USB_DRIVER, DCP_KAI_RELGAIN, + DCP_USB_PIXEL_DL_ENABLE, DCP_HIGH_THROUGHPUT, DCP_LAST } DRIVER_CONTROL_PARAM; +typedef enum { USB_AD_IMAGING_GAIN, USB_AD_IMAGING_OFFSET, USB_AD_TRACKING_GAIN, + USB_AD_TRACKING_OFFSET } USB_AD_CONTROL_COMMAND; +typedef enum { USBD_SBIGE, USBD_SBIGI, USBD_SBIGM, USBD_NEXT } ENUM_USB_DRIVER; +typedef enum { CFWSEL_UNKNOWN, CFWSEL_CFW2, CFWSEL_CFW5, CFWSEL_CFW8, CFWSEL_CFWL, + CFWSEL_CFWF, CFWSEL_AUTO } CFW_MODEL_SELECT; +typedef enum { CFWC_QUERY, CFWC_GOTO, CFWC_INIT, CFWC_GET_INFO } CFW_COMMAND; +typedef enum { CFWS_UNKNOWN, CFWS_IDLE, CFWS_BUSY } CFW_STATUS; +typedef enum { CFWE_NONE, CFWE_BUSY, CFWE_BAD_COMMAND, CFWE_CAL_ERROR, CFWE_MOTOR_TIMEOUT, + CFWE_BAD_MODEL} CFW_ERROR; +typedef enum { CFWP_UNKNOWN, CFWP_1, CFWP_2, CFWP_3, CFWP_4, CFWP_5, CFWP_6 } CFW_POSITION; +typedef enum { CFWG_FIRMWARE_VERSION, CFWG_CAL_DATA, CFWG_DATA_REGISTERS } CFW_GETINFO_SELECT; +typedef enum { BITIO_WRITE, BITIO_READ } BITIO_OPERATION; +typedef enum { BITI_PS_LOW, BITO_IO1, BITO_IO2, BITI_IO3, BITO_FPGA_WE } BITIO_NAME; + + +/* + + General Purpose Flags + +*/ +#define END_SKIP_DELAY 0x8000 /* set in ccd parameter of EndExposure + command to skip synchronization + delay - Use this to increase the + rep rate when taking darks to later + be subtracted from SC_LEAVE_SHUTTER + exposures such as when tracking and + imaging */ +#define START_SKIP_VDD 0x8000 /* set in ccd parameter of StartExposure + command to skip lowering Imaging CCD + Vdd during integration. - Use this to + increase the rep rate when you don't + care about glow in the upper-left + corner of the imaging CCD */ +#define START_MOTOR_ALWAYS_ON 0x4000 /* set in ccd parameter of StartExposure + and EndExposure commands to force shutter + motor to stay on all the time which reduces + delays in Start and End Exposure timing and + yields higher image throughput. Don't + do this too often or camera head will + heat up */ +#define EXP_WAIT_FOR_TRIGGER_IN 0x80000000 /* set in exposureTime to wait + for trigger in pulse */ +#define EXP_SEND_TRIGGER_OUT 0x40000000 /* set in exposureTime to send + trigger out Y- */ +#define EXP_LIGHT_CLEAR 0x20000000 /* set to do light clear of the + CCD */ +#define EXP_TIME_MASK 0x00FFFFFF /* mask with exposure time to + remove flags */ + +/* + + Capabilities Bits - Bit Field Definitions for the + capabilitiesBits in the GetCCDInfoResults4 struct. + +*/ +#define CB_CCD_TYPE_MASK 0x0001 /* mask for CCD type */ +#define CB_CCD_TYPE_FULL_FRAME 0x0000 /* b0=0 is full frame CCD */ +#define CB_CCD_TYPE_FRAME_TRANSFER 0x0001 /* b0=1 is frame transfer CCD */ +#define CB_CCD_ESHUTTER_MASK 0x0002 /* mask for electronic shutter type */ +#define CB_CCD_ESHUTTER_NO 0x0000 /* b1=0 indicates no electronic shutter */ +#define CB_CCD_ESHUTTER_YES 0x0002 /* b1=1 indicates electronic shutter */ + + +/* + + Defines + +*/ +#define MIN_ST7_EXPOSURE 12 /* Minimum exposure in 1/100ths second */ +#define MIN_STF_EXPOSURE 4 /* Minimum exposure in 1/100ths second */ + +/* + + Command Parameter and Results Structs + + Make sure you set your compiler for byte structure alignment + as that is how the driver was built. + +*/ +/* Force 8 Byte Struct Align */ +#if TARGET == ENV_MACOSX || TARGET == ENV_LINUX + #pragma pack(push,8) +#else + #pragma pack(push) + #pragma pack(8) +#endif + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + unsigned long exposureTime; + unsigned short /* ABG_STATE7 */ abgState; + unsigned short /* SHUTTER_COMMAND */ openShutter; + } StartExposureParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + } EndExposureParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + unsigned short readoutMode; + unsigned short pixelStart; + unsigned short pixelLength; + } ReadoutLineParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + unsigned short readoutMode; + unsigned short lineLength; + } DumpLinesParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + } EndReadoutParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + unsigned short readoutMode; + unsigned short top; + unsigned short left; + unsigned short height; + unsigned short width; +} StartReadoutParams; + +typedef struct { + unsigned short /* TEMPERATURE_REGULATION */ regulation; + unsigned short ccdSetpoint; + } SetTemperatureRegulationParams; + +typedef struct { + MY_LOGICAL enabled; + unsigned short ccdSetpoint; + unsigned short power; + unsigned short ccdThermistor; + unsigned short ambientThermistor; + } QueryTemperatureStatusResults; + +typedef struct { + unsigned short tXPlus; + unsigned short tXMinus; + unsigned short tYPlus; + unsigned short tYMinus; + } ActivateRelayParams; + +typedef struct { + unsigned short numberPulses; + unsigned short pulseWidth; + unsigned short pulsePeriod; + } PulseOutParams; + +typedef struct { + unsigned short dataLength; + unsigned char data[256]; + } TXSerialBytesParams; + +typedef struct { + unsigned short bytesSent; + } TXSerialBytesResults; + +typedef struct { + MY_LOGICAL clearToCOM; + } GetSerialStatusResults; + +typedef struct { + unsigned short sbigUseOnly; + } EstablishLinkParams; + +typedef struct { + unsigned short /* CAMERA_TYPE */ cameraType; + } EstablishLinkResults; + +typedef struct { + unsigned short /* DRIVER_REQUEST */ request; + } GetDriverInfoParams; +typedef struct { + unsigned short version; + char name[64]; + unsigned short maxRequest; + } GetDriverInfoResults0; + +typedef struct { + unsigned short /* CCD_INFO_REQUEST */ request; + } GetCCDInfoParams; +typedef struct { + unsigned short mode; + unsigned short width; + unsigned short height; + unsigned short gain; + unsigned long pixel_width; + unsigned long pixel_height; + } READOUT_INFO; +typedef struct { + unsigned short firmwareVersion; + unsigned short /* CAMERA_TYPE */ cameraType; + char name[64]; + unsigned short readoutModes; + struct { + unsigned short mode; + unsigned short width; + unsigned short height; + unsigned short gain; + unsigned long pixelWidth; + unsigned long pixelHeight; + } readoutInfo[20]; + } GetCCDInfoResults0; +typedef struct { + unsigned short badColumns; + unsigned short columns[4]; + unsigned short /* IMAGING_ABG */ imagingABG; + char serialNumber[10]; + } GetCCDInfoResults2; +typedef struct { + unsigned short /* AD_SIZE */ adSize; + unsigned short /* FILTER_TYPE */ filterType; + } GetCCDInfoResults3; +typedef struct { + unsigned short capabilitiesBits; + unsigned short dumpExtra; +} GetCCDInfoResults4; +typedef struct { + unsigned short command; + } QueryCommandStatusParams; +typedef struct { + unsigned short status; + } QueryCommandStatusResults; + +typedef struct { + MY_LOGICAL fanEnable; + unsigned short /* SHUTTER_COMMAND */ shutterCommand; + unsigned short /* LED_STATE */ ledState; + } MiscellaneousControlParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + } ReadOffsetParams; + +typedef struct { + unsigned short offset; + } ReadOffsetResults; + +typedef struct { + unsigned short xDeflection; + unsigned short yDeflection; + } AOTipTiltParams; + +typedef struct { + unsigned short /* AO_FOCUS_COMMAND */ focusCommand; + } AOSetFocusParams; + +typedef struct { + unsigned long delay; + } AODelayParams; + +typedef struct { + MY_LOGICAL turboDetected; + } GetTurboStatusResults; + +typedef struct { + unsigned short deviceType; /* SBIG_DEVICE_TYPE, specifies LPT, Ethernet, etc */ + unsigned short lptBaseAddress; /* DEV_LPTN: Windows 9x Only, Win NT uses deviceSelect */ + unsigned long ipAddress; /* DEV_ETH: Ethernet address */ + } OpenDeviceParams; + +typedef struct { + unsigned short level; + } SetIRQLParams; + +typedef struct { + unsigned short level; + } GetIRQLResults; + +typedef struct { + MY_LOGICAL linkEstablished; + unsigned short baseAddress; + unsigned short /* CAMERA_TYPE */ cameraType; + unsigned long comTotal; + unsigned long comFailed; + } GetLinkStatusResults; + +typedef struct { + unsigned long count; + } GetUSTimerResults; + +typedef struct { + unsigned short port; + unsigned short length; + unsigned char *source; + } SendBlockParams; + +typedef struct { + unsigned short port; + unsigned short data; + } SendByteParams; + +typedef struct { + unsigned short /* CCD_REQUEST */ ccd; + unsigned short readoutMode; + unsigned short pixelStart; + unsigned short pixelLength; + } ClockADParams; + +typedef struct { + unsigned short testClocks; + unsigned short testMotor; + unsigned short test5800; + unsigned short stlAlign; + unsigned short motorAlwaysOn; + } SystemTestParams; + +typedef struct { + unsigned short outLength; + unsigned char *outPtr; + unsigned short inLength; + unsigned char *inPtr; + } SendSTVBlockParams; + +typedef struct { + unsigned short errorNo; + } GetErrorStringParams; + +typedef struct { + char errorString[64]; + } GetErrorStringResults; + +typedef struct { + short handle; + } SetDriverHandleParams; + +typedef struct { + short handle; + } GetDriverHandleResults; + +typedef struct { + unsigned short /* DRIVER_CONTROL_PARAM */ controlParameter; + unsigned long controlValue; +} SetDriverControlParams; + +typedef struct { + unsigned short /* DRIVER_CONTROL_PARAM */ controlParameter; +} GetDriverControlParams; + +typedef struct { + unsigned long controlValue; +} GetDriverControlResults; + +typedef struct { + unsigned short /* USB_AD_CONTROL_COMMAND */ command; + short data; +} USBADControlParams; + +typedef struct { + MY_LOGICAL cameraFound; + unsigned short /* CAMERA_TYPE */ cameraType; + char name[64]; + char serialNumber[10]; +} QUERY_USB_INFO; + +typedef struct { + unsigned short camerasFound; + QUERY_USB_INFO usbInfo[4]; +} QueryUSBResults; + +typedef struct { + unsigned short rightShift; +} GetPentiumCycleCountParams; + +typedef struct { + unsigned long countLow; + unsigned long countHigh; +} GetPentiumCycleCountResults; + +typedef struct { + unsigned char address; + unsigned char data; + MY_LOGICAL write; + unsigned char deviceAddress; + } RWUSBI2CParams; +typedef struct { + unsigned char data; + } RWUSBI2CResults; + +typedef struct { + unsigned short /* CFW_MODEL_SELECT */ cfwModel; + unsigned short /* CFW_COMMAND */ cfwCommand; + unsigned long cwfParam1; + unsigned long cfwParam2; + unsigned short outLength; + + unsigned char *outPtr; + unsigned short inLength; + unsigned char *inPtr; +} CFWParams; + +typedef struct { + unsigned short /* CFW_MODEL_SELECT */ cfwModel; + unsigned short /* CFW_POSITION */ cfwPosition; + unsigned short /* CFW_STATUS */ cfwStatus; + unsigned short /* CFW_ERROR */ cfwError; + unsigned long cfwResult1; + unsigned long cfwResult2; +} CFWResults; + +typedef struct { + unsigned short /* BITIO_OPERATION */ bitOperation; + unsigned short /* BITIO_NAME */ bitName; + MY_LOGICAL setBit; +} BitIOParams; + +typedef struct { + MY_LOGICAL bitIsSet; +} BitIOResults; + +#pragma pack(pop) /* Restore previous struct align */ + +/* + + Function Prototypes + + This are the driver interface functions. + + SBIGUnivDrvCommand() - Supports Parallel, USB and Ethernet + based cameras. + + Each function takes a command parameter and pointers + to parameters and results structs. + + The calling program needs to allocate the memory for + the parameters and results structs and these routines + read them and fill them in respectively. + +*/ +#if TARGET == ENV_WIN + #ifdef __cplusplus + extern "C" short __stdcall SBIGUnivDrvCommand(short command, void *Params, void *Results); + #else + extern short __stdcall SBIGUnivDrvCommand(short command, void *Params, void *Results); + #endif +#else + #ifdef __cplusplus + extern "C" short SBIGUnivDrvCommand(short command, void *Params, void *Results); + #else + extern short SBIGUnivDrvCommand(short command, void *Params, void *Results); + #endif +#endif + +#endif /* ifndef _PARDRV_ */ + diff --git a/contrib/include/setproto.h b/contrib/include/setproto.h new file mode 100644 index 00000000..47dfdcdc --- /dev/null +++ b/contrib/include/setproto.h @@ -0,0 +1,28 @@ +/* : determine if prototype using or not */ +#ifndef SETPROTO_H +# define SETPROTO_H + +/* --------------------------------------------------------------------- */ + +# ifndef __PROTOTYPE__ + +# ifdef vms +# ifndef oldvms +# define __PROTOTYPE__ +# endif + +# else + +# if defined(sgi) || defined(apollo) || defined(__STDC__) || \ + defined(MCH_AMIGA) || defined(_AIX) || defined(__MSDOS__) || \ + defined(ultrix) || defined(__DECC) || defined(__alpha) || \ + defined(__osf__) || defined(__WIN32__) || defined(__linux) || \ + defined(_MSC_VER) || defined(os2) || defined(AS400) +# define __PROTOTYPE__ +# endif +# endif +# endif + +/* --------------------------------------------------------------------- */ + +#endif /* SETPROTO_H */ diff --git a/contrib/include/sockets.h b/contrib/include/sockets.h new file mode 100644 index 00000000..3b408fc4 --- /dev/null +++ b/contrib/include/sockets.h @@ -0,0 +1,440 @@ +/* sockets.h: this file is the header file for the tlm socket function + * library + * + * Version: 2.10f + * Authors: Dr. Charles E. Campbell, GSFC/NASA + * Terry McRoberts, GSFC/NASA + */ +#ifndef SOCKETS_H +#define SOCKETS_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "xtdio.h" + +/* -------------------------------------------------------------------------- + * Standard Include Section + */ +#ifdef vms +# define Sscanf Sktscanf +# define Sprintf Sktprintf +# include +# include +# include +# include +# include +# include +# include +# ifdef OldVMS +# include +# else +# include +# include +# endif +# ifdef SSLNEEDTIME +# include time +# endif +typedef int fd_set; /* at least on my current version of vms I need this, sheesh */ +#endif + +#ifdef apollo +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +/* for ibm's AS/400 */ +#ifdef AS400 +# define STRTSRVR_PGM "*libl/startau17" +/* # define SSLNOSETSOCKOPT */ +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +/* for Watcomm C++ on OS/2 */ +#ifdef os2 +# define STRTSRVR_PGM "startsrv.cmd" +# include +/* # include */ +# include +# include +# include +# include +# include +# include +/* order is important */ +# ifndef TCPV40HDRS +# include +# include +# define _lswap(x) ((x<<24)|(x>>24)|((x&0xff00)<<8)|((x&0xff0000)>>8)) +# define _bswap(x) (((unsigned)x<<8)|((unsigned)x>>8)) +# endif +# ifdef SSLNEEDTIME +# include +# endif +#endif + +#ifdef sgi +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include + int select(int,fd_set*,fd_set*,fd_set*,struct timeval *); +# endif +#endif + +#ifdef sun +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +#ifdef ultrix +# include +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +#ifdef MSC +# define SSLNOPEEK +# define SSLNOSETSOCKOPT +# define SSLNEEDTOSHAREPM +# define SSLSKTZERO +# define Sscanf sktscanf +# define Sprintf sktprintf +# define Stimeoutwait sktwait +# define close(skt) sock_close(skt) +# include + typedef unsigned short u_short; +# ifdef IRL_PC +# include +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include "c:\c600\iptcp\include\sys\time.h" +# endif +# endif +#endif + +/* for Microsoft Developer Studio */ +#ifdef _MSC_VER +# define close(s) closesocket(s) +# include +# include /* corresponds to version 2.2.x of the WinSock API */ +# include + typedef unsigned short u_short; +# ifdef SSLNEEDTIME +# include +# endif +#endif + +/* for amigas */ +#ifdef MCH_AMIGA + typedef unsigned short u_short; + typedef unsigned long fd_set; +# ifdef SSLNEEDTIME +# include +# endif +#endif + +/* for borland c */ +#ifdef __WIN32__ +# define SSLSKTZERO +# define Sscanf sktscanf +# define Sprintf sktprintf +# define Stimeoutwait sktwait +# define close(s) closesocket(s) +# include +# include +# include + typedef unsigned short u_short; +# ifdef SSLNEEDTIME +# include +# endif +#endif + + /* for ibm's AIX o/s */ +#ifdef _AIX +# define SSLNOSETSOCKOPT +# define _NO_BITFIELDS +# include +# include +struct ip_firstfour { /* copied from , who knows why it isn't getting defined!!! */ + u_char ip_fvhl; + u_char ip_ftos; + u_short ip_flen; +# define ip_fwin ip_flen + }; +# include +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +#ifdef vms +# define TCP_READ( MSG_SOCK, LINE, NCHARS ) netread( MSG_SOCK, LINE, NCHARS ) +# define TCP_CLOSE( MSG_SOCK ) netclose( MSG_SOCK ) +# define TCP_WRITE( SOCK, LINE, NCHARS ) netwrite( SOCK, LINE, NCHARS ) +#else +# define TCP_READ( MSG_SOCK, LINE, NCHARS ) recv( MSG_SOCK, LINE, NCHARS,0 ) +# define TCP_CLOSE( MSG_SOCK ) close( MSG_SOCK ) +# define TCP_WRITE( SOCK, LINE, NCHARS ) send( SOCK, LINE, NCHARS,0 ) +#endif + +/* for SCO Unix's cc compiler */ +#if defined(M_I386) && defined(M_SYSV) +# include +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +/* for OSF */ +#ifdef __osf__ +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +#endif + +/* for Linux */ +#ifdef __linux +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifdef SSLNEEDTIME +# include +# endif +# ifndef __USE_BSD + typedef unsigned short u_short; +#endif +#endif + +/* -------------------------------------------------------------------------- + * Definitions Section + */ +#define PORTMASTER ((u_short) 1750) /* standard PortMaster port -- IANA registered */ + +#ifdef vms +/* typedef unsigned long fd_set; */ +# define FD_SET(n,p) (*p|= (1<fds_bits[0] |= (1<fds_bits[0] &= ~(1<fds_bits[0] & (1<fds_bits[0] = 0) +#endif + +/* end of types ============================================================ */ + +/* PortMaster messages */ +#define PM_SERVER ((u_short) 1) +#define PM_CLIENT ((u_short) 2) +#define PM_CLOSE ((u_short) 3) +#define PM_RESEND ((u_short) 4) +#define PM_QUIT ((u_short) 5) +#define PM_SORRY ((u_short) 6) +#define PM_OK ((u_short) 7) +#define PM_ACCEPT ((u_short) 8) +#define PM_TABLE ((u_short) 9) +#define PM_RMSERVER ((u_short) 10) +#define PM_FWINIT ((u_short) 11) +#define PM_SHARE ((u_short) 12) +#define PM_OKSHARE ((u_short) 13) + +#define PM_BIGBUF 1024 +#define PM_MAXTRY 20 /* max number of resends to PortMaster */ +#define PM_MAXREQUESTS 10 /* max pending connects */ + +/* -------------------------------------------------------------------------- + * Typedef Section + */ +typedef int PrtMstrEvent; +typedef struct Skt_str Socket; +typedef struct Smask_str Smask; +typedef u_short SKTEVENT; +#if !defined(MCH_AMIGA) && !defined(__WIN32__) + typedef struct sockaddr_in sinpt; +#endif + +/* -------------------------------------------------------------------------- + * Data Structures: + */ +struct Skt_str { + int skt; /* skt handle */ + SKTEVENT port; /* associated port */ + int type; /* PM_SERVER, PM_CLIENT, PM_ACCEPT */ + char *sktname; /* name of socket */ + char *hostname; /* name of host */ + }; + +struct Smask_str { + fd_set mask; + unsigned waitall; + }; + +/* -------------------------------------------------------------------------- + * Prototypes: + */ +#ifdef __PROTOTYPE__ + +Socket *Saccept(Socket *); /* Saccept.c */ +void Sclose(Socket *); /* Sclose.c */ +char *Sgets( char *, int, Socket *); /* Sgets.c */ +void Sinit(void); /* Sinit.c */ +Socket *makeSocket(char *,char *,int); /* Smkskt.c */ +void freeSocket(Socket *); /* Smkskt.c */ +int Smaskwait(void); /* Smaskwait.c */ +void Smaskset(Socket *); /* Smaskwait.c */ +void Smaskfdset(int); /* Smaskwait.c */ +void Smasktime(long,long); /* Smaskwait.c */ +int Smasktest(void); /* Smaskwait.c */ +void Smaskunset(Socket *); /* Smaskwait.c */ +void Smaskunfdset(int); /* Smaskwait.c */ +Smask Smaskget(void); /* Smaskwait.c */ +void Smaskuse(Smask); /* Smaskwait.c */ +void Smaskpush(void); /* Smaskwait.c */ +void Smaskpop(void); /* Smaskwait.c */ +int Smaskisset(Socket *); /* Smaskwait.c */ +int Smaskfdisset(int); /* Smaskwait.c */ +Socket *Sopen( char *, char *); /* Sopen.c */ +Socket *Sopen_clientport( char *, char *, /* Sopen.c */ + u_short); +Socket *Sopenv( char *, char *, char *); /* Sopenv.c */ +int Speek( Socket *, void *, int); /* Speek.c */ +unsigned long Speeraddr(Socket *); /* Speeraddr.c */ +char *Speername(Socket *); /* Speername.c */ +int Sprintf( Socket *, char *, ...); /* Sprintf.c */ +char *Sprtskt(Socket *); /* Sprtskt.c */ +void Sputs( char *, Socket *); /* Sputs.c */ +int Sread( Socket *, void *, int); /* Sread.c */ +int Sreadbytes( Socket *, void *, int); /* Sreadbytes.c */ +SKTEVENT Srmsrvr(char *); /* Srmsrvr.c */ +int Sscanf(Socket *,char *,...); /* Sscanf.c */ +int Stest(Socket *); /* Stest.c */ +int Stimeoutwait(Socket *,long,long); /* Stimeoutwait.c */ +int Stvwaitmany(long,Socket **,int); /* Stvwaitmany.c */ +int Stwaitmany(long,int,...); /* Stwaitmany.c */ +int Svprintf(Socket *, char *, void *); /* Svprintf.c */ +int Svwaitmany(Socket **,int); /* Svwaitmany.c */ +int Swait(Socket *); /* Swait.c */ +int Swaitmany(int,...); /* Swaitmany.c */ +int Swrite( Socket *, void *, int); /* Swrite.c */ + +#else + +extern Socket *Saccept(); /* Saccept.c */ +extern void Sclose(); /* Sclose.c */ +extern char *Sgets(); /* Sgets.c */ +extern void Sinit(); /* Sinit.c */ +extern Socket *makeSocket(); /* Smkskt.c */ +extern void freeSocket(); /* Smkskt.c */ +extern int Smaskwait(); /* Smaskwait.c */ +extern void Smaskset(); /* Smaskwait.c */ +extern void Smaskfdset(); /* Smaskwait.c */ +extern void Smasktime(); /* Smaskwait.c */ +extern int Smasktest(); /* Smaskwait.c */ +extern void Smaskunset(); /* Smaskwait.c */ +extern void Smaskunfdset(); /* Smaskwait.c */ +extern Smask Smaskget(); /* Smaskwait.c */ +extern void Smaskuse(); /* Smaskwait.c */ +extern void Smaskpush(); /* Smaskwait.c */ +extern void Smaskpop(); /* Smaskwait.c */ +extern int Smaskisset(); /* Smaskwait.c */ +extern int Smaskfdisset(); /* Smaskwait.c */ +extern Socket *Sopen(); /* Sopen.c */ +extern Socket *Sopen_clientport(); /* Sopen.c */ +extern Socket *Sopenv(); /* Sopenv.c */ +extern int Speek(); /* Speek.c */ +extern unsigned long Speeraddr(); /* Speeraddr.c */ +extern char *Speername(); /* Speername.c */ +extern int Sprintf(); /* Sprintf.c */ +extern char *Sprtskt(); /* Sprtskt.c */ +extern void Sputs(); /* Sputs.c */ +extern int Sread(); /* Sread.c */ +extern int Sreadbytes(); /* Sreadbytes.c */ +extern SKTEVENT Srmsrvr(); /* Srmsrvr.c */ +extern int Sscanf(); /* Sscanf.c */ +extern int Stest(); /* Stest.c */ +extern int Stimeoutwait(); /* Stimeoutwait.c */ +extern int Stvwaitmany(); /* Stvwaitmany.c */ +extern int Stwaitmany(); /* Stwaitmany.c */ +extern int Stwaitmany(); /* Stwaitmany.c */ +extern int Svprintf(); /* Svprintf.c */ +extern int Svwaitmany(); /* Svwaitmany.c */ +extern int Swait(); /* Swait.c */ +extern int Swaitmany(); /* Swaitmany.c */ +extern int Swrite(); /* Swrite.c */ +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* #ifndef SOCKETS_H */ diff --git a/contrib/include/xstdlib.h b/contrib/include/xstdlib.h new file mode 100644 index 00000000..f128ca01 --- /dev/null +++ b/contrib/include/xstdlib.h @@ -0,0 +1,18 @@ +/* xstdlib.h: has standard library function prototypes */ +#ifndef XSTDLIB_H +#define XSTDLIB_H + +#include + +/* Prototypes for standard library functions */ +extern char *calloc(); +extern void exit(); +extern char *getenv(); +extern char *index(); +extern char *malloc(); +extern char *strchr(); +extern char *strrchr(); +#define remove unlink + + +#endif diff --git a/contrib/include/xtdio.h b/contrib/include/xtdio.h new file mode 100644 index 00000000..ad5f7ef7 --- /dev/null +++ b/contrib/include/xtdio.h @@ -0,0 +1,157 @@ +/* xtdio.h: */ +#ifndef XTDIO_H +#define XTDIO_H + +/* --------------------------------------------------------------------- */ + +#ifdef AS400 +# include +# include +# include +#endif + +#ifdef _AIX +# include +# include +# include +#endif + +#ifdef apollo +# include +# include +# include +#endif + +#ifdef __linux__ +# include +# include +# include +# include +#endif + +#ifdef _MSC_VER +# include +# include +# include +# include +#endif + +#ifdef os2 +# include +# include +# include +# include +#endif + +#ifdef MSDOS +# include +# include +# include +#endif + +/* SCO Unix */ +#if defined(M_I386) && defined(M_SYSV) +# include +# include +#endif + +#ifdef __osf__ +# include +# include +# include +#endif + +#ifdef sgi +# include +# include +# include +#endif + +#ifdef sun +# include +# ifdef __STDC__ +# include +# include +# else +# include "xstdlib.h" +# include "varargs.h" +# endif +#endif + +#ifdef ultrix +# include +# include "xstdlib.h" +# include +#endif + +#ifdef vms +# include +# include +# include +#endif + +#ifdef __WIN32__ +# include +# include +# include +#endif + +#include "rdcolor.h" +#include "setproto.h" + +/* --------------------------------------------------------------------- + * Definitions: + */ + +#define XTDIO_SEVERE 0 +#define XTDIO_ERROR 1 +#define XTDIO_WARNING 2 +#define XTDIO_NOTE 3 + +/* if your compiler supports prototyping, but does *not* support the keyword + * "const", then move the following line out of this comment +#define const + */ + +/* --------------------------------------------------------------------- + * Typedefs: + */ + +/* --------------------------------------------------------------------- + * Global Variables: + */ +#ifdef __PROTOTYPE__ +extern void (*error_exit)(int); +#else +extern void (*error_exit)(); +#endif + +/* --------------------------------------------------------------------- + * Prototypes: + */ +# ifdef __PROTOTYPE__ + +char *cprt(const char); /* cprt.c */ +void error(int, char *, ...); /* error.c */ +FILE *fopenv(char *, char *, char *); /* fopenv.c */ +void outofmem(void *, char *, ...); /* outofmem.c */ +void rdcolor(void); /* rdcolor.c */ +void rdcputs(char *, FILE *); /* rdcolor.c */ +char *sprt(const char *); /* sprt.c */ +void srmtrblk(char *); /* srmtrblk.c */ +char *stpblk(char *); /* stpblk.c */ +char *stpnxt(char *, char *); /* stpnxt.c */ +char *strnxtfmt(char *); /* strnxtfmt.c */ + +# else /* __PROTOTYPE__ */ + +extern char *cprt(); /* cprt.c */ +extern char *stpnxt(); /* stpnxt.c */ +extern char *stpblk(); /* stpblk.c */ +extern FILE *fopenv(); /* fopenv.c */ +extern char *sprt(); /* sprt.c */ +extern char *strnxtfmt(); /* strnxtfmt.c */ + +# endif /* __PROTOTYPE__ */ + +#endif diff --git a/contrib/lib/Makefile.am b/contrib/lib/Makefile.am new file mode 100644 index 00000000..27c4cf42 --- /dev/null +++ b/contrib/lib/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/rules.make + +dist_uts_lib_DATA = libcfitsio.a libsbigudrv.a libsimpleskts.a libcfitsio.so libsbigudrv.so \ + libsimpleskts.so libsimpleskts.so.2 sbiglptmod.o sbigusbmod.o \ + sbigusbmod_2_6.ko + diff --git a/contrib/lib/libcfitsio.a b/contrib/lib/libcfitsio.a new file mode 100644 index 00000000..8b9c3dd0 Binary files /dev/null and b/contrib/lib/libcfitsio.a differ diff --git a/contrib/lib/libcfitsio.so b/contrib/lib/libcfitsio.so new file mode 100755 index 00000000..2c721d3f Binary files /dev/null and b/contrib/lib/libcfitsio.so differ diff --git a/contrib/lib/libsbigudrv.a b/contrib/lib/libsbigudrv.a new file mode 100644 index 00000000..40d1a9f1 Binary files /dev/null and b/contrib/lib/libsbigudrv.a differ diff --git a/contrib/lib/libsbigudrv.so b/contrib/lib/libsbigudrv.so new file mode 100755 index 00000000..5758e41c Binary files /dev/null and b/contrib/lib/libsbigudrv.so differ diff --git a/contrib/lib/libsimpleskts.a b/contrib/lib/libsimpleskts.a new file mode 100644 index 00000000..3124d045 Binary files /dev/null and b/contrib/lib/libsimpleskts.a differ diff --git a/contrib/lib/libsimpleskts.so b/contrib/lib/libsimpleskts.so new file mode 100755 index 00000000..bf00a0ee Binary files /dev/null and b/contrib/lib/libsimpleskts.so differ diff --git a/contrib/lib/libsimpleskts.so.2 b/contrib/lib/libsimpleskts.so.2 new file mode 100755 index 00000000..bf00a0ee Binary files /dev/null and b/contrib/lib/libsimpleskts.so.2 differ diff --git a/contrib/lib/sbigusbmod_2_6.ko b/contrib/lib/sbigusbmod_2_6.ko new file mode 100644 index 00000000..38002440 Binary files /dev/null and b/contrib/lib/sbigusbmod_2_6.ko differ diff --git a/doc/SPEC b/doc/SPEC new file mode 100644 index 00000000..fb93a0f3 --- /dev/null +++ b/doc/SPEC @@ -0,0 +1,109 @@ +SPEC + +1. Haverá um conjunto de programas (sec, clientes, web) padrão a todo o +observatório. + +2. Haverá um arquivo de configuração único para o observatório, com +informações sobre que instrumentos estão ativos ou disponíveis. + +3. Haverá um script de inicialização seletiva do observatório, onde poderão +ser escolhidos os instruemntos a inicializar. + +4. Cada instrumento terá: (opcional) um programa de baixo nivel, (opcional) um +daemon de controle, e um arquivo de configuração. + +5. No script de instalação/configuração, o usuário poderá compilar quantos +módulos/instrumentos quiser, mas o módulo de controle básico é obrigatório +(item 1) (????) + + +PROPOSTA DE SOURCE TREE + +- ./prog/lib/* - estariam no include path de cada modulo que necessite de +alguma biblioteca, assim, os includes permaneceriam iguais (#include "sbig.h", +etc). + +- dentro de cada módulo de instrumento do ./prog/src só haverão includes do +próprio módulo, includes de bibliotecas devem ficar nos diretórios da +respectiva biblioteca. + + +prog/ +|-- lib/ +| |-- sbig/ +| |-- serial/ +`-- src/ + |-- cam/ + | |-- camd/ + | |-- camfits.fake/ + | |-- camfits.st4/ + | |-- camfits.st7/ + | |-- camfits.st8/ + | `-- etc/ + |-- client/ + | |-- gtk/ + | `-- simple/ + |-- dome/ + | |-- dome.fake/ + | |-- dome.iag/ + | |-- dome.ufsc/ + | |-- domed/ + | `-- etc/ + |-- etc/ + | `-- init_scripts/ + |-- monitor/ + | |-- etc/ + | `-- monitord/ + |-- sec/ + |-- sync/ + | |-- etc/ + | `-- syncd/ + |-- tel/ + | |-- etc/ + | |-- teld/ + | |-- telgo.fake/ + | |-- telgo.lx200/ + | `-- telgo.paramount/ + |-- weather/ + | |-- etc/ + | |-- weather.fake/ + | |-- weather.iag/ + | |-- weather.wx200/ + | `-- weatherd/ + `-- www/ + +PROPOSTA DE INSTALL TREE + +- No código, podemos usar as variáveis do config.h (não sei bem como :-) para +sabermos onde as coisas serão instaladas. Isto é definido pelo valor da flag +--prefix do ./configure. + +/ +|-- prefix/ +| |-- bin/ +| | |-- core_bins +| | |-- instruments +| | `-- start_script +| |-- etc/ +| | `-- prog/ +| | |-- instrument_configs +| | `-- main_config +| |-- include/ +| | `-- includes_das_libs +| |-- lib/ +| | |-- libcfitsio.a +| | |-- libcfitsio.so +| | |-- libprog-serial.a +| | |-- libprog-serial.so +| | |-- libsgib.a +| | |-- libsgib.so +| | |-- libssl.a +| | |-- libssl.so +| | `-- ... +| `-- man/ +|-- rc.d/ +| `-- start_script_links +|-- var/ +| `-- log/ +| `-- prog/ +`-- www/ diff --git a/doc/Technical_Description b/doc/Technical_Description new file mode 100644 index 00000000..4fa2b57f --- /dev/null +++ b/doc/Technical_Description @@ -0,0 +1,34 @@ +Instruments are controlled by a daemon. These daemons are +composed by three programs: + +1. A low level driver program, which interfaces to the hardware +such as a telescope or CCD camera. All the hardware-specific +code is kept in this level. + +2. A generic instrument daemon. This program sends requests to +the driver using a standard "protocol". + +3. A communication daemon - the Secretary. The instrument +daemon feeds the secretary with its status. All other instruments +that need to know the status of this instrument, will talk to +this +program. + +In our first approach there are three instruments. A telescope +(Meade LX-200), a CCD camera (SBIG ST-7E) and a "virtual" +instrument called Synchronizer, which takes care of scheduling +of observations. It receives observational data (coordinates, +imaging information, etc) from a web interface. + +One important character of the instrument control daemons is +that they do not receive commands, but rather take their +decisions based on the status of the rest of the observatory. We +believe that with this approach we avoid a super-complex +control program that takes care of everything, having instead +the +"intelligence" distributed through the various daemons. + +All the programs are being written in C/C++, and some scripts in +python and PHP. The communication is made through network +sockets, using the Simple Sockets Library. Please see +http://users.erols.com/astronaut/ssl/ \ No newline at end of file diff --git a/doc/daemons.txt b/doc/daemons.txt new file mode 100644 index 00000000..6f5d9cc5 --- /dev/null +++ b/doc/daemons.txt @@ -0,0 +1,54 @@ += Funcionando dos daemons = + +Um daemon é responsável pela execução de uma tarefa específica de +controle do sistema. + +Um daemon possui duas formas de interação com o mundo exterior: +notificações e invocação remota (RPC). + +As notificações permitem que um daemon converse com outro. Um daemon A +pode ser avisado quando um daemon B altera seu estado, e +vice-versa. As notificações são enviadas àqueles que se inscrevam +previamente, assim, é necessário registrar-se para obter notificações +de alteração de estado de um outro daemon. Além disso, o daemon que +origina as notificações precisa indicar quais estados ele irá +disponibilizar aos daemons que desejam notificações. + +A invocação remota (Remote Procedure Call) permite que uma entidade +externa controle o daemon. Os pontos de controle de um daemon são +previamente definidos, assim, entidades externas sabem (ou devem +saber) antecipadamente quais ações estão disponíveis para um daemon. + +Assim, um daemon precisa explicitar duas informações: quais estados +(ou propriedades) ele irá disponibilizar para o sistema de +notificações; quais pontos de controle (métodos/ações) ele possuirá. + +Estas definições são feitas através de um conjunto de variáveis +globais do daemon, que, seguindo uma convenção permitirá que o sistema +de controle identifique os estados e métodos do daemon. + +Veja o arquivo exemplo.py paara mais detalhes da implementação. + + += Os daemons por detrás das cortinas = + +Os daemons interagem com duas secretárias; as informações de +inicialização destas secretárias são geradas quando da inicialização +do sistema + +A primeira secretária é a RPC (Remote Procedure Call). Esta +secretária possui todos os pontos de controle de todos os daemons do +sistema (cada ponto de controle têm em seu nome um prefixo, originado +do nome do daemon ao qual ele pertence, ex. TEL_SLEW). + +A segunda secretária é responsável pelo sistema de notificações do +daemon, e que contém todos os estados possíveis de serem monitorados +do daemon em questão (seu nome será formado pelo nome do daemon +acrescido em letras maiúsculas, ex. TEL). + +Um script de inicialização procurará entre todos os daemons e gerará +os arquivos .conf necessários à inicialização destas secretárias, o +que implica na necessidade de reinicialização do sistema para a adição +de secretárias (esta implicação será removida quando as secretárias +permitirem adição de propriedades em tempo de execução). + diff --git a/rules.make b/rules.make new file mode 100644 index 00000000..8681cae1 --- /dev/null +++ b/rules.make @@ -0,0 +1,15 @@ + +uts_initddir = /etc/init.d +uts_initconfigdir = @UTS_INITCONFIG_DIR@ + +uts_etcdir = /etc/uts +uts_etc_secdir = /etc/uts/sec +uts_libdir = $(prefix)/lib + +uts_driverdir = /etc/uts/drivers + +AM_CFLAGS=-I$(top_srcdir)/contrib/include -I$(top_srcdir)/src/sec -I$(top_srcdir)/src/base + +AM_LDFLAGS=-L$(top_srcdir)/contrib/lib -L$(top_srcdir)/src/sec -L$(top_srcdir)/src/base -Wl,-rpath=$(uts_libdir) + +AM_CPPFLAGS=-I$(top_srcdir)/contrib/include -I$(top_srcdir)/src/sec -I$(top_srcdir)/src/base diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..747f7ac4 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = sec config drivers tools python diff --git a/src/config/Makefile.am b/src/config/Makefile.am new file mode 100644 index 00000000..19ac1cc4 --- /dev/null +++ b/src/config/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/rules.make +SUBDIRS = initscripts + +uts_etc_DATA = site.xml +uts_etc_sec_DATA = rpc.conf diff --git a/src/config/initscripts/Makefile.am b/src/config/initscripts/Makefile.am new file mode 100644 index 00000000..e5fc21d1 --- /dev/null +++ b/src/config/initscripts/Makefile.am @@ -0,0 +1,3 @@ +DIST_SUBDIRS = redhat suse debian + +SUBDIRS = @UTS_DISTRO@ diff --git a/src/config/initscripts/debian/Makefile.am b/src/config/initscripts/debian/Makefile.am new file mode 100644 index 00000000..69065ae8 --- /dev/null +++ b/src/config/initscripts/debian/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/rules.make + +dist_uts_initd_SCRIPTS = spmd secd sbigcam +dist_uts_initconfig_DATA = uts + +EXTRA_DIST = uts.in + diff --git a/src/config/initscripts/debian/sbigcam b/src/config/initscripts/debian/sbigcam new file mode 100644 index 00000000..9ae4d3a8 --- /dev/null +++ b/src/config/initscripts/debian/sbigcam @@ -0,0 +1,68 @@ +#! /bin/sh +# +# sbigcam UTS CCD Camera drivers +# Author: P. Henrique Silva +# + +set -e + +# Read config file if it is present. +if [ -r /etc/default/uts ]; then + . /etc/default/uts +else + echo "Error: cannot read '/etc/default/uts'. Check yout installation." + exit -1 +fi + +NAME=sbigcam +DESC="UTS CCD Camera drivers" +SCRIPTNAME=/etc/init.d/$NAME + +# Gracefully exit if the package has been removed. +test -x $UTS_BIN/sbig_load_usb_suse || exit 0 +test -x $UTS_BIN/sbig_unload_usb || exit 0 +test -x $UTS_BIN/sbig_load_lpt_suse || exit 0 +test -x $UTS_BIN/sbig_unload_lpt || exit 0 + +# +# Function that starts the daemon/service. +# +d_start() { + start-stop-daemon --start --quiet --exec $UTS_BIN/sbig_load_usb_suse + start-stop-daemon --start --quiet --exec $UTS_BIN/sbig_load_lpt_suse +} + +# +# Function that stops the daemon/service. +# +d_stop() { + start-stop-daemon --stop --quiet --name $UTS_BIN/sbig_unload_lpt + start-stop-daemon --stop --quiet --name $UTS_BIN/sbig_unload_usb +} + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + d_stop + echo "." + ;; + + restart) + echo -n "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + echo "." + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/src/config/initscripts/debian/secd b/src/config/initscripts/debian/secd new file mode 100644 index 00000000..d64610e6 --- /dev/null +++ b/src/config/initscripts/debian/secd @@ -0,0 +1,72 @@ +#! /bin/sh +# +# secd UTS Socket secretaries +# Author: P. Henrique Silva +# + +set -e + +# Read config file if it is present. +if [ -r /etc/default/uts ]; then + . /etc/default/uts +else + echo "Error: cannot read '/etc/default/uts'. Check yout installation." + exit -1 +fi + +NAME=secd +DESC="UTS Socket secretaries" +DAEMON=$UTS_BIN/$NAME +SCRIPTNAME=/etc/init.d/$NAME + +# Gracefully exit if the package has been removed. +test -x $DAEMON || exit 0 + +# +# Function that starts the daemon/service. +# +d_start() { + + for i in `ls -1 $UTS_SEC/*.conf`; do + start-stop-daemon --start --quiet --exec $DAEMON -- -d $i + done + +} + +# +# Function that stops the daemon/service. +# +d_stop() { + + for i in `ls -1 $UTS_SEC/*.conf`; do + start-stop-daemon --stop --quiet --name $NAME + done + +} + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + d_stop + echo "." + ;; + + restart) + echo -n "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + echo "." + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/src/config/initscripts/debian/spmd b/src/config/initscripts/debian/spmd new file mode 100644 index 00000000..531dc369 --- /dev/null +++ b/src/config/initscripts/debian/spmd @@ -0,0 +1,64 @@ +#! /bin/sh +# +# spmd UTS Sockets (Spm) +# Author: P. Henrique Silva +# + +set -e + +# Read config file if it is present. +if [ -r /etc/default/uts ]; then + . /etc/default/uts +else + echo "Error: cannot read '/etc/default/uts'. Check yout installation." + exit -1 +fi + +NAME=Spm +DESC="UTS Sockets (Spm)" +DAEMON=$UTS_BIN/$NAME +SCRIPTNAME=/etc/init.d/$NAME + +# Gracefully exit if the package has been removed. +test -x $DAEMON || exit 0 + +# +# Function that starts the daemon/service. +# +d_start() { + start-stop-daemon --start --quiet --exec $DAEMON +} + +# +# Function that stops the daemon/service. +# +d_stop() { + start-stop-daemon --stop --quiet --name $NAME +} + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + d_stop + echo "." + ;; + + restart) + echo -n "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + echo "." + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/src/config/initscripts/debian/uts.in b/src/config/initscripts/debian/uts.in new file mode 100644 index 00000000..f26731be --- /dev/null +++ b/src/config/initscripts/debian/uts.in @@ -0,0 +1,9 @@ +UTS_DIR=@prefix@ +UTS_BIN=$UTS_DIR/bin +UTS_ETC=/etc/uts +UTS_SEC=$UTS_ETC/sec + +PATH=/bin:/sbin:/usr/bin:/usr/local/bin + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$UTS_DIR/lib +export PATH=$UTS_BIN:$PATH diff --git a/src/config/initscripts/redhat/Makefile.am b/src/config/initscripts/redhat/Makefile.am new file mode 100644 index 00000000..96316a5a --- /dev/null +++ b/src/config/initscripts/redhat/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/rules.make + +dist_uts_initd_SCRIPTS = sbigcam secd spmd +dist_uts_initconfig_DATA = uts + +EXTRA_DIST = uts.in diff --git a/src/config/initscripts/redhat/sbigcam b/src/config/initscripts/redhat/sbigcam new file mode 100644 index 00000000..f7433ce5 --- /dev/null +++ b/src/config/initscripts/redhat/sbigcam @@ -0,0 +1,56 @@ +#!/bin/bash +# +# /etc/rc.d/init.d/sbigcam +# +# Loads camera modules. +# +# chkconfig: 3 40 62 +# description: Loads SBIG proprietary modules for ST-7 cameras. +# processname: sbigcam + +# Source function library. +. /etc/rc.d/init.d/functions + +. /etc/sysconfig/uts + +test -x $UTS_BIN/sbig_load_usb || exit 0 +test -x $UTS_BIN/sbig_unload_usb || exit 0 +test -x $UTS_BIN/sbig_load_lpt || exit 0 +test -x $UTS_BIN/sbig_unload_lpt || exit 0 + +RETVAL=0 + +# +# See how we were called. +# +case "$1" in + start) + # Check if modules are already loaded + if [ ! -f /var/lock/subsys/sbigcam ]; then + echo 'Loading SBIG proprietary ST-7E camera modules:' + $UTS_BIN/sbig_load_usb + $UTS_BIN/sbig_load_lpt + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/sbigcam + echo + fi + ;; + stop) + echo 'Unloading SBIG proprietary ST-7E camera modules:' + $UTS_BIN/sbig_unload_usb + $UTS_BIN/sbig_unload_lpt + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/sbigcam + echo + ;; + reload|restart) + $0 stop + $0 start + RETVAL=$? + ;; + *) + echo "Usage: /etc/rc.d/init.d/spmd {start|stop|restart|reload}" + exit 1 +esac + +exit $RETVAL diff --git a/src/config/initscripts/redhat/secd b/src/config/initscripts/redhat/secd new file mode 100644 index 00000000..d6a12801 --- /dev/null +++ b/src/config/initscripts/redhat/secd @@ -0,0 +1,52 @@ +#!/bin/bash +# +# /etc/rc.d/init.d/secd +# +# Starts the Socket Secretary daemon +# +# chkconfig: 3 41 61 +# description: Run socket secretaries for each instrument. + +# Source function library. +. /etc/rc.d/init.d/functions + +. /etc/sysconfig/uts + +test -x $UTS_BIN/sec || exit 0 + +RETVAL=0 + +# +# See how we were called. +# +case "$1" in + start) + echo -n 'Starting Socket Secretary daemons... ' + #daemon $UTS_BIN/runsecs.sh + for INST in `ls -1 $UTS_SEC/*.conf`; do + daemon $UTS_BIN/sec -d $INST; + done + touch /var/lock/subsys/secd + echo + ;; + stop) + echo -n 'Stopping Socket Secretary daemon: ' + killproc sec + rm -f /var/lock/subsys/secd + echo + ;; + reload|restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status $UTS_BIN/sec + RETVAL=$? + ;; + *) + echo "Usage: /etc/rc.d/init.d/secd {start|stop|restart|reload|status}" + exit 1 +esac + +exit $RETVAL diff --git a/src/config/initscripts/redhat/spmd b/src/config/initscripts/redhat/spmd new file mode 100644 index 00000000..df0fa3d2 --- /dev/null +++ b/src/config/initscripts/redhat/spmd @@ -0,0 +1,57 @@ +#!/bin/bash +# +# /etc/rc.d/init.d/spmd +# +# Starts the Spm daemon +# +# chkconfig: 4 40 62 +# description: Spm is the Simple Sockets Library (SSL) +# PortMaster. It controls server names and their port numbers. +# processname: Spm + +# Source function library. +. /etc/rc.d/init.d/functions + +. /etc/sysconfig/uts + +test -x $UTS_BIN/Spm || exit 0 + +RETVAL=0 + +# +# See how we were called. +# +case "$1" in + start) + # Check if Spm is already running + if [ ! -f /var/lock/subsys/Spm ]; then + echo -n 'Starting Spm daemon: ' + daemon $UTS_BIN/Spm + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/Spm + echo + sleep 2 + fi + ;; + stop) + echo -n 'Stopping Spm daemon: ' + killproc $UTS_BIN/Spm + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/Spm + echo + ;; + reload|restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status $UTS_BIN/Spm + RETVAL=$? + ;; + *) + echo "Usage: /etc/rc.d/init.d/spmd {start|stop|restart|reload|status}" + exit 1 +esac + +exit $RETVAL diff --git a/src/config/initscripts/redhat/uts.in b/src/config/initscripts/redhat/uts.in new file mode 100644 index 00000000..f26731be --- /dev/null +++ b/src/config/initscripts/redhat/uts.in @@ -0,0 +1,9 @@ +UTS_DIR=@prefix@ +UTS_BIN=$UTS_DIR/bin +UTS_ETC=/etc/uts +UTS_SEC=$UTS_ETC/sec + +PATH=/bin:/sbin:/usr/bin:/usr/local/bin + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$UTS_DIR/lib +export PATH=$UTS_BIN:$PATH diff --git a/src/config/initscripts/suse/Makefile.am b/src/config/initscripts/suse/Makefile.am new file mode 100644 index 00000000..84cedf0f --- /dev/null +++ b/src/config/initscripts/suse/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/rules.make + +dist_uts_initd_SCRIPTS = sbigcam secd spmd +dist_uts_initconfig_DATA = uts + +EXTRA_DIST = uts.in + diff --git a/src/config/initscripts/suse/sbigcam b/src/config/initscripts/suse/sbigcam new file mode 100644 index 00000000..31cc5921 --- /dev/null +++ b/src/config/initscripts/suse/sbigcam @@ -0,0 +1,146 @@ +#! /bin/sh +# Copyright (c) 2005 P. Henrique Silva +# +# Based on skeleton +# Copyright (c) 1995-2004 SUSE Linux AG, Nuernberg, Germany. +# All rights reserved. +# Author: Kurt Garloff +# +# 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. +# +# LSB compatible service control script; see http://www.linuxbase.org/spec/ +# +# Note: This template uses functions rc_XXX defined in /etc/rc.status on +# UnitedLinux (UL) based Linux distributions. If you want to base your +# script on this template and ensure that it works on non UL based LSB +# compliant Linux distributions, you either have to provide the rc.status +# functions from UL or change the script to work without them. +# +### BEGIN INIT INFO +# Provides: sbigcam +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Short-Description: UTS SBIG kernel modules +# Description: Start UTS SBIG kernel modules +### END INIT INFO + + +# Check for existence of needed config file and read it +UTS_CONFIG=/etc/sysconfig/uts +test -r $UTS_CONFIG || { echo "$UTS_CONFIG not existing"; + if [ "$1" = "stop" ]; then exit 0; + else exit 6; fi; } + +# Read config +. $UTS_CONFIG + +for i in `ls -1 $UTS_BIN/sbig_*`; do + test -x $i || { echo "$i not installed"; + if [ "$1" = "stop" ]; then exit 0; + else exit 5; fi; } +done + +# Source LSB init functions +# providing start_daemon, killproc, pidofproc, +# log_success_msg, log_failure_msg and log_warning_msg. +# This is currently not used by UnitedLinux based distributions and +# not needed for init scripts for UnitedLinux only. If it is used, +# the functions from rc.status should not be sourced or used. +#. /lib/lsb/init-functions + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v be verbose in local rc status and clear it afterwards +# rc_status -v -r ditto and clear both the local and overall rc status +# rc_status -s display "skipped" and exit with status 3 +# rc_status -u display "unused" and exit with status 3 +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear both the local and overall rc status +# rc_exit exit appropriate to overall rc status +# rc_active checks whether a service is activated by symlinks +. /etc/rc.status + +# Reset status of this service +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - generic or unspecified error +# 2 - invalid or excess argument(s) +# 3 - unimplemented feature (e.g. "reload") +# 4 - user had insufficient privileges +# 5 - program is not installed +# 6 - program is not configured +# 7 - program is not running +# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl) +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signaling is not supported) are +# considered a success. + +case "$1" in + start) + echo -n "Starting sbigcam " + ## Start daemon with startproc(8). If this fails + ## the return value is set appropriately by startproc. + startproc $UTS_BIN/sbig_load_usb_suse + + # Remember status and be verbose + rc_status -v + ;; + stop) + echo -n "Shutting down sbigcam " + ## Stop daemon with killproc(8) and if this fails + ## killproc sets the return value according to LSB. + + $UTS_BIN/sbig_unload_usb + + # Remember status and be verbose + rc_status -v + ;; + try-restart|condrestart) + ## Do a restart only if the service was active before. + ## Note: try-restart is now part of LSB (as of 1.9). + ## RH has a similar command named condrestart. + if test "$1" = "condrestart"; then + echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" + fi + $0 status + if test $? = 0; then + $0 restart + else + rc_reset # Not running is not a failure. + fi + # Remember status and be quiet + rc_status + ;; + restart) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac +rc_exit diff --git a/src/config/initscripts/suse/secd b/src/config/initscripts/suse/secd new file mode 100644 index 00000000..9ec04150 --- /dev/null +++ b/src/config/initscripts/suse/secd @@ -0,0 +1,208 @@ +#! /bin/sh +# Copyright (c) 2005 P. Henrique Silva +# +# Based on skeleton +# Copyright (c) 1995-2004 SUSE Linux AG, Nuernberg, Germany. +# All rights reserved. +# Author: Kurt Garloff +# +# 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. +# +# LSB compatible service control script; see http://www.linuxbase.org/spec/ +# +# Note: This template uses functions rc_XXX defined in /etc/rc.status on +# UnitedLinux (UL) based Linux distributions. If you want to base your +# script on this template and ensure that it works on non UL based LSB +# compliant Linux distributions, you either have to provide the rc.status +# functions from UL or change the script to work without them. +# +### BEGIN INIT INFO +# Provides: secd +# Required-Start: spmd +# Required-Stop: teld camd +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Short-Description: UTS Secretary daemon +# Description: Start UTS Secretary daemon +### END INIT INFO + + +# Check for existence of needed config file and read it +UTS_CONFIG=/etc/sysconfig/uts +test -r $UTS_CONFIG || { echo "$UTS_CONFIG not existing"; + if [ "$1" = "stop" ]; then exit 0; + else exit 6; fi; } + +# Read config +. $UTS_CONFIG + +SECD_BIN=$UTS_BIN/sec +test -x $SECD_BIN || { echo "$SECD_BIN not installed"; + if [ "$1" = "stop" ]; then exit 0; + else exit 5; fi; } + +GENCONF_BIN=$UTS_BIN/uts-gen-conf +test -x $GENCONF_BIN || { echo "$GENCONF_BIN not installed"; + if [ "$1" = "stop" ]; then exit 0; + else exit 5; fi; } + +# Source LSB init functions +# providing start_daemon, killproc, pidofproc, +# log_success_msg, log_failure_msg and log_warning_msg. +# This is currently not used by UnitedLinux based distributions and +# not needed for init scripts for UnitedLinux only. If it is used, +# the functions from rc.status should not be sourced or used. +#. /lib/lsb/init-functions + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v be verbose in local rc status and clear it afterwards +# rc_status -v -r ditto and clear both the local and overall rc status +# rc_status -s display "skipped" and exit with status 3 +# rc_status -u display "unused" and exit with status 3 +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear both the local and overall rc status +# rc_exit exit appropriate to overall rc status +# rc_active checks whether a service is activated by symlinks +. /etc/rc.status + +# Reset status of this service +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - generic or unspecified error +# 2 - invalid or excess argument(s) +# 3 - unimplemented feature (e.g. "reload") +# 4 - user had insufficient privileges +# 5 - program is not installed +# 6 - program is not configured +# 7 - program is not running +# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl) +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signaling is not supported) are +# considered a success. + +case "$1" in + start) + echo -n "Starting secd " + ## Start daemon with startproc(8). If this fails + ## the return value is set appropriately by startproc. + + # update .conf files + $GENCONF_BIN + + for i in `ls -1 $UTS_SEC/*.conf`; do + startproc -f -q $SECD_BIN -d $i + done + + # Remember status and be verbose + rc_status -v + ;; + stop) + echo -n "Shutting down secd " + ## Stop daemon with killproc(8) and if this fails + ## killproc sets the return value according to LSB. + + for i in `ls -1 $UTS_SEC/*.conf`; do + killproc -TERM $SECD_BIN + done + + # Remember status and be verbose + rc_status -v + ;; + try-restart|condrestart) + ## Do a restart only if the service was active before. + ## Note: try-restart is now part of LSB (as of 1.9). + ## RH has a similar command named condrestart. + if test "$1" = "condrestart"; then + echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" + fi + $0 status + if test $? = 0; then + $0 restart + else + rc_reset # Not running is not a failure. + fi + # Remember status and be quiet + rc_status + ;; + restart) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + force-reload) + ## Signal the daemon to reload its config. Most daemons + ## do this on signal 1 (SIGHUP). + ## If it does not support it, restart. + + echo -n "Reload service secd " + ## if it supports it: + killproc -HUP $SECD_BIN + #touch /var/run/secd.pid + rc_status -v + + ## Otherwise: + #$0 try-restart + #rc_status + ;; + reload) + ## Like force-reload, but if daemon does not support + ## signaling, do nothing (!) + + # If it supports signaling: + echo -n "Reload service secd " + killproc -HUP $SECD_BIN + #touch /var/run/secd.pid + rc_status -v + + ## Otherwise if it does not support reload: + #rc_failed 3 + #rc_status -v + ;; + status) + echo -n "Checking for service secd " + ## Check status with checkproc(8), if process is running + ## checkproc will return with exit status 0. + + # Return value is slightly different for the status command: + # 0 - service up and running + # 1 - service dead, but /var/run/ pid file exists + # 2 - service dead, but /var/lock/ lock file exists + # 3 - service not running (unused) + # 4 - service status unknown :-( + # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) + + # NOTE: checkproc returns LSB compliant status values. + checkproc $SECD_BIN + # NOTE: rc_status knows that we called this init script with + # "status" option and adapts its messages accordingly. + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" + exit 1 + ;; +esac +rc_exit diff --git a/src/config/initscripts/suse/spmd b/src/config/initscripts/suse/spmd new file mode 100644 index 00000000..a8a4eaa7 --- /dev/null +++ b/src/config/initscripts/suse/spmd @@ -0,0 +1,195 @@ +#! /bin/sh +# Copyright (c) 2005 P. Henrique Silva +# +# Based on skeleton +# Copyright (c) 1995-2004 SUSE Linux AG, Nuernberg, Germany. +# All rights reserved. +# Author: Kurt Garloff +# +# 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. +# +# LSB compatible service control script; see http://www.linuxbase.org/spec/ +# +# Note: This template uses functions rc_XXX defined in /etc/rc.status on +# UnitedLinux (UL) based Linux distributions. If you want to base your +# script on this template and ensure that it works on non UL based LSB +# compliant Linux distributions, you either have to provide the rc.status +# functions from UL or change the script to work without them. +# +### BEGIN INIT INFO +# Provides: spmd +# Required-Stop: secd +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Short-Description: UTS sockets daemon +# Description: Start UTS sockets daemon +### END INIT INFO + + +# Check for existence of needed config file and read it +UTS_CONFIG=/etc/sysconfig/uts +test -r $UTS_CONFIG || { echo "$UTS_CONFIG not existing"; + if [ "$1" = "stop" ]; then exit 0; + else exit 6; fi; } + +# Read config +. $UTS_CONFIG + +SPMD_BIN=$UTS_BIN/Spm +test -x $SPMD_BIN || { echo "$SPMD_BIN not installed"; + if [ "$1" = "stop" ]; then exit 0; + else exit 5; fi; } + + +# Source LSB init functions +# providing start_daemon, killproc, pidofproc, +# log_success_msg, log_failure_msg and log_warning_msg. +# This is currently not used by UnitedLinux based distributions and +# not needed for init scripts for UnitedLinux only. If it is used, +# the functions from rc.status should not be sourced or used. +#. /lib/lsb/init-functions + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v be verbose in local rc status and clear it afterwards +# rc_status -v -r ditto and clear both the local and overall rc status +# rc_status -s display "skipped" and exit with status 3 +# rc_status -u display "unused" and exit with status 3 +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear both the local and overall rc status +# rc_exit exit appropriate to overall rc status +# rc_active checks whether a service is activated by symlinks +. /etc/rc.status + +# Reset status of this service +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - generic or unspecified error +# 2 - invalid or excess argument(s) +# 3 - unimplemented feature (e.g. "reload") +# 4 - user had insufficient privileges +# 5 - program is not installed +# 6 - program is not configured +# 7 - program is not running +# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl) +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signaling is not supported) are +# considered a success. + +case "$1" in + start) + echo -n "Starting spmd " + ## Start daemon with startproc(8). If this fails + ## the return value is set appropriately by startproc. + startproc $SPMD_BIN &> /dev/null + + # Remember status and be verbose + rc_status -v + ;; + stop) + echo -n "Shutting down spmd " + ## Stop daemon with killproc(8) and if this fails + ## killproc sets the return value according to LSB. + + killproc -TERM $SPMD_BIN + + # Remember status and be verbose + rc_status -v + ;; + try-restart|condrestart) + ## Do a restart only if the service was active before. + ## Note: try-restart is now part of LSB (as of 1.9). + ## RH has a similar command named condrestart. + if test "$1" = "condrestart"; then + echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" + fi + $0 status + if test $? = 0; then + $0 restart + else + rc_reset # Not running is not a failure. + fi + # Remember status and be quiet + rc_status + ;; + restart) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + force-reload) + ## Signal the daemon to reload its config. Most daemons + ## do this on signal 1 (SIGHUP). + ## If it does not support it, restart. + + echo -n "Reload service spmd " + ## if it supports it: + killproc -HUP $SPMD_BIN + #touch /var/run/spmd.pid + rc_status -v + + ## Otherwise: + #$0 try-restart + #rc_status + ;; + reload) + ## Like force-reload, but if daemon does not support + ## signaling, do nothing (!) + + # If it supports signaling: + echo -n "Reload service spmd " + killproc -HUP $SPMD_BIN + #touch /var/run/spmd.pid + rc_status -v + + ## Otherwise if it does not support reload: + #rc_failed 3 + #rc_status -v + ;; + status) + echo -n "Checking for service spmd " + ## Check status with checkproc(8), if process is running + ## checkproc will return with exit status 0. + + # Return value is slightly different for the status command: + # 0 - service up and running + # 1 - service dead, but /var/run/ pid file exists + # 2 - service dead, but /var/lock/ lock file exists + # 3 - service not running (unused) + # 4 - service status unknown :-( + # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) + + # NOTE: checkproc returns LSB compliant status values. + checkproc $SPMD_BIN + # NOTE: rc_status knows that we called this init script with + # "status" option and adapts its messages accordingly. + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" + exit 1 + ;; +esac +rc_exit diff --git a/src/config/initscripts/suse/uts.in b/src/config/initscripts/suse/uts.in new file mode 100644 index 00000000..d05f62ab --- /dev/null +++ b/src/config/initscripts/suse/uts.in @@ -0,0 +1,11 @@ +UTS_DIR=@prefix@ +UTS_BIN=$UTS_DIR/bin +UTS_ETC=/etc/uts +UTS_SEC=$UTS_ETC/sec + +PYTHON=@PYTHON@ + +PATH=/bin:/sbin:/usr/bin:/usr/local/bin + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$UTS_DIR/lib +export PATH=$UTS_BIN:$PATH diff --git a/src/config/rpc.conf b/src/config/rpc.conf new file mode 100644 index 00000000..e69de29b diff --git a/src/config/site.xml b/src/config/site.xml new file mode 100644 index 00000000..f4f643fb --- /dev/null +++ b/src/config/site.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/drivers/Makefile.am b/src/drivers/Makefile.am new file mode 100644 index 00000000..ff379002 --- /dev/null +++ b/src/drivers/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = camfits.fake camfits.st4 camfits.st7 telgo.fake telgo.lx200 telgo.paramount weather.wx200 + diff --git a/src/drivers/camfits.fake/Makefile.am b/src/drivers/camfits.fake/Makefile.am new file mode 100644 index 00000000..6ca6a9df --- /dev/null +++ b/src/drivers/camfits.fake/Makefile.am @@ -0,0 +1,9 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = camfits.fake + +camfits_fake_SOURCES = ccd.c ccd.h errors.h main.c ser.c ser.h + +camfits_fake_LDADD = -lm -lcfitsio + +uts_driver_DATA = fake.camera.xml diff --git a/src/drivers/camfits.fake/ccd.c b/src/drivers/camfits.fake/ccd.c new file mode 100644 index 00000000..042a8dde --- /dev/null +++ b/src/drivers/camfits.fake/ccd.c @@ -0,0 +1,465 @@ +#include +#include "errors.h" +#include "ccd.h" + + +#undef CCDTEST +#ifdef CCDTEST + +char minhatty[] = "/dev/ttyS1"; + +cam_info *camera; + +int main() +{ + int i; + + puts("Programa para teste do CCD."); + printf("tty = %s\n\n", minhatty); + + camera = alloc_camera(minhatty); + if (camera == NULL) { + puts("alloc_camera()"); + exit(1); + } + + camera->ccd->baudrate = CAM_B57600; + camera->ccd->rom_version = ROM_VERSION; + if (init_camera(camera) != ERR_OK) { + puts("init_camera()"); + exit(0); + } + + camera->ccd->exptime = 5; + camera->ccd->first_line = CAM_FIRST_LINE; + camera->ccd->first_column = 0; + camera->ccd->nlines = CAM_MAX_NLINES; + camera->ccd->ncolumns = CAM_MAX_NCOLS; + camera->ccd->offset = 0; + camera->ccd->vref_plus = 255; + camera->ccd->vref_minus = 0; + camera->ccd->format_flag = 0; + camera->ccd->mode_flag = (CAM_MODE_FEXP | CAM_MODE_LA); + set_camera(camera); + take_image(camera, camera->ccd->image); + + free_camera(camera); +} +#endif + + +int init_camera(cam_info *camera) +{ + int res; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + + camera->serial->waitread = TRUE; + camera->serial->baudrate = B9600; + camera->serial->parity = PAR_EVEN; + camera->serial->stopbits = 1; + camera->serial->minchars = 0; + camera->serial->timeout = 5; + set_serial(camera->serial); + if (camera->serial->err_code != ERR_OK) + return(ERR_SERIAL); + + res = set_baudrate(camera, camera->ccd->baudrate); + return(res); + +} + + +int is_valid_camera(cam_info *camera) +{ + if (camera == NULL) + return(FALSE); + if (camera->ccd == NULL) + return(FALSE); + if (camera->serial == NULL) + return(FALSE); + return(TRUE); +} + + +cam_info *alloc_camera(char *ttyname) +{ + cam_info *camera; + int i; + + camera = (cam_info *) calloc(sizeof(cam_info), 1); + if (camera == NULL) + return(NULL); + camera->serial = (ser_info *) calloc(sizeof(ser_info), 1); + if (camera->serial == NULL) + return(NULL); + camera->ccd = (ccd_info *) calloc(sizeof(ccd_info), 1); + if (camera->ccd == NULL) + return(NULL); + open_serial(camera->serial, ttyname); + return(camera); +} + + +void free_camera(cam_info *camera) +{ + if (camera == NULL) + return; + if (camera->serial != NULL) { + if (camera->serial->ttyfd > 0) { + set_baudrate(camera, CAM_B9600); + close_serial(camera->serial); + } + free(camera->serial); + } + if (camera->ccd != NULL) + free(camera->ccd); + free(camera); +} + + +int set_camera(cam_info *camera) +{ + long int exptmp; + int res; + cmd_t cmd; + + if (!is_valid_camera(camera)) + return(ERR_CAM); +/* Set modes and format */ + cmd.nbytes = 2; + cmd.address = CAM_MODE; + cmd.ram = CAM_INT_RAM; + camera->ccd->mode_flag &= ~CAM_MODE_STEXP; + cmd.data[0] = camera->ccd->mode_flag; + cmd.data[1] = camera->ccd->format_flag; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +/* Set exposure time */ +/* cmd.nbytes = 2; + cmd.address = CAM_EXPTIME; + exptmp = camera->ccd->exptime * 100; + cmd.data[0] = exptmp & 0x00FF; + cmd.data[1] = (exptmp >> 8) & 0x00FF; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); */ + +/* Set first pixel and number of pixels per line */ + cmd.nbytes = 2; + cmd.address = CAM_XPOINTER; + cmd.data[0] = camera->ccd->first_column; + cmd.data[1] = camera->ccd->ncolumns; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +/* Set additional offset and Vref+ */ + cmd.nbytes = 2; + cmd.address = CAM_OFFSET; + cmd.data[0] = camera->ccd->offset; + cmd.data[1] = camera->ccd->vref_plus; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +/* Set Vref- */ + cmd.nbytes = 1; + cmd.address = CAM_VREFMINUS; + cmd.data[0] = camera->ccd->vref_minus; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +return(ERR_OK); +} + + +int write_mem(cam_info *camera, cmd_t *cmd) +{ + unsigned char buf[CAM_MAX_CMD], *pbuf, chksum, tmp; + int i, res; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (cmd == NULL) + return(ERR_CMD); + + pbuf = buf; + *pbuf++ = CAM_WRITE_MEM; + chksum = CAM_WRITE_MEM; + tmp = cmd->nbytes + 3; + *pbuf++ = tmp; + chksum += tmp; + *pbuf++ = cmd->ram; + chksum += cmd->ram; + tmp = cmd->address & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + tmp = (cmd->address >> 8) & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + + for (i = 0; i < (cmd->nbytes); i++) { + *pbuf++ = cmd->data[i]; + chksum += cmd->data[i]; + } + *pbuf = chksum; + if (write_serial(camera->serial, buf, (6 + cmd->nbytes)) == ERR_WRITE) + return(ERR_WRITE); + res = wait_response(camera); + if (res == CAM_NAK) + return(ERR_READ); + return(ERR_OK); +} + + +unsigned char wait_response(cam_info *camera) +{ + unsigned char c; + int res; + + if (!is_valid_camera(camera)) + return; + + if (read_serial(camera->serial, &c, 1) == ERR_READ) + return(CAM_NAK); + if (c != CAM_ACK) + return(CAM_NAK); + return(CAM_ACK); +} + + +int read_mem(cam_info *camera, cmd_t *cmd) +{ + unsigned char buf[CAM_MAX_CMD], *pbuf, tmp, chksum; + int res, i; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (cmd == NULL) + return(ERR_CMD); +/* Set command in buffer */ + pbuf = buf; + *pbuf++ = CAM_READ_MEM; + chksum = CAM_READ_MEM; + *pbuf++ = cmd->nbytes; + chksum += cmd->nbytes; + *pbuf++ = cmd->ram; + chksum += cmd->ram; + tmp = cmd->address & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + tmp = (cmd->address >> 8) & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + *pbuf = chksum; + res = write_serial(camera->serial, buf, 6); + if (res < 6) + return(ERR_WRITE); +/* Read header */ + res = read_serial(camera->serial, buf, 2); + if ((res < 2) || (buf[0] != 2) || (buf[1] != cmd->nbytes)) + return(ERR_READ); +/* Read data */ + res = read_serial(camera->serial, buf, cmd->nbytes); + if (res < cmd->nbytes) + return(ERR_READ); + pbuf = buf; + for (i = 0; i < cmd->nbytes;) + cmd->data[i++] = *pbuf++; +/* Checksum */ + res = read_serial(camera->serial, buf, 1); + if (res < 1) + return(ERR_READ); +/* Evaluate checksum in the futute */ + return(ERR_OK); +} + + +int set_baudrate(cam_info *camera, unsigned char baudrate) +{ + cmd_t cmd; + int tmp; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + +/* Write ROM version */ + cmd.nbytes = 1; + cmd.ram = CAM_INT_RAM; + cmd.address = CAM_ROMVER; + cmd.data[0] = camera->ccd->rom_version; + if (write_mem(camera, &cmd) != ERR_OK) + return(ERR_WRITE); + +/* Set baud rate */ + cmd.nbytes = 1; + cmd.address = CAM_BAUDRATE; + cmd.data[0] = baudrate; + if (write_mem(camera, &cmd) != ERR_OK) + return(ERR_WRITE); + + camera->ccd->baudrate = baudrate; + switch (baudrate) { + case CAM_B57600: + camera->serial->baudrate = B57600; + break; + case CAM_B19200: + camera->serial->baudrate = B19200; + break; + case CAM_B9600: + camera->serial->baudrate = B9600; + break; + case CAM_B4800: + camera->serial->baudrate = B4800; + break; + case CAM_B2400: + camera->serial->baudrate = B2400; + break; + case CAM_B1200: + camera->serial->baudrate = B1200; + break; + case CAM_B600: + camera->serial->baudrate = B600; + break; + case CAM_B300: + camera->serial->baudrate = B300; + break; + default: + return(ERR_BAUDRATE); + } + set_serial(camera->serial); + if (camera->serial->err_code != ERR_OK) + return(ERR_SERIAL); + + /* Read ROM version for testing */ + cmd.nbytes = 1; + cmd.address = CAM_ROMVER; + tmp = read_mem(camera, &cmd); + if (tmp != ERR_OK) + return(ERR_READ); + if (cmd.data[0] != camera->ccd->rom_version) + return(ERR_SERIAL); + + return(ERR_OK); +} + + +int expose_ccd(cam_info *camera, float time) +{ +cmd_t cmd; +int tmp, res; + +if (!is_valid_camera(camera)) + return(ERR_CAM); + +/* Set exposure time */ + cmd.nbytes = 2; + cmd.address = CAM_EXPTIME; + cmd.ram = CAM_INT_RAM; + camera->ccd->exptime = time; + tmp = time * 100; + cmd.data[0] = tmp & 0x00FF; + cmd.data[1] = (tmp >> 8) & 0x00FF; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(res); + +/* Start exposure */ + cmd.nbytes = 1; + cmd.address = CAM_MODE; + camera->ccd->mode_flag &= ~CAM_MODE_STEXP; + cmd.data[0] = camera->ccd->mode_flag | CAM_MODE_STEXP; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(res); + +/* Wait until exposure is done */ + cmd.nbytes = 1; + cmd.address = CAM_MODE; + sleep((int)time); + do { + if ((res = read_mem(camera, &cmd)) != ERR_OK) + return(res); + sleep(1); + } while((cmd.data[0] & CAM_MODE_EXPDONE) == CAM_MODE_EXPDONE); + +return(ERR_OK); +} + + +int read_line(cam_info *camera, int line, unsigned char *buf) +{ + unsigned char chksum; + int res; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if ((line < CAM_FIRST_LINE ) || (line > CAM_LAST_LINE)) + return; + buf[0] = line; + buf[1] = line; + res = write_serial(camera->serial, buf, 2); + if (res < 2) + return(ERR_WRITE); + res = read_serial(camera->serial, buf, 2); + if (res < 2) + return(ERR_READ); + if ((buf[0] != line) || (buf[1] != camera->ccd->ncolumns)) + return(ERR_READ); + + res = read_serial(camera->serial, buf, camera->ccd->ncolumns); + if (res < camera->ccd->ncolumns) + return(ERR_READ); + + res = read_serial(camera->serial, &chksum, 1); + if (res < 1) + return(ERR_READ); +/* Evaluate checksum in future */ + + return(ERR_OK); +} + + +int take_image(cam_info *camera, unsigned char *image) +{ + int res; + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (camera->ccd->image == NULL) + return(ERR_MEM); + + if ((res = expose_ccd(camera, camera->ccd->exptime)) != ERR_OK) + return(res); + + if ((res = download_image(camera, image)) != ERR_OK) + return(res); + + return(ERR_OK); + +} + + +int download_image(cam_info *camera, unsigned char *image) +{ + int i, l; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (image == NULL) + return(ERR_MEM); + + l = camera->ccd->first_line; + for (i = 0; i < camera->ccd->nlines; i++, l++) { + if (read_line(camera, l , image) != ERR_OK) + return(ERR_READ); +/* Pad to next line */ + image += CAM_MAX_NCOLS; + } + + return(ERR_OK); +} diff --git a/src/drivers/camfits.fake/ccd.h b/src/drivers/camfits.fake/ccd.h new file mode 100644 index 00000000..57741571 --- /dev/null +++ b/src/drivers/camfits.fake/ccd.h @@ -0,0 +1,120 @@ +#include "ser.h" + +#define ROM_VERSION (3) + +#define CAM_MAX_NLINES (165) +#define CAM_MAX_NCOLS (192) + +#define CAM_FIRST_LINE (64) +#define CAM_LAST_LINE (228) + +/* Commands */ +#define CAM_WRITE_MEM (1) +#define CAM_READ_MEM (2) +#define CAM_EXT_RAM (0) +#define CAM_INT_RAM (1) + +/* Responses */ +#define CAM_ACK (0x06) +#define CAM_NAK (0x15) + +/* Mode flags (46) */ +#define CAM_MODE_FEXP (0x80) /* Full exposure */ +#define CAM_MODE_LA (0x40) /* Light array */ +#define CAM_MODE_STEXP (0x20) /* Start exposure */ +#define CAM_MODE_EXPDONE (0x10) /* Exposure done */ +#define CAM_MODE_CMPRSIMG (0x08) /* Compress image in memory */ +#define CAM_MODE_SUBDARKF (0x04) /* Subtract dark frame */ +#define CAM_MODE_CMPRSDAT (0x02) /* Enable data compression */ +#define CAM_MODE_SMTH (0x01) /* Smooth image in memory */ + +/* Format flags (47) */ +#define CAM_FMT_FFOCUS (0x80) /* Find and focus mode */ +#define CAM_FMT_ANTIBLOOM (0x40) /* Anti-blooming gate enable */ +#define CAM_FMT_INTERRUPT (0x20) /* Interrupt from Find and focus, Track */ + /* and Calibrate modes. */ +#define CAM_FMT_TRACK (0x10) /* Track mode */ +#define CAM_FMT_CALIBRATE (0x08) /* Calibrate mode */ +#define CAM_FMT_CLOSE_R0 (0x04) /* Close `left' relay */ +#define CAM_FMT_CLOSE_R1 (0x05) /* Close `right' relay */ +#define CAM_FMT_CLOSE_R2 (0x06) /* Close `up' relay */ +#define CAM_FMT_CLOSE_R3 (0x07) /* Close `down' relay */ + +/* Baud rates */ +#define CAM_B57600 (255) +#define CAM_B19200 (253) +#define CAM_B9600 (250) +#define CAM_B4800 (244) +#define CAM_B2400 (232) +#define CAM_B1200 (208) +#define CAM_B600 (160) +#define CAM_B300 (64) + +/* Addresses */ +#define CAM_LAST_KEY (45) +#define CAM_MODE (46) +#define CAM_FORMAT (47) +#define CAM_EXPTIME (48) +#define CAM_XPOINTER (50) +#define CAM_NBYTES (51) +#define CAM_OFFSET (52) +#define CAM_VREFPLUS (53) +#define CAM_VREFMINUS (54) +#define CAM_ROMVER (55) +#define CAM_BAUDRATE (56) +#define CAM_INSTRUCT (58) + + +#define CAM_MAX_DATA (4) +#define CAM_MAX_CMD (CAM_MAX_DATA + 6) + + +typedef struct { + float exptime; /* seconds */ + unsigned char mode_flag; + unsigned char format_flag; + unsigned char first_line; + unsigned char first_column; + unsigned char nlines; + unsigned char ncolumns; + unsigned char offset; + unsigned char vref_plus; + unsigned char vref_minus; + unsigned char rom_version; + unsigned char baudrate; /* note: this is the constant specified */ + /* above, e.g. CAM_BXXXXX. */ + unsigned char *image; +} ccd_info; + +typedef struct { + ccd_info *ccd; + ser_info *serial; +} cam_info; + +typedef struct { + int nbytes; + int ram; + int address; + unsigned char data[CAM_MAX_DATA]; +} cmd_t; + + +/* Camera structure management */ +int is_valid_camera(cam_info *camera); +cam_info *alloc_camera(char *ttyname); +void free_camera(cam_info *camera); + +/* Low level functions */ +int set_baudrate(cam_info *camera, unsigned char baudrate); + /* values of baud rates are defined in camera.h */ +int init_camera(cam_info *camera); +int write_mem(cam_info *camera, cmd_t *command); +int read_mem(cam_info *camera, cmd_t *command); +unsigned char wait_response(cam_info *camera); + +/* user functions */ +int expose_ccd(cam_info *camera, float time); /* seconds */ +int read_line(cam_info *camera, int line, unsigned char *buf); +int download_image(cam_info *camera, unsigned char *image); +int set_camera(cam_info *camera); +int take_image(cam_info *camera, unsigned char *image); diff --git a/src/drivers/camfits.fake/errors.h b/src/drivers/camfits.fake/errors.h new file mode 100644 index 00000000..41941c97 --- /dev/null +++ b/src/drivers/camfits.fake/errors.h @@ -0,0 +1,19 @@ +#define TRUE (1) +#define FALSE (0) + + + +#define ERR_OK (0) +#define ERR_OPENTTY (-1) +#define ERR_SERIAL (-2) +#define ERR_BAUDRATE (-3) +#define ERR_PARITY (-4) +#define ERR_STOPB (-5) +#define ERR_WRITE (-6) +#define ERR_READ (-7) +#define ERR_MEM (-8) +#define ERR_NOTRESPOND (-9) + +#define ERR_CAM (-50) +#define ERR_CMD (-51) +#define ERR_EXPOSE (-52) diff --git a/src/drivers/camfits.fake/fake.camera.xml b/src/drivers/camfits.fake/fake.camera.xml new file mode 100644 index 00000000..46d28f52 --- /dev/null +++ b/src/drivers/camfits.fake/fake.camera.xml @@ -0,0 +1,44 @@ + + + + + Fake + Camera + + +camfits.fake -t $exp_time -n $n_exp -o $output + + + + + + exp_time + float + 1.0 + Integration time in seconds. Min and max comes from CCDcap. + + + + n_exp + int + 1 + Number of frames to take. + + + + output + str + img-$time-$object-$filter + Filename of the output image (wildcards allowed: $time, $object, $filter). + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/drivers/camfits.fake/main.c b/src/drivers/camfits.fake/main.c new file mode 100644 index 00000000..6116deb8 --- /dev/null +++ b/src/drivers/camfits.fake/main.c @@ -0,0 +1,323 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "errors.h" +#include "ccd.h" +#include "fitsio.h" + +#define TRUE (1) +#define FALSE (0) + +int getimage(cam_info *camera, float texp, char *bfname, int imindex); +int fileexists(char *fname); +void usage(void); +void setup(void); +void check_alloc_error(void); +void expose_error(int err); +void save_fits(char *fname); +void print_image(unsigned char *image); +void controlc(int signumber); +void hangup(int signumber); + + +cam_info *camera; +char command[128]; +int output = FALSE; /* Enable output to terminal */ +int nexp = 0; /* Number of images to take */ +char *porta; /* Serial port */ +char *bfname; /* Image base-file-name */ +int imindex; /* index to bfname */ +float texp; /* Exposure time */ +fitsfile *fptr; /* Image file */ +int fitstatus; /* Status returned by fits library */ + +int nimg; /* Number of images taken */ +int stop_imaging = FALSE; /* if TRUE stop imaging */ + +unsigned char image[CAM_MAX_NLINES][CAM_MAX_NCOLS]; +long naxes[2] = {CAM_MAX_NCOLS, CAM_MAX_NLINES}; + +int main(int argc, char ** argv) +{ + int res; + + signal(SIGINT, controlc); + signal(SIGHUP, hangup); + signal(SIGABRT, controlc); + + strcpy(command, argv[0]); + fprintf(stderr, "CCD faker, FITS file format support.\n" + "Ver0.6f - Image sequence enabled.\n\n"); + if (argc < 8) { + usage(); + exit(1); + } + +/* strcpy(porta, argv[1]); + strcpy(bfname, argv[4]); */ + porta = argv[1]; + bfname = argv[6]; + if (*bfname == '-') { + if (*(++bfname) == '\0') { + output = TRUE; + bfname = NULL; + } else { + usage(); + exit(1); + } + } + + +/* get index */ + if (!output) { + res = sscanf(argv[7], "%d", &imindex); + if (res != 1) { + fprintf(stderr, "\nError: \"%s\" is an invalid index.\n\n", argv[2]); + usage(); + exit(1); + } + } + +/* get exposure time */ + res = sscanf(argv[2], "%f", &texp); + if (res != 1) { + fprintf(stderr, "\nError: \"%s\" is an invalid exposure time.\n\n", argv[2]); + usage(); + exit(1); + } + +/* get number of exposures */ + res = sscanf(argv[3], "%d", &nexp); + if (res != 1) { + fprintf(stderr, "\nError: \"%s\" is an invalid number of exposures.\n\n", argv[2]); + usage(); + exit(1); + } + + setup(); + + for (nimg = 0; nimg < nexp; nimg++) { + fprintf(stderr, "\nTaking image #%d.\n", nimg); + getimage(camera, texp, bfname, (nimg + imindex)); + if (stop_imaging) break; + } + + free_camera(camera); + exit(nimg++); +} + + +int getimage(cam_info *camera, float texp, char *bfname, int imindex) +{ + char fname[128]; + char tmp[128]; + int res; + + fprintf(stderr, "Exposing CCD..."); +/* if ((res = expose_ccd(camera, texp)) != ERR_OK) { + expose_error(res); + abort(); + } */ + sleep((int) texp); + fprintf(stderr, "OK.\n"); + + fprintf(stderr, "Downloading image..."); +/* if ((res = download_image(camera, camera->ccd->image)) != ERR_OK) { + fprintf(stderr, "Error in download_image()\n"); + abort(); + } */ + sleep(5); + fprintf(stderr, "OK.\n"); + + if (output) { +/* fprintf(stderr, "Printing image...\n"); + print_image(camera->ccd->image); + fprintf(stderr, "\nDone.\n"); */ + } else { + sprintf(fname, "%s%04d.fits", bfname, imindex); + fprintf(stderr, "Saving image %s...", fname); + if (fileexists(fname)) + fprintf(stderr, " file already exists.\n"); + else { + snprintf(tmp,128, "touch %s", fname); + system(tmp); + /* save_fits(fname); */ + fprintf(stderr, "OK\n"); + } + } +} + + + +void usage(void) +{ + fprintf(stderr, "Specify terminal, exposure time (in seconds), # of exposures, base-file-name and indexer.\n"); + fprintf(stderr, "Use \"-\" instead of file name to output the image to stdout.\n\n"); + fprintf(stderr, "SYNTAX: %s terminal_device exposure_time nexposures x1:x2 y1:y2 { output_file indexer | - }\n\n", command); + fprintf(stderr, "E.g.: %s /dev/ttyS1 10.2 25 0:192 0:165 junk 0000\n", command); + fprintf(stderr, "E.g.: %s /dev/ttyS1 10.2 1 50:100 46:120 -\n\n\n", command); +} + + +/* test if file already exists */ +int fileexists(char *fname) +{ + int res; + + if ((res = open(fname, O_RDONLY)) != -1) { + close(res); + return (TRUE); /* File exists! */ + } + return (FALSE); /* File does not exist */ +} + + + +/* sets up camera structs and initializes its parameters */ +void setup(void) +{ +/* int tmp; + + camera = alloc_camera(porta); + check_alloc_error(); + + camera->ccd->image = &(image[0][0]); + + camera->ccd->baudrate = CAM_B57600; + camera->ccd->rom_version = ROM_VERSION; + if ((tmp = init_camera(camera)) != ERR_OK) { + fprintf(stderr, "Error in init_camera(): %d\n", tmp); + abort(); + } + camera->ccd->first_line = CAM_FIRST_LINE; + camera->ccd->first_column = 0; + camera->ccd->nlines = CAM_MAX_NLINES; + camera->ccd->ncolumns = CAM_MAX_NCOLS; + camera->ccd->offset = 0; + camera->ccd->vref_plus = 255; + camera->ccd->vref_minus = 0; + camera->ccd->format_flag = 0; + camera->ccd->mode_flag = (CAM_MODE_FEXP | CAM_MODE_LA); + if ((tmp = set_camera(camera)) != ERR_OK) { + fprintf(stderr, "Error in set_camera()\n"); + abort(); + } */ +} + + +void print_image(unsigned char *image) +{ + int i, j, lastline, lastcol; + + lastline = camera->ccd->nlines; + lastcol = camera->ccd->ncolumns; + for (i = 0; i < lastline; i++) { + for (j = 0; j < lastcol; j++) + printf("%d\n", *(image++)); + } + printf("$"); /* image terminator */ +} + + +void save_fits(char *fname) +{ + int x, y, i, j, lastline, lastcol; + unsigned char ** imgptr; + +/* Gradient fill + for (i = 0; i < 165; i++) + for (j = 0; j < 192; j++) + image[i][j] = (i+j)/2; +*/ + + naxes[0] = camera->ccd->ncolumns; + naxes[1] = camera->ccd->nlines; + +/* + imgptr = camera->ccd->image; + lastline = camera->ccd->nlines + camera->ccd->first_line; + lastcol = camera->ccd->first_column + camera->ccd->ncolumns; + + for (i = camera->ccd->first_line, x = 0; i < lastline; i++, x++, imgptr++) { + for (j = camera->ccd->first_column, y = 0; j < lastcol; j++, y++) + rawimage[x][y] = (*imgptr)[y]; + } +*/ + +/* open file for writing a FITS image */ + + if (fits_create_file(&fptr, fname, &fitstatus) || + fits_create_img(fptr, BYTE_IMG, 2, naxes, &fitstatus) || + fits_write_img(fptr, TBYTE, 1, (naxes[0] * naxes[1]), image, &fitstatus) || + fits_update_key(fptr, TFLOAT, "EXPTIME", &texp, "Exposure Time (secs.)", &fitstatus) || + fits_close_file(fptr, &fitstatus)) { + fits_report_error(stderr, fitstatus); + abort(); + } +} + + +void check_alloc_error(void) +{ + if (!is_valid_camera(camera)) { + fprintf(stderr, "Error allocating camera structures.\n"); + abort(); + } + if (camera->serial->err_code == ERR_OK) return; + + fprintf(stderr, "Error setting up camera, "); + if (camera->serial->err_code == ERR_READ) + fprintf(stderr, "could not read serial port.\n"); + else if (camera->serial->err_code == ERR_WRITE) + fprintf(stderr, "could not write serial port.\n"); + else if (camera->serial->err_code == ERR_OPENTTY) + fprintf(stderr, "could not open serial port.\n"); + else if (camera->serial->err_code == ERR_MEM) + fprintf(stderr, "serial structures could not be created.\n"); + else fprintf(stderr, "unexpected error.\n"); + abort(); +} + + +void expose_error(int err) +{ + fprintf(stderr, "Problem exposing CCD, "); + if (err == ERR_CAM) fprintf(stderr, "camera not allocated.\n"); + else if (err == ERR_WRITE) fprintf(stderr, "error writing camera.\n"); + else if (err == ERR_READ) fprintf(stderr, "error reading camera.\n"); + else fprintf(stderr, "unexpected error.\n"); + abort(); +} + + +void controlc(int signumber) +{ + if (signumber == SIGINT) + fprintf(stderr, "Control-C signal caught, exiting.\n"); + else + fprintf(stderr, "Aborting...\n"); + if (is_valid_camera(camera)) + tcflush(camera->serial->ttyfd, TCOFLUSH); + free_camera(camera); + exit(nimg++); +} + +void hangup(int signumber) +{ + fprintf(stderr, "\nHangup signal received, stopping imaging.\n"); + stop_imaging = TRUE; +} diff --git a/src/drivers/camfits.fake/ser.c b/src/drivers/camfits.fake/ser.c new file mode 100644 index 00000000..4925c033 --- /dev/null +++ b/src/drivers/camfits.fake/ser.c @@ -0,0 +1,250 @@ +/* This file contains the functions for serial communication */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "errors.h" +#include "ser.h" + +static int set_minchars(ser_info *serial, int nbytes); +static void rdtimeout(int signumber); +static ser_info *sertmp; + +#ifdef COMMTEST + +/* This example program writes a string in port `tty', and waits until + timeout for a response. */ + + +char teste[] = "Write test..."; +unsigned char buf[25]; +char tty[] = "/dev/ttyS1"; + + +int main(void) +{ + int result; + ser_info porta; + + open_serial(&porta, tty); + if (porta.err_code != ERR_OK) return(-1); + puts("Communication test.\n\n"); + + /* 9600,8e1 */ + porta.baudrate = B9600; + porta.parity = PAR_EVEN; + porta.stopbits = 1; + porta.timeout = 10; + porta.minchars = 25; + porta.waitread = FALSE; + set_serial(&porta); + write_serial(&porta, teste, strlen(teste)); + + if (read_serial(&porta, buf, 24)) + printf("Text received: %s\n\n", buf); + else printf("Read timeout.\n\n"); + + close_serial(&porta); + return(0); +} +#endif /* COMMTEST */ + + +int is_valid_serial(ser_info *serial) +{ + if ((serial == NULL) || + (serial->tty_name == NULL) || + (serial->tio == NULL) || + (serial->oldtio == NULL)) + return(FALSE); + return(TRUE); +} + + +void open_serial(ser_info *serial, char *ttyname) +{ + if (serial == NULL) return; + + serial->err_code = ERR_OK; + signal(SIGALRM, rdtimeout); + +/* Allocate memory for the structures */ + serial->tio = (struct termios *) malloc(sizeof(struct termios)); + if (serial->tio == NULL) { + serial->err_code = ERR_MEM; + return; + } + serial->oldtio = (struct termios *) malloc(sizeof(struct termios)); + if (serial->oldtio == NULL) { + serial->err_code = ERR_MEM; + return; + } + + serial->tty_name = (char *) calloc(strlen(ttyname), sizeof(char)); + if (serial->tty_name == NULL) { + serial->err_code = ERR_MEM; + return; + } + strcpy(serial->tty_name, ttyname); + + + serial->ttyfd = open(serial->tty_name, O_RDWR | O_NOCTTY); + if (serial->ttyfd < 0) { + serial->err_code = ERR_OPENTTY; + close_serial(serial); + return; + } + +/* Save current config */ + tcgetattr(serial->ttyfd, serial->oldtio); + serial->isopen = TRUE; +} + + +int close_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + signal(SIGALRM, SIG_DFL); +/* Restore terminal to its previous state; free memory */ + if (serial->isopen) { + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + close(serial->ttyfd); + } + if (serial->tio != NULL) free(serial->tio); + if (serial->oldtio != NULL) free(serial->oldtio); + if (serial->tty_name != NULL) free(serial->tty_name); + return(ERR_OK); +} + + +int set_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(ERR_SERIAL); + } + memset(serial->tio, 0, sizeof(struct termios)); + + cfsetospeed(serial->tio, serial->baudrate); + cfsetispeed(serial->tio, serial->baudrate); + +/* Set byte size to 8bit, enable reading and set local mode */ + serial->tio->c_cflag |= CS8 | CLOCAL | CREAD; + switch (serial->parity) { + case PAR_NONE: + serial->tio->c_iflag |= IGNPAR; + serial->tio->c_cflag &= ~PARENB; + break; + + case PAR_EVEN: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= ~PARODD; + break; + + case PAR_ODD: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= PARODD; + break; + default: + serial->err_code = ERR_PARITY; + return; + } + + if (serial->stopbits == 1) + serial->tio->c_cflag &= ~CSTOPB; + else if (serial->stopbits ==2) + serial->tio->c_cflag |= CSTOPB; + else { + serial->err_code = ERR_STOPB; + return; + } + +/* Raw input */ + serial-> tio->c_lflag = 0; + + serial->tio->c_cc[VTIME] = serial->timeout; + if (serial->waitread) + serial->tio->c_cc[VMIN] = serial->minchars; + + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); +} + + +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + result = write(serial->ttyfd, buf, nbytes); + if (result < nbytes) { + serial->err_code = ERR_WRITE; + return(result); + } + serial->err_code = ERR_OK; + return(result); +} + + +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + serial->err_code = ERR_OK; + +/* Set the minimum number of chars to read before returning */ + if (serial->waitread && (serial->minchars != nbytes)) { + if (set_minchars(serial, nbytes) != ERR_OK) { + serial->err_code = ERR_SERIAL; + return(0); + } + } +/* save serial stuff for alarm() timeout. */ + sertmp = serial; + alarm(serial->timeout); + result = read(serial->ttyfd, buf, nbytes); + alarm(0); + serial->bytesread = result; + if (result < nbytes) + serial->err_code = ERR_READ; + return(result); +} + + +static int set_minchars(ser_info *serial, int nbytes) +{ + if (!is_valid_serial(serial)) + return(ERR_MEM); + if (!serial->waitread) + return(ERR_READ); + serial->minchars = nbytes; + serial->tio->c_cc[VMIN] = nbytes; + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + return(ERR_OK); +} + +static void rdtimeout(int signumber) +{ + fprintf(stderr, "Serial communication failed, exiting...\n"); + if (sertmp != NULL) close_serial(sertmp); + exit(-1); +} + diff --git a/src/drivers/camfits.fake/ser.h b/src/drivers/camfits.fake/ser.h new file mode 100644 index 00000000..1a8145c5 --- /dev/null +++ b/src/drivers/camfits.fake/ser.h @@ -0,0 +1,34 @@ +#include + +#define RD_TIMEOUT (2) +#define TRUE (1) +#define FALSE (0) + +#define MAX_BUF_LEN (255) +#define PAR_NONE 'n' +#define PAR_EVEN 'e' +#define PAR_ODD 'o' + +typedef struct { + int isopen; + int waitread; + int err_code; + char *tty_name; + int ttyfd; + cc_t minchars; /* not used if waitread == FALSE */ + int bytesread; + int baudrate; + char parity; + int stopbits; + cc_t timeout; /* interchar time (1/10 secs), and read timeout (secs) */ + struct termios *tio; /* |- don't mess with these structs, */ + struct termios *oldtio; /* | the routines will handle it. */ +} ser_info; + +int is_valid_serial(ser_info *serial); +void open_serial(ser_info *serial, char *ttyname); +int close_serial(ser_info *serial); +int set_serial(ser_info *serial); +//static int set_minchars(ser_info *serial, int nbytes); +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); diff --git a/src/drivers/camfits.st4/Makefile.am b/src/drivers/camfits.st4/Makefile.am new file mode 100644 index 00000000..f66d9a2e --- /dev/null +++ b/src/drivers/camfits.st4/Makefile.am @@ -0,0 +1,10 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = camfits.st4 + +camfits_st4_SOURCES = camera.c ccd.c ser.c \ + camera.h ccd.h ser.h + +camfits_st4_LDADD = -lcfitsio -lm + +uts_driver_DATA = st4.camera.xml diff --git a/src/drivers/camfits.st4/camera.c b/src/drivers/camfits.st4/camera.c new file mode 100644 index 00000000..fe208ac9 --- /dev/null +++ b/src/drivers/camfits.st4/camera.c @@ -0,0 +1,243 @@ +#include +#include +#include +#include +#include + +#include "errors.h" +#include "ccd.h" +#include "fitsio.h" + +#define TRUE (1) +#define FALSE (0) + +void usage(char *command); +void setup(void); +void check_alloc_error(void); +void expose_error(int err); +void save_fits(void); +void print_image(unsigned char *image); +void controlc(int signumber); + +cam_info *camera; +int output = FALSE; +char *porta; +char *imagefile; +float texp; +fitsfile *fptr; +int fitstatus; +unsigned char image[CAM_MAX_NLINES][CAM_MAX_NCOLS]; +long naxes[2] = {CAM_MAX_NCOLS, CAM_MAX_NLINES}; + +int main(int argc, char ** argv) +{ + int res; + + signal(SIGINT, controlc); + signal(SIGABRT, controlc); + + fprintf(stderr, "CCD dump, FITS file format support.\n"); + if (argc < 4) { + usage(argv[0]); + exit(1); + } + +/* strcpy(porta, argv[1]); + strcpy(imagefile, argv[3]); */ + porta = argv[1]; + imagefile = argv[3]; + if (*imagefile == '-') { + if (*(++imagefile) == '\0') { + output = TRUE; + imagefile = NULL; + } else { + usage(argv[0]); + exit(1); + } + } + +/* get exposure time */ + res = sscanf(argv[2], "%f", &texp); + if (res != 1) { + fprintf(stderr, "\nError: \"%s\" is an invalid exposure time.\n\n", argv[2]); + usage(argv[0]); + exit(1); + } + +/* test if file already exists */ + if (!output && (res = open(imagefile, O_RDONLY)) != -1) { + close(res); + fprintf(stderr, "Error: File \"%s\" already exists.\n\n", argv[3]); + usage(argv[0]); + exit(1); + } + + setup(); + + fprintf(stderr, "Exposing CCD...\n"); + if ((res = expose_ccd(camera, texp)) != ERR_OK) { + expose_error(res); + abort(); + } + fprintf(stderr, "Exposure OK.\n\n"); + + fprintf(stderr, "Downloading image...\n"); + if ((res = download_image(camera, camera->ccd->image)) != ERR_OK) { + fprintf(stderr, "Error in download_image()\n"); + abort(); + } + fprintf(stderr, "Download done.\n\n"); + + if (output) { + fprintf(stderr, "Printing image...\n"); + print_image(camera->ccd->image); + fprintf(stderr, "\nDone.\n"); + } else { + fprintf(stderr, "Saving image...\n"); + save_fits(); + fprintf(stderr, "Image taken successfully.\n\n"); + } + + free_camera(camera); + return(0); +} + + +void usage(char *command) +{ + fprintf(stderr, "Specify terminal, exposure time (in seconds) and file name.\n"); + fprintf(stderr, "Use \"-\" instead of file name to output the image to stdout.\n\n"); + fprintf(stderr, "SYNTAX: %s terminal_device exposure_time { output_file | - }\n\n", command); + fprintf(stderr, "E.g.: %s /dev/ttyS1 10.2 output.fit\n", command); + fprintf(stderr, "E.g.: %s /dev/ttyS1 10.2 -\n\n\n", command); +} + + +/* sets up camera structs and initializes its parameters */ +void setup(void) +{ + int tmp; + + camera = alloc_camera(porta); + check_alloc_error(); + + camera->ccd->image = &(image[0][0]); + + camera->ccd->baudrate = CAM_B57600; + camera->ccd->rom_version = ROM_VERSION; + if ((tmp = init_camera(camera)) != ERR_OK) { + fprintf(stderr, "Error in init_camera(): %d\n", tmp); + abort(); + } + camera->ccd->first_line = CAM_FIRST_LINE; + camera->ccd->first_column = 0; + camera->ccd->nlines = CAM_MAX_NLINES; + camera->ccd->ncolumns = CAM_MAX_NCOLS; + camera->ccd->offset = 0; + camera->ccd->vref_plus = 255; + camera->ccd->vref_minus = 0; + camera->ccd->format_flag = 0; + camera->ccd->mode_flag = (CAM_MODE_FEXP | CAM_MODE_LA); + if ((tmp = set_camera(camera)) != ERR_OK) { + fprintf(stderr, "Error in set_camera()\n"); + abort(); + } +} + + +void print_image(unsigned char *image) +{ + int i, j, lastline, lastcol; + + lastline = camera->ccd->nlines; + lastcol = camera->ccd->ncolumns; + for (i = 0; i < lastline; i++) { + for (j = 0; j < lastcol; j++) + printf("%d\n", *(image++)); + } +} + + +void save_fits(void) +{ + int x, y, i, j, lastline, lastcol; + unsigned char ** imgptr; + +/* Gradient fill + for (i = 0; i < 165; i++) + for (j = 0; j < 192; j++) + image[i][j] = (i+j)/2; +*/ + + naxes[0] = camera->ccd->ncolumns; + naxes[1] = camera->ccd->nlines; + +/* + imgptr = camera->ccd->image; + lastline = camera->ccd->nlines + camera->ccd->first_line; + lastcol = camera->ccd->first_column + camera->ccd->ncolumns; + + for (i = camera->ccd->first_line, x = 0; i < lastline; i++, x++, imgptr++) { + for (j = camera->ccd->first_column, y = 0; j < lastcol; j++, y++) + rawimage[x][y] = (*imgptr)[y]; + } +*/ + +/* open file for writing a FITS image */ + + if (fits_create_file(&fptr, imagefile, &fitstatus) || + fits_create_img(fptr, BYTE_IMG, 2, naxes, &fitstatus) || + fits_write_img(fptr, TBYTE, 1, (naxes[0] * naxes[1]), image, &fitstatus) || + fits_update_key(fptr, TFLOAT, "EXPTIME", &texp, "Exposure Time (secs.)", &fitstatus) || + fits_close_file(fptr, &fitstatus)) { + fits_report_error(stderr, fitstatus); + abort(); + } +} + + +void check_alloc_error(void) +{ + if (!is_valid_camera(camera)) { + fprintf(stderr, "Error allocating camera structures.\n"); + abort(); + } + if (camera->serial->err_code == ERR_OK) return; + + fprintf(stderr, "Error setting up camera, "); + if (camera->serial->err_code == ERR_READ) + fprintf(stderr, "could not read serial port.\n"); + else if (camera->serial->err_code == ERR_WRITE) + fprintf(stderr, "could not write serial port.\n"); + else if (camera->serial->err_code == ERR_OPENTTY) + fprintf(stderr, "could not open serial port.\n"); + else if (camera->serial->err_code == ERR_MEM) + fprintf(stderr, "serial structures could not be created.\n"); + else fprintf(stderr, "unexpected error.\n"); + abort(); +} + + +void expose_error(int err) +{ + fprintf(stderr, "Problem exposing CCD, "); + if (err == ERR_CAM) fprintf(stderr, "camera not allocated.\n"); + else if (err == ERR_WRITE) fprintf(stderr, "error writing camera.\n"); + else if (err == ERR_READ) fprintf(stderr, "error reading camera.\n"); + else fprintf(stderr, "unexpected error.\n"); + abort(); +} + + +void controlc(int signumber) +{ + if (signumber == SIGINT) + fprintf(stderr, "Control-C signal caught, exiting.\n"); + else + fprintf(stderr, "Aborting...\n"); + if (is_valid_camera(camera)) + tcflush(camera->serial->ttyfd, TCOFLUSH); + free_camera(camera); + exit(2); +} + diff --git a/src/drivers/camfits.st4/ccd.c b/src/drivers/camfits.st4/ccd.c new file mode 100644 index 00000000..47e8082c --- /dev/null +++ b/src/drivers/camfits.st4/ccd.c @@ -0,0 +1,470 @@ +#include +#include "errors.h" +#include "ccd.h" + + +#undef CCDTEST +#ifdef CCDTEST + +char deftty[] = "/dev/ttyS1"; + +cam_info *camera; + +int main() +{ + int i; + + puts("ST-4 test program."); + printf("tty = %s\n\n", deftty); + + camera = alloc_camera(deftty); + if (camera == NULL) { + puts("alloc_camera()"); + exit(1); + } + + camera->ccd->baudrate = CAM_B57600; + camera->ccd->rom_version = ROM_VERSION; + if (init_camera(camera) != ERR_OK) { + puts("init_camera()"); + exit(0); + } + + camera->ccd->exptime = 5; + camera->ccd->first_line = CAM_FIRST_LINE; + camera->ccd->first_column = 0; + camera->ccd->nlines = CAM_MAX_NLINES; + camera->ccd->ncolumns = CAM_MAX_NCOLS; + camera->ccd->offset = 0; + camera->ccd->vref_plus = 255; + camera->ccd->vref_minus = 0; + camera->ccd->format_flag = 0; + camera->ccd->mode_flag = (CAM_MODE_FEXP | CAM_MODE_LA); + set_camera(camera); + take_image(camera, camera->ccd->image); + + free_camera(camera); +} +#endif + + +/* initializes camera's comm parameters */ +int init_camera(cam_info *camera) +{ + int res; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + + camera->serial->waitread = TRUE; + camera->serial->baudrate = B9600; + camera->serial->parity = PAR_EVEN; + camera->serial->stopbits = 1; + camera->serial->minchars = 0; + camera->serial->timeout = 5; + set_serial(camera->serial); + if (camera->serial->err_code != ERR_OK) + return(ERR_SERIAL); + + res = set_baudrate(camera, camera->ccd->baudrate); + return(res); + +} + + +int is_valid_camera(cam_info *camera) +{ + if (camera == NULL) + return(FALSE); + if (camera->ccd == NULL) + return(FALSE); + if (camera->serial == NULL) + return(FALSE); + return(TRUE); +} + + +/* allocates memory for camera's structures */ +cam_info *alloc_camera(char *ttyname) +{ + cam_info *camera; + int i; + + camera = (cam_info *) calloc(sizeof(cam_info), 1); + if (camera == NULL) + return(NULL); + camera->serial = (ser_info *) calloc(sizeof(ser_info), 1); + if (camera->serial == NULL) + return(NULL); + camera->ccd = (ccd_info *) calloc(sizeof(ccd_info), 1); + if (camera->ccd == NULL) + return(NULL); + open_serial(camera->serial, ttyname); + return(camera); +} + + +/* frees the memory allocated for camera's structures */ +void free_camera(cam_info *camera) +{ + if (camera == NULL) + return; + if (camera->serial != NULL) { + if (camera->serial->ttyfd > 0) { + set_baudrate(camera, CAM_B9600); + close_serial(camera->serial); + } + free(camera->serial); + } + if (camera->ccd != NULL) + free(camera->ccd); + free(camera); +} + + +/* sets up all the camera's parameters */ +int set_camera(cam_info *camera) +{ + long int exptmp; + int res; + cmd_t cmd; + + if (!is_valid_camera(camera)) + return(ERR_CAM); +/* Set modes and format */ + cmd.nbytes = 2; + cmd.address = CAM_MODE; + cmd.ram = CAM_INT_RAM; + camera->ccd->mode_flag &= ~CAM_MODE_STEXP; + cmd.data[0] = camera->ccd->mode_flag; + cmd.data[1] = camera->ccd->format_flag; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +/* Set exposure time */ +/* cmd.nbytes = 2; + cmd.address = CAM_EXPTIME; + exptmp = camera->ccd->exptime * 100; + cmd.data[0] = exptmp & 0x00FF; + cmd.data[1] = (exptmp >> 8) & 0x00FF; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); */ + +/* Set first pixel and number of pixels per line */ + cmd.nbytes = 2; + cmd.address = CAM_XPOINTER; + cmd.data[0] = camera->ccd->first_column; + cmd.data[1] = camera->ccd->ncolumns; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +/* Set additional offset and Vref+ */ + cmd.nbytes = 2; + cmd.address = CAM_OFFSET; + cmd.data[0] = camera->ccd->offset; + cmd.data[1] = camera->ccd->vref_plus; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +/* Set Vref- */ + cmd.nbytes = 1; + cmd.address = CAM_VREFMINUS; + cmd.data[0] = camera->ccd->vref_minus; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(ERR_WRITE); + +return(ERR_OK); +} + + +/* writes data in camera's ROM */ +int write_mem(cam_info *camera, cmd_t *cmd) +{ + unsigned char buf[CAM_MAX_CMD], *pbuf, chksum, tmp; + int i, res; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (cmd == NULL) + return(ERR_CMD); + + pbuf = buf; + *pbuf++ = CAM_WRITE_MEM; + chksum = CAM_WRITE_MEM; + tmp = cmd->nbytes + 3; + *pbuf++ = tmp; + chksum += tmp; + *pbuf++ = cmd->ram; + chksum += cmd->ram; + tmp = cmd->address & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + tmp = (cmd->address >> 8) & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + + for (i = 0; i < (cmd->nbytes); i++) { + *pbuf++ = cmd->data[i]; + chksum += cmd->data[i]; + } + *pbuf = chksum; + if (write_serial(camera->serial, buf, (6 + cmd->nbytes)) == ERR_WRITE) + return(ERR_WRITE); + res = wait_response(camera); + if (res == CAM_NAK) + return(ERR_READ); + return(ERR_OK); +} + + +unsigned char wait_response(cam_info *camera) +{ + unsigned char c; + int res; + + if (!is_valid_camera(camera)) + return; + + if (read_serial(camera->serial, &c, 1) == ERR_READ) + return(CAM_NAK); + if (c != CAM_ACK) + return(CAM_NAK); + return(CAM_ACK); +} + + +int read_mem(cam_info *camera, cmd_t *cmd) +{ + unsigned char buf[CAM_MAX_CMD], *pbuf, tmp, chksum; + int res, i; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (cmd == NULL) + return(ERR_CMD); +/* Set command in buffer */ + pbuf = buf; + *pbuf++ = CAM_READ_MEM; + chksum = CAM_READ_MEM; + *pbuf++ = cmd->nbytes; + chksum += cmd->nbytes; + *pbuf++ = cmd->ram; + chksum += cmd->ram; + tmp = cmd->address & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + tmp = (cmd->address >> 8) & 0x00FF; + *pbuf++ = tmp; + chksum += tmp; + *pbuf = chksum; + res = write_serial(camera->serial, buf, 6); + if (res < 6) + return(ERR_WRITE); +/* Read header */ + res = read_serial(camera->serial, buf, 2); + if ((res < 2) || (buf[0] != 2) || (buf[1] != cmd->nbytes)) + return(ERR_READ); +/* Read data */ + res = read_serial(camera->serial, buf, cmd->nbytes); + if (res < cmd->nbytes) + return(ERR_READ); + pbuf = buf; + for (i = 0; i < cmd->nbytes;) + cmd->data[i++] = *pbuf++; +/* Checksum */ + res = read_serial(camera->serial, buf, 1); + if (res < 1) + return(ERR_READ); +/* Evaluate checksum in the futute */ + return(ERR_OK); +} + + +int set_baudrate(cam_info *camera, unsigned char baudrate) +{ + cmd_t cmd; + int tmp; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + +/* Write ROM version */ + cmd.nbytes = 1; + cmd.ram = CAM_INT_RAM; + cmd.address = CAM_ROMVER; + cmd.data[0] = camera->ccd->rom_version; + if (write_mem(camera, &cmd) != ERR_OK) + return(ERR_WRITE); + +/* Set baud rate */ + cmd.nbytes = 1; + cmd.address = CAM_BAUDRATE; + cmd.data[0] = baudrate; + if (write_mem(camera, &cmd) != ERR_OK) + return(ERR_WRITE); + + camera->ccd->baudrate = baudrate; + switch (baudrate) { + case CAM_B57600: + camera->serial->baudrate = B57600; + break; + case CAM_B19200: + camera->serial->baudrate = B19200; + break; + case CAM_B9600: + camera->serial->baudrate = B9600; + break; + case CAM_B4800: + camera->serial->baudrate = B4800; + break; + case CAM_B2400: + camera->serial->baudrate = B2400; + break; + case CAM_B1200: + camera->serial->baudrate = B1200; + break; + case CAM_B600: + camera->serial->baudrate = B600; + break; + case CAM_B300: + camera->serial->baudrate = B300; + break; + default: + return(ERR_BAUDRATE); + } + set_serial(camera->serial); + if (camera->serial->err_code != ERR_OK) + return(ERR_SERIAL); + + /* Read ROM version for testing */ + cmd.nbytes = 1; + cmd.address = CAM_ROMVER; + tmp = read_mem(camera, &cmd); + if (tmp != ERR_OK) + return(ERR_READ); + if (cmd.data[0] != camera->ccd->rom_version) + return(ERR_SERIAL); + + return(ERR_OK); +} + + +int expose_ccd(cam_info *camera, float time) +{ +cmd_t cmd; +int tmp, res; + +if (!is_valid_camera(camera)) + return(ERR_CAM); + +/* Set exposure time */ + cmd.nbytes = 2; + cmd.address = CAM_EXPTIME; + cmd.ram = CAM_INT_RAM; + camera->ccd->exptime = time; + tmp = time * 100; + cmd.data[0] = tmp & 0x00FF; + cmd.data[1] = (tmp >> 8) & 0x00FF; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(res); + +/* Start exposure */ + cmd.nbytes = 1; + cmd.address = CAM_MODE; + camera->ccd->mode_flag &= ~CAM_MODE_STEXP; + cmd.data[0] = camera->ccd->mode_flag | CAM_MODE_STEXP; + res = write_mem(camera, &cmd); + if (res != ERR_OK) + return(res); + +/* Wait until exposure is done */ + cmd.nbytes = 1; + cmd.address = CAM_MODE; + sleep((int)time); + do { + if ((res = read_mem(camera, &cmd)) != ERR_OK) + return(res); + sleep(1); + } while((cmd.data[0] & CAM_MODE_EXPDONE) == CAM_MODE_EXPDONE); + +return(ERR_OK); +} + + +int read_line(cam_info *camera, int line, unsigned char *buf) +{ + unsigned char chksum; + int res; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if ((line < CAM_FIRST_LINE ) || (line > CAM_LAST_LINE)) + return; + buf[0] = line; + buf[1] = line; + res = write_serial(camera->serial, buf, 2); + if (res < 2) + return(ERR_WRITE); + res = read_serial(camera->serial, buf, 2); + if (res < 2) + return(ERR_READ); + if ((buf[0] != line) || (buf[1] != camera->ccd->ncolumns)) + return(ERR_READ); + + res = read_serial(camera->serial, buf, camera->ccd->ncolumns); + if (res < camera->ccd->ncolumns) + return(ERR_READ); + + res = read_serial(camera->serial, &chksum, 1); + if (res < 1) + return(ERR_READ); +/* Evaluate checksum in future */ + + return(ERR_OK); +} + + +int take_image(cam_info *camera, unsigned char *image) +{ + int res; + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (camera->ccd->image == NULL) + return(ERR_MEM); + + if ((res = expose_ccd(camera, camera->ccd->exptime)) != ERR_OK) + return(res); + + if ((res = download_image(camera, image)) != ERR_OK) + return(res); + + return(ERR_OK); + +} + + +int download_image(cam_info *camera, unsigned char *image) +{ + int i, l; + + if (!is_valid_camera(camera)) + return(ERR_CAM); + if (image == NULL) + return(ERR_MEM); + + l = camera->ccd->first_line; + for (i = 0; i < camera->ccd->nlines; i++, l++) { + if (read_line(camera, l , image) != ERR_OK) + return(ERR_READ); +/* Pad to next line */ + image += CAM_MAX_NCOLS; + } + + return(ERR_OK); +} diff --git a/src/drivers/camfits.st4/ccd.h b/src/drivers/camfits.st4/ccd.h new file mode 100644 index 00000000..57741571 --- /dev/null +++ b/src/drivers/camfits.st4/ccd.h @@ -0,0 +1,120 @@ +#include "ser.h" + +#define ROM_VERSION (3) + +#define CAM_MAX_NLINES (165) +#define CAM_MAX_NCOLS (192) + +#define CAM_FIRST_LINE (64) +#define CAM_LAST_LINE (228) + +/* Commands */ +#define CAM_WRITE_MEM (1) +#define CAM_READ_MEM (2) +#define CAM_EXT_RAM (0) +#define CAM_INT_RAM (1) + +/* Responses */ +#define CAM_ACK (0x06) +#define CAM_NAK (0x15) + +/* Mode flags (46) */ +#define CAM_MODE_FEXP (0x80) /* Full exposure */ +#define CAM_MODE_LA (0x40) /* Light array */ +#define CAM_MODE_STEXP (0x20) /* Start exposure */ +#define CAM_MODE_EXPDONE (0x10) /* Exposure done */ +#define CAM_MODE_CMPRSIMG (0x08) /* Compress image in memory */ +#define CAM_MODE_SUBDARKF (0x04) /* Subtract dark frame */ +#define CAM_MODE_CMPRSDAT (0x02) /* Enable data compression */ +#define CAM_MODE_SMTH (0x01) /* Smooth image in memory */ + +/* Format flags (47) */ +#define CAM_FMT_FFOCUS (0x80) /* Find and focus mode */ +#define CAM_FMT_ANTIBLOOM (0x40) /* Anti-blooming gate enable */ +#define CAM_FMT_INTERRUPT (0x20) /* Interrupt from Find and focus, Track */ + /* and Calibrate modes. */ +#define CAM_FMT_TRACK (0x10) /* Track mode */ +#define CAM_FMT_CALIBRATE (0x08) /* Calibrate mode */ +#define CAM_FMT_CLOSE_R0 (0x04) /* Close `left' relay */ +#define CAM_FMT_CLOSE_R1 (0x05) /* Close `right' relay */ +#define CAM_FMT_CLOSE_R2 (0x06) /* Close `up' relay */ +#define CAM_FMT_CLOSE_R3 (0x07) /* Close `down' relay */ + +/* Baud rates */ +#define CAM_B57600 (255) +#define CAM_B19200 (253) +#define CAM_B9600 (250) +#define CAM_B4800 (244) +#define CAM_B2400 (232) +#define CAM_B1200 (208) +#define CAM_B600 (160) +#define CAM_B300 (64) + +/* Addresses */ +#define CAM_LAST_KEY (45) +#define CAM_MODE (46) +#define CAM_FORMAT (47) +#define CAM_EXPTIME (48) +#define CAM_XPOINTER (50) +#define CAM_NBYTES (51) +#define CAM_OFFSET (52) +#define CAM_VREFPLUS (53) +#define CAM_VREFMINUS (54) +#define CAM_ROMVER (55) +#define CAM_BAUDRATE (56) +#define CAM_INSTRUCT (58) + + +#define CAM_MAX_DATA (4) +#define CAM_MAX_CMD (CAM_MAX_DATA + 6) + + +typedef struct { + float exptime; /* seconds */ + unsigned char mode_flag; + unsigned char format_flag; + unsigned char first_line; + unsigned char first_column; + unsigned char nlines; + unsigned char ncolumns; + unsigned char offset; + unsigned char vref_plus; + unsigned char vref_minus; + unsigned char rom_version; + unsigned char baudrate; /* note: this is the constant specified */ + /* above, e.g. CAM_BXXXXX. */ + unsigned char *image; +} ccd_info; + +typedef struct { + ccd_info *ccd; + ser_info *serial; +} cam_info; + +typedef struct { + int nbytes; + int ram; + int address; + unsigned char data[CAM_MAX_DATA]; +} cmd_t; + + +/* Camera structure management */ +int is_valid_camera(cam_info *camera); +cam_info *alloc_camera(char *ttyname); +void free_camera(cam_info *camera); + +/* Low level functions */ +int set_baudrate(cam_info *camera, unsigned char baudrate); + /* values of baud rates are defined in camera.h */ +int init_camera(cam_info *camera); +int write_mem(cam_info *camera, cmd_t *command); +int read_mem(cam_info *camera, cmd_t *command); +unsigned char wait_response(cam_info *camera); + +/* user functions */ +int expose_ccd(cam_info *camera, float time); /* seconds */ +int read_line(cam_info *camera, int line, unsigned char *buf); +int download_image(cam_info *camera, unsigned char *image); +int set_camera(cam_info *camera); +int take_image(cam_info *camera, unsigned char *image); diff --git a/src/drivers/camfits.st4/errors.h b/src/drivers/camfits.st4/errors.h new file mode 100644 index 00000000..41941c97 --- /dev/null +++ b/src/drivers/camfits.st4/errors.h @@ -0,0 +1,19 @@ +#define TRUE (1) +#define FALSE (0) + + + +#define ERR_OK (0) +#define ERR_OPENTTY (-1) +#define ERR_SERIAL (-2) +#define ERR_BAUDRATE (-3) +#define ERR_PARITY (-4) +#define ERR_STOPB (-5) +#define ERR_WRITE (-6) +#define ERR_READ (-7) +#define ERR_MEM (-8) +#define ERR_NOTRESPOND (-9) + +#define ERR_CAM (-50) +#define ERR_CMD (-51) +#define ERR_EXPOSE (-52) diff --git a/src/drivers/camfits.st4/fitsio.h b/src/drivers/camfits.st4/fitsio.h new file mode 100644 index 00000000..93301278 --- /dev/null +++ b/src/drivers/camfits.st4/fitsio.h @@ -0,0 +1,1355 @@ +#ifndef _FITSIO_H +#define _FITSIO_H + +#include +/* stddef.h is apparently needed to define size_t */ +#include + +/* The following exclusion if __CINT__ is defined is needed for ROOT */ +#ifndef __CINT__ +#include "longnam.h" +#endif + +/* global variables */ + +#define FLEN_FILENAME 1025 /* max length of a filename */ +#define FLEN_KEYWORD 72 /* max length of a keyword (HIERARCH convention) */ +#define FLEN_CARD 81 /* length of a FITS header card */ +#define FLEN_VALUE 71 /* max length of a keyword value string */ +#define FLEN_COMMENT 73 /* max length of a keyword comment string */ +#define FLEN_ERRMSG 81 /* max length of a FITSIO error message */ +#define FLEN_STATUS 31 /* max length of a FITSIO status text string */ + +#define TBIT 1 /* codes for FITS table data types */ +#define TBYTE 11 +#define TLOGICAL 14 +#define TSTRING 16 +#define TUSHORT 20 +#define TSHORT 21 +#define TUINT 30 +#define TINT 31 +#define TULONG 40 +#define TLONG 41 +#define TFLOAT 42 +#define TDOUBLE 82 +#define TCOMPLEX 83 +#define TDBLCOMPLEX 163 + +#define TYP_STRUC_KEY 10 +#define TYP_CMPRS_KEY 20 +#define TYP_SCAL_KEY 30 +#define TYP_NULL_KEY 40 +#define TYP_DIM_KEY 50 +#define TYP_RANG_KEY 60 +#define TYP_UNIT_KEY 70 +#define TYP_DISP_KEY 80 +#define TYP_HDUID_KEY 90 +#define TYP_CKSUM_KEY 100 +#define TYP_WCS_KEY 110 +#define TYP_REFSYS_KEY 120 +#define TYP_COMM_KEY 130 +#define TYP_CONT_KEY 140 +#define TYP_USER_KEY 150 + +#define INT32BIT int /* 32-bit integer datatype. Currently this */ + /* datatype is an 'int' on all useful platforms */ + /* however, it is possible that that are cases */ + /* where 'int' is a 2-byte integer, in which case */ + /* FITSINT would need to be defined as 'long'. */ + +#define BYTE_IMG 8 /* BITPIX code values for FITS image types */ +#define SHORT_IMG 16 +#define LONG_IMG 32 +#define FLOAT_IMG -32 +#define DOUBLE_IMG -64 + /* The following 2 codes are not true FITS */ + /* datatypes; these codes are only used internally */ + /* within cfitsio to make it easier for users */ + /* to deal with unsigned integers. */ +#define USHORT_IMG 20 +#define ULONG_IMG 40 + +#define IMAGE_HDU 0 /* Primary Array or IMAGE HDU */ +#define ASCII_TBL 1 /* ASCII table HDU */ +#define BINARY_TBL 2 /* Binary table HDU */ +#define ANY_HDU -1 /* matches any HDU type */ + +#define READONLY 0 /* options when opening a file */ +#define READWRITE 1 + +/* adopt a hopefully obscure number to use as a null value flag */ +/* could be problems if the FITS files contain data with these values */ +#define FLOATNULLVALUE -9.11912E-36F +#define DOUBLENULLVALUE -9.1191291391491E-36 + +/* Image compression algorithm types */ +#define MAX_COMPRESS_DIM 6 +#define RICE_1 11 +#define GZIP_1 21 +#define PLIO_1 31 +#define HCOMPRESS_1 41 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define CASESEN 1 /* do case-sensitive string match */ +#define CASEINSEN 0 /* do case-insensitive string match */ + +#define MAXHDU 1000 /* maximum number of extensions allowed in a FITS file */ + +#define GT_ID_ALL_URI 0 /* hierarchical grouping parameters */ +#define GT_ID_REF 1 +#define GT_ID_POS 2 +#define GT_ID_ALL 3 +#define GT_ID_REF_URI 11 +#define GT_ID_POS_URI 12 + +#define OPT_RM_GPT 0 +#define OPT_RM_ENTRY 1 +#define OPT_RM_MBR 2 +#define OPT_RM_ALL 3 + +#define OPT_GCP_GPT 0 +#define OPT_GCP_MBR 1 +#define OPT_GCP_ALL 2 + +#define OPT_MCP_ADD 0 +#define OPT_MCP_NADD 1 +#define OPT_MCP_REPL 2 +#define OPT_MCP_MOV 3 + +#define OPT_MRG_COPY 0 +#define OPT_MRG_MOV 1 + +#define OPT_CMT_MBR 1 +#define OPT_CMT_MBR_DEL 11 + +typedef struct /* structure used to store table column information */ +{ + char ttype[70]; /* column name = FITS TTYPEn keyword; */ + long tbcol; /* offset in row to first byte of each column */ + int tdatatype; /* datatype code of each column */ + long trepeat; /* repeat count of column; number of elements */ + double tscale; /* FITS TSCALn linear scaling factor */ + double tzero; /* FITS TZEROn linear scaling zero point */ + long tnull; /* FITS null value for int image or binary table cols */ + char strnull[20]; /* FITS null value string for ASCII table columns */ + char tform[10]; /* FITS tform keyword value */ + long twidth; /* width of each ASCII table column */ +}tcolumn; + +#define VALIDSTRUC 555 /* magic value used to identify if structure is valid */ + +typedef struct /* structure used to store basic FITS file information */ +{ + int filehandle; /* handle returned by the file open function */ + int driver; /* defines which set of I/O drivers should be used */ + int open_count; /* number of opened 'fitsfiles' using this structure */ + char *filename; /* file name */ + int validcode; /* magic value used to verify that structure is valid */ + long filesize; /* current size of the physical disk file in bytes */ + long logfilesize; /* logical size of file, including unflushed buffers */ + int lasthdu; /* is this the last HDU in the file? 0 = no, else yes */ + long bytepos; /* current logical I/O pointer position in file */ + long io_pos; /* current I/O pointer position in the physical file */ + int curbuf; /* number of I/O buffer currently in use */ + int curhdu; /* current HDU number; 0 = primary array */ + int hdutype; /* 0 = primary array, 1 = ASCII table, 2 = binary table */ + int writemode; /* 0 = readonly, 1 = readwrite */ + int maxhdu; /* highest numbered HDU known to exist in the file */ + long headstart[MAXHDU + 1]; /* byte offset in file to start of each HDU */ + long headend; /* byte offest in file to end of the current HDU header */ + long nextkey; /* byte offset in file to beginning of next keyword */ + long datastart; /* byte offset in file to start of the current data unit */ + int tfield; /* number of fields in the table (primary array has 2 */ + long origrows; /* original number of rows (value of NAXIS2 keyword) */ + long numrows; /* number of rows in the table (dynamically updated) */ + long rowlength; /* total length of a table row, in bytes */ + tcolumn *tableptr; /* pointer to the table structure */ + long heapstart; /* heap start byte relative to start of data unit */ + long heapsize; /* size of the heap, in bytes */ + + /* the following elements are related to compress images */ + int compressimg; /* 1 if HDU contains a compressed image, else 0 */ + char zcmptype[12]; /* compression type string */ + int compress_type; /* type of compression algorithm */ + int zbitpix; /* FITS data type of image (BITPIX) */ + int zndim; /* dimension of image */ + long znaxis[MAX_COMPRESS_DIM]; /* length of each axis */ + long tilesize[MAX_COMPRESS_DIM]; /* size of compression tiles */ + long maxtilelen; /* max number of pixels in each image tile */ + long maxelem; /* maximum length of variable length arrays */ + + int cn_compressed; /* column number for COMPRESSED_DATA column */ + int cn_uncompressed; /* column number for UNCOMPRESSED_DATA column */ + int cn_zscale; /* column number for ZSCALE column */ + int cn_zzero; /* column number for ZZERO column */ + int cn_zblank; /* column number for the ZBLANK column */ + + double zscale; /* scaling value, if same for all tiles */ + double zzero; /* zero pt, if same for all tiles */ + int zblank; /* value for null pixels, if not a column */ + + int rice_blocksize; /* first compression parameter */ + int rice_nbits; /* second compression parameter */ +} FITSfile; + +typedef struct /* structure used to store basic HDU information */ +{ + int HDUposition; /* HDU position in file; 0 = first HDU */ + FITSfile *Fptr; /* pointer to FITS file structure */ +}fitsfile; + +typedef struct /* structure for the iterator function column information */ +{ + /* elements required as input to fits_iterate_data: */ + + fitsfile *fptr; /* pointer to the HDU containing the column */ + int colnum; /* column number in the table (use name if < 1) */ + char colname[70]; /* name (= TTYPEn value) of the column (optional) */ + int datatype; /* output datatype (converted if necessary */ + int iotype; /* = InputCol, InputOutputCol, or OutputCol */ + + /* output elements that may be useful for the work function: */ + + void *array; /* pointer to the array (and the null value) */ + long repeat; /* binary table vector repeat value */ + long tlmin; /* legal minimum data value */ + long tlmax; /* legal maximum data value */ + char tunit[70]; /* physical unit string */ + char tdisp[70]; /* suggested display format */ + +} iteratorCol; + +#define InputCol 0 /* flag for input only iterator column */ +#define InputOutputCol 1 /* flag for input and output iterator column */ +#define OutputCol 2 /* flag for output only iterator column */ + +/* error status codes */ + +#define USE_MEM_BUFF -101 /* use memory buffer when opening file */ +#define OVERFLOW_ERR -11 /* overflow during datatype conversion */ +#define SAME_FILE 101 /* input and output files are the same */ +#define TOO_MANY_FILES 103 /* tried to open too many FITS files */ +#define FILE_NOT_OPENED 104 /* could not open the named file */ +#define FILE_NOT_CREATED 105 /* could not create the named file */ +#define WRITE_ERROR 106 /* error writing to FITS file */ +#define END_OF_FILE 107 /* tried to move past end of file */ +#define READ_ERROR 108 /* error reading from FITS file */ +#define FILE_NOT_CLOSED 110 /* could not close the file */ +#define ARRAY_TOO_BIG 111 /* array dimensions exceed internal limit */ +#define READONLY_FILE 112 /* Cannot write to readonly file */ +#define MEMORY_ALLOCATION 113 /* Could not allocate memory */ +#define BAD_FILEPTR 114 /* invalid fitsfile pointer */ +#define NULL_INPUT_PTR 115 /* NULL input pointer to routine */ +#define SEEK_ERROR 116 /* error seeking position in file */ + +#define BAD_URL_PREFIX 121 /* invalid URL prefix on file name */ +#define TOO_MANY_DRIVERS 122 /* tried to register too many IO drivers */ +#define DRIVER_INIT_FAILED 123 /* driver initialization failed */ +#define NO_MATCHING_DRIVER 124 /* matching driver is not registered */ +#define URL_PARSE_ERROR 125 /* failed to parse input file URL */ + +#define SHARED_ERRBASE (150) +#define SHARED_BADARG (SHARED_ERRBASE + 1) +#define SHARED_NULPTR (SHARED_ERRBASE + 2) +#define SHARED_TABFULL (SHARED_ERRBASE + 3) +#define SHARED_NOTINIT (SHARED_ERRBASE + 4) +#define SHARED_IPCERR (SHARED_ERRBASE + 5) +#define SHARED_NOMEM (SHARED_ERRBASE + 6) +#define SHARED_AGAIN (SHARED_ERRBASE + 7) +#define SHARED_NOFILE (SHARED_ERRBASE + 8) +#define SHARED_NORESIZE (SHARED_ERRBASE + 9) + +#define HEADER_NOT_EMPTY 201 /* header already contains keywords */ +#define KEY_NO_EXIST 202 /* keyword not found in header */ +#define KEY_OUT_BOUNDS 203 /* keyword record number is out of bounds */ +#define VALUE_UNDEFINED 204 /* keyword value field is blank */ +#define NO_QUOTE 205 /* string is missing the closing quote */ +#define BAD_KEYCHAR 207 /* illegal character in keyword name or card */ +#define BAD_ORDER 208 /* required keywords out of order */ +#define NOT_POS_INT 209 /* keyword value is not a positive integer */ +#define NO_END 210 /* couldn't find END keyword */ +#define BAD_BITPIX 211 /* illegal BITPIX keyword value*/ +#define BAD_NAXIS 212 /* illegal NAXIS keyword value */ +#define BAD_NAXES 213 /* illegal NAXISn keyword value */ +#define BAD_PCOUNT 214 /* illegal PCOUNT keyword value */ +#define BAD_GCOUNT 215 /* illegal GCOUNT keyword value */ +#define BAD_TFIELDS 216 /* illegal TFIELDS keyword value */ +#define NEG_WIDTH 217 /* negative table row size */ +#define NEG_ROWS 218 /* negative number of rows in table */ +#define COL_NOT_FOUND 219 /* column with this name not found in table */ +#define BAD_SIMPLE 220 /* illegal value of SIMPLE keyword */ +#define NO_SIMPLE 221 /* Primary array doesn't start with SIMPLE */ +#define NO_BITPIX 222 /* Second keyword not BITPIX */ +#define NO_NAXIS 223 /* Third keyword not NAXIS */ +#define NO_NAXES 224 /* Couldn't find all the NAXISn keywords */ +#define NO_XTENSION 225 /* HDU doesn't start with XTENSION keyword */ +#define NOT_ATABLE 226 /* the CHDU is not an ASCII table extension */ +#define NOT_BTABLE 227 /* the CHDU is not a binary table extension */ +#define NO_PCOUNT 228 /* couldn't find PCOUNT keyword */ +#define NO_GCOUNT 229 /* couldn't find GCOUNT keyword */ +#define NO_TFIELDS 230 /* couldn't find TFIELDS keyword */ +#define NO_TBCOL 231 /* couldn't find TBCOLn keyword */ +#define NO_TFORM 232 /* couldn't find TFORMn keyword */ +#define NOT_IMAGE 233 /* the CHDU is not an IMAGE extension */ +#define BAD_TBCOL 234 /* TBCOLn keyword value < 0 or > rowlength */ +#define NOT_TABLE 235 /* the CHDU is not a table */ +#define COL_TOO_WIDE 236 /* column is too wide to fit in table */ +#define COL_NOT_UNIQUE 237 /* more than 1 column name matches template */ +#define BAD_ROW_WIDTH 241 /* sum of column widths not = NAXIS1 */ +#define UNKNOWN_EXT 251 /* unrecognizable FITS extension type */ +#define UNKNOWN_REC 252 /* unrecognizable FITS record */ +#define END_JUNK 253 /* END keyword is not blank */ +#define BAD_HEADER_FILL 254 /* Header fill area not blank */ +#define BAD_DATA_FILL 255 /* Data fill area not blank or zero */ +#define BAD_TFORM 261 /* illegal TFORM format code */ +#define BAD_TFORM_DTYPE 262 /* unrecognizable TFORM datatype code */ +#define BAD_TDIM 263 /* illegal TDIMn keyword value */ + +#define BAD_HDU_NUM 301 /* HDU number < 1 or > MAXHDU */ +#define BAD_COL_NUM 302 /* column number < 1 or > tfields */ +#define NEG_FILE_POS 304 /* tried to move before beginning of file */ +#define NEG_BYTES 306 /* tried to read or write negative bytes */ +#define BAD_ROW_NUM 307 /* illegal starting row number in table */ +#define BAD_ELEM_NUM 308 /* illegal starting element number in vector */ +#define NOT_ASCII_COL 309 /* this is not an ASCII string column */ +#define NOT_LOGICAL_COL 310 /* this is not a logical datatype column */ +#define BAD_ATABLE_FORMAT 311 /* ASCII table column has wrong format */ +#define BAD_BTABLE_FORMAT 312 /* Binary table column has wrong format */ +#define NO_NULL 314 /* null value has not been defined */ +#define NOT_VARI_LEN 317 /* this is not a variable length column */ +#define BAD_DIMEN 320 /* illegal number of dimensions in array */ +#define BAD_PIX_NUM 321 /* first pixel number greater than last pixel */ +#define ZERO_SCALE 322 /* illegal BSCALE or TSCALn keyword = 0 */ +#define NEG_AXIS 323 /* illegal axis length < 1 */ + +#define NOT_GROUP_TABLE 340 +#define HDU_ALREADY_MEMBER 341 +#define MEMBER_NOT_FOUND 342 +#define GROUP_NOT_FOUND 343 +#define BAD_GROUP_ID 344 +#define TOO_MANY_HDUS_TRACKED 345 +#define HDU_ALREADY_TRACKED 346 +#define BAD_OPTION 347 +#define IDENTICAL_POINTERS 348 + +#define BAD_I2C 401 /* bad int to formatted string conversion */ +#define BAD_F2C 402 /* bad float to formatted string conversion */ +#define BAD_INTKEY 403 /* can't interprete keyword value as integer */ +#define BAD_LOGICALKEY 404 /* can't interprete keyword value as logical */ +#define BAD_FLOATKEY 405 /* can't interprete keyword value as float */ +#define BAD_DOUBLEKEY 406 /* can't interprete keyword value as double */ +#define BAD_C2I 407 /* bad formatted string to int conversion */ +#define BAD_C2F 408 /* bad formatted string to float conversion */ +#define BAD_C2D 409 /* bad formatted string to double conversion */ +#define BAD_DATATYPE 410 /* bad keyword datatype code */ +#define BAD_DECIM 411 /* bad number of decimal places specified */ +#define NUM_OVERFLOW 412 /* overflow during datatype conversion */ + +# define DATA_COMPRESSION_ERR 413 /* error in imcompress routines */ +# define DATA_DECOMPRESSION_ERR 414 /* error in imcompress routines */ + +#define BAD_DATE 420 /* error in date or time conversion */ + +#define PARSE_SYNTAX_ERR 431 /* syntax error in parser expression */ +#define PARSE_BAD_TYPE 432 /* expression did not evaluate to desired type */ +#define PARSE_LRG_VECTOR 433 /* vector result too large to return in array */ +#define PARSE_NO_OUTPUT 434 /* data parser failed not sent an out column */ +#define PARSE_BAD_COL 435 /* bad data encounter while parsing column */ +#define PARSE_BAD_OUTPUT 436 /* Output file not of proper type */ + +#define ANGLE_TOO_BIG 501 /* celestial angle too large for projection */ +#define BAD_WCS_VAL 502 /* bad celestial coordinate or pixel value */ +#define WCS_ERROR 503 /* error in celestial coordinate calculation */ +#define BAD_WCS_PROJ 504 /* unsupported type of celestial projection */ +#define NO_WCS_KEY 505 /* celestial coordinate keywords not found */ +#define APPROX_WCS_KEY 506 /* approximate WCS keywords were calculated */ + +/*------- following error codes are used in the grparser.c file -----------*/ +#define NGP_ERRBASE (360) /* base chosen so not to interfere with CFITSIO */ +#define NGP_OK (0) +#define NGP_NO_MEMORY (NGP_ERRBASE + 0) /* malloc failed */ +#define NGP_READ_ERR (NGP_ERRBASE + 1) /* read error from file */ +#define NGP_NUL_PTR (NGP_ERRBASE + 2) /* null pointer passed as argument */ +#define NGP_EMPTY_CURLINE (NGP_ERRBASE + 3) /* line read seems to be empty */ +#define NGP_UNREAD_QUEUE_FULL (NGP_ERRBASE + 4) /* cannot unread more then 1 line (or single line twice) */ +#define NGP_INC_NESTING (NGP_ERRBASE + 5) /* too deep include file nesting (inf. loop ?) */ +#define NGP_ERR_FOPEN (NGP_ERRBASE + 6) /* fopen() failed, cannot open file */ +#define NGP_EOF (NGP_ERRBASE + 7) /* end of file encountered */ +#define NGP_BAD_ARG (NGP_ERRBASE + 8) /* bad arguments passed */ +#define NGP_TOKEN_NOT_EXPECT (NGP_ERRBASE + 9) /* token not expected here */ + +/* The following exclusion if __CINT__ is defined is needed for ROOT */ +#ifndef __CINT__ +/* the following 3 lines are needed to support C++ compilers */ +#ifdef __cplusplus +extern "C" { +#endif +#endif + +/*---------------- FITS file URL parsing routines -------------*/ +int fits_get_token(char **ptr, char *delimiter, char *token, int *isanumber); +int ffiurl(char *url, char *urltype, char *infile, + char *outfile, char *extspec, char *rowfilter, + char *binspec, char *colspec, int *status); +int ffrtnm(char *url, char *rootname, int *status); +int ffourl(char *url, char *urltype, char *outfile, char *tmplfile, + int *status); +int ffexts(char *extspec, int *extnum, char *extname, int *extvers, + int *hdutype, char *colname, char *rowexpress, int *status); +int ffextn(char *url, int *extension_num, int *status); +int ffurlt(fitsfile *fptr, char *urlType, int *status); +int ffbins(char *binspec, int *imagetype, int *haxis, + char colname[4][FLEN_VALUE], double *minin, + double *maxin, double *binsizein, + char minname[4][FLEN_VALUE], char maxname[4][FLEN_VALUE], + char binname[4][FLEN_VALUE], double *weight, char *wtname, + int *recip, int *status); +int ffbinr(char **binspec, char *colname, double *minin, + double *maxin, double *binsizein, char *minname, + char *maxname, char *binname, int *status); +int ffimport_file( char *filename, char **contents, int *status ); + +/*---------------- FITS file I/O routines -------------*/ +int ffomem(fitsfile **fptr, const char *name, int mode, void **buffptr, + size_t *buffsize, size_t deltasize, + void *(*mem_realloc)(void *p, size_t newsize), + int *status); +int ffopen(fitsfile **fptr, const char *filename, int iomode, int *status); +int ffreopen(fitsfile *openfptr, fitsfile **newfptr, int *status); +int ffinit(fitsfile **fptr, const char *filename, int *status); +int fftplt(fitsfile **fptr, const char *filename, const char *tempname, + int *status); +int ffflus(fitsfile *fptr, int *status); +int ffclos(fitsfile *fptr, int *status); +int ffdelt(fitsfile *fptr, int *status); +int ffflnm(fitsfile *fptr, char *filename, int *status); +int ffflmd(fitsfile *fptr, int *filemode, int *status); + +/*---------------- utility routines -------------*/ +float ffvers(float *version); +void ffupch(char *string); +void ffgerr(int status, char *errtext); +void ffpmsg(const char *err_message); +int ffgmsg(char *err_message); +void ffcmsg(void); +void ffrprt(FILE *stream, int status); +void ffcmps(char *templt, char *colname, int casesen, int *match, + int *exact); +int fftkey(char *keyword, int *status); +int fftrec(char *card, int *status); +int ffnchk(fitsfile *fptr, int *status); +int ffkeyn(char *keyroot, int value, char *keyname, int *status); +int ffnkey(int value, char *keyroot, char *keyname, int *status); +int ffgkcl(char *card); +int ffdtyp(char *cval, char *dtype, int *status); +int ffpsvc(char *card, char *value, char *comm, int *status); +int ffgknm(char *card, char *name, int *length, int *status); +int ffgthd(char *tmplt, char *card, int *hdtype, int *status); +int ffasfm(char *tform, int *datacode, long *width, int *decim, int *status); +int ffbnfm(char *tform, int *datacode, long *repeat, long *width, int *status); +int ffgabc(int tfields, char **tform, int space, long *rowlen, long *tbcol, + int *status); + +/*----------------- write single keywords --------------*/ +int ffpky(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status); +int ffprec(fitsfile *fptr, const char *card, int *status); +int ffpcom(fitsfile *fptr, const char *comm, int *status); +int ffpunt(fitsfile *fptr, char *keyname, char *unit, int *status); +int ffphis(fitsfile *fptr, const char *history, int *status); +int ffpdat(fitsfile *fptr, int *status); +int ffgstm(char *timestr, int *timeref, int *status); +int ffgsdt(int *day, int *month, int *year, int *status); +int ffdt2s(int year, int month, int day, char *datestr, int *status); +int fftm2s(int year, int month, int day, int hour, int minute, double second, + int decimals, char *datestr, int *status); +int ffs2dt(char *datestr, int *year, int *month, int *day, int *status); +int ffs2tm(char *datestr, int *year, int *month, int *day, int *hour, + int *minute, double *second, int *status); +int ffpkyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffpkys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffpkls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffplsw(fitsfile *fptr, int *status); +int ffpkyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffpkyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffpkyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffpkye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffpkyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffpkyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffpkyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffpkym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffpkfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffpkfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffpkyt(fitsfile *fptr, char *keyname, long intval, double frac, char *comm, + int *status); +int ffptdm( fitsfile *fptr, int colnum, int naxis, long naxes[], int *status); + +/*----------------- write array of keywords --------------*/ +int ffpkns(fitsfile *fptr, char *keyroot, int nstart, int nkey, char *value[], + char *comm[], int *status); +int ffpknl(fitsfile *fptr, char *keyroot, int nstart, int nkey, int *value, + char *comm[], int *status); +int ffpknj(fitsfile *fptr, char *keyroot, int nstart, int nkey, long *value, + char *comm[], int *status); +int ffpknf(fitsfile *fptr, char *keyroot, int nstart, int nkey, float *value, + int decim, char *comm[], int *status); +int ffpkne(fitsfile *fptr, char *keyroot, int nstart, int nkey, float *value, + int decim, char *comm[], int *status); +int ffpkng(fitsfile *fptr, char *keyroot, int nstart, int nkey, double *value, + int decim, char *comm[], int *status); +int ffpknd(fitsfile *fptr, char *keyroot, int nstart, int nkey, double *value, + int decim, char *comm[], int *status); +int ffcpky(fitsfile *infptr,fitsfile *outfptr,int incol,int outcol, + char *rootname, int *status); + +/*----------------- write required header keywords --------------*/ +int ffphps( fitsfile *fptr, int bitpix, int naxis, long naxes[], int *status); +int ffphpr( fitsfile *fptr, int simple, int bitpix, int naxis, long naxes[], + long pcount, long gcount, int extend, int *status); +int ffphtb(fitsfile *fptr, long naxis1, long naxis2, int tfields, char **ttype, + long *tbcol, char **tform, char **tunit, char *extname, int *status); +int ffphbn(fitsfile *fptr, long naxis2, int tfields, char **ttype, + char **tform, char **tunit, char *extname, long pcount, int *status); + +/*----------------- write template keywords --------------*/ +int ffpktp(fitsfile *fptr, const char *filename, int *status); + +/*------------------ get header information --------------*/ +int ffghsp(fitsfile *fptr, int *nexist, int *nmore, int *status); +int ffghps(fitsfile *fptr, int *nexist, int *position, int *status); + +/*------------------ move position in header -------------*/ +int ffmaky(fitsfile *fptr, int nrec, int *status); +int ffmrky(fitsfile *fptr, int nrec, int *status); + +/*------------------ read single keywords -----------------*/ +int ffgnxk(fitsfile *fptr, char **inclist, int ninc, char **exclist, + int nexc, char *card, int *status); +int ffgrec(fitsfile *fptr, int nrec, char *card, int *status); +int ffgcrd(fitsfile *fptr, char *keyname, char *card, int *status); +int ffgunt(fitsfile *fptr, char *keyname, char *unit, int *status); +int ffgkyn(fitsfile *fptr, int nkey, char *keyname, char *keyval, char *comm, + int *status); +int ffgkey(fitsfile *fptr, char *keyname, char *keyval, char *comm, + int *status); + +int ffgky( fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status); +int ffgkys(fitsfile *fptr, char *keyname, char *value, char *comm, int *status); +int ffgkls(fitsfile *fptr, char *keyname, char **value, char *comm, int *status) +; +int ffgkyl(fitsfile *fptr, char *keyname, int *value, char *comm, int *status); +int ffgkyj(fitsfile *fptr, char *keyname, long *value, char *comm, int *status); +int ffgkye(fitsfile *fptr, char *keyname, float *value, char *comm,int *status); +int ffgkyd(fitsfile *fptr, char *keyname, double *value,char *comm,int *status); +int ffgkyc(fitsfile *fptr, char *keyname, float *value, char *comm,int *status); +int ffgkym(fitsfile *fptr, char *keyname, double *value,char *comm,int *status); +int ffgkyt(fitsfile *fptr, char *keyname, long *ivalue, double *dvalue, + char *comm, int *status); +int ffgtdm(fitsfile *fptr, int colnum, int maxdim, int *naxis, long naxes[], + int *status); +int ffdtdm(fitsfile *fptr, char *tdimstr, int colnum, int maxdim, + int *naxis, long naxes[], int *status); + +/*------------------ read array of keywords -----------------*/ +int ffgkns(fitsfile *fptr, char *keyname, int nstart, int nmax, char *value[], + int *nfound, int *status); +int ffgknl(fitsfile *fptr, char *keyname, int nstart, int nmax, int *value, + int *nfound, int *status); +int ffgknj(fitsfile *fptr, char *keyname, int nstart, int nmax, long *value, + int *nfound, int *status); +int ffgkne(fitsfile *fptr, char *keyname, int nstart, int nmax, float *value, + int *nfound, int *status); +int ffgknd(fitsfile *fptr, char *keyname, int nstart, int nmax, double *value, + int *nfound, int *status); +int ffh2st(fitsfile *fptr, char **header, int *status); + +/*----------------- read required header keywords --------------*/ +int ffghpr(fitsfile *fptr, int maxdim, int *simple, int *bitpix, int *naxis, + long naxes[], long *pcount, long *gcount, int *extend, int *status); + +int ffghtb(fitsfile *fptr,int maxfield, long *naxis1, long *naxis2, + int *tfields, char **ttype, long *tbcol, char **tform, char **tunit, + char *extname, int *status); + +int ffghbn(fitsfile *fptr, int maxfield, long *naxis2, int *tfields, + char **ttype, char **tform, char **tunit, char *extname, + long *pcount, int *status); + +/*--------------------- update keywords ---------------*/ +int ffuky(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status); +int ffucrd(fitsfile *fptr, char *keyname, char *card, int *status); +int ffukyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffukys(fitsfile *fptr, char *keyname, char *value, char *comm, int *status); +int ffukls(fitsfile *fptr, char *keyname, char *value, char *comm, int *status); +int ffukyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffukyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffukyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffukye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffukyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffukyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffukyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffukym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffukfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffukfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); + +/*--------------------- modify keywords ---------------*/ +int ffmrec(fitsfile *fptr, int nkey, char *card, int *status); +int ffmcrd(fitsfile *fptr, char *keyname, char *card, int *status); +int ffmnam(fitsfile *fptr, char *oldname, char *newname, int *status); +int ffmcom(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffmkyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffmkys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffmkls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffmkyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffmkyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffmkyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffmkye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffmkyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffmkyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffmkyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffmkym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffmkfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffmkfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); + +/*--------------------- insert keywords ---------------*/ +int ffirec(fitsfile *fptr, int nkey, char *card, int *status); +int ffikyu(fitsfile *fptr, char *keyname, char *comm, int *status); +int ffikys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffikls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status); +int ffikyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status); +int ffikyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status); +int ffikyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffikye(fitsfile *fptr, char *keyname, float value, int decim, char *comm, + int *status); +int ffikyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffikyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm, + int *status); +int ffikyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffikym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); +int ffikfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm, + int *status); +int ffikfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm, + int *status); + +/*--------------------- delete keywords ---------------*/ +int ffdkey(fitsfile *fptr, char *keyname, int *status); +int ffdrec(fitsfile *fptr, int keypos, int *status); + +/*--------------------- get HDU information -------------*/ +int ffghdn(fitsfile *fptr, int *chdunum); +int ffghdt(fitsfile *fptr, int *exttype, int *status); +int ffghad(fitsfile *fptr, long *headstart, long *datastart, long *dataend, + int *status); +int ffgipr(fitsfile *fptr, int maxaxis, int *imgtype, int *naxis, + long *naxes, int *status); +int ffgidt(fitsfile *fptr, int *imgtype, int *status); +int ffgidm(fitsfile *fptr, int *naxis, int *status); +int ffgisz(fitsfile *fptr, int nlen, long *naxes, int *status); + +/*--------------------- HDU operations -------------*/ +int ffmahd(fitsfile *fptr, int hdunum, int *exttype, int *status); +int ffmrhd(fitsfile *fptr, int hdumov, int *exttype, int *status); +int ffmnhd(fitsfile *fptr, int exttype, char *hduname, int hduvers, + int *status); +int ffthdu(fitsfile *fptr, int *nhdu, int *status); +int ffcrhd(fitsfile *fptr, int *status); +int ffcrim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status); +int ffcrtb(fitsfile *fptr, int tbltype, long naxis2, int tfields, char **ttype, + char **tform, char **tunit, char *extname, int *status); +int ffiimg(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status); +int ffitab(fitsfile *fptr, long naxis1, long naxis2, int tfields, char **ttype, + long *tbcol, char **tform, char **tunit, char *extname, int *status); +int ffibin(fitsfile *fptr,long naxis2, int tfields, char **ttype, char **tform, + char **tunit, char *extname, long pcount, int *status); +int ffrsim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status); +int ffdhdu(fitsfile *fptr, int *hdutype, int *status); +int ffcopy(fitsfile *infptr, fitsfile *outfptr, int morekeys, int *status); +int ffcphd(fitsfile *infptr, fitsfile *outfptr, int *status); +int ffcpdt(fitsfile *infptr, fitsfile *outfptr, int *status); +int ffchfl(fitsfile *fptr, int *status); +int ffcdfl(fitsfile *fptr, int *status); + +int ffrdef(fitsfile *fptr, int *status); +int ffhdef(fitsfile *fptr, int morekeys, int *status); +int ffpthp(fitsfile *fptr, long theap, int *status); + +int ffcsum(fitsfile *fptr, long nrec, unsigned long *sum, int *status); +void ffesum(unsigned long sum, int complm, char *ascii); +unsigned long ffdsum(char *ascii, int complm, unsigned long *sum); +int ffpcks(fitsfile *fptr, int *status); +int ffupck(fitsfile *fptr, int *status); +int ffvcks(fitsfile *fptr, int *datastatus, int *hdustatus, int *status); +int ffgcks(fitsfile *fptr, unsigned long *datasum, unsigned long *hdusum, + int *status); + +/*--------------------- define scaling or null values -------------*/ +int ffpscl(fitsfile *fptr, double scale, double zero, int *status); +int ffpnul(fitsfile *fptr, long nulvalue, int *status); +int fftscl(fitsfile *fptr, int colnum, double scale, double zero, int *status); +int fftnul(fitsfile *fptr, int colnum, long nulvalue, int *status); +int ffsnul(fitsfile *fptr, int colnum, char *nulstring, int *status); + +/*--------------------- get column information -------------*/ +int ffgcno(fitsfile *fptr, int casesen, char *templt, int *colnum, + int *status); +int ffgcnn(fitsfile *fptr, int casesen, char *templt, char *colname, + int *colnum, int *status); + +int ffgtcl(fitsfile *fptr, int colnum, int *typecode, long *repeat, + long *width, int *status); +int ffgncl(fitsfile *fptr, int *ncols, int *status); +int ffgnrw(fitsfile *fptr, long *nrows, int *status); +int ffgacl(fitsfile *fptr, int colnum, char *ttype, long *tbcol, + char *tunit, char *tform, double *tscal, double *tzero, + char *tnull, char *tdisp, int *status); +int ffgbcl(fitsfile *fptr, int colnum, char *ttype, char *tunit, + char *dtype, long *repeat, double *tscal, double *tzero, + long *tnull, char *tdisp, int *status); +int ffgrsz(fitsfile *fptr, long *nrows, int *status); +int ffgcdw(fitsfile *fptr, int colnum, int *width, int *status); + +/*--------------------- read primary array or image elements -------------*/ +int ffgpv(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *nulval, void *array, int *anynul, int *status); +int ffgpf(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, char *nullarray, int *anynul, int *status); +int ffgpvb(fitsfile *fptr, long group, long firstelem, long nelem, unsigned + char nulval, unsigned char *array, int *anynul, int *status); +int ffgpvui(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned short nulval, unsigned short *array, int *anynul, + int *status); +int ffgpvi(fitsfile *fptr, long group, long firstelem, long nelem, + short nulval, short *array, int *anynul, int *status); +int ffgpvuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long nulval, unsigned long *array, int *anynul, + int *status); +int ffgpvj(fitsfile *fptr, long group, long firstelem, long nelem, + long nulval, long *array, int *anynul, int *status); +int ffgpvuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int nulval, unsigned int *array, int *anynul, int *status); +int ffgpvk(fitsfile *fptr, long group, long firstelem, long nelem, + int nulval, int *array, int *anynul, int *status); +int ffgpve(fitsfile *fptr, long group, long firstelem, long nelem, + float nulval, float *array, int *anynul, int *status); +int ffgpvd(fitsfile *fptr, long group, long firstelem, long nelem, + double nulval, double *array, int *anynul, int *status); + +int ffgpfb(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned char *array, char *nularray, int *anynul, int *status); +int ffgpfui(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned short *array, char *nularray, int *anynul, int *status); +int ffgpfi(fitsfile *fptr, long group, long firstelem, long nelem, + short *array, char *nularray, int *anynul, int *status); +int ffgpfuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long *array, char *nularray, int *anynul, int *status); +int ffgpfj(fitsfile *fptr, long group, long firstelem, long nelem, + long *array, char *nularray, int *anynul, int *status); +int ffgpfuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int *array, char *nularray, int *anynul, int *status); +int ffgpfk(fitsfile *fptr, long group, long firstelem, long nelem, + int *array, char *nularray, int *anynul, int *status); +int ffgpfe(fitsfile *fptr, long group, long firstelem, long nelem, + float *array, char *nularray, int *anynul, int *status); +int ffgpfd(fitsfile *fptr, long group, long firstelem, long nelem, + double *array, char *nularray, int *anynul, int *status); + +int ffg2db(fitsfile *fptr, long group, unsigned char nulval, long ncols, + long naxis1, long naxis2, unsigned char *array, + int *anynul, int *status); +int ffg2dui(fitsfile *fptr, long group, unsigned short nulval, long ncols, + long naxis1, long naxis2, unsigned short *array, + int *anynul, int *status); +int ffg2di(fitsfile *fptr, long group, short nulval, long ncols, + long naxis1, long naxis2, short *array, + int *anynul, int *status); +int ffg2duj(fitsfile *fptr, long group, unsigned long nulval, long ncols, + long naxis1, long naxis2, unsigned long *array, + int *anynul, int *status); +int ffg2dj(fitsfile *fptr, long group, long nulval, long ncols, + long naxis1, long naxis2, long *array, + int *anynul, int *status); +int ffg2duk(fitsfile *fptr, long group, unsigned int nulval, long ncols, + long naxis1, long naxis2, unsigned int *array, + int *anynul, int *status); +int ffg2dk(fitsfile *fptr, long group, int nulval, long ncols, + long naxis1, long naxis2, int *array, + int *anynul, int *status); +int ffg2de(fitsfile *fptr, long group, float nulval, long ncols, + long naxis1, long naxis2, float *array, + int *anynul, int *status); +int ffg2dd(fitsfile *fptr, long group, double nulval, long ncols, + long naxis1, long naxis2, double *array, + int *anynul, int *status); + +int ffg3db(fitsfile *fptr, long group, unsigned char nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned char *array, int *anynul, int *status); +int ffg3dui(fitsfile *fptr, long group, unsigned short nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned short *array, int *anynul, int *status); +int ffg3di(fitsfile *fptr, long group, short nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + short *array, int *anynul, int *status); +int ffg3duj(fitsfile *fptr, long group, unsigned long nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned long *array, int *anynul, int *status); +int ffg3dj(fitsfile *fptr, long group, long nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + long *array, int *anynul, int *status); +int ffg3duk(fitsfile *fptr, long group, unsigned int nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + unsigned int *array, int *anynul, int *status); +int ffg3dk(fitsfile *fptr, long group, int nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + int *array, int *anynul, int *status); +int ffg3de(fitsfile *fptr, long group, float nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + float *array, int *anynul, int *status); +int ffg3dd(fitsfile *fptr, long group, double nulval, long ncols, + long nrows, long naxis1, long naxis2, long naxis3, + double *array, int *anynul, int *status); + +int ffgsvb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned char nulval, unsigned char *array, + int *anynul, int *status); +int ffgsvui(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned short nulval, unsigned short *array, + int *anynul, int *status); +int ffgsvi(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, short nulval, short *array, int *anynul, int *status); +int ffgsvuj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned long nulval, unsigned long *array, + int *anynul, int *status); +int ffgsvj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, long nulval, long *array, int *anynul, int *status); +int ffgsvuk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned int nulval, unsigned int *array, + int *anynul, int *status); +int ffgsvk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, int nulval, int *array, int *anynul, int *status); +int ffgsve(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, float nulval, float *array, int *anynul, int *status); +int ffgsvd(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, double nulval, double *array, int *anynul, + int *status); + +int ffgsfb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned char *array, char *flagval, + int *anynul, int *status); +int ffgsfui(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned short *array, char *flagval, int *anynul, + int *status); +int ffgsfi(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, short *array, char *flagval, int *anynul, int *status); +int ffgsfuj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned long *array, char *flagval, int *anynul, + int *status); +int ffgsfj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, long *array, char *flagval, int *anynul, int *status); +int ffgsfuk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, unsigned int *array, char *flagval, int *anynul, + int *status); +int ffgsfk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, int *array, char *flagval, int *anynul, int *status); +int ffgsfe(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, float *array, char *flagval, int *anynul, int *status); +int ffgsfd(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, + long *trc, long *inc, double *array, char *flagval, int *anynul, + int *status); + +int ffggpb(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned char *array, int *status); +int ffggpui(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned short *array, int *status); +int ffggpi(fitsfile *fptr, long group, long firstelem, long nelem, + short *array, int *status); +int ffggpuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long *array, int *status); +int ffggpj(fitsfile *fptr, long group, long firstelem, long nelem, + long *array, int *status); +int ffggpuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int *array, int *status); +int ffggpk(fitsfile *fptr, long group, long firstelem, long nelem, + int *array, int *status); +int ffggpe(fitsfile *fptr, long group, long firstelem, long nelem, + float *array, int *status); +int ffggpd(fitsfile *fptr, long group, long firstelem, long nelem, + double *array, int *status); + +/*--------------------- read column elements -------------*/ +int ffgcv( fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *nulval, void *array, int *anynul, + int *status); +int ffgcf( fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, char *nullarray, + int *anynul, int *status); +int ffgcvs(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *nulval, char **array, int *anynul, int *status); +int ffgcl (fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *array, int *status); +int ffgcvl (fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char nulval, char *array, int *anynul, int *status); +int ffgcvb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned char nulval, unsigned char *array, + int *anynul, int *status); +int ffgcvui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short nulval, unsigned short *array, + int *anynul, int *status); +int ffgcvi(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short nulval, short *array, int *anynul, int *status); +int ffgcvuj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long nulval, unsigned long *array, int *anynul, + int *status); +int ffgcvj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long nulval, long *array, int *anynul, int *status); +int ffgcvuk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int nulval, unsigned int *array, int *anynul, + int *status); +int ffgcvk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int nulval, int *array, int *anynul, int *status); +int ffgcve(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float nulval, float *array, int *anynul, int *status); +int ffgcvd(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double nulval, double *array, int *anynul, int *status); +int ffgcvc(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float nulval, float *array, int *anynul, int *status); +int ffgcvm(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double nulval, double *array, int *anynul, int *status); +int ffgcx(fitsfile *fptr, int colnum, long firstrow, long firstbit, + long nbits, char *larray, int *status); +int ffgcxui(fitsfile *fptr, int colnum, long firstrow, long nrows, + long firstbit, int nbits, unsigned short *array, int *status); +int ffgcxuk(fitsfile *fptr, int colnum, long firstrow, long nrows, + long firstbit, int nbits, unsigned int *array, int *status); + +int ffgcfs(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, char **array, char *nularray, int *anynul, int *status); +int ffgcfl(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, char *array, char *nularray, int *anynul, int *status); +int ffgcfb(fitsfile *fptr, int colnum, long firstrow, long firstelem, long + nelem, unsigned char *array, char *nularray, int *anynul, int *status); +int ffgcfui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short *array, char *nularray, int *anynul, + int *status); +int ffgcfi(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short *array, char *nularray, int *anynul, int *status); +int ffgcfuj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long *array, char *nularray, int *anynul, + int *status); +int ffgcfj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long *array, char *nularray, int *anynul, int *status); +int ffgcfuk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int *array, char *nularray, int *anynul, + int *status); +int ffgcfk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *array, char *nularray, int *anynul, int *status); +int ffgcfe(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, char *nularray, int *anynul, int *status); +int ffgcfd(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, char *nularray, int *anynul, int *status); +int ffgcfc(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, char *nularray, int *anynul, int *status); +int ffgcfm(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, char *nularray, int *anynul, int *status); + +int ffgdes(fitsfile *fptr, int colnum, long rownum, long *length, + long *heapaddr, int *status); + +int ffgdess(fitsfile *fptr, int colnum, long firstrow, long nrows, long *length, + long *heapaddr, int *status); + +int ffgtbb(fitsfile *fptr, long firstrow, long firstchar, long nchars, + unsigned char *values, int *status); + +/*------------ write primary array or image elements -------------*/ +int ffppr(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, int *status); +int ffpprb(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned char *array, int *status); +int ffpprui(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned short *array, int *status); +int ffppri(fitsfile *fptr, long group, long firstelem, + long nelem, short *array, int *status); +int ffppruj(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned long *array, int *status); +int ffpprj(fitsfile *fptr, long group, long firstelem, + long nelem, long *array, int *status); +int ffppruk(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned int *array, int *status); +int ffpprk(fitsfile *fptr, long group, long firstelem, + long nelem, int *array, int *status); +int ffppre(fitsfile *fptr, long group, long firstelem, + long nelem, float *array, int *status); +int ffpprd(fitsfile *fptr, long group, long firstelem, + long nelem, double *array, int *status); + +int ffppru(fitsfile *fptr, long group, long firstelem, long nelem, + int *status); +int ffpprn(fitsfile *fptr, long firstelem, long nelem, int *status); + +int ffppn(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, void *nulval, int *status); +int ffppnb(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned char *array, unsigned char nulval, int *status); +int ffppnui(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned short *array, unsigned short nulval, + int *status); +int ffppni(fitsfile *fptr, long group, long firstelem, + long nelem, short *array, short nulval, int *status); +int ffppnj(fitsfile *fptr, long group, long firstelem, + long nelem, long *array, long nulval, int *status); +int ffppnuj(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned long *array, unsigned long nulval, int *status); +int ffppnuk(fitsfile *fptr, long group, long firstelem, long nelem, + unsigned int *array, unsigned int nulval, int *status); +int ffppnk(fitsfile *fptr, long group, long firstelem, + long nelem, int *array, int nulval, int *status); +int ffppne(fitsfile *fptr, long group, long firstelem, + long nelem, float *array, float nulval, int *status); +int ffppnd(fitsfile *fptr, long group, long firstelem, + long nelem, double *array, double nulval, int *status); + +int ffp2db(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned char *array, int *status); +int ffp2dui(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned short *array, int *status); +int ffp2di(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, short *array, int *status); +int ffp2duj(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned long *array, int *status); +int ffp2dj(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, long *array, int *status); +int ffp2duk(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, unsigned int *array, int *status); +int ffp2dk(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, int *array, int *status); +int ffp2de(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, float *array, int *status); +int ffp2dd(fitsfile *fptr, long group, long ncols, long naxis1, + long naxis2, double *array, int *status); + +int ffp3db(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned char *array, int *status); +int ffp3dui(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned short *array, int *status); +int ffp3di(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, short *array, int *status); +int ffp3duj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned long *array, int *status); +int ffp3dj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, long *array, int *status); +int ffp3duk(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, unsigned int *array, int *status); +int ffp3dk(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, int *array, int *status); +int ffp3de(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, float *array, int *status); +int ffp3dd(fitsfile *fptr, long group, long ncols, long nrows, long naxis1, + long naxis2, long naxis3, double *array, int *status); + +int ffpssb(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned char *array, int *status); +int ffpssui(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned short *array, int *status); +int ffpssi(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, short *array, int *status); +int ffpssuj(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned long *array, int *status); +int ffpssj(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, long *array, int *status); +int ffpssuk(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, unsigned int *array, int *status); +int ffpssk(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, int *array, int *status); +int ffpsse(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, float *array, int *status); +int ffpssd(fitsfile *fptr, long group, long naxis, long *naxes, + long *fpixel, long *lpixel, double *array, int *status); + +int ffpgpb(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned char *array, int *status); +int ffpgpui(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned short *array, int *status); +int ffpgpi(fitsfile *fptr, long group, long firstelem, + long nelem, short *array, int *status); +int ffpgpuj(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned long *array, int *status); +int ffpgpj(fitsfile *fptr, long group, long firstelem, + long nelem, long *array, int *status); +int ffpgpuk(fitsfile *fptr, long group, long firstelem, + long nelem, unsigned int *array, int *status); +int ffpgpk(fitsfile *fptr, long group, long firstelem, + long nelem, int *array, int *status); +int ffpgpe(fitsfile *fptr, long group, long firstelem, + long nelem, float *array, int *status); +int ffpgpd(fitsfile *fptr, long group, long firstelem, + long nelem, double *array, int *status); + +/*--------------------- iterator functions -------------*/ +int fits_iter_set_by_name(iteratorCol *col, fitsfile *fptr, char *colname, + int datatype, int iotype); +int fits_iter_set_by_num(iteratorCol *col, fitsfile *fptr, int colnum, + int datatype, int iotype); +int fits_iter_set_file(iteratorCol *col, fitsfile *fptr); +int fits_iter_set_colname(iteratorCol *col, char *colname); +int fits_iter_set_colnum(iteratorCol *col, int colnum); +int fits_iter_set_datatype(iteratorCol *col, int datatype); +int fits_iter_set_iotype(iteratorCol *col, int iotype); + +fitsfile * fits_iter_get_file(iteratorCol *col); +char * fits_iter_get_colname(iteratorCol *col); +int fits_iter_get_colnum(iteratorCol *col); +int fits_iter_get_datatype(iteratorCol *col); +int fits_iter_get_iotype(iteratorCol *col); +void * fits_iter_get_array(iteratorCol *col); +long fits_iter_get_tlmin(iteratorCol *col); +long fits_iter_get_tlmax(iteratorCol *col); +long fits_iter_get_repeat(iteratorCol *col); +char * fits_iter_get_tunit(iteratorCol *col); +char * fits_iter_get_tdisp(iteratorCol *col); + +int ffiter(int ncols, iteratorCol *data, long offset, long nPerLoop, + int (*workFn)( long totaln, long offset, long firstn, + long nvalues, int narrays, iteratorCol *data, void *userPointer), + void *userPointer, int *status); + +/*--------------------- write column elements -------------*/ +int ffpcl(fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, int *status); +int ffpcls(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char **array, int *status); +int ffpcll(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *array, int *status); +int ffpclb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned char *array, int *status); +int ffpclui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short *array, int *status); +int ffpcli(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short *array, int *status); +int ffpcluj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long *array, int *status); +int ffpclj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long *array, int *status); +int ffpcluk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int *array, int *status); +int ffpclk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *array, int *status); +int ffpcle(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, int *status); +int ffpcld(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, int *status); +int ffpclc(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, int *status); +int ffpclm(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, int *status); +int ffpclu(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *status); +int ffpclx(fitsfile *fptr, int colnum, long frow, long fbit, long nbit, + char *larray, int *status); + +int ffpcn(fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, void *nulval, int *status); +int ffpcns( fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char **array, char *nulvalue, int *status); +int ffpcnl( fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, char *array, char nulvalue, int *status); +int ffpcnb(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned char *array, unsigned char nulvalue, + int *status); +int ffpcnui(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned short *array, unsigned short nulvalue, + int *status); +int ffpcni(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, short *array, short nulvalue, int *status); +int ffpcnuj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned long *array, unsigned long nulvalue, + int *status); +int ffpcnj(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, long *array, long nulvalue, int *status); +int ffpcnuk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, unsigned int *array, unsigned int nulvalue, + int *status); +int ffpcnk(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, int *array, int nulvalue, int *status); +int ffpcne(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, float *array, float nulvalue, int *status); +int ffpcnd(fitsfile *fptr, int colnum, long firstrow, long firstelem, + long nelem, double *array, double nulvalue, int *status); + +int ffpdes(fitsfile *fptr, int colnum, long rownum, long length, + long heapaddr, int *status); + +int ffptbb(fitsfile *fptr, long firstrow, long firstchar, long nchars, + unsigned char *values, int *status); + +int ffirow(fitsfile *fptr, long firstrow, long nrows, int *status); +int ffdrow(fitsfile *fptr, long firstrow, long nrows, int *status); +int ffdrws(fitsfile *fptr, long *rownum, long nrows, int *status); +int fficol(fitsfile *fptr, int numcol, char *ttype, char *tform, int *status); +int fficls(fitsfile *fptr, int firstcol, int ncols, char **ttype, + char **tform, int *status); +int ffmvec(fitsfile *fptr, int colnum, long newveclen, int *status); +int ffdcol(fitsfile *fptr, int numcol, int *status); +int ffcpcl(fitsfile *infptr, fitsfile *outfptr, int incol, int outcol, + int create_col, int *status); + +/*--------------------- WCS Utilities ------------------*/ +int ffgics(fitsfile *fptr, double *xrval, double *yrval, double *xrpix, + double *yrpix, double *xinc, double *yinc, double *rot, + char *type, int *status); +int ffgtcs(fitsfile *fptr, int xcol, int ycol, double *xrval, + double *yrval, double *xrpix, double *yrpix, double *xinc, + double *yinc, double *rot, char *type, int *status); +int ffwldp(double xpix, double ypix, double xref, double yref, + double xrefpix, double yrefpix, double xinc, double yinc, + double rot, char *type, double *xpos, double *ypos, int *status); +int ffxypx(double xpos, double ypos, double xref, double yref, + double xrefpix, double yrefpix, double xinc, double yinc, + double rot, char *type, double *xpix, double *ypix, int *status); + +/* WCS support routines (provide interface to Doug Mink's WCS library */ +int ffgiwcs(fitsfile *fptr, char **header, int *status); +int ffgtwcs(fitsfile *fptr, int xcol, int ycol, char **header, int *status); + +/*--------------------- lexical parsing routines ------------------*/ +int fftexp( fitsfile *fptr, char *expr, int maxdim, + int *datatype, long *nelem, int *naxis, + long *naxes, int *status ); + +int fffrow( fitsfile *infptr, char *expr, + long firstrow, long nrows, + long *n_good_rows, char *row_status, int *status); + +int ffffrw( fitsfile *fptr, char *expr, long *rownum, int *status); + +int fffrwc( fitsfile *fptr, char *expr, char *timeCol, + char *parCol, char *valCol, long ntimes, + double *times, char *time_status, int *status ); + +int ffsrow( fitsfile *infptr, fitsfile *outfptr, char *expr, + int *status); + +int ffcrow( fitsfile *fptr, int datatype, char *expr, + long firstrow, long nelements, void *nulval, + void *array, int *anynul, int *status ); + +int ffcalc_rng( fitsfile *infptr, char *expr, fitsfile *outfptr, + char *parName, char *parInfo, int nRngs, + long *start, long *end, int *status ); + +int ffcalc( fitsfile *infptr, char *expr, fitsfile *outfptr, + char *parName, char *parInfo, int *status ); + + /* ffhist is not really intended as a user-callable routine */ + /* but it may be useful for some specialized applications */ + +int ffhist(fitsfile **fptr, char *outfile, int imagetype, int naxis, + char colname[4][FLEN_VALUE], + double *minin, double *maxin, double *binsizein, + char minname[4][FLEN_VALUE], char maxname[4][FLEN_VALUE], + char binname[4][FLEN_VALUE], + double weightin, char wtcol[FLEN_VALUE], + int recip, char *rowselect, int *status); + +int fits_select_image_section(fitsfile **fptr, char *outfile, + char *imagesection, int *status); +int fits_select_section( fitsfile *infptr, fitsfile *outfptr, + char *imagesection, int *status); + +/*--------------------- grouping routines ------------------*/ + +int ffgtcr(fitsfile *fptr, char *grpname, int grouptype, int *status); +int ffgtis(fitsfile *fptr, char *grpname, int grouptype, int *status); +int ffgtch(fitsfile *gfptr, int grouptype, int *status); +int ffgtrm(fitsfile *gfptr, int rmopt, int *status); +int ffgtcp(fitsfile *infptr, fitsfile *outfptr, int cpopt, int *status); +int ffgtmg(fitsfile *infptr, fitsfile *outfptr, int mgopt, int *status); +int ffgtcm(fitsfile *gfptr, int cmopt, int *status); +int ffgtvf(fitsfile *gfptr, long *firstfailed, int *status); +int ffgtop(fitsfile *mfptr,int group,fitsfile **gfptr,int *status); +int ffgtam(fitsfile *gfptr, fitsfile *mfptr, int hdupos, int *status); +int ffgtnm(fitsfile *gfptr, long *nmembers, int *status); +int ffgmng(fitsfile *mfptr, long *nmembers, int *status); +int ffgmop(fitsfile *gfptr, long member, fitsfile **mfptr, int *status); +int ffgmcp(fitsfile *gfptr, fitsfile *mfptr, long member, int cpopt, + int *status); +int ffgmtf(fitsfile *infptr, fitsfile *outfptr, long member, int tfopt, + int *status); +int ffgmrm(fitsfile *fptr, long member, int rmopt, int *status); + +/*--------------------- group template parser routines ------------------*/ + +int fits_execute_template(fitsfile *ff, char *ngp_template, int *status); + +/*--------------------- image compression routines ------------------*/ + +int fits_comp_img(fitsfile *infptr, fitsfile *outfptr, int compress_type, + long *tilesize, int parm1, int parm2, int *status); +int fits_is_compressed_image(fitsfile *fptr, int *status); +int fits_decomp_img (fitsfile *infptr, fitsfile *outfptr, int *status); +int fits_read_compressed_img(fitsfile *fptr, + int datatype, long *fpixel,long *lpixel,long *inc, + int nullcheck, void *nulval, void *array, char *nullarray, + int *anynul, int *status); + +int fits_read_compressed_pixels(fitsfile *fptr, + int datatype, long fpixel, long npixels, + int nullcheck, void *nulval, void *array, char *nullarray, + int *anynul, int *status); + +int fits_quantize_float (float fdata[], int nx, float in_null_value, + int noise_bits, int idata[], double *bscale, double *bzero, + int *iminval, int *imaxval); +int fits_quantize_double (double fdata[], int nx, double in_null_value, + int noise_bits, int idata[], double *bscale, double *bzero, + int *iminval, int *imaxval); +int fits_rcomp(int a[], int nx, unsigned char *c, int clen,int nblock); +int fits_rdecomp (unsigned char *c, int clen, unsigned int array[], int nx, + int nblock); + +/* The following exclusion if __CINT__ is defined is needed for ROOT */ +#ifndef __CINT__ +#ifdef __cplusplus +} +#endif +#endif + +#endif + diff --git a/src/drivers/camfits.st4/longnam.h b/src/drivers/camfits.st4/longnam.h new file mode 100644 index 00000000..ac083bc5 --- /dev/null +++ b/src/drivers/camfits.st4/longnam.h @@ -0,0 +1,476 @@ +#ifndef _LONGNAME_H +#define _LONGNAME_H + +#define fits_parse_input_url ffiurl +#define fits_parse_rootname ffrtnm +#define fits_parse_output_url ffourl +#define fits_parse_extspec ffexts +#define fits_parse_extnum ffextn +#define fits_parse_binspec ffbins +#define fits_parse_binrange ffbinr +#define fits_open_memfile ffomem +#define fits_open_file ffopen +#define fits_reopen_file ffreopen +#define fits_create_file ffinit +#define fits_create_template fftplt +#define fits_flush_file ffflus +#define fits_close_file ffclos +#define fits_delete_file ffdelt +#define fits_file_name ffflnm +#define fits_file_mode ffflmd +#define fits_url_type ffurlt + +#define fits_get_version ffvers +#define fits_uppercase ffupch +#define fits_get_errstatus ffgerr +#define fits_write_errmsg ffpmsg +#define fits_read_errmsg ffgmsg +#define fits_clear_errmsg ffcmsg +#define fits_report_error ffrprt +#define fits_compare_str ffcmps +#define fits_test_keyword fftkey +#define fits_test_record fftrec +#define fits_null_check ffnchk +#define fits_make_keyn ffkeyn +#define fits_make_nkey ffnkey +#define fits_get_keyclass ffgkcl +#define fits_get_keytype ffdtyp +#define fits_parse_value ffpsvc +#define fits_get_keyname ffgknm +#define fits_parse_template ffgthd +#define fits_ascii_tform ffasfm +#define fits_binary_tform ffbnfm +#define fits_get_tbcol ffgabc +#define fits_get_rowsize ffgrsz +#define fits_get_col_display_width ffgcdw + +#define fits_write_record ffprec +#define fits_write_key ffpky +#define fits_write_key_unit ffpunt +#define fits_write_comment ffpcom +#define fits_write_history ffphis +#define fits_write_date ffpdat +#define fits_get_system_time ffgstm +#define fits_get_system_date ffgsdt +#define fits_date2str ffdt2s +#define fits_time2str fftm2s +#define fits_str2date ffs2dt +#define fits_str2time ffs2tm +#define fits_write_key_longstr ffpkls +#define fits_write_key_longwarn ffplsw +#define fits_write_key_null ffpkyu +#define fits_write_key_str ffpkys +#define fits_write_key_log ffpkyl +#define fits_write_key_lng ffpkyj +#define fits_write_key_fixflt ffpkyf +#define fits_write_key_flt ffpkye +#define fits_write_key_fixdbl ffpkyg +#define fits_write_key_dbl ffpkyd +#define fits_write_key_fixcmp ffpkfc +#define fits_write_key_cmp ffpkyc +#define fits_write_key_fixdblcmp ffpkfm +#define fits_write_key_dblcmp ffpkym +#define fits_write_key_triple ffpkyt +#define fits_write_tdim ffptdm +#define fits_write_keys_str ffpkns +#define fits_write_keys_log ffpknl +#define fits_write_keys_lng ffpknj +#define fits_write_keys_fixflt ffpknf +#define fits_write_keys_flt ffpkne +#define fits_write_keys_fixdbl ffpkng +#define fits_write_keys_dbl ffpknd +#define fits_copy_key ffcpky +#define fits_write_imghdr ffphps +#define fits_write_grphdr ffphpr +#define fits_write_atblhdr ffphtb +#define fits_write_btblhdr ffphbn +#define fits_write_key_template ffpktp + +#define fits_get_hdrspace ffghsp +#define fits_get_hdrpos ffghps +#define fits_movabs_key ffmaky +#define fits_movrel_key ffmrky +#define fits_find_nextkey ffgnxk + +#define fits_read_record ffgrec +#define fits_read_card ffgcrd +#define fits_read_key_unit ffgunt +#define fits_read_keyn ffgkyn +#define fits_read_key ffgky +#define fits_read_keyword ffgkey +#define fits_read_key_str ffgkys +#define fits_read_key_log ffgkyl +#define fits_read_key_lng ffgkyj +#define fits_read_key_flt ffgkye +#define fits_read_key_dbl ffgkyd +#define fits_read_key_cmp ffgkyc +#define fits_read_key_dblcmp ffgkym +#define fits_read_key_triple ffgkyt +#define fits_read_key_longstr ffgkls +#define fits_read_tdim ffgtdm +#define fits_decode_tdim ffdtdm +#define fits_read_keys_str ffgkns +#define fits_read_keys_log ffgknl +#define fits_read_keys_lng ffgknj +#define fits_read_keys_flt ffgkne +#define fits_read_keys_dbl ffgknd +#define fits_read_imghdr ffghpr +#define fits_read_atblhdr ffghtb +#define fits_read_btblhdr ffghbn +#define fits_header2str ffh2st + +#define fits_update_card ffucrd +#define fits_update_key ffuky +#define fits_update_key_null ffukyu +#define fits_update_key_str ffukys +#define fits_update_key_longstr ffukls +#define fits_update_key_log ffukyl +#define fits_update_key_lng ffukyj +#define fits_update_key_fixflt ffukyf +#define fits_update_key_flt ffukye +#define fits_update_key_fixdbl ffukyg +#define fits_update_key_dbl ffukyd +#define fits_update_key_fixcmp ffukfc +#define fits_update_key_cmp ffukyc +#define fits_update_key_fixdblcmp ffukfm +#define fits_update_key_dblcmp ffukym + +#define fits_modify_record ffmrec +#define fits_modify_card ffmcrd +#define fits_modify_name ffmnam +#define fits_modify_comment ffmcom +#define fits_modify_key_null ffmkyu +#define fits_modify_key_str ffmkys +#define fits_modify_key_longstr ffmkls +#define fits_modify_key_log ffmkyl +#define fits_modify_key_lng ffmkyj +#define fits_modify_key_fixflt ffmkyf +#define fits_modify_key_flt ffmkye +#define fits_modify_key_fixdbl ffmkyg +#define fits_modify_key_dbl ffmkyd +#define fits_modify_key_fixcmp ffmkfc +#define fits_modify_key_cmp ffmkyc +#define fits_modify_key_fixdblcmp ffmkfm +#define fits_modify_key_dblcmp ffmkym + +#define fits_insert_record ffirec +#define fits_insert_key_null ffikyu +#define fits_insert_key_str ffikys +#define fits_insert_key_longstr ffikls +#define fits_insert_key_log ffikyl +#define fits_insert_key_lng ffikyj +#define fits_insert_key_fixflt ffikyf +#define fits_insert_key_flt ffikye +#define fits_insert_key_fixdbl ffikyg +#define fits_insert_key_dbl ffikyd +#define fits_insert_key_fixcmp ffikfc +#define fits_insert_key_cmp ffikyc +#define fits_insert_key_fixdblcmp ffikfm +#define fits_insert_key_dblcmp ffikym + +#define fits_delete_key ffdkey +#define fits_delete_record ffdrec +#define fits_get_hdu_num ffghdn +#define fits_get_hdu_type ffghdt +#define fits_get_hduaddr ffghad + +#define fits_get_img_param ffgipr +#define fits_get_img_type ffgidt +#define fits_get_img_dim ffgidm +#define fits_get_img_size ffgisz + +#define fits_movabs_hdu ffmahd +#define fits_movrel_hdu ffmrhd +#define fits_movnam_hdu ffmnhd +#define fits_get_num_hdus ffthdu +#define fits_create_img ffcrim +#define fits_create_tbl ffcrtb +#define fits_create_hdu ffcrhd +#define fits_insert_img ffiimg +#define fits_insert_atbl ffitab +#define fits_insert_btbl ffibin +#define fits_resize_img ffrsim +#define fits_delete_hdu ffdhdu +#define fits_copy_hdu ffcopy +#define fits_copy_header ffcphd +#define fits_copy_data ffcpdt + +#define fits_set_hdustruc ffrdef +#define fits_set_hdrsize ffhdef +#define fits_write_theap ffpthp + +#define fits_encode_chksum ffesum +#define fits_decode_chksum ffdsum +#define fits_write_chksum ffpcks +#define fits_update_chksum ffupck +#define fits_verify_chksum ffvcks +#define fits_get_chksum ffgcks + +#define fits_set_bscale ffpscl +#define fits_set_tscale fftscl +#define fits_set_imgnull ffpnul +#define fits_set_btblnull fftnul +#define fits_set_atblnull ffsnul + +#define fits_get_colnum ffgcno +#define fits_get_colname ffgcnn +#define fits_get_coltype ffgtcl +#define fits_get_num_rows ffgnrw +#define fits_get_num_cols ffgncl +#define fits_get_acolparms ffgacl +#define fits_get_bcolparms ffgbcl + +#define fits_iterate_data ffiter + +#define fits_read_grppar_byt ffggpb +#define fits_read_grppar_usht ffggpui +#define fits_read_grppar_ulng ffggpuj +#define fits_read_grppar_sht ffggpi +#define fits_read_grppar_lng ffggpj +#define fits_read_grppar_int ffggpk +#define fits_read_grppar_uint ffggpuk +#define fits_read_grppar_flt ffggpe +#define fits_read_grppar_dbl ffggpd + +#define fits_read_img ffgpv +#define fits_read_imgnull ffgpf +#define fits_read_img_byt ffgpvb +#define fits_read_img_usht ffgpvui +#define fits_read_img_ulng ffgpvuj +#define fits_read_img_sht ffgpvi +#define fits_read_img_lng ffgpvj +#define fits_read_img_uint ffgpvuk +#define fits_read_img_int ffgpvk +#define fits_read_img_flt ffgpve +#define fits_read_img_dbl ffgpvd + +#define fits_read_imgnull_byt ffgpfb +#define fits_read_imgnull_usht ffgpfui +#define fits_read_imgnull_ulng ffgpfuj +#define fits_read_imgnull_sht ffgpfi +#define fits_read_imgnull_lng ffgpfj +#define fits_read_imgnull_uint ffgpfuk +#define fits_read_imgnull_int ffgpfk +#define fits_read_imgnull_flt ffgpfe +#define fits_read_imgnull_dbl ffgpfd + +#define fits_read_2d_byt ffg2db +#define fits_read_2d_usht ffg2dui +#define fits_read_2d_ulng ffg2duj +#define fits_read_2d_sht ffg2di +#define fits_read_2d_lng ffg2dj +#define fits_read_2d_uint ffg2duk +#define fits_read_2d_int ffg2dk +#define fits_read_2d_flt ffg2de +#define fits_read_2d_dbl ffg2dd + +#define fits_read_3d_byt ffg3db +#define fits_read_3d_usht ffg3dui +#define fits_read_3d_ulng ffg3duj +#define fits_read_3d_sht ffg3di +#define fits_read_3d_lng ffg3dj +#define fits_read_3d_uint ffg3duk +#define fits_read_3d_int ffg3dk +#define fits_read_3d_flt ffg3de +#define fits_read_3d_dbl ffg3dd + +#define fits_read_subset_byt ffgsvb +#define fits_read_subset_usht ffgsvui +#define fits_read_subset_ulng ffgsvuj +#define fits_read_subset_sht ffgsvi +#define fits_read_subset_lng ffgsvj +#define fits_read_subset_uint ffgsvuk +#define fits_read_subset_int ffgsvk +#define fits_read_subset_flt ffgsve +#define fits_read_subset_dbl ffgsvd + +#define fits_read_subsetnull_byt ffgsfb +#define fits_read_subsetnull_usht ffgsfui +#define fits_read_subsetnull_ulng ffgsfuj +#define fits_read_subsetnull_sht ffgsfi +#define fits_read_subsetnull_lng ffgsfj +#define fits_read_subsetnull_uint ffgsfuk +#define fits_read_subsetnull_int ffgsfk +#define fits_read_subsetnull_flt ffgsfe +#define fits_read_subsetnull_dbl ffgsfd + +#define fits_read_col ffgcv +#define fits_read_colnull ffgcf +#define fits_read_col_str ffgcvs +#define fits_read_col_log ffgcvl +#define fits_read_col_byt ffgcvb +#define fits_read_col_usht ffgcvui +#define fits_read_col_ulng ffgcvuj +#define fits_read_col_sht ffgcvi +#define fits_read_col_lng ffgcvj +#define fits_read_col_uint ffgcvuk +#define fits_read_col_int ffgcvk +#define fits_read_col_flt ffgcve +#define fits_read_col_dbl ffgcvd +#define fits_read_col_cmp ffgcvc +#define fits_read_col_dblcmp ffgcvm +#define fits_read_col_bit ffgcx +#define fits_read_col_bit_usht ffgcxui +#define fits_read_col_bit_uint ffgcxuk + +#define fits_read_colnull_str ffgcfs +#define fits_read_colnull_log ffgcfl +#define fits_read_colnull_byt ffgcfb +#define fits_read_colnull_usht ffgcfui +#define fits_read_colnull_ulng ffgcfuj +#define fits_read_colnull_sht ffgcfi +#define fits_read_colnull_lng ffgcfj +#define fits_read_colnull_uint ffgcfuk +#define fits_read_colnull_int ffgcfk +#define fits_read_colnull_flt ffgcfe +#define fits_read_colnull_dbl ffgcfd +#define fits_read_colnull_cmp ffgcfc +#define fits_read_colnull_dblcmp ffgcfm + +#define fits_read_descript ffgdes +#define fits_read_descripts ffgdess +#define fits_read_tblbytes ffgtbb + +#define fits_write_grppar_byt ffpgpb +#define fits_write_grppar_usht ffpgpui +#define fits_write_grppar_ulng ffpgpuj +#define fits_write_grppar_sht ffpgpi +#define fits_write_grppar_lng ffpgpj +#define fits_write_grppar_uint ffpgpuk +#define fits_write_grppar_int ffpgpk +#define fits_write_grppar_flt ffpgpe +#define fits_write_grppar_dbl ffpgpd + +#define fits_write_img ffppr +#define fits_write_img_byt ffpprb +#define fits_write_img_usht ffpprui +#define fits_write_img_ulng ffppruj +#define fits_write_img_sht ffppri +#define fits_write_img_lng ffpprj +#define fits_write_img_uint ffppruk +#define fits_write_img_int ffpprk +#define fits_write_img_flt ffppre +#define fits_write_img_dbl ffpprd + +#define fits_write_imgnull ffppn +#define fits_write_imgnull_byt ffppnb +#define fits_write_imgnull_usht ffppnui +#define fits_write_imgnull_ulng ffppnuj +#define fits_write_imgnull_sht ffppni +#define fits_write_imgnull_lng ffppnj +#define fits_write_imgnull_uint ffppnuk +#define fits_write_imgnull_int ffppnk +#define fits_write_imgnull_flt ffppne +#define fits_write_imgnull_dbl ffppnd + +#define fits_write_img_null ffppru +#define fits_write_null_img ffpprn + +#define fits_write_2d_byt ffp2db +#define fits_write_2d_usht ffp2dui +#define fits_write_2d_ulng ffp2duj +#define fits_write_2d_sht ffp2di +#define fits_write_2d_lng ffp2dj +#define fits_write_2d_uint ffp2duk +#define fits_write_2d_int ffp2dk +#define fits_write_2d_flt ffp2de +#define fits_write_2d_dbl ffp2dd + +#define fits_write_3d_byt ffp3db +#define fits_write_3d_usht ffp3dui +#define fits_write_3d_ulng ffp3duj +#define fits_write_3d_sht ffp3di +#define fits_write_3d_lng ffp3dj +#define fits_write_3d_uint ffp3duk +#define fits_write_3d_int ffp3dk +#define fits_write_3d_flt ffp3de +#define fits_write_3d_dbl ffp3dd + +#define fits_write_subset_byt ffpssb +#define fits_write_subset_usht ffpssui +#define fits_write_subset_ulng ffpssuj +#define fits_write_subset_sht ffpssi +#define fits_write_subset_lng ffpssj +#define fits_write_subset_uint ffpssuk +#define fits_write_subset_int ffpssk +#define fits_write_subset_flt ffpsse +#define fits_write_subset_dbl ffpssd + +#define fits_write_col ffpcl +#define fits_write_col_str ffpcls +#define fits_write_col_log ffpcll +#define fits_write_col_byt ffpclb +#define fits_write_col_usht ffpclui +#define fits_write_col_ulng ffpcluj +#define fits_write_col_sht ffpcli +#define fits_write_col_lng ffpclj +#define fits_write_col_uint ffpcluk +#define fits_write_col_int ffpclk +#define fits_write_col_flt ffpcle +#define fits_write_col_dbl ffpcld +#define fits_write_col_cmp ffpclc +#define fits_write_col_dblcmp ffpclm +#define fits_write_col_null ffpclu +#define fits_write_col_bit ffpclx + +#define fits_write_colnull ffpcn +#define fits_write_colnull_str ffpcns +#define fits_write_colnull_log ffpcnl +#define fits_write_colnull_byt ffpcnb +#define fits_write_colnull_usht ffpcnui +#define fits_write_colnull_ulng ffpcnuj +#define fits_write_colnull_sht ffpcni +#define fits_write_colnull_lng ffpcnj +#define fits_write_colnull_uint ffpcnuk +#define fits_write_colnull_int ffpcnk +#define fits_write_colnull_flt ffpcne +#define fits_write_colnull_dbl ffpcnd + +#define fits_write_descript ffpdes + +#define fits_write_tblbytes ffptbb +#define fits_insert_rows ffirow +#define fits_delete_rows ffdrow +#define fits_delete_rowlist ffdrws +#define fits_insert_col fficol +#define fits_insert_cols fficls +#define fits_delete_col ffdcol +#define fits_copy_col ffcpcl +#define fits_modify_vector_len ffmvec + +#define fits_read_img_coord ffgics +#define fits_read_tbl_coord ffgtcs +#define fits_pix_to_world ffwldp +#define fits_world_to_pix ffxypx + +#define fits_get_image_wcs_keys ffgiwcs +#define fits_get_table_wcs_keys ffgtwcs + +#define fits_find_rows fffrow +#define fits_find_first_row ffffrw +#define fits_find_rows_cmp fffrwc +#define fits_select_rows ffsrow +#define fits_calc_rows ffcrow +#define fits_calculator ffcalc +#define fits_calculator_rng ffcalc_rng +#define fits_test_expr fftexp + +#define fits_create_group ffgtcr +#define fits_insert_group ffgtis +#define fits_change_group ffgtch +#define fits_remove_group ffgtrm +#define fits_copy_group ffgtcp +#define fits_merge_groups ffgtmg +#define fits_compact_group ffgtcm +#define fits_verify_group ffgtvf +#define fits_open_group ffgtop +#define fits_add_group_member ffgtam +#define fits_get_num_members ffgtnm + +#define fits_get_num_groups ffgmng +#define fits_open_member ffgmop +#define fits_copy_member ffgmcp +#define fits_transfer_member ffgmtf +#define fits_remove_member ffgmrm + +#endif diff --git a/src/drivers/camfits.st4/ser.c b/src/drivers/camfits.st4/ser.c new file mode 100644 index 00000000..2eec8c93 --- /dev/null +++ b/src/drivers/camfits.st4/ser.c @@ -0,0 +1,249 @@ +/* This file contains the functions for serial communication */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "errors.h" +#include "ser.h" + +static void rdtimeout(int signumber); +static ser_info *sertmp; + +#ifdef COMMTEST + +/* This example program writes a string in port `tty', and waits until + timeout for a response. */ + + +char teste[] = "Write test..."; +unsigned char buf[25]; +char tty[] = "/dev/ttyS1"; + + +int main(void) +{ + int result; + ser_info porta; + + open_serial(&porta, tty); + if (porta.err_code != ERR_OK) return(-1); + puts("Communication test.\n\n"); + + /* 9600,8e1 */ + porta.baudrate = B9600; + porta.parity = PAR_EVEN; + porta.stopbits = 1; + porta.timeout = 10; + porta.minchars = 25; + porta.waitread = FALSE; + set_serial(&porta); + write_serial(&porta, teste, strlen(teste)); + + if (read_serial(&porta, buf, 24)) + printf("Text received: %s\n\n", buf); + else printf("Read timeout.\n\n"); + + close_serial(&porta); + return(0); +} +#endif /* COMMTEST */ + + +int is_valid_serial(ser_info *serial) +{ + if ((serial == NULL) || + (serial->tty_name == NULL) || + (serial->tio == NULL) || + (serial->oldtio == NULL)) + return(FALSE); + return(TRUE); +} + + +void open_serial(ser_info *serial, char *ttyname) +{ + if (serial == NULL) return; + + serial->err_code = ERR_OK; + signal(SIGALRM, rdtimeout); + +/* Allocate memory for the structures */ + serial->tio = (struct termios *) malloc(sizeof(struct termios)); + if (serial->tio == NULL) { + serial->err_code = ERR_MEM; + return; + } + serial->oldtio = (struct termios *) malloc(sizeof(struct termios)); + if (serial->oldtio == NULL) { + serial->err_code = ERR_MEM; + return; + } + + serial->tty_name = (char *) calloc(strlen(ttyname), sizeof(char)); + if (serial->tty_name == NULL) { + serial->err_code = ERR_MEM; + return; + } + strcpy(serial->tty_name, ttyname); + + + serial->ttyfd = open(serial->tty_name, O_RDWR | O_NOCTTY); + if (serial->ttyfd < 0) { + serial->err_code = ERR_OPENTTY; + close_serial(serial); + return; + } + +/* Save current config */ + tcgetattr(serial->ttyfd, serial->oldtio); + serial->isopen = TRUE; +} + + +int close_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + signal(SIGALRM, SIG_DFL); +/* Restore terminal to its previous state; free memory */ + if (serial->isopen) { + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + close(serial->ttyfd); + } + if (serial->tio != NULL) free(serial->tio); + if (serial->oldtio != NULL) free(serial->oldtio); + if (serial->tty_name != NULL) free(serial->tty_name); + return(ERR_OK); +} + + +int set_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(ERR_SERIAL); + } + memset(serial->tio, 0, sizeof(struct termios)); + + cfsetospeed(serial->tio, serial->baudrate); + cfsetispeed(serial->tio, serial->baudrate); + +/* Set byte size to 8bit, enable reading and set local mode */ + serial->tio->c_cflag |= CS8 | CLOCAL | CREAD; + switch (serial->parity) { + case PAR_NONE: + serial->tio->c_iflag |= IGNPAR; + serial->tio->c_cflag &= ~PARENB; + break; + + case PAR_EVEN: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= ~PARODD; + break; + + case PAR_ODD: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= PARODD; + break; + default: + serial->err_code = ERR_PARITY; + return; + } + + if (serial->stopbits == 1) + serial->tio->c_cflag &= ~CSTOPB; + else if (serial->stopbits ==2) + serial->tio->c_cflag |= CSTOPB; + else { + serial->err_code = ERR_STOPB; + return; + } + +/* Raw input */ + serial-> tio->c_lflag = 0; + + serial->tio->c_cc[VTIME] = serial->timeout; + if (serial->waitread) + serial->tio->c_cc[VMIN] = serial->minchars; + + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); +} + + +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + result = write(serial->ttyfd, buf, nbytes); + if (result < nbytes) { + serial->err_code = ERR_WRITE; + return(result); + } + serial->err_code = ERR_OK; + return(result); +} + + +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + serial->err_code = ERR_OK; + +/* Set the minimum number of chars to read before returning */ + if (serial->waitread && (serial->minchars != nbytes)) { + if (set_minchars(serial, nbytes) != ERR_OK) { + serial->err_code = ERR_SERIAL; + return(0); + } + } +/* save serial stuff for alarm() timeout. */ + sertmp = serial; + alarm(serial->timeout); + result = read(serial->ttyfd, buf, nbytes); + alarm(0); + serial->bytesread = result; + if (result < nbytes) + serial->err_code = ERR_READ; + return(result); +} + + +static int set_minchars(ser_info *serial, int nbytes) +{ + if (!is_valid_serial(serial)) + return(ERR_MEM); + if (!serial->waitread) + return(ERR_READ); + serial->minchars = nbytes; + serial->tio->c_cc[VMIN] = nbytes; + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + return(ERR_OK); +} + +static void rdtimeout(int signumber) +{ + fprintf(stderr, "Serial communication failed, exiting...\n"); + if (sertmp != NULL) close_serial(sertmp); + exit(-1); +} + diff --git a/src/drivers/camfits.st4/ser.h b/src/drivers/camfits.st4/ser.h new file mode 100644 index 00000000..eb4ca68c --- /dev/null +++ b/src/drivers/camfits.st4/ser.h @@ -0,0 +1,34 @@ +#include + +#define RD_TIMEOUT (2) +#define TRUE (1) +#define FALSE (0) + +#define MAX_BUF_LEN (255) +#define PAR_NONE 'n' +#define PAR_EVEN 'e' +#define PAR_ODD 'o' + +typedef struct { + int isopen; + int waitread; + int err_code; + char *tty_name; + int ttyfd; + cc_t minchars; /* not used if waitread == FALSE */ + int bytesread; + int baudrate; + char parity; + int stopbits; + cc_t timeout; /* interchar time (1/10 secs), and read timeout (secs) */ + struct termios *tio; /* |- don't mess with these structs, */ + struct termios *oldtio; /* | the routines will handle it. */ +} ser_info; + +int is_valid_serial(ser_info *serial); +void open_serial(ser_info *serial, char *ttyname); +int close_serial(ser_info *serial); +int set_serial(ser_info *serial); +static int set_minchars(ser_info *serial, int nbytes); +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); diff --git a/src/drivers/camfits.st4/st4.camera.xml b/src/drivers/camfits.st4/st4.camera.xml new file mode 100644 index 00000000..aed346fa --- /dev/null +++ b/src/drivers/camfits.st4/st4.camera.xml @@ -0,0 +1,64 @@ + + + + + SBIG_ST4 + Camera + + +camfits.st4 -d $device -s $shutter -c $ccd -t $exp_time -n $n_exp -o $output + + + + + device + int + 0 + Device to connect. 0 = USB, 1 = LPT1, 2 = LPT2, ... + + + + ccd + int + 0 + CCD chip to use. 0 = Imaging, 1 = Tracking. + + + + exp_time + float + 1.0 + Integration time in seconds. Min and max comes from CCDcap. + + + + n_exp + int + 1 + Number of frames to take. + + + + shutter + bool + True + Open the shutter?. + + + + output + str + img-$time-$object-$filter + Filename of the output image (wildcards allowed: $time, $object, $filter). + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/drivers/camfits.st7/Makefile.am b/src/drivers/camfits.st7/Makefile.am new file mode 100644 index 00000000..332514fc --- /dev/null +++ b/src/drivers/camfits.st7/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = camfits.st7 ccdcap + +camfits_st7_SOURCES = csbigimg.h csbigimg.cpp csbigcam.h csbigcam.cpp getindex.h getindex.c main.cpp +camfits_st7_LDADD = -lm -lcfitsio -lsbigudrv + +ccdcap_SOURCES = ccdcap-test.cpp ccdcap.h sbigcamcap.cpp sbigcamcap.h csbigimg.h csbigimg.cpp csbigcam.h csbigcam.cpp +ccdcap_LDADD = -lsbigudrv + +uts_driver_DATA = st7.camera.xml diff --git a/src/drivers/camfits.st7/ccdcap-test.cpp b/src/drivers/camfits.st7/ccdcap-test.cpp new file mode 100644 index 00000000..c4564965 --- /dev/null +++ b/src/drivers/camfits.st7/ccdcap-test.cpp @@ -0,0 +1,81 @@ +/* + * camfits.st7 - SBIG ST 7/8 Controller + * Copyright (C) 2005 Paulo Henrique Silva + * + * This file is part of camfits.st7 + * camfits.st7 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. + * + * camfits.st7 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 + * + */ + +/* $Id: ccdcap-test.cpp,v 1.1.2.1 2006/05/17 16:32:41 henrique Exp $ */ + +#include "sbigudrv.h" +#include "sbigcamcap.h" + +#include + +void cameraDump(const CCDCap& cap) { + + printf("%s\n===\n", cap.ccdModel().c_str()); + + int n = cap.nReadoutModes(); + const vector rmodes = cap.readoutModes(); + + for(int i = 0; i < n; i++) { + printf("%20s : %hd\n" + "%20s : %hd pixel\n" + "%20s : %hd pixel\n" + "%20s : %0x um\n" + "%20s : %0x um\n" + "%20s : %0x e-/ADU\n\n", "Mode", rmodes[i]->modeFlag, "Width", rmodes[i]->width, "Height", rmodes[i]->height, + "Pixel Width", rmodes[i]->pixelWidth, "Pixel Height", rmodes[i]->pixelHeight, "Gain", rmodes[i]->gain); + } + + printf("%20s : %d\n" + "%20s : %d\n" + "%20s : %d\n" + "%20s : %d\n\n", "Full Frame", cap.fullFrame(), "Fraame Transfer", cap.frameTransfer(), + "Interline", cap.interline(), "Shutter", cap.shutter()); + + printf("%20s : %0x\n", "Firmware Version", cap.firmwareVersion()); + +} + +int main() { + + CSBIGCam *cam = new CSBIGCam(DEV_LPT1); + + PAR_ERROR err; + + err = cam->EstablishLink(); + if (err != CE_NO_ERROR) { + printf("Error linking to camera.\n"); + delete cam; + exit(1); + } + + CCDCap img = SBIGCamCap(cam, CCD_IMAGING); + CCDCap track= SBIGCamCap(cam, CCD_TRACKING); + + cameraDump(img); + + printf("\n"); + + cameraDump(track); + + return 0; + + +} diff --git a/src/drivers/camfits.st7/ccdcap.h b/src/drivers/camfits.st7/ccdcap.h new file mode 100644 index 00000000..442ffac8 --- /dev/null +++ b/src/drivers/camfits.st7/ccdcap.h @@ -0,0 +1,85 @@ +/* + * camfits.st7 - SBIG ST 7/8 Controller + * Copyright (C) 2005 Paulo Henrique Silva + * + * This file is part of camfits.st7 + * camfits.st7 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. + * + * camfits.st7 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 + * + */ + +/* $Id: ccdcap.h,v 1.1.2.1 2006/05/17 16:32:33 henrique Exp $ */ + +#ifndef _CCD_CAP_H_ +#define _CCD_CAP_H_ 1 + +#include +#include + +struct ReadoutMode { + unsigned short width; + unsigned short height; + unsigned long pixelWidth; + unsigned long pixelHeight; + unsigned short gain; + unsigned short modeFlag; +}; + +class CCDCap { + + public: + + CCDCap() { loadData(); }; + virtual ~CCDCap() { }; + + virtual int loadData() { return 1; }; + + std::string ccdModel() const { return _ccdModel; } + std::string ccdSubModel() const { return _ccdSubModel; } + std::string ccdMaker() const { return _ccdMaker; } + + bool fullFrame() const { return _fullFrame; } + bool frameTransfer() const { return _frameTransfer; } + bool interline() const { return _interline; } + bool shutter() const { return _shutter; } + bool antiBlooming() const { return _antiBlooming; } + + unsigned short firmwareVersion() const { return _firmwareVersion; } + + int nReadoutModes() const { return _nReadoutModes; } + + const std::vector& readoutModes() const { return _readoutModes; } + + +protected: + + std::string _ccdModel; + std::string _ccdSubModel; + std::string _ccdMaker; + + bool _fullFrame; + bool _frameTransfer; + bool _interline; + bool _shutter; + bool _antiBlooming; + + unsigned short _firmwareVersion; + + int _nReadoutModes; + + std::vector _readoutModes; + +}; + +#endif // !_CAM_CAP_H_ diff --git a/src/drivers/camfits.st7/cfw8.filter.xml b/src/drivers/camfits.st7/cfw8.filter.xml new file mode 100644 index 00000000..547827e1 --- /dev/null +++ b/src/drivers/camfits.st7/cfw8.filter.xml @@ -0,0 +1,38 @@ + + + + + CFW8 + FilterWheel + + builtin + + + + 0 + clear + + + + 1 + red + + + + 2 + green + + + + 3 + blue + + + + 4 + lunar + + + + + diff --git a/src/drivers/camfits.st7/csbigcam.cpp b/src/drivers/camfits.st7/csbigcam.cpp new file mode 100644 index 00000000..41dda814 --- /dev/null +++ b/src/drivers/camfits.st7/csbigcam.cpp @@ -0,0 +1,981 @@ +/* + + csbigcam.cpp - Contains the code for the sbigcam class + + 1. This software (c)2004 Santa Barbara Instrument Group. + 2. This free software is provided as an example of how + to communicate with SBIG cameras. It is provided AS-IS + without any guarantees by SBIG of suitability for a + particular purpose and without any guarantee to be + bug-free. If you use it you agree to these terms and + agree to do so at your own risk. + 3. Any distribution of this source code to include these + terms. + + Revision History + Date Modification + ========================================================= + 1/26/04 Initial release + +*/ +#include "sbigudrv.h" +#include "csbigcam.h" +#include "csbigimg.h" +#include +#include + +using namespace std; + +#ifndef INVALID_HANDLE_VALUE + #define INVALID_HANDLE_VALUE -1 +#endif + +/* + + Temperature Conversion Constants + Defined in the SBIG Universal Driver Documentation + +*/ +#define T0 25.0 +#define R0 3.0 +#define DT_CCD 25.0 +#define DT_AMB 45.0 +#define RR_CCD 2.57 +#define RR_AMB 7.791 +#define RB_CCD 10.0 +#define RB_AMB 3.0 +#define MAX_AD 4096 + +/* + + hex2double: + + Convert the passed hex value to double. + The hex value is assumed to be in the + format: XXXXXX.XX + +*/ +static double hex2double(unsigned long ul) +{ + double res, mult; + int i; + + res = 0.0; + mult = 1.0; + for (i=0; i<8; i++) + { + res += mult * (double)(ul & 0x0F); + ul >>= 4; + mult *= 10.0; + } + return res / 100.0; + +} + +/* + + Init: + + Initialize the base variables. + +*/ +void CSBIGCam::Init() +{ + m_eLastError = CE_NO_ERROR; + m_eLastCommand = CC_NULL; + m_nDrvHandle = INVALID_HANDLE_VALUE; + m_eCameraType = NO_CAMERA; + m_eActiveCCD = CCD_IMAGING; + m_dExposureTime = 1.0; + m_uReadoutMode = 0; + m_eABGState = ABG_CLK_MED7; +} + +/* + + GetCameraTypeString: + + Return a string describing the model camera + that has been linked to. + +*/ +//typedef enum { ST7_CAMERA=4, ST8_CAMERA, ST5C_CAMERA, TCE_CONTROLLER, +// ST237_CAMERA, STK_CAMERA, ST9_CAMERA, STV_CAMERA, ST10_CAMERA, +// ST1K_CAMERA, ST2K_CAMERA, STL_CAMERA, STF_CAMERA, NEXT_CAMERA, NO_CAMERA=0xFFFF } CAMERA_TYPE; +static const char *CAM_NAMES[] = { + "Type 0", "Type 1", "Type 2", "Type 3", + "ST-7", "ST-8", "ST-5C", "TCE", + "ST-237", "ST-K", "ST-9", "STV", "ST-10", + "ST-1K", "ST-2K", "ST-L", "ST-F" }; +string CSBIGCam::GetCameraTypeString(void) +{ + string s; + GetCCDInfoParams gcip; + GetCCDInfoResults0 gcir; + char *p1, *p2; + + if ( m_eCameraType < (CAMERA_TYPE)(sizeof(CAM_NAMES)/sizeof(const char *)) ) { + // default name + s = CAM_NAMES[m_eCameraType]; + + // see if ST-237A and if so indicate it in the name + if ( m_eCameraType == ST237_CAMERA ) { + gcip.request = CCD_INFO_IMAGING; + if ( SBIGUnivDrvCommand(CC_GET_CCD_INFO, &gcip, &gcir) == CE_NO_ERROR ) + if ( gcir.readoutInfo[0].gain >= 0x100 ) + s += "A"; + } + + // include the ST-L sub-models + if ( m_eCameraType == STL_CAMERA ) { + gcip.request = CCD_INFO_IMAGING; + if ( SBIGUnivDrvCommand(CC_GET_CCD_INFO, &gcip, &gcir) == CE_NO_ERROR ) { + // driver reports name as "SBIG ST-L-XXX..." + p1 = gcir.name + 5; + if ( (p2 = strchr(p1,' ')) != NULL ) { + *p2 = 0; + s = p1; + } + } + } + } + else if ( m_eCameraType == NO_CAMERA ) + s = "No Camera"; + else + s = "Unknown"; + return s; +} + + +/* + + CSBIGCam: + + Stamdard constructor. Initialize appropriate member variables. + +*/ +CSBIGCam::CSBIGCam() +{ + Init(); +} + +/* + + CSBIGCam: + + Alternate constructor. Init the vars, Open the driver and then + try to open the passed device. + + If you want to use the Ethernet connection this is the best + constructor. If you're using the LPT or USB connections + the alternate constructor below may make more sense. + +*/ +CSBIGCam::CSBIGCam(OpenDeviceParams odp) +{ + Init(); + if ( OpenDriver() == CE_NO_ERROR ) + m_eLastError = OpenDevice(odp); +} + +/* + + CSBIGCam: + + Alternate constructor. Init the vars, Open the driver and then + try to open the passed device. + + This won't work the Ethernet port because no IP address + is specified. Use the constructor above where you can + pass the OpenDeviceParams struct. + +*/ +CSBIGCam::CSBIGCam(SBIG_DEVICE_TYPE dev) +{ + OpenDeviceParams odp; + + Init(); + if ( dev == DEV_ETH ) + m_eLastError = CE_BAD_PARAMETER; + else { + odp.deviceType = dev; + if ( OpenDriver() == CE_NO_ERROR ) + m_eLastError = OpenDevice(odp); + } +} + + +/* + + ~CSBIGCam: + + Standard destructor. Close the device then the driver. + +*/ +CSBIGCam::~CSBIGCam() +{ + CloseDevice(); + CloseDriver(); +} + +/* + + GetError: + + Return the error generated in the previous driver call. + +*/ +PAR_ERROR CSBIGCam::GetError() +{ + return m_eLastError; +} + +/* + + GetCommand: + + Return the command last passed to the driver. + +*/ +PAR_COMMAND CSBIGCam::GetCommand() +{ + return m_eLastCommand; +} + +/* + + SBIGUnivDrvCommand: + + Bottleneck function for all calls to the driver that logs + the command and error. First it activates our handle and + then it calls the driver. Activating the handle first + allows having multiple instances of this class dealing + with multiple cameras on different communications port. + + Also allows direct access to the SBIG Universal Driver after + the driver has been opened. + +*/ +PAR_ERROR CSBIGCam::SBIGUnivDrvCommand(short command, void *Params, void *Results) +{ + SetDriverHandleParams sdhp; + + // make sure we have a valid handle to the driver + m_eLastCommand = (PAR_COMMAND)command; + if ( m_nDrvHandle == INVALID_HANDLE_VALUE ) + m_eLastError = CE_DRIVER_NOT_OPEN; + else + { + // handle is valid so install it in the driver + sdhp.handle = m_nDrvHandle; + if ( (m_eLastError = (PAR_ERROR)::SBIGUnivDrvCommand(CC_SET_DRIVER_HANDLE, &sdhp, NULL)) == CE_NO_ERROR ) + // call the desired command + m_eLastError = (PAR_ERROR)::SBIGUnivDrvCommand(command, Params, Results); + } + return m_eLastError; +} + +/* + + OpenDriver: + + Open the driver. Must be made before any other calls and + should be called only once per instance of the camera class. + Based on the results of the open call to the driver this can + open a new handle to the driver. + + The alternate constructors do this for you when you specify + the communications port to use. + +*/ +PAR_ERROR CSBIGCam::OpenDriver() +{ + short res; + GetDriverHandleResults gdhr; + SetDriverHandleParams sdhp; + + // call the driver directly so doesn't install our handle + res = ::SBIGUnivDrvCommand(m_eLastCommand = CC_OPEN_DRIVER, NULL, NULL); + if ( res == CE_DRIVER_NOT_CLOSED ) + { + /* + the driver is open already which we interpret + as having been opened by another instance of + the class so get the driver to allocate a new + handle and then record it + */ + sdhp.handle = INVALID_HANDLE_VALUE; + res = ::SBIGUnivDrvCommand(CC_SET_DRIVER_HANDLE, &sdhp, NULL); + if ( res == CE_NO_ERROR ) { + res = ::SBIGUnivDrvCommand(CC_OPEN_DRIVER, NULL, NULL); + if ( res == CE_NO_ERROR ) { + res = ::SBIGUnivDrvCommand(CC_GET_DRIVER_HANDLE, NULL, &gdhr); + if ( res == CE_NO_ERROR ) + m_nDrvHandle = gdhr.handle; + } + } + } + else if ( res == CE_NO_ERROR ) + { + /* + the driver was not open so record the driver handle + so we can support multiple instances of this class + talking to multiple cameras + */ + res = ::SBIGUnivDrvCommand(CC_GET_DRIVER_HANDLE, NULL, &gdhr); + if ( res == CE_NO_ERROR ) + m_nDrvHandle = gdhr.handle; + } + return m_eLastError = (PAR_ERROR)res; +} + +/* + + CloseDriver: + + Should be called for every call to OpenDriver. + Standard destructor does this for you as well. + Closing the Drriver multiple times won't hurt + but will return an error. + + The destructor will do this for you if you + don't do it explicitly. + +*/ +PAR_ERROR CSBIGCam::CloseDriver() +{ + PAR_ERROR res; + + res = SBIGUnivDrvCommand(CC_CLOSE_DRIVER, NULL, NULL); + if ( res == CE_NO_ERROR ) + m_nDrvHandle = INVALID_HANDLE_VALUE; + return res; +} + +/* + + OpenDevice: + + Call once to open a particular port (USB, LPT, + Ethernet, etc). Must be balanced with a call + to CloseDevice. + + Note that the alternate constructors will make + this call for you so you don't have to do it + explicitly. + +*/ +PAR_ERROR CSBIGCam::OpenDevice(OpenDeviceParams odp) +{ + return SBIGUnivDrvCommand(CC_OPEN_DEVICE, &odp, NULL); +} + +/* + + CloseDevice: + + Closes which ever device was opened by OpenDriver. + + The destructor does this for you so you don't have + to call it explicitly. + +*/ +PAR_ERROR CSBIGCam::CloseDevice() +{ + return SBIGUnivDrvCommand(CC_CLOSE_DEVICE, NULL, NULL); +} + +/* + + GetErrorString: + + Return a string object describing the passed error code. + +*/ +string CSBIGCam::GetErrorString(PAR_ERROR err) +{ + GetErrorStringParams gesp; + GetErrorStringResults gesr; + string s; + + gesp.errorNo = err; + SBIGUnivDrvCommand(CC_GET_ERROR_STRING, &gesp, &gesr); + s = gesr.errorString; + return s; +} + +/* + + GetDriverInfo: + + Get the requested driver info for the passed request. + This call only works with the DRIVER_STANDARD and + DRIVER_EXTENDED requests as you pass it a result + reference that only works with those 2 requests. + For other requests simply call the + SBIGUnivDrvCommand class function. + +*/ +PAR_ERROR CSBIGCam::GetDriverInfo(DRIVER_REQUEST request, GetDriverInfoResults0 &gdir) +{ + GetDriverInfoParams gdip; + + gdip.request = request; + m_eLastCommand = CC_GET_DRIVER_INFO; + if ( request > DRIVER_EXTENDED ) + return m_eLastError = CE_BAD_PARAMETER; + else + return SBIGUnivDrvCommand(CC_GET_DRIVER_INFO, &gdip, &gdir); +} + +/* + + GrabImage: + + Grab an image into the passed image of the passed type. + This does the whole processing for you: Starts + and Ends the Exposure then Readsout the data. + +*/ +PAR_ERROR CSBIGCam::GrabImage(CSBIGImg *pImg, SBIG_DARK_FRAME dark) +{ + int height, width; + GetCCDInfoResults0 gcir; + GetCCDInfoParams gcip; + double ccdTemp; + unsigned short vertNBinning; + unsigned short rm; + string s; + unsigned short es; + MY_LOGICAL expComp; + PAR_ERROR err; + StartReadoutParams srp; + int i; + ReadoutLineParams rlp; + + // Get the image dimensions + vertNBinning = m_uReadoutMode >> 8; + if ( vertNBinning == 0 ) + vertNBinning = 1; + rm = m_uReadoutMode & 0xFF; + gcip.request = (m_eActiveCCD == CCD_IMAGING ? CCD_INFO_IMAGING : CCD_INFO_TRACKING); + if ( SBIGUnivDrvCommand(CC_GET_CCD_INFO, &gcip, &gcir) != CE_NO_ERROR ) + return m_eLastError; + if ( rm >= gcir.readoutModes ) + return CE_BAD_PARAMETER; + width = gcir.readoutInfo[rm].width; + height = gcir.readoutInfo[rm].height / vertNBinning; + + // try to allocate the image buffer + if ( !pImg->AllocateImageBuffer(height, width) ) + return CE_MEMORY_ERROR; + + // initialize some image header params + if ( GetCCDTemperature(ccdTemp) != CE_NO_ERROR ) + return m_eLastError; + pImg->SetCCDTemperature(ccdTemp); + pImg->SetEachExposure(m_dExposureTime); + pImg->SetEGain(hex2double(gcir.readoutInfo[rm].gain)); + pImg->SetPixelHeight(hex2double(gcir.readoutInfo[rm].pixelHeight) * + vertNBinning / 1000.0); + pImg->SetPixelWidth(hex2double(gcir.readoutInfo[rm].pixelWidth) / 1000.0); + es = ES_DCS_ENABLED | ES_DCR_DISABLED | ES_AUTOBIAS_ENABLED; + if ( m_eCameraType == ST5C_CAMERA ) + es |= (ES_ABG_CLOCKED | ES_ABG_RATE_MED); + else if ( m_eCameraType == ST237_CAMERA ) + es |= (ES_ABG_CLOCKED | ES_ABG_RATE_FIXED); + else if ( m_eActiveCCD == CCD_TRACKING ) + es |= (ES_ABG_CLOCKED | ES_ABG_RATE_MED); + else + es |= ES_ABG_LOW; + pImg->SetExposureState(es); + pImg->SetExposureTime(m_dExposureTime); + pImg->SetNumberExposures(1); + pImg->SetReadoutMode(m_uReadoutMode); + s = GetCameraTypeString(); + if ( m_eCameraType == ST5C_CAMERA || ( m_eCameraType == ST237_CAMERA && + s.find("ST-237A", 0) == string::npos) ) + pImg->SetSaturationLevel(4095); + else + pImg->SetSaturationLevel(65535); + s = gcir.name; + pImg->SetCameraModel(s); + + // end any exposure in case one in progress + EndExposure(); + if ( m_eLastError != CE_NO_ERROR && m_eLastError != CE_NO_EXPOSURE_IN_PROGRESS ) + return m_eLastError; + + // start the exposure + if ( StartExposure(dark == SBDF_LIGHT_ONLY ? SC_OPEN_SHUTTER : SC_CLOSE_SHUTTER) != CE_NO_ERROR ) + return m_eLastError; + pImg->SetImageStartTime(time(NULL)); + + // wait for exposure to complete + do { + } while ((err = IsExposureComplete(expComp)) == CE_NO_ERROR && !expComp ); + EndExposure(); + if ( err != CE_NO_ERROR ) + return err; + if ( m_eLastError != CE_NO_ERROR ) + return m_eLastError; + + // readout the CCD + srp.ccd = m_eActiveCCD; + srp.left = srp.top = 0; + srp.height = height; + srp.width = width; + srp.readoutMode = m_uReadoutMode; + if ( (err = StartReadout(srp)) == CE_NO_ERROR ) { + rlp.ccd = m_eActiveCCD; + rlp.pixelStart = 0; + rlp.pixelLength = width; + rlp.readoutMode = m_uReadoutMode; + for (i=0; iGetImagePointer() + (long)i * width); + } + EndReadout(); + if ( err != CE_NO_ERROR ) + return err; + if ( m_eLastError != CE_NO_ERROR ) + return err; + + // we're done unless we wanted a dark also image + if ( dark != SBDF_DARK_ALSO ) + return CE_NO_ERROR; + + // start the light exposure + if ( StartExposure(SC_OPEN_SHUTTER) != CE_NO_ERROR ) + return m_eLastError; + pImg->SetImageStartTime(time(NULL)); + + // wait for exposure to complete + do { + } while ((err = IsExposureComplete(expComp)) == CE_NO_ERROR && !expComp ); + EndExposure(); + if ( err != CE_NO_ERROR ) + return err; + if ( m_eLastError != CE_NO_ERROR ) + return m_eLastError; + + // readout the CCD + srp.ccd = m_eActiveCCD; + srp.left = srp.top = 0; + srp.height = height; + srp.width = width; + srp.readoutMode = m_uReadoutMode; + if ( (err = StartReadout(srp)) == CE_NO_ERROR ) { + rlp.ccd = m_eActiveCCD; + rlp.pixelStart = 0; + rlp.pixelLength = width; + rlp.readoutMode = m_uReadoutMode; + for (i=0; iGetImagePointer() + (long)i * width); + } + EndReadout(); + if ( err != CE_NO_ERROR ) + return err; + if ( m_eLastError != CE_NO_ERROR ) + return err; + + // record dark subtraction in history + if ( m_eCameraType == ST5C_CAMERA || m_eCameraType == ST237_CAMERA ) + pImg->SetHistory("f"); + else + pImg->SetHistory("R"); + + return CE_NO_ERROR; +} + + +/* + + StartExposure: + + Start an exposure in the camera. Should be matched + with an EndExposure call. + +*/ +PAR_ERROR CSBIGCam::StartExposure(SHUTTER_COMMAND shutterState) +{ + StartExposureParams sep; + + sep.ccd = m_eActiveCCD; + sep.exposureTime = (unsigned long)(m_dExposureTime * 100.0 + 0.5); + if ( sep.exposureTime < 1 ) + sep.exposureTime = 1; + sep.abgState = m_eABGState; + sep.openShutter = shutterState; + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_START_EXPOSURE, &sep, NULL); + else + return m_eLastError; +} + +/* + + EndExposure: + + End or abort an exposure in the camera. Should be + matched to a StartExposure but no damage is done + by calling it by itself if you don't know if an + exposure was started for example. + +*/ +PAR_ERROR CSBIGCam::EndExposure(void) +{ + EndExposureParams eep; + + eep.ccd = m_eActiveCCD; + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_END_EXPOSURE, &eep, NULL); + else + return m_eLastError; +} + +/* + + IsExposueComplete: + + Query the camera to see if the exposure in progress is complete. + This returns TRUE if the CCD is idle (an exposure was never + started) or if the CCD exposure is complete. + +*/ +PAR_ERROR CSBIGCam::IsExposureComplete(MY_LOGICAL &complete) +{ + QueryCommandStatusParams qcsp; + QueryCommandStatusResults qcsr; + + complete = FALSE; + if ( CheckLink() ) { + qcsp.command = CC_START_EXPOSURE; + if ( SBIGUnivDrvCommand(CC_QUERY_COMMAND_STATUS, &qcsp, &qcsr) == CE_NO_ERROR ) { + if ( m_eActiveCCD == CCD_IMAGING ) + complete = (qcsr.status & 0x03) != 0x02; + else + complete = (qcsr.status & 0x0C) != 0x08; + } + } + return m_eLastError; +} + +/* + + StartReadout: + + Start the readout process. This should be called + after EndExposure and should be matched with an + EndExposure call. + +*/ +PAR_ERROR CSBIGCam::StartReadout(StartReadoutParams srp) +{ + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_START_READOUT, &srp, NULL); + else + return m_eLastError; +} + +/* + + EndReadout: + + End a readout started with StartReadout. + Don't forget to make this call to prepare the + CCD for idling. + +*/ +PAR_ERROR CSBIGCam::EndReadout(void) +{ + EndReadoutParams erp; + + erp.ccd = m_eActiveCCD; + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_END_READOUT, &erp, NULL); + else + return m_eLastError; +} + +/* + + ReadoutLine: + + Readout a line of data from the camera, optionally + performing a dark subtraction, placing the data + at dest. + +*/ +PAR_ERROR CSBIGCam::ReadoutLine(ReadoutLineParams rlp, MY_LOGICAL darkSubtract, + unsigned short *dest) +{ + if ( CheckLink() ) { + if ( darkSubtract ) + return SBIGUnivDrvCommand(CC_READ_SUBTRACT_LINE, &rlp, dest); + else + return SBIGUnivDrvCommand(CC_READOUT_LINE, &rlp, dest); + } + else + return m_eLastError; + +} + +/* + + DumpLines: + + Discard data from one or more lines in the camera. + +*/ +PAR_ERROR CSBIGCam::DumpLines(unsigned short noLines) +{ + DumpLinesParams dlp; + + dlp.ccd = m_eActiveCCD; + dlp.lineLength = noLines; + dlp.readoutMode = m_uReadoutMode; + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_DUMP_LINES, &dlp, NULL); + else + return m_eLastError; +} + +/* + + SetTemperatureRegulation: + + Enable or disable the temperatre controll at + the passed setpoint which is the absolute + (not delta) temperature in degrees C. + +*/ +PAR_ERROR CSBIGCam::SetTemperatureRegulation(MY_LOGICAL enable, double setpoint) +{ + PAR_ERROR e; + + SetTemperatureRegulationParams strp; + + if ( CheckLink() ) { + strp.regulation = enable ? REGULATION_ON : REGULATION_OFF; + strp.ccdSetpoint = DegreesCToAD(setpoint, TRUE); + e = SBIGUnivDrvCommand(CC_SET_TEMPERATURE_REGULATION, &strp, NULL); + if (e != CE_NO_ERROR) return e; + // enable autofreeze, by Andre + strp.regulation = REGULATION_ENABLE_AUTOFREEZE; + return SBIGUnivDrvCommand(CC_SET_TEMPERATURE_REGULATION, &strp, NULL); + } + else + return m_eLastError; +} + +/* + + QueryTemperatureStatus: + + Get whether the cooling is enabled, the CCD temp + and setpoint in degrees C and the percent power + applied to the TE cooler. + +*/ +PAR_ERROR CSBIGCam::QueryTemperatureStatus(MY_LOGICAL &enabled, double &ccdTemp, + double &setpointTemp, double &percentTE) +{ + QueryTemperatureStatusResults qtsr; + + if ( CheckLink() ) { + if ( SBIGUnivDrvCommand(CC_QUERY_TEMPERATURE_STATUS, NULL, &qtsr) == CE_NO_ERROR ) + { + enabled = qtsr.enabled; + ccdTemp = ADToDegreesC(qtsr.ccdThermistor, TRUE); + setpointTemp = ADToDegreesC(qtsr.ccdSetpoint, TRUE); + percentTE = qtsr.power/255.0 * 100; + } + } + return m_eLastError; +} + +/* + + GetCCDTemperature: + + Read and return the current CCD temperature. + +*/ +PAR_ERROR CSBIGCam::GetCCDTemperature(double &ccdTemp) +{ + double setpointTemp, percentTE; + MY_LOGICAL teEnabled; + + return QueryTemperatureStatus(teEnabled, ccdTemp, setpointTemp, percentTE); +} + + +/* + + ActivateRelay: + + Activate one of the four relays for the passed + period of time. Cancel a relay by passing + zero for the time. + +*/ +PAR_ERROR CSBIGCam::ActivateRelay(CAMERA_RELAY relay, double time) +{ + ActivateRelayParams arp; + unsigned short ut; + + if ( CheckLink() ) { + arp.tXMinus = arp.tXPlus = arp.tYMinus = arp.tYPlus = 0; + if ( time >= 655.35 ) + ut = 65535; + else + ut = (unsigned short)(time/0.01); + switch ( relay ){ + case RELAY_XPLUS: arp.tXPlus = ut; break; + case RELAY_XMINUS: arp.tXPlus = ut; break; + case RELAY_YPLUS: arp.tXPlus = ut; break; + case RELAY_YMINUS: arp.tXPlus = ut; break; + } + return SBIGUnivDrvCommand(CC_ACTIVATE_RELAY, &arp, NULL); + } + else + return m_eLastError; +} + +/* + + AOTipTilt: + + Send a tip/tilt command to the AO-7. + +*/ +PAR_ERROR CSBIGCam::AOTipTilt(AOTipTiltParams attp) +{ + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_AO_TIP_TILT, &attp, NULL); + else + return m_eLastError; +} + +/* + + CFWCommand: + + Send a command to the Color Filter Wheel. + +*/ +PAR_ERROR CSBIGCam::CFWCommand(CFWParams cfwp, CFWResults &cfwr) +{ + if ( CheckLink() ) + return SBIGUnivDrvCommand(CC_CFW, &cfwp, &cfwr); + else + return m_eLastError; +} + +/* + + EstablishLink: + + Once the driver and device are open call this to + establish a communications link with the camera. + May be called multiple times without problem. + + If there's no error and you want to find out what + model of camera was found use the GetCameraType() + function. + +*/ +PAR_ERROR CSBIGCam::EstablishLink(void) +{ + PAR_ERROR res; + EstablishLinkResults elr; + EstablishLinkParams elp; + + res = SBIGUnivDrvCommand(CC_ESTABLISH_LINK, &elp, &elr); + if ( res == CE_NO_ERROR ) + m_eCameraType = (CAMERA_TYPE)elr.cameraType; + return res; +} + +/* + + GetErrorString: + + Returns a ANSI C++ standard string object describing + the error code returned from the lass call to the driver. + +*/ +string CSBIGCam::GetErrorString() +{ + return GetErrorString(m_eLastError); +} + +/* + + CheckLink: + + If a link has been established to a camera return TRUE. + Otherwise try to establish a link and if successful + return TRUE. If fails return FALSE. + +*/ +MY_LOGICAL CSBIGCam::CheckLink(void) +{ + if ( m_eCameraType != NO_CAMERA || EstablishLink() == CE_NO_ERROR ) + return TRUE; + else + return FALSE; +} + +/* + + DegreesCToAD: + + Convert temperatures in degrees C to + camera AD setpoints. + +*/ +unsigned short CSBIGCam::DegreesCToAD(double degC, MY_LOGICAL ccd /* = TRUE */) +{ + double r; + unsigned short setpoint; + + if ( degC < -50.0 ) + degC = -50.0; + else if ( degC > 35.0 ) + degC = 35.0; + if ( ccd ) { + r = R0 * exp(log(RR_CCD)*(T0 - degC)/DT_CCD); + setpoint = (unsigned short)(MAX_AD/((RB_CCD/r) + 1.0) + 0.5); + } else { + r = R0 * exp(log(RR_AMB)*(T0 - degC)/DT_AMB); + setpoint = (unsigned short)(MAX_AD/((RB_AMB/r) + 1.0) + 0.5); + } + return setpoint; +} + +/* + + ADToDegreesC: + + Convert camera AD temperatures to + degrees C + +*/ +double CSBIGCam::ADToDegreesC(unsigned short ad, MY_LOGICAL ccd /* = TRUE */) +{ + double r, degC; + + if ( ad < 1 ) + ad = 1; + else if ( ad >= MAX_AD - 1 ) + ad = MAX_AD - 1; + if ( ccd ) { + r = RB_CCD/(((double)MAX_AD/ad) - 1.0); + degC = T0 - DT_CCD*(log(r/R0)/log(RR_CCD)); + } else { + r = RB_AMB/(((double)MAX_AD/ad) - 1.0); + degC = T0 - DT_AMB*(log(r/R0)/log(RR_AMB)); + } + return degC; +} diff --git a/src/drivers/camfits.st7/csbigcam.h b/src/drivers/camfits.st7/csbigcam.h new file mode 100644 index 00000000..264f8aea --- /dev/null +++ b/src/drivers/camfits.st7/csbigcam.h @@ -0,0 +1,113 @@ +/* + + csbigcam.h - Contains the interface to the csbigcam + camera class + + 1. This software (c)2004 Santa Barbara Instrument Group. + 2. This free software is provided as an example of how + to communicate with SBIG cameras. It is provided AS-IS + without any guarantees by SBIG of suitability for a + particular purpose and without any guarantee to be + bug-free. If you use it you agree to these terms and + agree to do so at your own risk. + 3. Any distribution of this source code to include these + terms. + +*/ +#ifndef _CSBIGCAM_ +#define _CSBIGCAM_ + +#ifndef _PARDRV_ + #include "sbigudrv.h" +#endif + +#ifndef _CSBIGIMG_ + #include "csbigimg.h" +#endif + +#include +using namespace std; + +typedef enum {RELAY_XPLUS, RELAY_XMINUS, RELAY_YPLUS, RELAY_YMINUS } CAMERA_RELAY; +typedef enum {SBDF_LIGHT_ONLY, SBDF_DARK_ONLY, SBDF_DARK_ALSO } SBIG_DARK_FRAME; + +class CSBIGCam { +private: + PAR_ERROR m_eLastError; + PAR_COMMAND m_eLastCommand; + short m_nDrvHandle; + CAMERA_TYPE m_eCameraType; + CCD_REQUEST m_eActiveCCD; + double m_dExposureTime; + unsigned short m_uReadoutMode; + ABG_STATE7 m_eABGState; + +public: + // Constructors/Destructors + CSBIGCam(); + CSBIGCam(OpenDeviceParams odp); + CSBIGCam(SBIG_DEVICE_TYPE dev); + ~CSBIGCam(); + void Init(); + + // Error Reporting Routines + PAR_ERROR GetError(); + string GetErrorString(); + string GetErrorString(PAR_ERROR err); + PAR_COMMAND GetCommand(); + + // Accessor Functions + double GetExposureTime(void) { return m_dExposureTime; } + void SetExposureTime(double exp) { m_dExposureTime = exp; } + CCD_REQUEST GetActiveCCD(void) { return m_eActiveCCD; } + void SetActiveCCD(CCD_REQUEST ccd) { m_eActiveCCD = ccd; } + unsigned short GetReadoutMode(void) { return m_uReadoutMode; } + void SetReadoutMode(unsigned short rm) { m_uReadoutMode = rm; } + CAMERA_TYPE GetCameraType(void) { return m_eCameraType; } + ABG_STATE7 GetABGState(void) { return m_eABGState; } + void SetABGState(ABG_STATE7 abgState) { m_eABGState = abgState; } + + // Driver/Device Routines + PAR_ERROR OpenDriver(); + PAR_ERROR CloseDriver(); + PAR_ERROR OpenDevice(OpenDeviceParams odp); + PAR_ERROR CloseDevice(); + PAR_ERROR GetDriverInfo(DRIVER_REQUEST request, GetDriverInfoResults0 &gdir); + + // High-Level Exposure Related Commands + PAR_ERROR GrabImage(CSBIGImg *pImg, SBIG_DARK_FRAME dark); + + // Low-Level Exposure Related Commands + PAR_ERROR StartExposure(SHUTTER_COMMAND shutterState); + PAR_ERROR EndExposure(void); + PAR_ERROR IsExposureComplete(MY_LOGICAL &complete); + PAR_ERROR StartReadout(StartReadoutParams srp); + PAR_ERROR EndReadout(void); + PAR_ERROR ReadoutLine(ReadoutLineParams rlp, MY_LOGICAL darkSubtract, unsigned short *dest); + PAR_ERROR DumpLines(unsigned short noLines); + + //Temperature Related Commands + PAR_ERROR GetCCDTemperature(double &ccdTemp); + PAR_ERROR SetTemperatureRegulation(MY_LOGICAL enable, double setpoint); + PAR_ERROR QueryTemperatureStatus(MY_LOGICAL &enabled, double &ccdTemp, + double &setpointTemp, double &percentTE); + + // Control Related Commands + PAR_ERROR ActivateRelay(CAMERA_RELAY relay, double time); + PAR_ERROR AOTipTilt(AOTipTiltParams attp); + PAR_ERROR CFWCommand(CFWParams cfwp, CFWResults &cfwr); + + // General Purpose Commands + PAR_ERROR EstablishLink(void); + string GetCameraTypeString(void); + + // Utility functions + MY_LOGICAL CheckLink(void); + unsigned short DegreesCToAD(double degC, MY_LOGICAL ccd = TRUE); + double ADToDegreesC(unsigned short ad, MY_LOGICAL ccd = TRUE); + + // Allows access directly to driver + PAR_ERROR SBIGUnivDrvCommand(short command, void *Params, void *Results); +}; + +#endif /* #ifndef _CSBIGCAM_ */ diff --git a/src/drivers/camfits.st7/csbigimg.cpp b/src/drivers/camfits.st7/csbigimg.cpp new file mode 100644 index 00000000..9851e207 --- /dev/null +++ b/src/drivers/camfits.st7/csbigimg.cpp @@ -0,0 +1,379 @@ +/* + + csbigimg.cpp - SBIG Image Class + + 1. This software (c)2004 Santa Barbara Instrument Group. + 2. This free software is provided as an example of how + to communicate with SBIG cameras. It is provided AS-IS + without any guarantees by SBIG of suitability for a + particular purpose and without any guarantee to be + bug-free. If you use it you agree to these terms and + agree to do so at your own risk. + 3. Any distribution of this source code to include these + terms. + + Revision History + Date Modification + ========================================================= + 1/26/04 Initial release + +*/ +#include "csbigimg.h" +#include +#include + +/* + + Local Constants + +*/ +#define FILE_VERSION 3 /* current header version written */ +#define DATA_VERSION 1 /* current data version written */ +#define HEADER_LEN 2048 +#define VERSION_STR "1.0" /* version of this class */ +#ifndef PI + #define PI 3.1415926535 +#endif + +/* + + CSBIGImg: + + Standard constructor. Init member variables. + +*/ +CSBIGImg::CSBIGImg() +{ + Init(); +} + +/* + + CSBIGImg: + + Alternate constructor. Try to allocate the image buffer. + +*/ +CSBIGImg::CSBIGImg(int height, int width) +{ + Init(); + AllocateImageBuffer(height, width); +} + +/* + + ~CSBIGImg: + + Deallocate the image buffer. + +*/ +CSBIGImg::~CSBIGImg() +{ + if ( m_pImage ) + delete m_pImage; + m_pImage = NULL; +} + +/* + + Init: + + Initialize the member variables with reasonable default values. + +*/ +void CSBIGImg::Init() +{ + string s1, s2; + + m_nHeight = m_nWidth = 0; + m_pImage = NULL; + m_imageStartTime = time(NULL); + m_dCCDTemperature = 25.0; + m_dExposureTime = m_dEachExposure = 1.0; + m_dTrackExposure = 0.0; + m_dFocalLength = 80.0; + m_dApertureArea = PI * 4.0 * 4.0; + m_dResponseFactor = 2000.0; + m_dPixelHeight = m_dPixelWidth = 0.009; + m_dEGain = 2.3; + m_uBackground = 0; + m_uRange = 65535; + m_uNumberExposures = 1; + m_uSaturationLevel = 65535; + m_uPedestal = 0; + m_uExposureState = ES_ABG_LOW | ES_ABG_RATE_FIXED | + ES_DCS_ENABLED | ES_DCR_DISABLED | ES_AUTOBIAS_ENABLED; + m_uReadoutMode = 0; + m_cImageNote = "Image acquired with CSBIGImg"; + m_cObserver = ""; + m_cHistory = "0"; + m_cFilter = "None"; + s1 = "CSBIGImg Ver "; + s2 = VERSION_STR; + m_cSoftware = s1 + s2; + m_cCameraModel = "ST-7"; +} + +/* + + SaveImage: + + Save the image in passed path and format. + Returns any file errors that occur. + +*/ +SBIG_FILE_ERROR CSBIGImg::SaveImage(const char *pFullPath, SBIG_IMAGE_FORMAT fmt) +{ + char header[HEADER_LEN]; + FILE *fp; + SBIG_FILE_ERROR res; + int i, cmpWidth; + unsigned char *pCmpData, *pRevData; + unsigned short byteTest = 0x1234; + MY_LOGICAL reverseBytes; + + switch ( fmt ) { + case SBIF_COMPRESSED: + /* SBIG Commpressed Format - create and write the image header + then compress and write each row of the image */ + CreateSBIGHeader(header, TRUE); + res = SBFE_MEMORY_ERROR; + pCmpData = new unsigned char[m_nWidth*2 + 2]; + if ( pCmpData ) + { + res = SBFE_OPEN_ERROR; + if ( (fp = fopen(pFullPath, "wb")) != 0 ) + { + res = SBFE_WRITE_ERROR; + if ( fwrite(header, HEADER_LEN, 1, fp) == 1 ) + { + for (i=0; i 0 && width > 0 ) { + m_pImage = new unsigned short[(long)height * width * sizeof(unsigned short)]; + if ( m_pImage ) { + m_nHeight = height; + m_nWidth = width; + } + memset(m_pImage, 0, 2L * m_nHeight * m_nWidth); + } + return m_pImage != NULL; +} + +void CSBIGImg::CreateSBIGHeader(char *pHeader, MY_LOGICAL isCompressed) +{ + char *p; + struct tm *plt; + + memset(pHeader, 0, HEADER_LEN); + plt = gmtime(&m_imageStartTime); + p = pHeader; + p += sprintf(p,"SBIG %sImage\n\r", isCompressed ? "Compressed " : ""); + p += sprintf(p,"File_version = %d\n\r",FILE_VERSION); + p += sprintf(p,"Data_version = %d\n\r",DATA_VERSION); + p += sprintf(p,"Exposure = %ld\n\r",m_dExposureTime < 0.01 ? 1 : + (long)(m_dExposureTime * 100.0 + 0.5)); + p += sprintf(p,"Focal_length = %1.3lf\n\r", m_dFocalLength); + p += sprintf(p,"Aperture = %1.4lf\n\r", m_dApertureArea); + p += sprintf(p,"Response_factor = %1.3lf\n\r",m_dResponseFactor); + p += sprintf(p,"Note = %s\n\r", m_cImageNote.length() == 0 ? "-" : + m_cImageNote.c_str()); + p += sprintf(p,"Background = %u\n\r", m_uBackground); + p += sprintf(p,"Range = %u\n\r", m_uRange); + p += sprintf(p,"Height = %d\n\r", m_nHeight); + p += sprintf(p,"Width = %d\n\r", m_nWidth); + p += sprintf(p,"Date = %02d/%02d/%02d\n\r", plt->tm_mon+1, plt->tm_mday, plt->tm_year % 100); + p += sprintf(p,"Time = %02d:%02d:%02d\n\r", plt->tm_hour, plt->tm_min, plt->tm_sec); + p += sprintf(p,"Exposure_state = %u\n\r", m_uExposureState); + p += sprintf(p,"Temperature = %1.2lf\n\r", m_dCCDTemperature); + p += sprintf(p,"Number_exposures = %d\n\r", m_uNumberExposures); + p += sprintf(p,"Each_exposure = %ld\n\r", m_dEachExposure < 0.01 ? 1 : + (long)(m_dEachExposure * 100.0 + 0.5)); + p += sprintf(p,"History = %s\n\r", m_cHistory.c_str()); + p += sprintf(p,"Observer = %s\n\r", m_cObserver.length() == 0 ? "-" : + m_cObserver.c_str()); + p += sprintf(p,"X_pixel_size = %1.4lf\n\r", m_dPixelWidth); + p += sprintf(p,"Y_pixel_size = %1.4lf\n\r", m_dPixelHeight); + p += sprintf(p,"Pedestal = %u\n\r", m_uPedestal); + p += sprintf(p,"E_gain = %1.2lf\n\r", m_dEGain); + + /* create user parameters */ + p += sprintf(p,"User_1 = %s\n\r", m_cSoftware.length() == 0 ? "-" : + m_cSoftware.c_str()); + p += sprintf(p,"User_2 = %s\n\r", m_cCameraModel.length() == 0 ? "-" : + m_cCameraModel.c_str()); + p += sprintf(p,"User_3 = Exposure = %1.3lf, Each_exposure = %1.3lf\n\r", + m_dExposureTime, m_dEachExposure); + p += sprintf(p,"User_4 = %s%d\n\r", "Y2KYear = ", plt->tm_year + 1900); + + /* create filter string */ + p += sprintf(p,"Filter = %s\n\r", m_cFilter.length() == 0 ? "-" : + m_cFilter.c_str()); + + /* create readout mode */ + p += sprintf(p,"Readout_mode = %u\n\r", m_uReadoutMode); + + /* create track time */ + p += sprintf(p,"Track_time = %ld\n\r", m_dTrackExposure < 0.01 ? 0 : + (long)(m_dTrackExposure * 100.0 + 0.5)); + + /* create saturation level */ + p += sprintf(p,"Sat_level = %u\n\r", m_uSaturationLevel); + p += sprintf(p,"End\n\r%c",0x1a); +} + +/* + + CompressSBIGData: + + Compress the imgRow row of pixel data into the pCmpData buffer, + returning the length of the combressed data in bytes. + +*/ +int CSBIGImg::CompressSBIGData(unsigned char *pCmpData, int imgRow) +{ + unsigned short us, *pImg; + unsigned char *puc; + int cmpLen, i; + long delta; + + pImg = m_pImage + (long)imgRow * m_nWidth; + puc = pCmpData + 2; // offset passed length + cmpLen = 0; + + // encode first pixel as is + us = *pImg++; + *puc++ = (unsigned char)(us & 0xFF); // ls byte first + *puc++ = (unsigned char)(us >> 8); + cmpLen += 2; + + // compress remaining pixels + for (i=1; i= -127 && delta <= 127 ) + { + // encode pixel as delta; + *puc++ = (unsigned char)delta; + cmpLen++; + if ( cmpLen >= 2*m_nWidth ) // make syre don't overwrite buffer + break; + } + else + { + // encode pixel directly + if ( cmpLen+3 >= 2*m_nWidth ) + break; + *puc++ = 0x80; + *puc++ = (unsigned char)(us & 0xFF); // ls byte first + *puc++ = (unsigned char)(us >> 8); + cmpLen += 3; + } + } + if ( i < m_nWidth ) + { + // compressed data is longer, simply copy uncompressed data + // note we don't use memcpy here because the the byte order + // in memory may be different that ls then ms required by + // the file + IntelCopyBytes(pCmpData + 2, imgRow); + cmpLen = 2 * m_nWidth; + } + // encode length at start of buffer + pCmpData[0] = (unsigned char)(cmpLen & 0xFF); // ls byte of len + pCmpData[1] = (unsigned char)(cmpLen >> 8); + return cmpLen + 2; +} + +/* + + IntelCopyBytes: + + Copy the imgRow row of pixels to the passed buffer + preserving the Intel byte order (ls them ms). + +*/ +void CSBIGImg::IntelCopyBytes(unsigned char *pRevData, int imgRow) +{ + int i; + unsigned short us, *pImg; + unsigned char *puc; + + pImg = m_pImage + (long)imgRow * m_nWidth; + puc = pRevData; + for (i=0; i> 8); + } +} diff --git a/src/drivers/camfits.st7/csbigimg.h b/src/drivers/camfits.st7/csbigimg.h new file mode 100644 index 00000000..3d7bf720 --- /dev/null +++ b/src/drivers/camfits.st7/csbigimg.h @@ -0,0 +1,157 @@ +/* + + csbigimg.h - Contains the definition of the interface to + the SBIG Image Class + + 1. This software (c)2004 Santa Barbara Instrument Group. + 2. This free software is provided as an example of how + to communicate with SBIG cameras. It is provided AS-IS + without any guarantees by SBIG of suitability for a + particular purpose and without any guarantee to be + bug-free. If you use it you agree to these terms and + agree to do so at your own risk. + 3. Any distribution of this source code to include these + terms. + +*/ +#ifndef _CSBIGIMG_ +#define _CSBIGIMG_ + +#ifndef _PARDRV_ + #include "sbigudrv.h" +#endif + +#include +#include +using namespace std; + +/* + + Exposure State Field Defines + +*/ +#define ES_ABG_MASK 0x0003 +#define ES_ABG_UNKNOWN 0x0000 +#define ES_ABG_LOW 0x0001 +#define ES_ABG_CLOCKED 0x0002 +#define ES_ABG_MID 0x0003 + +#define ES_ABG_RATE_MASK 0x00C0 +#define ES_ABG_RATE_FIXED 0x0000 +#define ES_ABG_RATE_LOW 0x0040 +#define ES_ABG_RATE_MED 0x0080 +#define ES_ABG_RATE_HI 0x00C0 + +#define ES_DCS_MASK 0x000c +#define ES_DCS_UNKNOWN 0x0000 +#define ES_DCS_ENABLED 0x0004 +#define ES_DCS_DISABLED 0x0008 + +#define ES_DCR_MASK 0x0030 +#define ES_DCR_UNKNOWN 0x0000 +#define ES_DCR_ENABLED 0x0010 +#define ES_DCR_DISABLED 0x0020 + +#define ES_AUTOBIAS_MASK 0x0100 +#define ES_AUTOBIAS_ENABLED 0x0100 +#define ES_AUTOBIAS_DISABLED 0x0000 + + +typedef enum { SBIF_COMPRESSED, SBIF_UNCOMPRESSED } SBIG_IMAGE_FORMAT; +typedef enum {SBFE_NO_ERROR, SBFE_OPEN_ERROR, SBRE_CLOSE_ERROR, SBFE_READ_ERROR, SBFE_WRITE_ERROR, + SBFE_FORMAT_ERROR, SBFE_MEMORY_ERROR } SBIG_FILE_ERROR; + +class CSBIGImg { +private: + int m_nHeight, m_nWidth; // image size in pixels + unsigned short *m_pImage; // pointer to image data + time_t m_imageStartTime; // time that light exposure started + double m_dCCDTemperature; // CCD Temp at start of exposure + double m_dExposureTime; // Exposure time in seconds + double m_dTrackExposure; // Exposure when tracking + double m_dEachExposure; // Snapshot time in seconds + double m_dFocalLength; // Lens/Telescope Focal Length in inches + double m_dApertureArea; // Lens/Telescope Aperture Are in Sq-Inches + double m_dResponseFactor; // Magnitude Calibration Factor + double m_dPixelHeight, m_dPixelWidth; // Pixel Dimensions in mm + double m_dEGain; // Electronic Gain, e-/ADU + unsigned short m_uBackground, m_uRange; // Display Background and Range + unsigned short m_uNumberExposures; // Number of exposures co-added + unsigned short m_uSaturationLevel; // Pixels at this level are saturated + unsigned short m_uPedestal; // Image Pedestal + unsigned short m_uExposureState; // Exposure State + unsigned short m_uReadoutMode; // Camera Readout Mode use to acquire image + string m_cImageNote; // Note attached to image + string m_cObserver; // Observer name + string m_cHistory; // Image History string of modification chars + string m_cFilter; // Filter name imaged through + string m_cSoftware; // Software App Name and Version + string m_cCameraModel; // Model of camera used to acquire image + +public: + /* Constructors/Destructor */ + CSBIGImg(); + CSBIGImg(int height, int width); + ~CSBIGImg(); + void Init(); + + /* Accessor Functions */ + int GetHeight() {return m_nHeight;} + int GetWidth() {return m_nWidth;} + unsigned short *GetImagePointer() {return m_pImage;} + void SetImageStartTime(time_t startTime){m_imageStartTime = startTime;} + time_t GetImageStartTime(void) {return m_imageStartTime;} + void SetCCDTemperature(double temp) {m_dCCDTemperature = temp;} + double GetCCDTemperature(void) {return m_dCCDTemperature;} + void SetExposureTime(double exp) {m_dExposureTime = exp;} + double GetExposureTime(void) {return m_dExposureTime;} + void SetEachExposure(double exp) {m_dEachExposure = exp;} + double GetEachExposure(void) {return m_dEachExposure;} + void SetFocalLength(double fl) {m_dFocalLength = fl;} + double GetFocalLength(void) {return m_dFocalLength;} + void SetApertureArea(double ap) {m_dApertureArea = ap;} + double GetApertureArea(void) {return m_dApertureArea;} + void SetResponseFactor(double resp) {m_dResponseFactor = resp;} + double GetResponseFactor(void) {return m_dResponseFactor;} + void SetPixelHeight(double ht) {m_dPixelHeight = ht;} + double GetPixelHeight(void) {return m_dPixelHeight;} + void SetPixelWidth(double wd) {m_dPixelWidth = wd;} + double GetPixelWidth(void) {return m_dPixelWidth;} + void SetEGain(double gn) {m_dEGain = gn;} + double GetEGain(void) {return m_dEGain;} + void SetBackground(unsigned short back) {m_uBackground = back;} + unsigned short GetBackground(void) {return m_uBackground;} + void SetRange(unsigned short range) {m_uRange = range;} + unsigned short GetRange(void) {return m_uRange;} + void SetSaturationLevel(unsigned short sat) {m_uSaturationLevel = sat;} + unsigned short GetSaturationLevel(void) {return m_uSaturationLevel;} + void SetNumberExposures(unsigned short no) {m_uNumberExposures = no;} + unsigned short GetNumberExposures(void) {return m_uNumberExposures;} + void SetTrackExposure(double exp) {m_dTrackExposure = exp;} + double GetTrackExposure(void) {return m_dTrackExposure;} + void SetReadoutMode(unsigned short rm) {m_uReadoutMode = rm;} + unsigned short GetReadoutMode(void) {return m_uReadoutMode;} + void SetPedestal(unsigned short ped) {m_uPedestal = ped;} + unsigned short GetPedestal(void) {return m_uPedestal;} + void SetExposureState(unsigned short es) {m_uExposureState = es;} + unsigned short GetExposureState(void) {return m_uExposureState;} + void SetImageNote(string str) {m_cImageNote = str;} + string GetImageNote(void) {return m_cImageNote;} + void SetObserver(string str) {m_cObserver = str;} + string GetObserver(void) {return m_cObserver;} + void SetHistory(string str) {m_cHistory = str;} + string GetHistory(void) {return m_cHistory;} + void SetCameraModel(string str) {m_cCameraModel = str;} + string GetCameraModel(void) {return m_cCameraModel;} + + /* File IO Routines */ + SBIG_FILE_ERROR SaveImage(const char *pFullPath, SBIG_IMAGE_FORMAT fmt); + + /* Utility Functions */ + MY_LOGICAL AllocateImageBuffer(int height, int width); + void CreateSBIGHeader(char *pHeader, MY_LOGICAL isCompressed); + int CompressSBIGData(unsigned char *pCmpData, int imgRow); + void IntelCopyBytes(unsigned char *pRevData, int imgRow); +}; + +#endif /* #ifndef _CSBIGIMG_ */ diff --git a/src/drivers/camfits.st7/getindex.c b/src/drivers/camfits.st7/getindex.c new file mode 100644 index 00000000..42d616ad --- /dev/null +++ b/src/drivers/camfits.st7/getindex.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +static int matchfits(const struct dirent *d); + +static char pattern[256]; + + +// returns last index of bfname-####.fits +int getindex(char *bfname) +{ + struct dirent **namelist; + int nd; + char scanfmt[256]; + char dirc[256]; + char basec[256]; + char *dir, *base; + char *lastent; + int lastindex; + + strncpy(dirc, bfname, 255); + strncpy(basec, bfname, 255); + dir = dirname(dirc); + base = basename(basec); + + snprintf(pattern, 255, "%s-[0-9][0-9][0-9][0-9].fits", base); + + //find files that match pattern, see matchfits() below + nd = scandir(dir, &namelist, matchfits, alphasort); + if (nd == 0) // no file with this base name + return -1; + + // extract index from filename + snprintf(scanfmt, 255, "%s-%%d.fits", base); + lastent = namelist[nd-1]->d_name; + sscanf(lastent, scanfmt, &lastindex); + + /* TODO: must somehow free the space allocated by scandir() + for (i = 0; i < nd; i++) { + free(namelist[i]->d_name); + } + free(namelist); + */ + + return lastindex; + +} + + + +int matchfits(const struct dirent *d) +{ + //printf("pattern: %s\nfname : %s\n\n", pattern, d->d_name); + return !fnmatch(pattern, d->d_name, FNM_PATHNAME); +} diff --git a/src/drivers/camfits.st7/getindex.h b/src/drivers/camfits.st7/getindex.h new file mode 100644 index 00000000..87886373 --- /dev/null +++ b/src/drivers/camfits.st7/getindex.h @@ -0,0 +1,14 @@ +#ifndef GETINDEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +int getindex(char *bfname); + +#ifdef __cplusplus +} +#endif + +#define GETINDEX_H +#endif diff --git a/src/drivers/camfits.st7/main.cpp b/src/drivers/camfits.st7/main.cpp new file mode 100644 index 00000000..fcf40eb3 --- /dev/null +++ b/src/drivers/camfits.st7/main.cpp @@ -0,0 +1,671 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "fitsio.h" +#include "csbigcam.h" +#include "getindex.h" + +using namespace std; + + +#define PROGRAM_NAME "SBIG CCD camera controller" + +#define boolstring(x) (x?"true":"false") +#define shutterstate (openshutter?"OPEN":"CLOSED") +#define selectedccd (ccd?"tracking":"imaging") + + +// filled by get_args() +int verbose; +char *exec_name; // Name of executable file +static char *conffname; // configuration file +static char *bfname; // image base file name +static char imagefname[256]; // image file name +static double exptime; // seconds +static int interval; // seconds +static int nexp; // number of exposures +static int openshutter; // 1: open, 0: closed +static unsigned short binning; +static SBIG_DEVICE_TYPE device;// camera device +static CCD_REQUEST ccd; // imaging=0, tracking=1 +static ABG_STATE7 abg; // abg state +static unsigned short filter; // color filter. +static unsigned short top, left, width, height; // image window +static int tr; // set temperature regulation (if set to 1) +static double setpoint; // target temperature for regulation + +static void print_title(void); +static void print_help(void); +static void print_version(void); +static void print_usage(void); +static void get_args(int argc, char **argv); + + +/*-------------------------------------------------------------------------*/ + +int main(int argc, char **argv) +{ + CSBIGCam *cam; + PAR_ERROR err; + unsigned short *data; + + char errmsg[255]; + char buffer[80]; + + // get command line arguments + get_args(argc, argv); + + if (verbose) { + print_version(); + // list arguments + printf("\n*** Options:\n\n"); + printf("Exptime : %'.2f seconds\n", exptime); + printf("Interval: %d seconds\n", interval); + printf("Nexp : %d\n", nexp); + printf("Shutter : %s\n", shutterstate); + printf("Binning : %d\n", binning); + printf("Filter : %d\n", filter); + printf("Device : %x\n", device); + printf("CCD : %s\n", selectedccd); + printf("Temperature regulation: %d\n", tr); + printf("Setpoint temperature : %'.1f C\n", setpoint); + printf("ABG state: %d\n", abg); + printf("top : %d\n", top); + printf("height: %d\n", height); + printf("left : %d\n", left); + printf("width : %d\n", width); + printf("Output: %s-####.fits\n\n", bfname); + //printf("Config file: %s\n", conffname); + } + + + // start talking to camera + cam = new CSBIGCam(device); + + if (verbose) { + printf("Establishing link... "); + fflush(stdout); + } + + err = cam->EstablishLink(); + if (err != CE_NO_ERROR) { + printf("Error linking to camera.\n"); + delete cam; + exit(1); + } + + if (verbose) printf("OK.\nCamera type: %s\n", + (cam->GetCameraTypeString()).c_str()); + + + // Do temperature regulation stuff + double ccd_temperature; + MY_LOGICAL ccd_tr_enabled; + double percentTE; + double ccd_setpoint; + + if (verbose) printf("\nReading temperature regulation status...\n"); + cam->QueryTemperatureStatus(ccd_tr_enabled, ccd_temperature, + ccd_setpoint, percentTE); + + if (verbose) { + printf("Temperature regulation: %s\n", + boolstring(ccd_tr_enabled)); + printf("Chip temperature: %'.1f C\n", + ccd_temperature); + printf("Setpoint temperature: %'.1f\n", + ccd_setpoint); + printf("TE regulation power: %'.0f%%\n\n", + percentTE); + } + + switch (tr) { + case 2: // set regulation and wait stabilization + if (setpoint == 1000) setpoint = ccd_setpoint; + printf("Activating temperature regulation.\n"); + printf("Target temperature: %'.1f C\n", + setpoint); + cam->SetTemperatureRegulation(1, setpoint); + + printf("Waiting temperature stabilization...\n"); + + // wait temperature regulation + for (;;) { + cam->QueryTemperatureStatus(ccd_tr_enabled, + ccd_temperature, + ccd_setpoint, percentTE); + if (verbose) printf("Current temperature is %'.1f C." + " Target: %'.1f C." + " TE regulation power: %'.0f%%\n", + ccd_temperature, setpoint, + percentTE); + if (fabs(ccd_temperature - setpoint) < 0.5) break; + sleep(5); + } + printf("Temperature regulation completed.\n"); + delete cam; + exit(0); + break; + + } + + + // allocate image buffer + data = (unsigned short*)calloc(width*height, sizeof(unsigned short)); + if (data == NULL) { + printf("Error malloc\'ing! :-/\n"); + delete cam; + exit(1); + } + + + // set up camera + cam->SetActiveCCD(ccd); + cam->SetExposureTime(exptime); + cam->SetReadoutMode(binning); + cam->SetABGState(abg); + + + // set filter + if (filter != 0) { + CFWResults cfwr; + CFWParams cfwp = {CFWSEL_CFW8, CFWC_GOTO, filter, + 0,0,NULL,0,NULL}; + + printf("Moving filter wheel to position %d... ", filter); + fflush(stdout); + cam->CFWCommand(cfwp, cfwr); + + //wait GOTO command finish + do { + usleep(500000); // .5 sec + cfwp.cfwCommand = CFWC_QUERY; + cam->CFWCommand(cfwp, cfwr); + //printf("status: %d\n", cfwr.cfwStatus); + } while (cfwr.cfwStatus == CFWS_BUSY); + printf("Done.\n"); + } + + + // start taking images + int i; + int index; + + // find last image + index = getindex(bfname) + 1; + + if (verbose) + printf("Taking %d images of %'.2f sec., with %d sec. interval.\n", + nexp, exptime, interval); + + for (i = 0; i < nexp; i++){ + int fitstatus = 0; + long int naxes[2]; + fitsfile *fptr = NULL; + + + // initialize file and header + naxes[0] = width; + naxes[1] = height; + + + // create file name + sprintf(imagefname,"%s-%04d.fits", bfname, index + i); + if(fits_create_file(&fptr, imagefname, &fitstatus)) { + fits_get_errstatus(fitstatus, errmsg); + printf("%s - criando arquivo\n", errmsg); + } + + + if(fits_create_img(fptr, USHORT_IMG, 2, naxes, &fitstatus)) { + fits_get_errstatus(fitstatus, errmsg); + printf("%s - criando imagem\n", errmsg); + } + + + // fill the header // FIXME add more header here + fits_update_key(fptr, TDOUBLE, "EXPTIME", &exptime, "Exposure Time (secs.)", &fitstatus); + +// // DETSIZE +// snprintf(buffer, 80, "[%d:%d,%d:%d]", 1, 2, 3, 4); +// fits_update_key(fptr, TSTRING, "DETSIZE", buffer, "Size of CCD detector", &fitstatus); + +// // CCDSEC +// snprintf(buffer, 80, "[%d:%d,%d:%d]", top, width, left, height); +// fits_update_key(fptr, TSTRING, "CCDSEC", buffer, "Region of CCD read", &fitstatus); + +// // DATASEC +// snprintf(buffer, 80, "[%d:%d,%d:%d]", top, width, left, height); +// fits_update_key(fptr, TSTRING, "DATASEC", buffer, "Region of CCD read", &fitstatus); + +// // BIASSEC +// snprintf(buffer, 80, "[%d:%d,%d:%d]", 1, 2, 3, 4); +// fits_update_key(fptr, TSTRING, "BIASSEC", buffer, "Bias level section", &fitstatus); + +// // TRIMSEC +// snprintf(buffer, 80, "[%d:%d,%d:%d]", 1, 2, 3, 4); +// fits_update_key(fptr, TSTRING, "TRIMSEC", buffer, "Useful section", &fitstatus); + +// // CCDSUM (for binning) +// snprintf(buffer, 80, "%d %d", &binning, &binning); +// fits_update_key(fptr, TSTRING, "CCDSUM", buffer, "CCD on-chip summing", &fitstatus); + + fits_write_date(fptr, &fitstatus); + + + // expose + printf("\nFile: %s\n", imagefname); + printf("Starting a %'.2f seconds exposure (shutter is %s)... ", + exptime, shutterstate); + fflush(stdout); + if (openshutter) + cam->StartExposure(SC_OPEN_SHUTTER); + else + cam->StartExposure(SC_CLOSE_SHUTTER); + + + // wait exposure done + MY_LOGICAL expcomplete; + + if (exptime < 0.5) + usleep((unsigned long)exptime*1000000UL + 50000UL); + else + sleep((unsigned int)(exptime+1.0)); + + cam->IsExposureComplete(expcomplete); + if (!expcomplete) do { + // check every 0.2 sec + usleep(200000UL); + cam->IsExposureComplete(expcomplete); + } while (!expcomplete); + cam->EndExposure(); + printf("Done.\n"); + + + // exposure complete, download data + StartReadoutParams srp; + ReadoutLineParams rlp; + + srp.ccd = ccd; + srp.readoutMode = binning; + srp.top = top; + srp.left = left; + srp.height = height; + srp.width = width; + + rlp.ccd = ccd; + rlp.readoutMode = binning; + rlp.pixelStart = left; + rlp.pixelLength = width; + + printf("Downloading image of size %dx%d... ", width, height); + fflush(stdout); + cam->StartReadout(srp); + unsigned short *dest = data; + int j; + for (j = 0; j < height; j++) { + dest = data + j*width; + cam->ReadoutLine(rlp, FALSE, dest); + } + cam->EndReadout(); + printf("Done.\n"); + + + // save file + //fitstatus = 0; + if(fits_write_img(fptr, TUSHORT, 1, (naxes[0] * naxes[1]), + data, &fitstatus)) { + fits_get_errstatus(fitstatus, errmsg); + printf("%s\n", errmsg); + } + + //fits_write_2d_usht(fptr, 0, naxes[0], + // naxes[0], naxes[1], data, &fitstatus); + + fits_close_file(fptr, &fitstatus); + + + // sleep until next image + if (i == nexp) break; + if (interval == 0) continue; + printf("Sleeping %d seconds until next image... ", interval); + fflush(stdout); + sleep(interval); + printf("Done.\n"); + + + } // imaging loop + printf("\nImaging complete.\n"); + + + // all done, clean up the mess + free(data); + delete cam; + + exit(0); +} + + +/*-------------------------------------------------------------------------*/ + +static void print_title(void) +{ + printf("%s - version: %s\n", PROGRAM_NAME, VERSION); +} + +/*-------------------------------------------------------------------------*/ + +static void print_help(void) +{ + print_title(); + print_usage(); + printf("Command line options:\n\n" + " -h / --help\n" + " This help screen.\n\n" + + " -v / --version\n" + " Display version and copyright information.\n\n" + + " -V / --verbose\n" + " Display more progress stuff.\n\n" + + " -C / --config-file CONFFILE\n" + " Read options from CONFFILE.\n\n" + + " -d / --device DEVICE\n" + " Use camera connected to DEVICE.\n" + " 0: USB (default)\n" + " 1: LPT1\n" + " 2: LPT2\n" + " 3: LPT3\n\n" + + " -c / --CCD N\n" + " Use imaging (0) or tracking (1) ccd.\n" + " Default: imaging.\n\n" + + " -r / --tregulation N\n" + " Control temperature regulation.\n" + " -1: Keep previous settings (default).\n" + " 0: Disable.\n" + " 1: Enable. If -T is present, change\n" + " setpoint temperature.\n" + " 2: Enable and wait temperature\n" + " stabilization. If -T is present,\n" + " change setpoint temperature.\n" + " With this option no imaging will\n" + " take place.\n\n" + + " -T / --temperature N\n" + " Setpoint temperature for regulation, in\n" + " degrees Celsius.\n\n" + + " -a / --ABG ABG_STATE\n" + " Antiblooming gate state during integration.\n" + " 0: Low (default).\n" + " 1: Clocked low.\n" + " 2: Clocked medium.\n" + " 3: Clocked high.\n\n" + + " -f / --filter N\n" + " Use Nth filter. N = 1 to 5\n" + " N = 0 (default) keeps the current filter.\n\n" + + " -t / --exptime TIME\n" + " Exposure time, in seconds.\n" + " Exposure times can be from 0.01 to 9999\n" + " seconds, in 0.01 sec. steps.\n" + " Default: 0 seconds.\n\n" + + " -n / --nexp N\n" + " Number of images to take.\n" + " Default: 1 image.\n\n" + + " -s / --openshutter 0/1\n" + " Open shutter? 0: No, 1: Yes.\n" + " Default: 0 - Shutter closed.\n\n" + + " -i / --interval TIME\n" + " Time interval between images, in seconds.\n" + " Default: 0 seconds.\n\n" + + " -w / --window X1:X2,Y1:Y2\n" + " Image window to be downloaded (zero-based).\n" + " Default: 0:765,0:510.\n\n" + + " -b / --binning N\n" + " Type of binning.\n" + " 0: No binning (default)\n" + " 1: 2x2\n" + " 2: 3x3\n\n" + + " -o / --output IMAGEFILE\n" + " Save image to IMAGEFILE.\n\n" + ); + + printf("\nFor more information visit the home page: %s\n", PROGRAM_URL); + exit(0); +} + +/*-------------------------------------------------------------------------*/ + +static void print_version(void) +{ + print_title(); + printf("Copyright (C) 2004 Andre Luiz de Amorim\n"); + printf("%s comes with NO WARRANTY,\n" + "to the extent permitted by law.\n", PROGRAM_NAME); + printf("You may redistribute copies of %s\n" + "under the terms of the GNU General Public License.\n" + "For more information about these matters,\n" + "see the files named COPYING.\n", PROGRAM_NAME); + + //exit(0); +} + +/*-------------------------------------------------------------------------*/ + +static void print_usage(void) +{ + printf("SYNTAX:\n" + " %s -t exptime -n nexp -d device -o imagefile\n\n" + " %s {-h|--help}\n\n", exec_name, exec_name); +} + +/*-------------------------------------------------------------------------*/ + +static void get_args(int argc, char **argv) +{ + int next_opt; + const char *short_options = "hvVC:d:c:r:T:a:f:t:n:s:i:w:b:o:"; + const struct option long_options [] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'v' }, + { "verbose", 0, NULL, 'V' }, + + { "config-file", 1, NULL, 'C' }, + { "device", 1, NULL, 'd' }, + { "CCD", 1, NULL, 'c' }, + { "tregulation", 1, NULL, 'r' }, + { "temperature", 1, NULL, 'T' }, + { "ABG", 1, NULL, 'a' }, + { "filter", 1, NULL, 'f' }, + { "exptime", 1, NULL, 't' }, + { "nexp", 1, NULL, 'n' }, + { "openshutter", 1, NULL, 's' }, + { "interval", 1, NULL, 'i' }, + { "window", 1, NULL, 'w' }, + { "binning", 1, NULL, 'b' }, + { "output", 1, NULL, 'o' }, + { NULL, 0, NULL, 0 } + }; + + // default values + exec_name = argv[0]; + verbose = 0; + conffname = NULL; + bfname = "img"; + filter = 0; // keep the same + device = DEV_USB; + ccd = CCD_IMAGING; + tr = -1; // keep the same + setpoint = 1000; // default value will be read from camera + abg = ABG_LOW7; + exptime = 0; + nexp = 1; + openshutter = 0; // dont open shutter + interval = 0; + binning = 0; // no binning + + top = 0; // full frame + left = 0; + width = 765; + height = 510; + + do { + next_opt = getopt_long(argc, argv, short_options, + long_options, NULL); + switch (next_opt) { + case 'h': + print_help(); + break; + + case 'v': + print_version(); + exit(0); + break; + + case 'V': + verbose = 1; + break; + + case 'C': + /* config file */ + conffname = optarg; + break; + + case 'd': + /* device */ + int temp; + sscanf(optarg, "%d", &temp); + switch (temp) { + case 0: + device = DEV_USB; + break; + + case 1: + device = DEV_LPT1; + break; + + case 2: + device = DEV_LPT2; + break; + + case 3: + device = DEV_LPT3; + break; + } // temp + break; + + case 'c': + /* ccd */ + sscanf(optarg, "%hu", &ccd); + break; + + case 'r': + /* temperature regulation */ + sscanf(optarg, "%d", &tr); + break; + + case 'T': + /* target temperature */ + sscanf(optarg, "%lf", &setpoint); + break; + + case 'a': + /* abg state */ + sscanf(optarg, "%hu", &abg); + break; + + case 'f': + /* filter */ + sscanf(optarg, "%hu", &filter); + break; + + case 't': + /* exposure time */ + sscanf(optarg, "%lf", &exptime); + break; + + case 'n': + /* number of images */ + sscanf(optarg, "%d", &nexp); + break; + + case 's': + /* open shutter? */ + sscanf(optarg, "%d", &openshutter); + break; + + case 'i': + /* time interval between images */ + sscanf(optarg, "%d", &interval); + break; + + case 'w': + /* set image window */ + sscanf(optarg, "%hu:%hu,%hu:%hu", + &left, &width, &top, &height); + // optarg comes as X1:X2,Y1:Y2, fix width and height + width -= left; + height -= top; + break; + + case 'b': + /* set readout mode */ + sscanf(optarg, "%hu", &binning); + break; + + case 'o': + /* base image file name */ + //imagefname = optarg; + bfname = optarg; + break; + + case '?': + /* Invalid option */ + print_usage(); + exit(1); + break; + + case -1: + /* end of options */ + break; + + default: + printf("Tell author he should read the getopt_long man page.\n"); + exit(1); + break; + } + } while (next_opt != -1); + +} + +/*-------------------------------------------------------------------------*/ + diff --git a/src/drivers/camfits.st7/sbigcamcap.cpp b/src/drivers/camfits.st7/sbigcamcap.cpp new file mode 100644 index 00000000..c4964165 --- /dev/null +++ b/src/drivers/camfits.st7/sbigcamcap.cpp @@ -0,0 +1,98 @@ +/* + * camfits.st7 - SBIG ST 7/8 Controller + * Copyright (C) 2005 Paulo Henrique Silva + * + * This file is part of camfits.st7 + * camfits.st7 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. + * + * camfits.st7 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 + * + */ + +/* $Id: sbigcamcap.cpp,v 1.1.2.1 2006/05/17 16:32:34 henrique Exp $ */ + +#include "sbigcamcap.h" +#include "csbigcam.h" + +using namespace std; + +int SBIGCamCap::loadData() { + + if(ccd == CCD_IMAGING) { + infoPars.request = 0; + } else if(ccd == CCD_TRACKING) { + infoPars.request = 1; + } + + if(cam->SBIGUnivDrvCommand(CC_GET_CCD_INFO, &infoPars, &infoRes0) == CE_NO_ERROR) { + + _ccdModel = infoRes0.name; + _ccdMaker = "SBIG"; + _ccdSubModel = ""; + + _nReadoutModes = infoRes0.readoutModes; + + for(int i = 0; i < _nReadoutModes; i++) { + ReadoutMode* m = new ReadoutMode; + m->width = infoRes0.readoutInfo[i].width; + m->height = infoRes0.readoutInfo[i].height; + m->pixelWidth = infoRes0.readoutInfo[i].pixelWidth; + m->pixelHeight = infoRes0.readoutInfo[i].pixelHeight; + m->gain = infoRes0.readoutInfo[i].gain; + m->modeFlag = infoRes0.readoutInfo[i].mode; + + _readoutModes.push_back(m); + + } + + _firmwareVersion = infoRes0.firmwareVersion; + + } else { + return 1; + } + + infoPars.request = 2; + + if(cam->SBIGUnivDrvCommand(CC_GET_CCD_INFO, &infoPars, &infoRes2) == CE_NO_ERROR) { + + _antiBlooming = infoRes2.imagingABG; + + } else { + return 1; + } + + if(ccd == CCD_IMAGING) { + infoPars.request = 4; + } else if(ccd == CCD_TRACKING) { + infoPars.request = 5; + } + + if(cam->SBIGUnivDrvCommand(CC_GET_CCD_INFO, &infoPars, &infoRes4) == CE_NO_ERROR) { + + unsigned short capbits; + + capbits = infoRes4.capabilitiesBits & CB_CCD_TYPE_MASK; + + _fullFrame = (((capbits) & (CB_CCD_TYPE_FULL_FRAME)) != 0); + _frameTransfer = (((capbits) & (CB_CCD_TYPE_FRAME_TRANSFER)) != 0); + + capbits = infoRes4.capabilitiesBits & CB_CCD_ESHUTTER_MASK; + + _interline = (((capbits) & (CB_CCD_ESHUTTER_YES)) != 0); + _shutter = (((capbits) & (CB_CCD_ESHUTTER_NO)) != 0); + + } else { + return 1; + } + +} diff --git a/src/drivers/camfits.st7/sbigcamcap.h b/src/drivers/camfits.st7/sbigcamcap.h new file mode 100644 index 00000000..035c1a60 --- /dev/null +++ b/src/drivers/camfits.st7/sbigcamcap.h @@ -0,0 +1,53 @@ +/* + * camfits.st7 - SBIG ST 7/8 Controller + * Copyright (C) 2005 Paulo Henrique Silva + * + * This file is part of camfits.st7 + * camfits.st7 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. + * + * camfits.st7 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 + * + */ + +/* $Id: sbigcamcap.h,v 1.1.2.1 2006/05/17 16:32:35 henrique Exp $ */ + +#ifndef _SBIG_CAM_CAP_h_ +#define _SBIG_CAM_CAP_h_ + +#include "ccdcap.h" +#include "csbigcam.h" + +class SBIGCamCap: public CCDCap { + +public: + SBIGCamCap(CSBIGCam* mCam, CCD_REQUEST mCcd): cam(mCam), + ccd(mCcd) { loadData(); }; + + virtual ~SBIGCamCap() { }; + +private: + + int loadData(); + + CSBIGCam* cam; + CCD_REQUEST ccd; + + GetCCDInfoParams infoPars; + GetCCDInfoResults0 infoRes0; + GetCCDInfoResults2 infoRes2; + GetCCDInfoResults4 infoRes4; + +}; + + +#endif // !_SBIG_CAM_CAP_H_ diff --git a/src/drivers/camfits.st7/st7.camera.xml b/src/drivers/camfits.st7/st7.camera.xml new file mode 100644 index 00000000..5183414a --- /dev/null +++ b/src/drivers/camfits.st7/st7.camera.xml @@ -0,0 +1,92 @@ + + + + + SBIG + Camera + + +camfits.st7 --device $device --CCD $ccd --filter $filter --exptime $exp_time --nexp $n_exp --openshutter $shutter --interval $interval --window $window --binning $binning --output $output + + + + + device + int + 0 + Device to connect. 0 = USB, 1 = LPT1, 2 = LPT2, ... + + + + ccd + int + 0 + CCD chip to use. 0 = Imaging, 1 = Tracking. + + + + filter + str + clear + Filter to use. Names come from filter device used. (Always will exists a clear one). + + + + exp_time + float + 1.0 + Integration time in seconds. Min and max comes from CCDcap. + + + + n_exp + int + 1 + Number of frames to take. + + + + shutter + bool + True + Open the shutter?. + + + + interval + float + 1.0 + Interval between exposures. + + + + window + str + 0:$max,0,$max + Sub-window to be readout. x1:y1,x2:y2. $max means the maximun value in the given direction. Math can be used, e.g. $max /2 (half chip) + + + + binning + int + 0 + Binning mode. Values come from CCDcap. + + + + output + str + img-$time-$object-$filter + Filename of the output image (wildcards allowed: $time, $object, $filter). + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/drivers/telgo.fake/Makefile.am b/src/drivers/telgo.fake/Makefile.am new file mode 100644 index 00000000..d302263e --- /dev/null +++ b/src/drivers/telgo.fake/Makefile.am @@ -0,0 +1,9 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = telgo.fake + +telgo_fake_SOURCES = errors.h fields.c fields.h main.c ser.c ser.h + +telgo_fake_LDADD = -lm -lcfitsio + +uts_driver_DATA = fake.telescope.xml diff --git a/src/drivers/telgo.fake/errors.h b/src/drivers/telgo.fake/errors.h new file mode 100644 index 00000000..e68db79a --- /dev/null +++ b/src/drivers/telgo.fake/errors.h @@ -0,0 +1,35 @@ +/*************************************************************************** + errors.h - description + ------------------- + begin : Wed Jun 14 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#define TRUE (1) +#define FALSE (0) + + + +#define ERR_OK (0) +#define ERR_OPENTTY (-1) +#define ERR_SERIAL (-2) +#define ERR_BAUDRATE (-3) +#define ERR_PARITY (-4) +#define ERR_STOPB (-5) +#define ERR_WRITE (-6) +#define ERR_READ (-7) +#define ERR_MEM (-8) +#define ERR_NOTRESPOND (-9) + +#define ERR_CAM (-50) +#define ERR_CMD (-51) +#define ERR_EXPOSE (-52) diff --git a/src/drivers/telgo.fake/fake.telescope.xml b/src/drivers/telgo.fake/fake.telescope.xml new file mode 100644 index 00000000..6112e058 --- /dev/null +++ b/src/drivers/telgo.fake/fake.telescope.xml @@ -0,0 +1,50 @@ + + + + + Fake + Telescope + + + telgo.fake -d $device -P $paranoia $ra,$dec + + + + + device + str + /dev/ttyS0 + Device to connect. + + + + paranoia + int + 1 + Iteration on Paranoia's mode. see man telgo.lx200 for more on Paranoia mode. + + + + ra + str + 00:00:00 + RA to slew. Hours mode. + + + + dec + str + 00:00:00 + DEC to slew. Sexagesimal mode. + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/drivers/telgo.fake/fields.c b/src/drivers/telgo.fake/fields.c new file mode 100644 index 00000000..494980c3 --- /dev/null +++ b/src/drivers/telgo.fake/fields.c @@ -0,0 +1,67 @@ +/*************************************************************************** + fields.c - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include +#include +#include "fields.h" + +/* char *fieldnames[] = { "EXPTIME", "START", "NEXP", "BFNAME", "INDEX", "BEGPIXX", "BEGPIXY", "ENDPIXX", "ENDPIXY" }; */ +extern char *fieldnames[]; + +#ifdef FIELDTEST +int main(void) +{ + field f; + char texto[] = " # EXPTIME 1.3 "; + + if (get_field(texto, &f) == EOF) { + puts("Comment line"); + return(1); + } + printf("The field is %s. Contents: %s\n\n", fieldnames[f.index], f.contents); + return(0); +} +#endif /* FIELDTEST */ + + + +int get_field(char *command, field *f) +{ + int i; + char tmp[MAX_FIELD_SIZE]; + char *ptr; + + if (command == NULL || *command == '\0') return(EOF); + /* find field type */ + ptr = tmp; + while (isspace(*command)) command++; + if (*command == COMMENT_CHAR) return(EOF); + while (!isspace(*command)) *ptr++ = *command++; + *ptr = '\0'; + for (i = 0; (i < 6) && strncmp(tmp, fieldnames[i], MAX_FIELD_SIZE); i++); + f->index = i; + + /* store field content */ + ptr = f->contents; + while (isspace(*command)) command++; + while (*ptr++ = *command++); + *(ptr -= 2) = '\0'; + +/* strcpy(f->contents, command); */ + return(i); +} + diff --git a/src/drivers/telgo.fake/fields.h b/src/drivers/telgo.fake/fields.h new file mode 100644 index 00000000..7e7df0ab --- /dev/null +++ b/src/drivers/telgo.fake/fields.h @@ -0,0 +1,32 @@ +/*************************************************************************** + fields.h - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef FIELDS_H +#define FIELDS_H +#define MAX_FIELD_SIZE 20 +#define MAX_FIELD_CONTENT 64 +#define COMMENT_CHAR '#' + +//extern char **fieldnames; + +typedef struct { + int index; + char contents[MAX_FIELD_CONTENT]; +} field; + +int get_field(char *command, field *f); + +#endif /* FIELDS_H */ diff --git a/src/drivers/telgo.fake/main.c b/src/drivers/telgo.fake/main.c new file mode 100644 index 00000000..f35d6193 --- /dev/null +++ b/src/drivers/telgo.fake/main.c @@ -0,0 +1,237 @@ +/*************************************************************************** + tel.c - description + ------------------- + begin : Wed Aug 1 2001 + copyright : (C) 2001 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "fields.h" +#include "errors.h" +#include "ser.h" + +/* enum { FALSE, TRUE };*/ +typedef enum { BUSY, WAIT } stat_t; + +/* mount types */ +enum { LAND, POLAR, ALTAZ }; + +struct ras { + int hh; + int mm; + int ss; +}; + +struct decs { + int dd; + int mm; + int ss; +}; + +typedef struct { + struct ras ra; + float ra_range; + struct decs dec; + float dec_range; + float lat; + float lon; + stat_t status; + int moving; + int mnt_type; + ser_info *serial; + char *outbuf; +} tel_info; + + +void wait_tel(tel_info *tel); +void usage(char *command); +void setup(void); +void status(tel_info *tel, stat_t stat); +void controlc(int signumber); + + +field f; +tel_info tel; +char *porta; +char linebuf[128]; +char outbuf[128]; +char fmask[20]; +char imgfname[50]; +int ram, rah, decm, decd; +float ras, decs; + +enum { QUIT, RA, DEC, ACTION }; +char *fieldnames[] = { "QUIT", "RA", "DEC", "ACTION" }; + +int main(int argc, char ** argv) +{ + + signal(SIGINT, controlc); + signal(SIGABRT, controlc); + + fprintf(stderr, "LX-200 Fake Telescope controller ver. 0.01f.\n\n"); + if (argc < 4) { + usage(argv[0]); + exit(1); + } + + porta = argv[1]; + + sscanf(argv[2], "%d:%d:%d", &tel.ra.hh, &tel.ra.mm, &tel.ra.ss); + sscanf(argv[3], "%d:%d:%d", &tel.dec.dd, &tel.dec.mm, &tel.dec.ss); + + printf("Moving to ra=%s dec=%s\n", argv[2], argv[3]); + //setup(); + + /*** Write Coords. ***/ + + tel.moving = TRUE; + /*set RA */ +/* sprintf(tel.outbuf, ":Sr%02d:%4.1f#", + tel.ra.hh, (double)tel.ra.mm + (double)tel.ra.ss / 60); + //printf(tel.outbuf); + //fflush(stdout); + write_serial(tel.serial, tel.outbuf, strlen(outbuf)); + read_serial(tel.serial, tel.outbuf, 128); + if (*(tel.outbuf) == '0') { + sprintf(tel.outbuf, ":Sr%02d:%4.1f#", + tel.ra.hh, (double)(tel.ra.mm + (tel.ra.ss / 60))); + write_serial(tel.serial, tel.outbuf, strlen(outbuf)); + read_serial(tel.serial, tel.outbuf, 128); + } */ +// fprintf(stderr, "%c", *(tel.outbuf)); + + /* set DEC */ +/* sprintf(tel.outbuf, ":Sd%02d*%02d#", + tel.dec.dd, tel.dec.mm); + write_serial(tel.serial, tel.outbuf, strlen(outbuf)); + read_serial(tel.serial, tel.outbuf, 128); + if (*(tel.outbuf) == '0') { + sprintf(tel.outbuf, ":Sd%02d*%02d#", + tel.dec.dd, tel.dec.mm); + write_serial(tel.serial, tel.outbuf, strlen(outbuf)); + read_serial(tel.serial, tel.outbuf, 128); + } */ +// fprintf(stderr, "%c", *(tel.outbuf)); + + /* move telescope */ +/* sprintf(tel.outbuf, ":MS#"); + write_serial(tel.serial, tel.outbuf, strlen(outbuf)); + read_serial(tel.serial, tel.outbuf, 128); +// fprintf(stderr, "%c", *(tel.outbuf)); +// fprintf(stderr, "\n%s\n", tel.outbuf); + + if (*(tel.outbuf) == '0') { + wait_tel(&tel); */ + sleep(5); + fprintf(stderr, "\nDone\n"); +/* } */ + //else fprintf(stderr, "\nCould not move\n"); + + + exit(0); +} + + +void wait_tel(tel_info *tel) +{ + int rah; + float ram; + int decd, decm; + float delta_dec; + float delta_ra; + char buf[64]; + + while (tel->moving) { + /* get current RA */ + strcpy(buf, ":GR#"); + write_serial(tel->serial, buf, strlen(buf)); + read_serial(tel->serial, buf, 64); + sscanf(buf, "%d:%f#", &rah, &ram); + + + /* get current DEC */ + strcpy(buf, ":GD#"); + write_serial(tel->serial, buf, strlen(buf)); + read_serial(tel->serial, buf, 64); + sscanf(buf, "%d%*c%d#", &decd, &decm); + + + /* are DEC and RA in range? */ + decd -= tel->dec.dd; + decm -= tel->dec.mm; + delta_dec = fabs(decd + (decm / 60)); + + rah -= tel->ra.hh; + ram -= tel->ra.mm; + ram -= ((double)tel->ra.ss / 60); + delta_ra = fabs(rah + (ram / 60)); + /* limpa a linha e escreve os deltas */ + fprintf(stderr, "\r "); + fprintf(stderr, "\rdelta-dec = %f; delta-ra = %f", delta_dec, delta_ra); + fflush(stderr); + if ((delta_dec < tel->dec_range) && (delta_ra < tel->ra_range)) + tel->moving = FALSE; + sleep(1); + } + sleep(1); +} + + +void usage(char *command) +{ + fprintf(stderr, "SYNTAX: %s terminal_device RA DEC\n\n", command); + fprintf(stderr, "E.g.: %s /dev/ttyS1 12:12:12 13:12:14\n\n", command); +} + + +/* sets up telescope structs and initializes its parameters */ +void setup(void) +{ + tel.serial = (ser_info*) calloc(sizeof(ser_info), 1); + open_serial(tel.serial, porta); + if (tel.serial->err_code != ERR_OK) { + free(tel.serial); + abort(); + } + + /* 9600,8n1 */ + tel.serial->baudrate = B9600; + tel.serial->parity = PAR_NONE; + tel.serial->stopbits = 1; + tel.serial->timeout = 5; + tel.serial->minchars = 20; + tel.serial->waitread = TRUE; + set_serial(tel.serial); + + tel.ra_range = 0.007; /* 1min */ + tel.dec_range = 0.007; /* 1min */ + tel.moving = FALSE; + tel.status = BUSY; + tel.outbuf = outbuf; + +} + + +void controlc(int signumber) +{ + if (signumber == SIGINT) + fprintf(stderr, "\nControl-C signal caught, exiting.\n"); + else + fprintf(stderr, "\nAborting...\n"); + exit(2); +} diff --git a/src/drivers/telgo.fake/ser.c b/src/drivers/telgo.fake/ser.c new file mode 100644 index 00000000..1a250b50 --- /dev/null +++ b/src/drivers/telgo.fake/ser.c @@ -0,0 +1,267 @@ +/*************************************************************************** + ser.c - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 file contains the functions for serial communication */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "errors.h" +#include "ser.h" + +static void rdtimeout(int signumber); +static int set_minchars(ser_info *serial, int nbytes); +static ser_info *sertmp; + +#ifdef COMMTEST + +/* This example program writes a string in port `tty', and waits until + timeout for a response. */ + + +char teste[] = "Write test..."; +unsigned char buf[25]; +char tty[] = "/dev/ttyS1"; + + +int main(void) +{ + int result; + ser_info porta; + + open_serial(&porta, tty); + if (porta.err_code != ERR_OK) return(-1); + puts("Communication test.\n\n"); + + /* 9600,8e1 */ + porta.baudrate = B9600; + porta.parity = PAR_EVEN; + porta.stopbits = 1; + porta.timeout = 10; + porta.minchars = 25; + porta.waitread = FALSE; + set_serial(&porta); + write_serial(&porta, teste, strlen(teste)); + + if (read_serial(&porta, buf, 24)) + printf("Text received: %s\n\n", buf); + else printf("Read timeout.\n\n"); + + close_serial(&porta); + return(0); +} +#endif /* COMMTEST */ + + +int is_valid_serial(ser_info *serial) +{ + if ((serial == NULL) || + (serial->tty_name == NULL) || + (serial->tio == NULL) || + (serial->oldtio == NULL)) + return(FALSE); + return(TRUE); +} + + +void open_serial(ser_info *serial, char *ttyname) +{ + if (serial == NULL) return; + + serial->err_code = ERR_OK; + signal(SIGALRM, rdtimeout); + +/* Allocate memory for the structures */ + serial->tio = (struct termios *) malloc(sizeof(struct termios)); + if (serial->tio == NULL) { + serial->err_code = ERR_MEM; + return; + } + serial->oldtio = (struct termios *) malloc(sizeof(struct termios)); + if (serial->oldtio == NULL) { + serial->err_code = ERR_MEM; + return; + } + + serial->tty_name = (char *) calloc(strlen(ttyname), sizeof(char)); + if (serial->tty_name == NULL) { + serial->err_code = ERR_MEM; + return; + } + strcpy(serial->tty_name, ttyname); + + + serial->ttyfd = open(serial->tty_name, O_RDWR | O_NOCTTY); + if (serial->ttyfd < 0) { + serial->err_code = ERR_OPENTTY; + close_serial(serial); + return; + } + +/* Save current config */ + tcgetattr(serial->ttyfd, serial->oldtio); + serial->isopen = TRUE; +} + + +int close_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + signal(SIGALRM, SIG_DFL); +/* Restore terminal to its previous state; free memory */ + if (serial->isopen) { + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + close(serial->ttyfd); + } + if (serial->tio != NULL) free(serial->tio); + if (serial->oldtio != NULL) free(serial->oldtio); + if (serial->tty_name != NULL) free(serial->tty_name); + return(ERR_OK); +} + + +int set_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(ERR_SERIAL); + } + memset(serial->tio, 0, sizeof(struct termios)); + + cfsetospeed(serial->tio, serial->baudrate); + cfsetispeed(serial->tio, serial->baudrate); + +/* Set byte size to 8bit, enable reading and set local mode */ + serial->tio->c_cflag |= CS8 | CLOCAL | CREAD; + switch (serial->parity) { + case PAR_NONE: + serial->tio->c_iflag |= IGNPAR; + serial->tio->c_cflag &= ~PARENB; + break; + + case PAR_EVEN: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= ~PARODD; + break; + + case PAR_ODD: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= PARODD; + break; + default: + serial->err_code = ERR_PARITY; + return(ERR_PARITY); + } + + if (serial->stopbits == 1) + serial->tio->c_cflag &= ~CSTOPB; + else if (serial->stopbits ==2) + serial->tio->c_cflag |= CSTOPB; + else { + serial->err_code = ERR_STOPB; + return(ERR_STOPB); + } + +/* Raw input */ + serial-> tio->c_lflag = 0; + + serial->tio->c_cc[VTIME] = serial->timeout; + if (serial->waitread) + serial->tio->c_cc[VMIN] = serial->minchars; + + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + return(ERR_OK); +} + + +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + result = write(serial->ttyfd, buf, nbytes); + if (result < nbytes) { + serial->err_code = ERR_WRITE; + return(result); + } + serial->err_code = ERR_OK; + return(result); +} + + +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + serial->err_code = ERR_OK; + +/* Set the minimum number of chars to read before returning */ + if (serial->waitread && (serial->minchars != nbytes)) { + if (set_minchars(serial, nbytes) != ERR_OK) { + serial->err_code = ERR_SERIAL; + return(0); + } + } +/* save serial stuff for alarm() timeout. */ + sertmp = serial; + + alarm(serial->timeout); + result = read(serial->ttyfd, buf, nbytes); + alarm(0); + serial->bytesread = result; + if (result < nbytes) + serial->err_code = ERR_READ; + return(result); +} + + +static int set_minchars(ser_info *serial, int nbytes) +{ + if (!is_valid_serial(serial)) + return(ERR_MEM); + if (!serial->waitread) + return(ERR_READ); + serial->minchars = nbytes; + serial->tio->c_cc[VMIN] = nbytes; + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + return(ERR_OK); +} + +static void rdtimeout(int signumber) +{ + fprintf(stderr, "Serial communication failed, closing %s...\n", sertmp->tty_name); + if (sertmp != NULL) close_serial(sertmp); + /* exit(-1); */ +} + diff --git a/src/drivers/telgo.fake/ser.h b/src/drivers/telgo.fake/ser.h new file mode 100644 index 00000000..5547455e --- /dev/null +++ b/src/drivers/telgo.fake/ser.h @@ -0,0 +1,49 @@ +/*************************************************************************** + ser.h - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include + +#define RD_TIMEOUT (2) +#define TRUE (1) +#define FALSE (0) + +#define MAX_BUF_LEN (255) +#define PAR_NONE 'n' +#define PAR_EVEN 'e' +#define PAR_ODD 'o' + +typedef struct { + int isopen; + int waitread; + int err_code; + char *tty_name; + int ttyfd; + cc_t minchars; /* not used if waitread == FALSE */ + int bytesread; + int baudrate; + char parity; + int stopbits; + cc_t timeout; /* interchar time (1/10 secs), and read timeout (secs) */ + struct termios *tio; /* |- don't mess with these structs, */ + struct termios *oldtio; /* | the routines will handle it. */ +} ser_info; + +int is_valid_serial(ser_info *serial); +void open_serial(ser_info *serial, char *ttyname); +int close_serial(ser_info *serial); +int set_serial(ser_info *serial); +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); diff --git a/src/drivers/telgo.lx200/Makefile.am b/src/drivers/telgo.lx200/Makefile.am new file mode 100644 index 00000000..376c48c2 --- /dev/null +++ b/src/drivers/telgo.lx200/Makefile.am @@ -0,0 +1,9 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = telgo.lx200 + +telgo_lx200_SOURCES = errors.h main.c ser.c ser.h lx200.c lx200.h + +telgo_lx200_LDADD = -lm + +uts_driver_DATA = lx200.telescope.xml diff --git a/src/drivers/telgo.lx200/errors.h b/src/drivers/telgo.lx200/errors.h new file mode 100644 index 00000000..e68db79a --- /dev/null +++ b/src/drivers/telgo.lx200/errors.h @@ -0,0 +1,35 @@ +/*************************************************************************** + errors.h - description + ------------------- + begin : Wed Jun 14 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#define TRUE (1) +#define FALSE (0) + + + +#define ERR_OK (0) +#define ERR_OPENTTY (-1) +#define ERR_SERIAL (-2) +#define ERR_BAUDRATE (-3) +#define ERR_PARITY (-4) +#define ERR_STOPB (-5) +#define ERR_WRITE (-6) +#define ERR_READ (-7) +#define ERR_MEM (-8) +#define ERR_NOTRESPOND (-9) + +#define ERR_CAM (-50) +#define ERR_CMD (-51) +#define ERR_EXPOSE (-52) diff --git a/src/drivers/telgo.lx200/lx200.c b/src/drivers/telgo.lx200/lx200.c new file mode 100644 index 00000000..b3ba94cd --- /dev/null +++ b/src/drivers/telgo.lx200/lx200.c @@ -0,0 +1,348 @@ +#include +#include +#include +#include +#include +#include +#include "errors.h" +#include "ser.h" + +#include "lx200.h" + + +static void controlc(int signumber); + + +/*-------------------------------------------------------------------------*/ + + +int lx200_point(tel_info *tel, struct ras ra, struct decs dec) +{ + lx200_set_coords(tel, ra, dec); + lx200_slew(tel); + lx200_wait_slew(tel); + + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_wait_slew(tel_info *tel) +{ + struct ras Dra; //delta RA + struct decs Ddec; //delta DEC + int i = LX_SLEW_TIMEOUT; + + + + while (i--) { + lx200_update_coords(tel); + + // evaluate displacement. + Ddec.dd = tel->pdec.dd - tel->cdec.dd; + Ddec.mm = tel->pdec.mm - tel->cdec.mm; + Ddec.ss = tel->pdec.ss - tel->cdec.ss; + + Dra.hh = tel->pra.hh - tel->cra.hh; + Dra.mm = tel->pra.mm - tel->cra.mm; + Dra.ss = tel->pra.ss - tel->cra.ss; + + if (abs(Dra.hh) <= tel->ra_range.hh && + abs(Dra.mm) <= tel->ra_range.mm && + abs(Dra.ss) <= tel->ra_range.ss && + + abs(Ddec.dd) <= tel->dec_range.dd && + abs(Ddec.mm) <= tel->dec_range.mm && + abs(Ddec.ss) <= tel->dec_range.ss) { + //Close enough + sleep(10); + return (0); + } + sleep(1); + } + // bad, timeout :( + return (-1); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_update_coords(tel_info *tel) +{ + char cmd1[] = ":GR#"; + char cmd2[] = ":GD#"; + + /* get current RA */ + write_serial(tel->serial, cmd1, strlen(cmd1)); + read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + sscanf(tel->outbuf, "%d:%d:%d#", + &(tel->cra.hh), + &(tel->cra.mm), + &(tel->cra.ss)); + + + /* get current DEC */ + write_serial(tel->serial, cmd2, strlen(cmd2)); + read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + sscanf(tel->outbuf, "%d%*c%d:%d#", + &(tel->cdec.dd), + &(tel->cdec.mm), + &(tel->cdec.ss)); + return(0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_slew(tel_info *tel) +{ + char cmd[] = ":MS#"; + + // make sure tracking is ON + lx200_ra_drive_on(tel); + + write_serial(tel->serial, cmd, strlen(cmd)); + read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + if (*(tel->outbuf) != '0') // can not slew + return (-1); + + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_match_coords(tel_info *tel) +{ + char cmd[] = ":CM#"; + + write_serial(tel->serial, cmd, strlen(cmd)); + read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + // Finda way to check the success of this operation + + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_set_coords(tel_info *tel, struct ras ra, struct decs dec) +{ + /*set RA */ + sprintf(tel->outbuf, ":Sr %02d:%02d:%02d#", + ra.hh, ra.mm, ra.ss); + + write_serial(tel->serial, tel->outbuf, strlen(tel->outbuf)); + read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + /* set DEC */ + sprintf(tel->outbuf, ":Sd %02d*%02d:%02d#", + dec.dd, dec.mm, dec.ss); + + write_serial(tel->serial, tel->outbuf, strlen(tel->outbuf)); + read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + tel->pra = ra; + tel->pdec = dec; + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_set_precision(tel_info *tel, int precision) +{ + char cmd1[] = ":GR#"; + char cmd2[] = ":U#"; + int nb; + int rdprec; + + write_serial(tel->serial, cmd1, strlen(cmd1)); + nb = read_serial(tel->serial, tel->outbuf, LX_BUFSIZE); + + //depending on precision, "get RA returns: + // :NN:NN:NN# == 10 char, or + // :NN:NN.N# == 9 char. + + rdprec = (nb==LX_HIPRECISION_RESP)?LX_PRECISION_HIGH:LX_PRECISION_LOW; + if (rdprec != precision) write_serial(tel->serial, cmd2, strlen(cmd2)); + + return (0); + } + + +/*-------------------------------------------------------------------------*/ + + +/* sets up telescope structs and initializes its parameters */ +tel_info *lx200_open(char *device) +{ + tel_info *tel; + ser_info *ser; + + tel = calloc(sizeof(tel_info), 1); + tel->outbuf = calloc(sizeof(char), LX_BUFSIZE); + if(device == NULL) device = LX_DEFAULT_DEVICE; + ser = open_serial(device); + if (ser == NULL) { + free(tel->outbuf); + free(tel); + return (NULL); + } + /* 9600,8n1 */ + ser->baudrate = B9600; + ser->parity = PAR_NONE; + ser->stopbits = 1; + ser->timeout = 5; + ser->minchars = 20; + ser->waitread = TRUE; + set_serial(ser); + + tel->ra_range.hh = 0; + tel->ra_range.mm = 0; + tel->ra_range.ss = 1; + + tel->dec_range.dd = 0; + tel->dec_range.mm = 0; + tel->dec_range.ss = 3; + + tel->moving = FALSE; + tel->serial = ser; + + signal(SIGINT, controlc); + signal(SIGABRT, controlc); + + lx200_set_precision(tel, LX_PRECISION_HIGH); + lx200_update_coords(tel); + return (tel); +} + + +/*-------------------------------------------------------------------------*/ + + +void lx200_close(tel_info *tel) +{ + // stop/wait slewing and focus? + + close_serial(tel->serial); + free(tel); +} + + +/*-------------------------------------------------------------------------*/ + + +static void controlc(int signumber) +{ + if (signumber == SIGINT) + fprintf(stderr, "\nInterrupt signal caught, exiting.\n"); + else + fprintf(stderr, "\nAborting...\n"); + + /* if (tel.focus) + write_serial(tel.serial, ":FQ#", 4);*/ + exit(2); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_change_focus(tel_info *tel, int steps, int speed) +{ + if (steps == 0) { + lx200_focus_control(tel, LX_FOCUS_STOP, speed); + return (0); + } + + // start motor in which direction? + if (steps < 0) + lx200_focus_control(tel, LX_FOCUS_MINUS, speed); + + else + lx200_focus_control(tel, LX_FOCUS_PLUS, speed); + + // this kind of focuser really s**** + // sleep then stop motor + usleep(abs(steps) * LX_FOCUS_GAIN); + + lx200_focus_control(tel, LX_FOCUS_STOP, speed); + + return(0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_focus_control(tel_info *tel, int direction, int speed) +{ + char cmdSlow[] = ":FS#"; + char cmdFast[] = ":FF#"; + char cmdMinus[] = ":F-#"; + char cmdPlus[] = ":F+#"; + char cmdStop[] = ":FQ#"; + + + if (speed == LX_FOCUS_FAST) + write_serial(tel->serial, cmdFast, strlen(cmdFast)); + else + write_serial(tel->serial, cmdSlow, strlen(cmdFast)); + + switch (direction) { + case LX_FOCUS_MINUS: + write_serial(tel->serial, cmdMinus, strlen(cmdMinus)); + break; + case LX_FOCUS_PLUS: + write_serial(tel->serial, cmdPlus, strlen(cmdPlus)); + break; + case LX_FOCUS_STOP: + write_serial(tel->serial, cmdStop, strlen(cmdStop)); + break; + } + + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_ra_drive_off(tel_info *tel) +{ + char cmdGuideRate[] = ":RG#"; + char cmdMoveEast[] = ":Me#"; + + write_serial(tel->serial, cmdGuideRate, strlen(cmdGuideRate)); + write_serial(tel->serial, cmdMoveEast, strlen(cmdMoveEast)); + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int lx200_ra_drive_on(tel_info *tel) +{ + char cmdStop[] = ":Qe#"; + + write_serial(tel->serial, cmdStop, strlen(cmdStop)); + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + diff --git a/src/drivers/telgo.lx200/lx200.h b/src/drivers/telgo.lx200/lx200.h new file mode 100644 index 00000000..328e379b --- /dev/null +++ b/src/drivers/telgo.lx200/lx200.h @@ -0,0 +1,77 @@ +#ifndef LX200_H +#define LX200_H + +#include "ser.h" +#include "lx200.h" + + +#define LX_BUFSIZE 128 +#define LX_SLEW_TIMEOUT 30 // ~seconds +#define LX_DEFAULT_DEVICE "/dev/ttyS0" + +/* precision */ +#define LX_HIPRECISION_RESP 9 +#define LX_LOPRECISION_RESP 8 +enum { LX_PRECISION_LOW, LX_PRECISION_HIGH }; + +#define LX_FOCUS_GAIN 10000 /* 1/100 seconds */ +enum {LX_FOCUS_MINUS, LX_FOCUS_PLUS, LX_FOCUS_STOP}; // direction +enum {LX_FOCUS_SLOW, LX_FOCUS_FAST}; // speed + + + +struct ras { + int hh; + int mm; + int ss; +}; + + +struct decs { + int he; // celestial hesmisphere. +1 = N, -1 = S. + int dd; + int mm; + int ss; +}; + + +typedef struct { + struct ras pra; //pointed RA + struct ras cra; //current RA + struct ras ra_range; //maximum displacement allowed in RA + + struct decs pdec; //pointed DEC + struct decs cdec; //current DEC + struct decs dec_range; //maximum displacement allowed in DEC + + float lat; + float lon; + int moving; + int focus; + int mnt_type; + ser_info *serial; + char *outbuf; +} tel_info; + + + + +int lx200_set_coords(tel_info *tel, struct ras ra, struct decs dec); +int lx200_slew(tel_info *tel); +int lx200_update_coords(tel_info *tel); +int lx200_wait_slew(tel_info *tel); +int lx200_match_coords(tel_info *tel); + +int lx200_point(tel_info *tel, struct ras ra, struct decs dec); + +tel_info *lx200_open(char *device); +void lx200_close(tel_info *tel); + +int lx200_change_focus(tel_info *tel, int steps, int speed); +int lx200_focus_control(tel_info *tel, int direction, int speed); + +int lx200_ra_drive_on(tel_info *tel); +int lx200_ra_drive_off(tel_info *tel); + + +#endif /* LX200_H */ diff --git a/src/drivers/telgo.lx200/lx200.telescope.xml b/src/drivers/telgo.lx200/lx200.telescope.xml new file mode 100644 index 00000000..14cc9044 --- /dev/null +++ b/src/drivers/telgo.lx200/lx200.telescope.xml @@ -0,0 +1,50 @@ + + + + + MeadeLX200 + Telescope + + + telgo.lx200 -d $device -P $paranoia $ra,$dec + + + + + device + str + /dev/ttyS0 + Device to connect. + + + + paranoia + int + 1 + Iteration on Paranoia's mode. see man telgo.lx200 for more on Paranoia mode. + + + + ra + str + 00:00:00 + RA to slew. Hours mode. + + + + dec + str + 00:00:00 + DEC to slew. Sexagesimal mode. + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/drivers/telgo.lx200/main.c b/src/drivers/telgo.lx200/main.c new file mode 100644 index 00000000..9d17a789 --- /dev/null +++ b/src/drivers/telgo.lx200/main.c @@ -0,0 +1,460 @@ +/*************************************************************************** + tel.c - description + ------------------- + begin : Wed Aug 1 2001 + copyright : (C) 2001 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "lx200.h" + +/*-------------------------------------------------------------------------*/ + +#define PROGRAM_NAME "LX200/Compatible Telescope Controller" + +/*-------------------------------------------------------------------------*/ + +// filled by get_args() +int verbose; +char *exec_name; // Name of executable file +char *conffname; // configuration file +char *device; // serial device to connect + + +// Modes of operation +// TEL_POINT - Point to given coordinates +// TEL_MATCH - Perform coordinates match +// TEL_STOP - Stop RA drive / stop tracking + +#define TEL_POINT 0 +#define TEL_MATCH 1 +#define TEL_STOP 2 +#define TEL_FOCUS 3 +int mode; + +int focsteps; // how much? +int focspeed; // how fast? + +int paranoia; // level of paranoia while pointing. + // actually # of pointing iterations. + +int coords_present; // coordinates were given? +struct ras ra; // RA to point at. +struct decs dec; // DEC to point at. + +/*-------------------------------------------------------------------------*/ + +static void print_title(void); +static void print_help(void); +static void print_version(void); +static void print_usage(void); +static void show_options(void); +static void get_args(int argc, char **argv); + +int match_coords(tel_info *tel); +int point_telescope(tel_info *tel); +int change_focus(tel_info *tel); + + +/*-------------------------------------------------------------------------*/ + + +int main(int argc, char ** argv) +{ + tel_info *tel; + + // get command line arguments + get_args(argc, argv); + + if (verbose) { + print_version(); + show_options(); + } + + + if (verbose) printf("Opening device %s.\n", device); + tel = lx200_open(device); + + // match coords is exclusive + switch (mode) { + case TEL_POINT: + point_telescope(tel); + break; + + case TEL_MATCH: + match_coords(tel); + break; + + case TEL_FOCUS: + change_focus(tel); + break; + + case TEL_STOP: + printf("Stopping RA drive.\n"); + lx200_ra_drive_off(tel); + if (verbose) printf("Done.\n"); + break; + } + + lx200_close(tel); + exit (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int point_telescope(tel_info *tel) +{ + int i; + + printf("Pointing Telescope.\n"); + + if (verbose) + printf("Current position:\n" + " RA %02d:%02d:%02d\n" + " DEC %02d:%02d:%02d\n", + tel->cra.hh, tel->cra.mm, tel->cra.ss, + tel->cdec.dd, tel->cdec.mm, tel->cdec.ss); + + + if (verbose) printf("Setting destination coordinates:\n" + " RA %02d:%02d:%02d\n" + " DEC %02d:%02d:%02d\n", + ra.hh, ra.mm, ra.ss, + dec.dd, dec.mm, dec.ss); + + lx200_set_coords(tel, ra, dec); + + + for(i = 1; i <= paranoia; i++) { + if (verbose) printf("Sending GOTO command, pass #%d\n", i); + lx200_slew(tel); + + if (verbose) printf("Waiting telescope movement.\n"); + lx200_wait_slew(tel); + + if (verbose) + printf("New position:\n" + " RA %02d:%02d:%02d\n" + " DEC %02d:%02d:%02d\n", + tel->cra.hh, tel->cra.mm, tel->cra.ss, + tel->cdec.dd, tel->cdec.mm, tel->cdec.ss); + } + + printf("Pointing completed.\n"); + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int change_focus(tel_info *tel) +{ + if (verbose) + printf("Changing focus.\n" + "Amount: %d\n", focsteps); + + lx200_change_focus(tel, focsteps, focspeed); + + if (verbose) printf("Focus changed.\n"); + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +int match_coords(tel_info *tel) +{ + printf("Performing coordinates match.\n"); + + lx200_update_coords(tel); + lx200_match_coords(tel); + + if (verbose) printf("Coordinates matched:\n" + " RA %02d:%02d:%02d\n" + " DEC %02d:%02d:%02d\n", + tel->cra.hh, tel->cra.mm, tel->cra.ss, + tel->cdec.dd, tel->cdec.mm, tel->cdec.ss); + + printf("Coordinates match completed.\n"); + return (0); +} + + +/*-------------------------------------------------------------------------*/ + + +static void print_title(void) +{ + printf("%s - version: %s\n", PROGRAM_NAME, VERSION); +} + + +/*-------------------------------------------------------------------------*/ + + +void show_options(void) +{ + // list arguments + // default values + printf("\n*** Options:\n\n"); + printf("Device : %s\n", device); + printf("Paranoia : %d\n\n", paranoia); + + switch (mode) { + + case TEL_POINT: + printf("Mode: POINT\n"); + printf("\n*** Coordinates:\n\n"); + printf("RA : %02d:%02d:%02d\n", + ra.hh, ra.mm, ra.ss); + printf("DEC : %02d:%02d:%02d\n\n", + dec.dd, dec.mm, dec.ss); + break; + + case TEL_MATCH: + printf("Mode: MATCH\n"); + break; + + + case TEL_STOP: + printf("Mode: STOP\n"); + break; + + case TEL_FOCUS: + printf("Mode: FOCUS\n"); + printf("Speed : %d\n", focspeed); + printf("Steps : %d\n\n", focsteps); + break; + } +} + + +/*-------------------------------------------------------------------------*/ + + +static void print_help(void) +{ + print_title(); + print_usage(); + printf("Command line options:\n\n" + " -h / --help\n" + " This help screen.\n\n" + + " -v / --version\n" + " Display version and copyright information.\n\n" + + " -V / --verbose\n" + " Display more progress stuff.\n\n" + + " -C / --config-file CONFFILE\n" + " Read options from CONFFILE.\n\n" + + " -d / --device DEVICE\n" + " Use given serial port.\n" + " Default: /dev/ttyS0\n\n" + + " -m / --match-coords\n" + " Match the position of the telescope in the\n" + " sky to the last pointed coordinates.\n\n" + + " -S / --stop-ra-drive\n" + " Stops RA drive, no tracking will occur.\n\n" + + " -f / --focus N\n" + " Move focus N \"steps\", where N is a\n" + " positive or negative integer.\n\n" + + " -s / --focus-speed N\n" + " Speed of focus motor.\n" + " 0: Slow.\n" + " 1: Fast. (default)\n\n" + + " -P / --paranoia N\n" + " Paranoid pointing checking.\n\n" + " Perform N pointing iterations.\n" + " Default: 1 iteration.\n\n" + ); + + printf("\nFor more information visit our home page: %s\n", PROGRAM_URL); + exit(0); +} + +/*-------------------------------------------------------------------------*/ + +static void print_version(void) +{ + print_title(); + printf("Copyright (C) 2004 Andre Luiz de Amorim\n"); + printf("%s comes with NO WARRANTY,\n" + "to the extent permitted by law.\n", PROGRAM_NAME); + printf("You may redistribute copies of %s\n" + "under the terms of the GNU General Public License.\n" + "For more information about these matters,\n" + "see the files named COPYING.\n", PROGRAM_NAME); + + //exit(0); +} + +/*-------------------------------------------------------------------------*/ + +static void print_usage(void) +{ + printf("SYNTAX:\n" + " %s [options] \n\n" + " %s {-h|--help}\n\n" + " in the form HH:MM:SS.S\n" + " in the form +DD:MM:SS.S\n\n", exec_name, exec_name); +} + +/*-------------------------------------------------------------------------*/ + +static void get_args(int argc, char **argv) +{ + int next_opt; + const char *short_options = "hvVC:d:mSf:s:P:"; + const struct option long_options [] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'v' }, + { "verbose", 0, NULL, 'V' }, + { "config-file", 1, NULL, 'C' }, + { "device", 1, NULL, 'd' }, + { "match-coords", 0, NULL, 'm' }, + { "stop-ra-drive", 0, NULL, 'S' }, + { "focus", 1, NULL, 'f' }, + { "focus-speed", 1, NULL, 's' }, + { "paranoia", 1, NULL, 'P' }, + { NULL, 0, NULL, 0 } + }; + + // default values + exec_name = argv[0]; + verbose = 0; + conffname = NULL; + device = LX_DEFAULT_DEVICE; + mode = TEL_POINT; + focsteps = 0; + focspeed = 1; + paranoia = 1; + + + + do { + next_opt = getopt_long(argc, argv, short_options, + long_options, NULL); + switch (next_opt) { + case 'h': + print_help(); + break; + + case 'v': + print_version(); + exit(0); + break; + + case 'V': + verbose = 1; + break; + + case 'C': + /* config file */ + conffname = optarg; + break; + + case 'd': + /* device */ + device = optarg; + break; + + case 'm': + /* device */ + mode = TEL_MATCH; + return; // do nothing else when matching + break; + + case 'S': + /* stop RA drive */ + mode = TEL_STOP; + return; + break; + + + case 'f': + /* focus control */ + sscanf(optarg, "%d", &focsteps); + mode = TEL_FOCUS; + break; + + case 's': + /* focus speed */ + sscanf(optarg, "%d", &focspeed); + if (focspeed == 0) focspeed = LX_FOCUS_SLOW; + else focspeed = LX_FOCUS_FAST; + break; + + case 'P': + /* level of paranoia */ + sscanf(optarg, "%d", ¶noia); + break; + + + + case '?': + /* Invalid option */ + print_usage(); + exit(1); + break; + + case -1: + /* end of options */ + break; + + default: + printf("Tell author he should read the getopt_long man page.\n"); + exit(1); + break; + } + } while (next_opt != -1); + + if (mode == TEL_FOCUS) { + return; + } + + + // extra argument mandatory if in point mode + if(optind != argc-1 && mode == TEL_POINT) { + print_usage(); + exit(1); + } + + // read RA and DEC + coords_present = 1; + sscanf(argv[optind], "%d:%d:%d,%d:%d:%d", + &ra.hh, &ra.mm, &ra.ss, &dec.dd, &dec.mm, &dec.ss); + +} + +/*-------------------------------------------------------------------------*/ + diff --git a/src/drivers/telgo.lx200/ser.c b/src/drivers/telgo.lx200/ser.c new file mode 100644 index 00000000..174cea80 --- /dev/null +++ b/src/drivers/telgo.lx200/ser.c @@ -0,0 +1,269 @@ +/*************************************************************************** + ser.c - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 file contains the functions for serial communication */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "errors.h" +#include "ser.h" + +static void rdtimeout(int signumber); +static int set_minchars(ser_info *serial, int nbytes); +static ser_info *sertmp; + +#ifdef COMMTEST + +/* This example program writes a string in port `tty', and waits until + timeout for a response. */ + + +char teste[] = "Write test..."; +unsigned char buf[25]; +char tty[] = "/dev/ttyS1"; + + +int main(void) +{ + int result; + ser_info porta; + + open_serial(&porta, tty); + if (porta.err_code != ERR_OK) return(-1); + puts("Communication test.\n\n"); + + /* 9600,8e1 */ + porta.baudrate = B9600; + porta.parity = PAR_EVEN; + porta.stopbits = 1; + porta.timeout = 10; + porta.minchars = 25; + porta.waitread = FALSE; + set_serial(&porta); + write_serial(&porta, teste, strlen(teste)); + + if (read_serial(&porta, buf, 24)) + printf("Text received: %s\n\n", buf); + else printf("Read timeout.\n\n"); + + close_serial(&porta); + return(0); +} +#endif /* COMMTEST */ + + +int is_valid_serial(ser_info *serial) +{ + if ((serial == NULL) || + (serial->tty_name == NULL) || + (serial->tio == NULL) || + (serial->oldtio == NULL)) + return(FALSE); + return(TRUE); +} + + +ser_info *open_serial(char *ttyname) +{ + ser_info *serial; + +/* Allocate memory for the structures */ + serial = (ser_info *) calloc(sizeof(ser_info), 1); + if (serial == NULL) return (NULL); + + serial->tio = (struct termios *) calloc(sizeof(struct termios), 1); + serial->oldtio = (struct termios *) calloc(sizeof(struct termios), 1); + serial->tty_name = (char *) calloc(strlen(ttyname), sizeof(char)); + + if (serial->tio == NULL || + serial->oldtio == NULL || + serial->tty_name == NULL) { + free(serial->tio); + free(serial->oldtio); + free(serial->tty_name); + free(serial); + return(NULL); + } + + serial->err_code = ERR_OK; + signal(SIGALRM, rdtimeout); + strcpy(serial->tty_name, ttyname); + + serial->ttyfd = open(serial->tty_name, O_RDWR | O_NOCTTY); + if (serial->ttyfd < 0) { + serial->err_code = ERR_OPENTTY; + close_serial(serial); + return (NULL); + } + +/* Save current config */ + tcgetattr(serial->ttyfd, serial->oldtio); + serial->isopen = TRUE; + return (serial); +} + + +int close_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + signal(SIGALRM, SIG_DFL); +/* Restore terminal to its previous state; free memory */ + if (serial->isopen) { + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + close(serial->ttyfd); + } + free(serial->tio); + free(serial->oldtio); + free(serial->tty_name); + free(serial); + return(ERR_OK); +} + + +int set_serial(ser_info *serial) +{ + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(ERR_SERIAL); + } + memset(serial->tio, 0, sizeof(struct termios)); + + cfsetospeed(serial->tio, serial->baudrate); + cfsetispeed(serial->tio, serial->baudrate); + +/* Set byte size to 8bit, enable reading and set local mode */ + serial->tio->c_cflag |= CS8 | CLOCAL | CREAD; + switch (serial->parity) { + case PAR_NONE: + serial->tio->c_iflag |= IGNPAR; + serial->tio->c_cflag &= ~PARENB; + break; + + case PAR_EVEN: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= ~PARODD; + break; + + case PAR_ODD: + serial->tio->c_iflag &= ~IGNPAR; + serial->tio->c_cflag |= PARENB; + serial->tio->c_cflag &= PARODD; + break; + default: + serial->err_code = ERR_PARITY; + return(ERR_PARITY); + } + + if (serial->stopbits == 1) + serial->tio->c_cflag &= ~CSTOPB; + else if (serial->stopbits ==2) + serial->tio->c_cflag |= CSTOPB; + else { + serial->err_code = ERR_STOPB; + return(ERR_STOPB); + } + +/* Raw input */ + serial-> tio->c_lflag = 0; + + serial->tio->c_cc[VTIME] = serial->timeout; + if (serial->waitread) + serial->tio->c_cc[VMIN] = serial->minchars; + + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + return(ERR_OK); +} + + +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + result = write(serial->ttyfd, buf, nbytes); + if (result < nbytes) { + serial->err_code = ERR_WRITE; + return(result); + } + serial->err_code = ERR_OK; + return(result); +} + + +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes) +{ + int result; + + if (!is_valid_serial(serial)) return(ERR_MEM); + if (!serial->isopen) { + serial->err_code = ERR_SERIAL; + return(0); + } + serial->err_code = ERR_OK; + +/* Set the minimum number of chars to read before returning */ + if (serial->waitread && (serial->minchars != nbytes)) { + if (set_minchars(serial, nbytes) != ERR_OK) { + serial->err_code = ERR_SERIAL; + return(0); + } + } +/* save serial stuff for alarm() timeout. */ + sertmp = serial; + + alarm(serial->timeout); + result = read(serial->ttyfd, buf, nbytes); + alarm(0); + serial->bytesread = result; + if (result < nbytes) + serial->err_code = ERR_READ; + return(result); +} + + +static int set_minchars(ser_info *serial, int nbytes) +{ + if (!is_valid_serial(serial)) + return(ERR_MEM); + if (!serial->waitread) + return(ERR_READ); + serial->minchars = nbytes; + serial->tio->c_cc[VMIN] = nbytes; + tcsetattr(serial->ttyfd,TCSANOW,serial->tio); + return(ERR_OK); +} + +static void rdtimeout(int signumber) +{ + fprintf(stderr, "Serial communication failed, closing %s...\n", sertmp->tty_name); + if (sertmp != NULL) close_serial(sertmp); + /* exit(-1); */ +} + diff --git a/src/drivers/telgo.lx200/ser.h b/src/drivers/telgo.lx200/ser.h new file mode 100644 index 00000000..2429ce53 --- /dev/null +++ b/src/drivers/telgo.lx200/ser.h @@ -0,0 +1,56 @@ +/*************************************************************************** + ser.h - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef SER_H +#define SER_H + +#include + +#define RD_TIMEOUT (2) +#define TRUE (1) +#define FALSE (0) + +#define MAX_BUF_LEN (255) +#define PAR_NONE 'n' +#define PAR_EVEN 'e' +#define PAR_ODD 'o' + +typedef struct { + int isopen; + int waitread; + int err_code; + char *tty_name; + int ttyfd; + cc_t minchars; /* not used if waitread == FALSE */ + int bytesread; + int baudrate; + char parity; + int stopbits; + cc_t timeout; /* interchar time (1/10 secs), and read timeout (secs) */ + struct termios *tio; /* |- don't mess with these structs, */ + struct termios *oldtio; /* | the routines will handle it. */ +} ser_info; + +int is_valid_serial(ser_info *serial); +ser_info *open_serial(char *ttyname); +int close_serial(ser_info *serial); +int set_serial(ser_info *serial); +int read_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); +int write_serial(ser_info *serial, unsigned char *buf, unsigned int nbytes); + + +#endif /* SER_H */ diff --git a/src/drivers/telgo.paramount/Makefile.am b/src/drivers/telgo.paramount/Makefile.am new file mode 100644 index 00000000..6b0a9b7c --- /dev/null +++ b/src/drivers/telgo.paramount/Makefile.am @@ -0,0 +1,8 @@ +include $(top_srcdir)/rules.make + +bin_SCRIPTS = telgo.paramount.py telgo.server.py + +EXTRA_DIST = telgo.paramount.py telgo.server.py + +uts_driver_DATA = paramount.telescope.xml + diff --git a/src/drivers/telgo.paramount/paramount.telescope.xml b/src/drivers/telgo.paramount/paramount.telescope.xml new file mode 100644 index 00000000..25abb691 --- /dev/null +++ b/src/drivers/telgo.paramount/paramount.telescope.xml @@ -0,0 +1,50 @@ + + + + + Paramount + Telescope + + +telgo.paramount.py $server:$port $ra $dec + + + + + server + str + localhost + Server IP address. + + + + port + int + 10000 + Server port. + + + + ra + str + 00:00:00 + RA to slew. Hours mode. + + + + dec + str + 00:00:00 + DEC to slew. Sexagesimal mode. + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/drivers/telgo.paramount/telgo.paramount.py b/src/drivers/telgo.paramount/telgo.paramount.py new file mode 100644 index 00000000..dd43a72f --- /dev/null +++ b/src/drivers/telgo.paramount/telgo.paramount.py @@ -0,0 +1,97 @@ +#! /usr/bin/python + +import sys +import string + +from socket import * +import select + +__description__ = "Paramount ME telgo wrapper" +__version__ = "0.1" +__date__ = "01/03/2004" + +# parse arguments +if len(sys.argv) < 4: + print """ + %s - versao %s - %s + + Usage: %s server[:port] ra dec + Ex. : %s localhost:10000 +12:12:12 21:21:21 + %s server +12:12:12 21:21:21 + %s - +12:12:12 21:21:21 + + """ % (__description__, __version__, __date__, + sys.argv[0], sys.argv[0], sys.argv[0], sys.argv[0]) + + sys.exit(-1) + + +# get target host and port from command line +if ":" in sys.argv[1]: + target = string.split(sys.argv[1], ":") + target[1] = int(target[1]) +elif sys.argv[1] != "-": + target = [sys.argv[1], 10000] +else: + target = [gethostname(), 10000] + + +# helpful names +targetRA = sys.argv[2] +targetDEC = sys.argv[3] + +# connect, send coordinates, and wait until telescope stop + +try: + + skt = socket(AF_INET, SOCK_STREAM) + + print "Connecting to %s:%d... wait... " % tuple(target) + sys.stdout.flush() + skt.connect(tuple(target)) + print "OK" + + skt.sendall("%s*%s*MOVE" % (targetRA, targetDEC)) + + print "Moving to %s %s... wait... " % (targetRA, targetDEC) + sys.stdout.flush() + + # wait until telescope move + wait = select.select([skt], [], [skt], 60) + + if len(wait[0]) or len(wait[2]): + data = skt.recv(256) + + if data == "OK": + print "OK" + else: + print "ERROR (%s)" % data + else: + print "ERROR (Timeout)" + + skt.sendall("BYE") + + skt.close() + sys.exit(0) + +except KeyboardInterrupt: + print "Ctrl+C... exiting..." + skt.sendall("BYE") + skt.close() + sys.exit(1) + +except error, e: + print "ERROR (%s)" % (e[1]) + #skt.sendall("BYE") + skt.close() + sys.exit(1) + + + + + + + + + + diff --git a/src/drivers/telgo.paramount/telgo.server.py b/src/drivers/telgo.paramount/telgo.server.py new file mode 100644 index 00000000..4ae14dbc --- /dev/null +++ b/src/drivers/telgo.paramount/telgo.server.py @@ -0,0 +1,130 @@ +import sys +import win32com.client + +import servicemanager +from pywintypes import com_error + +from socket import * + +def _log(str): +# servicemanager.LogMsg( +# servicemanager.EVENTLOG_INFORMATION_TYPE, +# servicemanager.PYS_SERVICE_STOPPED, +# ("UTS", "%s" % str) +# ) + print str + sys.stdout.flush() + +class UTSException(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + +class UTSPointing: + + def __init__(self, port = 10000): + self.sk = None + self.port = port + + self.tel = None + self.util = None + + def start(self, findHome = True): + try: + self.tel = win32com.client.Dispatch("TheSky.Telescope") + self.thesky = win32com.client.Dispatch("TheSky.RASCOMTheSky") + self.util = win32com.client.Dispatch("DriverHelper.Util") + + self.sk = socket(AF_INET, SOCK_STREAM) + self.sk.bind((gethostname(), self.port)) + self.sk.listen(5) + + self.tel.Connected = True + self.thesky.Connect() + + if(findHome): + self.tel.FindHome() + + except error, e: + raise UTSException("Erro ao iniciar o servidor (%s)." % (e[1])) + + except AttributeError: + raise UTSException("Nao foi possivel conectar-se ao telescopio.\n" \ + "Verifique se o telescopio esta ligado e devidamente conectado ao computador.") + except com_error, e: + raise UTSException("Nao foi possivel criar os objetos COM. Contate o administrador." \ + "(%s)" % str(e)) + + def run(self): + + fim = False + + try: + + # connections loop + while not fim: + conn, addr = self.sk.accept() + _log("entrando %s:%s." % addr) + + # data loop + while 1: + data = conn.recv(1024) + + if not data: continue + + if data == "BYE": + conn.close() + break + if data in ("SHUTDOWN", "PARK"): + conn.close() + fim = True + break + else: + target = data.split('*') + targetRA = target[0] + targetDEC = target[1] + + _log("movendo para %s %s." % (str(targetRA), str(targetDEC))) + + self.tel.SlewToCoordinates(self.util.HMSToHours(targetRA), self.util.DMSToDegrees(targetDEC)) + + conn.send("OK") + # end of data loop + + conn.close() + _log("saindo") + + #end of connections loop + + except error, e: + raise UTSException("%s: %s", e[0],e[1]) + except com_error, e: + raise UTSException(str(e)) + + def stop(self, park = True): + if(park): + _log("parking...") + self.tel.Park() + + _log("closing...") + self.sk.close() + + self.tel.Connected = False + self.thesky.Quit() + +if __name__=='__main__': + + try: + uts = UTSPointing() + uts.start() + uts.run() + uts.stop() + + sys.exit(-1) + + except (UTSException, KeyboardInterrupt), e: + uts.stop() + print e + diff --git a/src/drivers/telgo.paramount/telgo.service.py b/src/drivers/telgo.paramount/telgo.service.py new file mode 100644 index 00000000..9ed828e6 --- /dev/null +++ b/src/drivers/telgo.paramount/telgo.service.py @@ -0,0 +1,33 @@ +import win32serviceutil, win32service +import pywintypes, win32con, winerror +import servicemanager + + +class UTSPointingService(win32serviceutil.ServiceFramework): + + _svc_name_ = "UTSPointingService" + _svc_display_name_ = "UTS Pointing Service" + + def __init__(self, args): + win32serviceutil.ServiceFramework.__init__(self, args) + + def SvcStop(self): + self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) + SetEvent(self.hWaitStop) + + def SvcDoRun(self): + servicemanager.LogMsg( + servicemanager.EVENTLOG_INFORMATION_TYPE, + servicemanager.PYS_SERVICE_STARTED, + (self._svc_name_, 'normal starting.') + ) + + servicemanager.LogMsg( + servicemanager.EVENTLOG_INFORMATION_TYPE, + servicemanager.PYS_SERVICE_STOPPED, + (self._svc_name_, "normal stop.") + ) + + +if __name__=='__main__': + win32serviceutil.HandleCommandLine(UTSPointingService) diff --git a/src/drivers/weather.wx200/Makefile.am b/src/drivers/weather.wx200/Makefile.am new file mode 100644 index 00000000..40ea1110 --- /dev/null +++ b/src/drivers/weather.wx200/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/rules.make + +uts_driver_DATA = wx200.weather.xml + diff --git a/src/drivers/weather.wx200/wx200.weather.xml b/src/drivers/weather.wx200/wx200.weather.xml new file mode 100644 index 00000000..a2ec2240 --- /dev/null +++ b/src/drivers/weather.wx200/wx200.weather.xml @@ -0,0 +1,29 @@ + + + + + WX200 + Weather + + +wx200 --nounits --celsius --temp $device + + + + + device + str + /dev/ttyS0 + Device to connect. + + + + verbose + bool + True + Verbose mode. + + + + + diff --git a/src/python/Makefile.am b/src/python/Makefile.am new file mode 100644 index 00000000..3cb950b3 --- /dev/null +++ b/src/python/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/rules.make + +SUBDIRS = uts + +EXTRA_DIST = *.py diff --git a/src/python/bin/uts b/src/python/bin/uts new file mode 100644 index 00000000..1b9846eb --- /dev/null +++ b/src/python/bin/uts @@ -0,0 +1,26 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-1 -*- + +import os +import sys + +here = os.path.dirname(os.path.realpath(__file__)) +swhome = os.path.dirname(here) + +for parts in [("src",), ("lib", "python"), ("Lib", "site-packages")]: + d = os.path.join(swhome, *(parts + ("uts", "core", "site"))) + if os.path.isdir(d): + d = os.path.join(swhome, *parts) + sys.path.insert(0, d) + break +else: + try: + import uts.core.site + except ImportError: + print >>sys.stderr, "Could not locate UTS software installation!" + sys.exit(1) + + +from uts.core.site import main + +sys.exit(main(sys.argv)) diff --git a/src/python/doc/doc.sh b/src/python/doc/doc.sh new file mode 100644 index 00000000..3d3600fd --- /dev/null +++ b/src/python/doc/doc.sh @@ -0,0 +1 @@ +epydoc --html -o doc/api --graph=umlclasstree --show-sourcecode --name "UTS - Unified Telescope System" uts diff --git a/src/python/doc/exemplo/exemplo.py b/src/python/doc/exemplo/exemplo.py new file mode 100644 index 00000000..c1672b36 --- /dev/null +++ b/src/python/doc/exemplo/exemplo.py @@ -0,0 +1,68 @@ +#! /usr/bin/python +# -*- coding: iso-8859-1 -*- + +_me = "EXEMPLO" + +_rpc = ["SLEW", + "STOP", + "INFO"] + +_notify = ["SLEW_COMPLETE"] + +import time + +from uts.core.instrument import Instrument + +class Exemplo(Instrument): + + def __init__(self): + Instrument.__init__(self, _me) + + # registra os callbacks responsáveis por cada um dos pontos + # de controle definidos em _rpc (na mesma ordem) + self.registerRPC([self.slew, + self.stop, + self.info]) + + # adiciona quantas secretárias externas forem necessárias +# self.addSec("WEATHER") +# self.addSec("CAFE") + +# self.notify("WEATHER", "HUMID", self.humidChanged) + +# def run(self): +# pass + + + def slew(self, event, data): + """ + slew callback: recebe um objeto Notify com informações sobre + quem enviou a ordem e uma lista de argumentos. + """ + + # slew ... + + # notifica os interessados que o telescópio chegou ao alvo. + self.status("SLEW_COMPLETE", "Chegou!") + print event + print data + + + def stop(self, event, data): + print event + print data + + def info(self, event, data): + print event + print data + time.sleep(1000) + + def inst_main(self): + print "Running main control function.. waiting.." + time.sleep(1) + +if __name__ == '__main__': + + e = Exemplo() + e.main() + diff --git a/src/python/doc/exemplo/falso_chefao.py b/src/python/doc/exemplo/falso_chefao.py new file mode 100644 index 00000000..e7cf5042 --- /dev/null +++ b/src/python/doc/exemplo/falso_chefao.py @@ -0,0 +1,43 @@ +#! /usr/bin/python +# -*- coding: iso-8859-1 -*- + +_me = "FALSO_CHEFAO" + + +from uts.core.instrument import Instrument + +class FalsoChefao(Instrument): + + def __init__(self): + Instrument.__init__(self, _me) + + # adiciona quantas secretárias externas forem necessárias + self.addSec("WEATHER") + self.notify("WEATHER", "LOW_TEMP", self.lowTemp) + self.notify("WEATHER", "HIGH_TEMP", self.highTemp) + + def lowTemp(self, event, data): + """ + lowTemp callback: + """ + # notifica os interessados que o telescópio chegou ao alvo. + # self.status("SLEW_COMPLETE", "Chegou!") + print event + print data + + + def highTemp(self, event, data): + """ + highTemp callback: + """ + # notifica os interessados que o telescópio chegou ao alvo. + # self.status("SLEW_COMPLETE", "Chegou!") + print event + print data + + +if __name__ == '__main__': + + e = FalsoChefao() + e.main() + diff --git a/src/python/setup.py b/src/python/setup.py new file mode 100644 index 00000000..19f4ced6 --- /dev/null +++ b/src/python/setup.py @@ -0,0 +1,13 @@ +#! /usr/bin/python + +from distutils.core import setup + +setup(name='uts', + version='0.1', + description='UTS python wrappers', + author='P. Henrique Silva', + author_email='heneique@astro.ufsc.br', + packages=['uts', 'uts.core', 'uts.controllers', 'uts.interfaces', 'uts.instruments', 'uts.util', 'uts.util.etree'], + package_data={'uts.core': ['log.config']}, + scripts=['bin/uts'] + ) diff --git a/src/python/test/uts.pylint b/src/python/test/uts.pylint new file mode 100644 index 00000000..bf5129a1 --- /dev/null +++ b/src/python/test/uts.pylint @@ -0,0 +1,353 @@ +# lint Python modules using external checkers. +# +# This is the main checker controling the other ones and the reports +# generation. It is itself both a raw checker and an astng checker in order +# to: +# * handle message activation / deactivation at the module level +# * handle some basic but necessary stats'data (number of classes, methods...) +# +# This checker also defines the following reports: +# * R0001: Total errors / warnings +# * R0002: % errors / warnings by module +# * R0003: Messages +# * R0004: Global evaluation +[MASTER] + +# Profiled execution. +profile=no + +# Add to the black list. It should be a base name, not a +# path. You may set this option multiple times. +ignore=CVS +ignore=etree + +# Pickle collected data for later comparisons. +persistent=yes + +# Set the cache size for astng objects. +cache-size=500 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[REPORTS] + +# Tells wether to display a full report or only the messages +reports=yes + +# Use HTML as output format instead of text +html=yes + +# Use a parseable text output format, so your favorite text editor will be able +# to jump to the line corresponding to a message. +parseable=no + +# Colorizes text output using ansi escape codes +color=no + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Python expression which should return a note less than 10 (10 is the highest +# note).You have access to the variables errors warning, statement which +# respectivly contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (R0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (R0004). +comment=no + +# Include message's id in output +include-ids=no + + +# checks for +# * unused variables / imports +# * undefined variables +# * redefinition of variable from builtins or from an outer scope +# * use of variable before assigment +# +[VARIABLES] + +# Enable / disable this checker +enable-variables=yes + +# Tells wether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching names used for dummy variables (i.e. not used). +dummy-variables-rgx=__|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +# try to find bugs in the code using type inference +# +[TYPECHECK] + +# Enable / disable this checker +enable-typecheck=yes + +# Tells wether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# When zope mode is activated, consider the acquired-members option to ignore +# access to some undefined attributes. +zope=no + +# List of members which are usually get through zope's acquisition mecanism and +# so shouldn't trigger E0201 when accessed (need zope=yes to be considered. +acquired-members=REQUEST,acl_users,aq_parent + + +# checks for : +# * doc strings +# * modules / classes / functions / methods / arguments / variables name +# * number of arguments, local variables, branchs, returns and statements in +# functions, methods +# * required module attributes +# * dangerous default values as arguments +# * redefinition of function / method / class +# * uses of the global statement +# +# This checker also defines the following reports: +# * R0101: Statistics by type +[BASIC] + +# Enable / disable this checker +enable-basic=yes + +# Required attributes for module, separated by a comma +required-attributes= + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k + +# Bad variable names which should always be refused, separated by a comma +bad-names=lixo + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + + +# checks for sign of poor/misdesign: +# * number of methods, attributes, local variables... +# * size, complexity of functions, methods +# +[DESIGN] + +# Enable / disable this checker +enable-design=yes + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=1 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +# checks for usage of new style capabilities on old style classes and +# other new/old styles conflicts problems +# * use of property, __slots__, super +# * "super" usage +# * raising a new style class as exception +# +[NEWSTYLE] + +# Enable / disable this checker +enable-newstyle=yes + + +# checks for +# * external modules dependencies +# * relative / wildcard imports +# * cyclic imports +# * uses of deprecated modules +# +# This checker also defines the following reports: +# * R0401: External dependencies +# * R0402: Modules dependencies graph +[IMPORTS] + +# Enable / disable this checker +enable-imports=yes + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report R0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report R0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report R0402 must +# not be disabled) +int-import-graph= + + +# checks for : +# * methods without self as first argument +# * overriden methods signature +# * access only to existant members via self +# * attributes not defined in the __init__ method +# * supported interfaces implementation +# * unreachable code +# +[CLASSES] + +# Enable / disable this checker +enable-classes=yes + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + + +# checks for +# * excepts without exception filter +# * string exceptions +# +[EXCEPTIONS] + +# Enable / disable this checker +enable-exceptions=yes + + +# does not check anything but gives some raw metrics : +# * total number of lines +# * total number of code lines +# * total number of docstring lines +# * total number of comments lines +# * total number of empty lines +# +# This checker also defines the following reports: +# * R0701: Raw metrics +[METRICS] + +# Enable / disable this checker +enable-metrics=yes + + +# checks for similarities and duplicated code. This computation may be +# memory / CPU intensive, so you should disable it if you experiments some +# problems. +# +# This checker also defines the following reports: +# * R0801: Duplication +[SIMILARITIES] + +# Enable / disable this checker +enable-similarities=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +# checks for: +# * warning notes in the code like FIXME, XXX +# * PEP 263: source code with non ascii character but no encoding declaration +# +[MISCELLANEOUS] + +# Enable / disable this checker +enable-miscellaneous=yes + +# List of note tags to take in consideration, separated by a comma. Default to +# FIXME, XXX, TODO +notes=FIXME,FIXME:,XXX,TODO,TODO: + + +# checks for : +# * unauthorized constructions +# * strict indentation +# * line length +# * use of <> instead of != +# +[FORMAT] + +# Enable / disable this checker +enable-format=yes + +# Maximum number of characters on a single line. +max-line-length=79 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' diff --git a/src/python/uts/Makefile.am b/src/python/uts/Makefile.am new file mode 100644 index 00000000..44a3fac9 --- /dev/null +++ b/src/python/uts/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/rules.make + +SUBDIRS = core instruments + +EXTRA_DIST = *.py diff --git a/src/python/uts/__init__.py b/src/python/uts/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/python/uts/__init__.py @@ -0,0 +1 @@ + diff --git a/src/python/uts/controllers/__init__.py b/src/python/uts/controllers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/core/Makefile.am b/src/python/uts/core/Makefile.am new file mode 100644 index 00000000..98fd35b4 --- /dev/null +++ b/src/python/uts/core/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = *.py diff --git a/src/python/uts/core/__init__.py b/src/python/uts/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/core/async.py b/src/python/uts/core/async.py new file mode 100644 index 00000000..4b8a1bd2 --- /dev/null +++ b/src/python/uts/core/async.py @@ -0,0 +1,61 @@ +import logging +import time + +from uts.core.threads import getThreadPool + +class AsyncResult(object): + + def __init__(self, func, pool = None): + + self.func = func + self.result = None + self.userCallback = False + + self.waiting = False + self.sleepTime = 0.1 + + self.pool = pool or getThreadPool(10) + + def __call__(self, *args, **kwargs): + logging.debug("calling synchronously %s with %s %s" % (self.func, + args, kwargs)) + + if(hasattr(self.func, "lock")): + self.func.lock.acquire() + + result = self.func(*args, **kwargs) + + if(hasattr(self.func, "lock")): + self.func.lock.release() + + return result + + def begin(self, *args, **kwargs): + logging.debug("calling asynchronously %s with %s %s" % (self.func, + args, kwargs)) + + if(not self.pool): + logging.error("Cannot run async calls, pool is not seted") + return False + + self.userCallback = kwargs.pop('callback', None) + self.waiting = True + + self.pool.queueTask(self.func, args, kwargs, self.resultCallback) + + return self + + def end(self): + while (self.waiting): + #wait + time.sleep(self.sleepTime) + + return self.result + + def resultCallback(self, result): + self.result = result + self.waiting = False + + if(self.userCallback): + self.userCallback(self.result) + diff --git a/src/python/uts/core/config.py b/src/python/uts/core/config.py new file mode 100644 index 00000000..d37d1157 --- /dev/null +++ b/src/python/uts/core/config.py @@ -0,0 +1,123 @@ +#! /usr/bin/python +# -*- coding: iso8859-1 -*- + +import sys +import logging + +import uts.util.etree.ElementTree as ET + +class SiteConfiguration(object): + + def __init__(self): + + self.__sites = [] + self.__instruments = [] + self.__controllers = [] + + def getInstruments(self): + + return self.__instruments + + def getControllers(self): + + return self.__controllers + + def getSites(self): + + return self.__sites + + def read(self, config): + + self._read(config) + + def _read(self, config): + + try: + + root = ET.parse(config) + + except IOError, e: + + logging.exception("Error opening %s" % config) + return False + + # ok, let's go! + + # sites (ok, just one site makes sense by now, but we can expand this later) + sites = root.findall("site") + + for site in sites: + + tmpSite = {} + tmpSite["name"] = site.get("name", "UFSC") + tmpSite["latitude"] = site.get("latitude", "0") + tmpSite["longitude"] = site.get("longitude", "0") + tmpSite["altitude"] = site.get("altitude", "0") + + self.__sites.append(tmpSite) + + # get all instruments + insts = root.findall("instruments/instrument") + + for inst in insts: + tmpInst = {} + tmpInst["name"] = inst.get("name", "inst" + str(len(self.__instruments) + 1)) + tmpInst["class"] = inst.get("class", object) + tmpInst["options"] = [] + + # get all options + opts = inst.findall("option") + + for opt in opts: + tmpOpt = {} + tmpOpt["name"] = opt.get("name") + tmpOpt["value"] = opt.get("value") + + tmpInst["options"].append(tmpOpt) + + self.__instruments.append(tmpInst) + + + ctrls = root.findall("controllers/controller") + + for ctrl in ctrls: + + tmpCtrl = {} + tmpCtrl["name"] = ctrl.get("name", "ctrl" + str(len(self.__controllers) + 1)) + tmpCtrl["class"] = ctrl.get("class", object) + tmpCtrl["options"] = [] + + # get all options + opts = ctrl.findall("option") + + for opt in opts: + tmpOpt = {} + tmpOpt["name"] = opt.get("name") + tmpOpt["value"] = opt.get("value") + + tmpCtrl["options"].append(tmpOpt) + + self.__controllers.append(tmpCtrl) + + + def dump(self): + for i in self.__instruments: + print i + + for c in self.__controllers: + print c + + for s in self.__sites: + print s + + +if __name__ == '__main__': + + import sys + + if(len(sys.argv) > 1): + + conf = SiteConfiguration() + conf.read(sys.argv[1]) + conf.dump() + diff --git a/src/python/uts/core/controller.py b/src/python/uts/core/controller.py new file mode 100644 index 00000000..90bf5831 --- /dev/null +++ b/src/python/uts/core/controller.py @@ -0,0 +1,13 @@ +import threading + +class Controller(object): + + def __init__(self, manager, location): + + self.manager = manager + self.location = location + self.term = threading.Event() + + def main(self): + pass + diff --git a/src/python/uts/core/driver.py b/src/python/uts/core/driver.py new file mode 100644 index 00000000..8d1a5f05 --- /dev/null +++ b/src/python/uts/core/driver.py @@ -0,0 +1,192 @@ +#! /usr/bin/python +# -*- coding: iso-8859-1 -*- + +import glob +import logging + +from string import Template +import uts.util.etree.ElementTree as ET + +class Driver(object): + + def __init__(self, config): + + self._config = config + + self._name = None + self._type = None + self._cmdline = None + + self._parameters = {} + + self._pars = {} + self._defaults = {} + + self._filterSet = {} + + self._parseConfig() + + def __iadd__(self, data): + + if not isinstance(data, dict): + return self + + for k,v in data.items(): + + try: + # FIXME type checking + self._pars[k] = v + except KeyError, e: + pass + + return self + + def __getitem__(self, item): + # FIXME type checking and conversion as appopriate + if item in self._pars: + return self._pars[item] + else: + raise KeyError + + def __setitem__(self, item, value): + # FIXME type checking + self._pars[item] = value + + def __contains__(self, item): + return (item in self._pars) + + def __len__(self): + return len(self._pars) + + def __iter__(self): + return iter(self._pars) + + def buildCommand(self, parameters = {}): + + # FIXME: $max on window, filter name to index, + # bool values, output wildcards + + # try to replace every parameter in parameters, + # if any parameters rest in blank use default value + + # use last-minute parameters + self += parameters + + t1 = Template(self._cmdline) + + s1 = t1.safe_substitute(self._pars) + + t2 = Template(s1) + s2 = t2.safe_substitute(self._defaults) + + return s2 + + def help(self): + + _str = "%s - %s\n===\n\n" % (self._name, self._type) + + if self._cmdline: + _str += "cmdline\n===\n\n%s\n\n" % self._cmdline + + if self._parameters: + _str += "parameters\n===\n\n" + + for par, value in self._parameters.items(): + _str += "# %s (type: %s, default: %s)\n%s\n\n" % (par, + value[0], + value[1], + value[2]) + + if self._filterSet: + _str += "Filter set\n===\n\n" + + for _filter, _index in self._filterSet.items(): + _str += "%d %s\n" % (_index, _filter) + + return _str[:-1] + + def _parseConfig(self): + + try: + + f = ET.parse(self._config) + + except IOError, e: + logging.error("Error opening %s (%s)" % (self._config, repr(e))) + return False + + + driver = f.getroot() + + self._type = driver.findtext("type") + self._name = driver.findtext("name") + self._cmdline = driver.findtext("cmdline") + + parameters = driver.findall('parameters/parameter') + + for parameter in parameters: + + p_name = parameter.findtext("name") + + p_type = parameter.findtext("type") + + p_default = parameter.findtext("default") + + p_doc = parameter.findtext("doc") + + # name => [type, default, doc] possible unchanged for the whole life of the driver + self._parameters[p_name] = [p_type, p_default, p_doc] + + # to speedup some things + self._pars[p_name] = p_default + self._defaults[p_name] = p_default + + + filters = driver.findall("filterset/filter") + + for _filter in filters: + f_index = _filter.findtext("index") + f_name = _filter.findtext("name") + + self._filterSet[f_name] = int(f_index) + + +class NullDriver(object): + def __init__(self): + pass + def help(self): + return "null driver" + +class DriverFactory(object): + + def __init__(self, base = '/etc/uts/drivers/'): + self.base = base + pass + + def get(self, drv): + + drivers = glob.glob('%s/*%s*.xml' % (self.base, drv)) + + if drivers: + driver = Driver(drivers[0]) + return driver + else: + return NullDriver() + +if __name__ == '__main__': + + import sys + + if (len (sys.argv) == 3): + driver = DriverFactory(sys.argv[1]).get(sys.argv[2]) + print driver.help() + +# if (len(sys.argv) > 1): + +# for inst in sys.argv[1:]: +# d = Driver(inst) +# d.buildCommand({}) +# print d.help() +# print + + diff --git a/src/python/uts/core/event.py b/src/python/uts/core/event.py new file mode 100644 index 00000000..8a89318a --- /dev/null +++ b/src/python/uts/core/event.py @@ -0,0 +1,79 @@ +#! /usr;bin/python +# -*- coding: iso-8859-1 -*- + +def event(f): + f.event = True + return f + +# based on this recipe http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/410686 +# by Zoran Isailovskii + +class EventsProxy: + + def __init__(self, evs): + self.__events__ = evs + + def __getattr__(self, name): + if hasattr(self, '__events__'): + assert name in self.__events__, "Event '%s' is not declared" % name + self.__dict__[name] = ev = _EventSlot(name) + return ev + + def __repr__(self): + return 'Events' + str(list(self)) + + def __str__(self): + return self.__repr__() + + def __contains__(self, attr): + return attr in self.__events__ + +class _EventSlot: + + def __init__(self, name): + self.targets = [] + self.__name__ = name + +# def __repr__(self): +# return 'event ' + self.__name__ + + def __call__(self, *a, **kw): + for f in self.targets: f(*a, **kw) + + def __iadd__(self, f): + self.targets.append(f) + return self + + def __isub__(self, f): + while f in self.targets: self.targets.remove(f) + return self + + +if __name__ == '__main__': + + from uts.core.instrument import Instrument + + class ExampleDefinition(Instrument): + + def __init__(self): + Instrument.__init__(self) + + def doSomething(self, data): + self.somethingHappened(self, data) + + @event + def somethingHappened(self, obj, data): + pass + + class ExampleUsage(object): + + def __init__(self, obj): + obj.somethingHappened += self.somethingHappened + + def somethingHappened(self, obj, data): + print self, obj, data + + ex = ExampleDefinition() + us = ExampleUsage(ex) + + ex.doSomething("now") diff --git a/src/python/uts/core/exceptions.py b/src/python/uts/core/exceptions.py new file mode 100644 index 00000000..56698b66 --- /dev/null +++ b/src/python/uts/core/exceptions.py @@ -0,0 +1,3 @@ + +class NotImplemented(Exception): + pass diff --git a/src/python/uts/core/instrument.py b/src/python/uts/core/instrument.py new file mode 100644 index 00000000..561f9d05 --- /dev/null +++ b/src/python/uts/core/instrument.py @@ -0,0 +1,88 @@ +import uts + +from uts.core.proxy import AsyncResult +from uts.core.event import EventsProxy + +import time + +import threading + +### TODO Add life cycle code (start/stop/query/etc) + +class InstrumentMeta(type): + + def __new__(metacls, clsname, bases, dictionary): + + _evs = [] + for name, obj in dictionary.iteritems(): + if callable(obj) and not name.startswith('__') and hasattr(obj, 'event'): + _evs.append(name) + + for name in _evs: + del dictionary[name] + + dictionary['__events__'] = _evs + + return super(InstrumentMeta, metacls).__new__(metacls, clsname, bases, dictionary) + + +class Instrument: + + __metaclass__ = InstrumentMeta + + def __init__(self, name): + + self.name = name + + self.manager = None + self.location = None + self.rpc = None + + self.driver = None + + self.events = EventsProxy(self.__events__) + + # loop control + self.timeslice = 0.5 + self.looping = False + + # term event + self.term = threading.Event() + + def __getattr__(self, attr): + if attr in self.events: + return self.events.__getattr__(attr) + else: + raise AttributeError + + def inst_main(self): + pass + + def main(self): + + # enter main loop + self._main() + + return True + + def _main(self): + + self.looping = True + + try: + + while(self.looping): + + if (self.term.isSet()): + self.looping = False + return + + # run instrument control functions + self.inst_main() + + time.sleep(self.timeslice) + + except KeyboardInterrupt, e: + self.looping = False + return + diff --git a/src/python/uts/core/location.py b/src/python/uts/core/location.py new file mode 100644 index 00000000..99c4b9cd --- /dev/null +++ b/src/python/uts/core/location.py @@ -0,0 +1,83 @@ +#! /usr/bin/python +# -*- coding: iso8859-1 -*- + +import re +import logging + +from types import (DictType, ListType, + TupleType, StringType) + + +class Location(object): + + def __init__(self, location): + + self._re = re.compile('/+(?P[\w]*)/+(?P[\w]*)\??(?P[\w=,]*)') + + self._class = "class" + self._name = "name" + self._options = {} + + self._valid = True + + try: + + if type(location) == DictType: + self._class = location["class"] + self._name = location["name"] + self._options = location["options"] + + elif type(location) in [ListType, TupleType]: + self._class = location[1] + self._name = location[2] + self._options = location[3] + + elif type(location) == StringType: + + (self._class, self._name, self._options) = matches = self.parse(location) + + except (KeyError, IndexError), e: + self._valid = False + + def isValid(self): + + return self._valid + + def parse(self, location): + + matches = self._re.search(location) + + if matches: + + cls, name, tmpOpts = matches.groups() + + opts = {} + + if tmpOpts: + for opt in tmpOpts.split(","): + k, v = opt.split("=") + opts[k.strip()] = v.strip() + + else : + self._valid = False + cls = "class" + name = "name" + opts = {} + + logging.debug("Invalid location %s." % location) + + return (cls, name, opts) + + def __eq__(self, loc): + + return (loc._class == self._class) and \ + (loc._name == self._name) + + def __repr__(self): + _str = "/%s/%s" % (self._class, + self._name) + + return _str + + def get(self): + return self.__repr__(self) diff --git a/src/python/uts/core/log.config b/src/python/uts/core/log.config new file mode 100644 index 00000000..d2eb1578 --- /dev/null +++ b/src/python/uts/core/log.config @@ -0,0 +1,44 @@ +[loggers] +keys=root,uts,instruments,controllers + +[handlers] +keys=err + +[formatters] +keys=uts + +[logger_root] +handlers=err +level=DEBUG + +[logger_uts] +handlers=err +level=DEBUG +propagate=0 +qualname=uts + +[logger_instruments] +handlers=err +level=DEBUG +propagate=1 +qualname=uts.instruments + +[logger_controllers] +handlers=err +level=DEBUG +propagate=1 +qualname=uts.controllers + +[formatter_uts] +format=%(asctime)s %(levelname)s %(name)s %(module)s:%(lineno)d %(message)s +datefmt=%d %m %Y %H %M %S (%j) + +[handler_novo] +class=FileHandler +formatter=uts +args=("/var/log/uts/uts.log", "a") + +[handler_err] +class=StreamHandler +formatter=uts +args=(sys.stderr,) diff --git a/src/python/uts/core/manager.py b/src/python/uts/core/manager.py new file mode 100644 index 00000000..a2dee068 --- /dev/null +++ b/src/python/uts/core/manager.py @@ -0,0 +1,145 @@ +#! /usr/bin/python +#! -*- coding: iso-8859-1 -*- + +from uts.core.register import Register +from uts.core.proxy import Proxy +from uts.core.location import Location + +import sys +import os.path +import logging + +class Manager(object): + + def __init__(self): + logging.debug("Starting manager.") + + self._includePath = [] + + self._instruments = Register() + self._controllers = Register() + + self._pool = None + + self._cache = { } + + def appendPath(self, path): + if not os.path.isabs(path): + path = os.path.abspath(path) + + logging.debug("Adding %s to include path." % path) + self._includePath.append(path) + + def setPool(self, pool): + self._pool = pool + + def addInstrument(self, location): + cls = self._getClass(location._class) + + if cls: + return self._instruments.register(location, cls(self, location)) + else: + return False + + def removeInstrument(self, location): + self._instruments.unregister(location) + + def addController(self, location): + cls = self._getClass(location._class) + + if cls: + return self._controllers.register(location, cls(self, location)) + else: + return False + + def removeController(self, location): + + self._controllers.unregister(location) + + def initInstrument(self, location): + + if(not location in self._instruments): + return False + + if(not self._pool): + logging.debug("There is no thread pool avaiable.") + logging.debug("You should create one and set with setPool.") + return False + + logging.debug("Initializing instrument %s." % location) + self._pool.queueTask(self._instruments[location].main) + + def initController(self, location): + + if(not location in self._controllers): + return False + + if(not self._pool): + logging.debug("There is no thread pool avaiable.") + logging.debug("You should create one and set with setPool.") + return False + + logging.debug("Initializing controller %s." % location) + self._pool.queueTask(self._controllers[location].main) + + def stopInstrument(self, location): + try: + self._instruments[location].term.set() + logging.debug("Stopping instrument %s." % location) + except KeyError: + return False + + def stopController(self, location): + try: + self._controllers[location].term.set() + logging.debug("Stopping controller %s." % location) + except KeyError: + return False + + def stopAll(self): + + for location in self._controllers.keys(): + self.stopController(location) + self.removeController(location) + + for location in self._instruments.keys(): + self.stopInstrument(location) + self.removeInstrument(location) + + def getProxy(self, location): + + # FIXME: extend to controllers + + inst = self._instruments.get(Location(location)) + + if inst: + return Proxy(inst, self._pool) + else: + return None + + def _getClass(self, name): + """ + Based on this recipe + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241 + by Jorgen Hermann + """ + + if name in self._cache: + return self._cache[name] + + for path in self._includePath: + if path not in sys.path: + sys.path.insert(0, path) + + try: + module = __import__(name.lower(), globals(), locals(), [name]) + logging.debug("Loading class %s from %s" % (name, module.__file__)) + + except ImportError: + logging.exception("Couldn't load class %s.\nsys.path = %s\nException follows..." % (name, sys.path)) + return None + + self._cache[name] = vars(module)[name] + + return self._cache[name] + diff --git a/src/python/uts/core/proxy.py b/src/python/uts/core/proxy.py new file mode 100644 index 00000000..a6f1bec2 --- /dev/null +++ b/src/python/uts/core/proxy.py @@ -0,0 +1,89 @@ +#! /usr/bin/python +# -*- coding: iso8859-1 -*- + + +import logging +import threading + +from uts.core.async import AsyncResult + +class Proxy(object): + + def __init__(self, obj, threadPool = None): + + self._obj = obj + self._pool = threadPool + + def __getattribute__(self, value): + obj = object.__getattribute__(self, '_obj') + pool = object.__getattribute__(self, '_pool') + + if(hasattr(obj, value)): + prop = getattr(obj, value) + +# if(callable(prop) and hasattr(prop, "event")): +# return AsyncEvent(prop, pool) + + if(callable(prop)): + return AsyncResult(prop, pool) + + # non callable, just returns + return prop + else: + raise AttributeError + +def lock(func): + func.lock = threading.Lock() + return func + + +if __name__ == '__main__': + + import time + import threading + + from uts.core.threads import ThreadPool + + class Simples(object): + + def __init__(self): + self.coisa = "haha" + + def nome(self): + print "nome:", threading.currentThread().getName() + return "nome: result (" + threading.currentThread().getName() + ")" + + def outroNome(self): + time.sleep(5) + print "outroNome:", threading.currentThread().getName() + return "outroNome: result("+threading.currentThread().getName()+")" + + def nomeCallback(self, result): + print "callback:", result + + + try: + + pool = ThreadPool(5) + + p1 = Proxy(Simples(), pool) + + # calls nome synchronously in the main thread + r1 = p1.nome() + print r1 + + # calls nome asynchronously in a new thread, will + # call p1.nomeCallback when nome finishes + r2 = p1.nome.begin(callback=p1.nomeCallback) + + # calls outroNome asynchronously in a new thread + r3 = p1.outroNome.begin() + + # block until r3 (nome) ends + print r3.end() + + print p1.coisa + + finally: + pool.joinAll() + diff --git a/src/python/uts/core/register.py b/src/python/uts/core/register.py new file mode 100644 index 00000000..8825e18b --- /dev/null +++ b/src/python/uts/core/register.py @@ -0,0 +1,129 @@ +from types import StringType + +class Register(object): + + def __init__(self, kind = None): + + self.objects = {} + + def register(self, location, instance): + + if location in self.objects: + return False + + self.objects[location] = instance + + def unregister(self, location): + if not location in self.objects: + return False + + del self.objects[location] + + def update(self, location, instance): + self.unregister(location) + self.register(location, instance) + + def __repr__(self): + _str = "There are %d objects avaiable.\n" % len(self.objects) + _str += self.objects.__repr__() + + return _str + + def __contains__(self, item): + _ret = filter(lambda x: x == item, self.objects.keys()) + + if _ret: + return True + else: + return False + + def __len__(self): + return self.objects.__len__() + + def __iter__(self): + return self.objects.__iter__() + + def items(self): + return self.objects.items() + + def keys(self): + return self.objects.keys() + + def values(self): + return self.objects.values() + + def __getitem__(self, item): + r = self.get(item) + + if not r: + raise KeyError + else: + return r + + def get(self, item): + + if type(item) == StringType: + item = Location(item) + + if not item.isValid(): + return False + + # try to get by index first + try: + numberedInstance = True + number = int(item._name) + except ValueError: + numberedInstance = False + + if numberedInstance: + return self.getByIndex(item._class, number) + + if self.__contains__(item): + ret = filter(lambda x: x == item, self.objects.keys()) + + return self.objects[ret[0]] + else: + return False + + + def getByClass(self, cls): + + _insts = filter(lambda inst: inst._class == cls, self.objects.keys()) + + return _insts + + def getByIndex(self, cls, index): + + insts = self.getByClass(cls) + + if insts: + try: + ret = self.get(insts[index]) + return ret + except IndexError: + return False + else: + return False + + +if __name__ == '__main__': + + from uts.core.location import Location + a = object() + l = Location("/Telescope/meade?opt1=val1,opt2=val2") + + b = object() + ll = Location("/Telescope/paramount?opt1=val1,opt2=val2") + + + r = Register() + r.register(l, a) + r.register(ll, b) + + print r + print r[l] + print r["/Telescope/meade"] + + lll = r.getByClass("Telescope") + for i in lll: + print r[i] diff --git a/src/python/uts/core/sec.py b/src/python/uts/core/sec.py new file mode 100644 index 00000000..f34125ce --- /dev/null +++ b/src/python/uts/core/sec.py @@ -0,0 +1,363 @@ + +from spm import Spm + +import sys +import logging +import socket +import select + +class PropertyList(dict): + + def __init__(self, config = "/etc/uts/sec/tel.conf"): + dict.__init__(self) + + self.__config = config + + + def readConfig(self, config = None): + if config: + self.__config = config + + try: + f = open(self.__config) + + for line in f.readlines(): + + if ("STATUS" in line) or ("INSTNAME" in line): + self[line.split(" ")[1][:-1]] = None + + f.close() + + except Exception, e: + logging.exception("Error reading sec config %s." % self.__config) + + +class Notify: + + def __init__(self, sec = "TEL", prop = None, value = None): + + self.sec = sec + self.prop = prop + self.value = value + + def __repr__(self): + return "Event at %s. %s => %s" % (str(self.sec), str(self.prop), + str(self.value)) + + +class Sec: + """ + Low-level access to UTS Secretary + + UTS Secretary manage instrument properties and register notifies. + """ + + def __init__(self, name, level = "control", + server = None, + interactive = False, + port = None): + + """ + @param name: Instrument name (from uts.config) + @type name: str + @param level: Access level (control, status) + @type level: string + @param server: Server name or IP of Spm (the sockets port Oracle) + @type server: str + @param interactive: Verbose mode, default it's False. + @type interactive: bool + @param port: not used (future) + + @returns: None + """ + + self.name = name + self.level = level + self.server = server + self.port = port + self.interactive = interactive + + #-- + self.props = PropertyList("/etc/uts/sec/" + self.name.lower() + ".conf") + self.props.readConfig() + + self.notifies = [] + + self.sk = None + + def connect(self, server = None, port = None): + """ + Establish a connection with the Secretary. + + @param server: Server name or IP of Spm (the sockets port Oracle) + @type server: str + @param port: not used (future) + + @returns: True on success, False on error. + """ + + if(self.sk): + self.disconnect() + + self.server = server or 'localhost' + + spm = Spm(self.server) + + self.port = spm.getPort(self.name+self.level) + + if (not self.port): + self.err("Spm: Cannot get %s port." % (self.name + self.level)) + return False + + try: + self.sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sk.connect((self.server, self.port)) + + except socket.error, msg: + self.err("Cannot connect to %s (%s)." % + (str(self.server) + ":" + str(self.port), msg[1])) + self.sk = None + + return False + + # OK, connect, here we go! + + # check SERVER_FULL + full = self.sk.recv(100) + full = self.removeNULL(full) + + if (full == "SERVER_FULL"): + self.err("Server full.") + return False + + # ident + self.sk.send(self.appendNULL("IDENT INSTRUMENT")) + + ret = self.sk.recv(100) + ret = self.removeNULL(ret); + + if(ret == "ERROR"): + self.err("Error trying IDENT INSTRUMENT.") + return False + else: + return True + + def disconnect(self): + if(self.sk): + self.sk.send(self.appendNULL("QUIT")) + self.sk.close() + self.sk = None + + def appendNULL(self, s): + + return s + "\x00" + + def removeNULL(self, s): + + return s[:-1] + + def out(self, msg, buff = sys.stdout): + logging.debug(msg) + + def err(self, msg): + logging.error(msg) + + def setInteractive(self, t = True): + self.interactive = t + + def status(self, prop, value = None): + """ + Get or set a property. + + @param prop: The property to get/set. + @type prop: str + @param value: The value to set. + @type value: str + + If C{value} not None, set C{prop} to C{value} and return True on success and False on error. + + If C{value} equals None (the default), get C{prop} and returns the property value as string or False on error. + + If C{self.level} not equals to 'control', return False ('status' secretaries don't have permission to SETSTATUS). + """ + + if(not self.sk): + self.err("Not connected.") + return False + + if not (prop in self.props.keys()): + self.err("%s it's not a valid property." % prop) + return False + + if (value): # SETSTATUS + + if(self.level != "control"): + self.err("You dont' have control permission.") + return False + + self.sk.send(self.appendNULL( + "SETSTATUS " + str(prop) + " " + str(value))) + + res = self.sk.recv(100) + res = self.removeNULL(res) + + if(res == "OK"): + self.out("%s ==> %s" % (prop, value)) + return True + + elif(res == "ERROR"): + self.err("Bad...") + return False + + else: # GETSTATUS + + # check for notifies + if(self.level == "status"): + self.checkNotifies(buffer=True) + + self.sk.send(self.appendNULL("STATUS " + str(prop))) + + res = self.sk.recv(100) + res = self.removeNULL(res) + + if(res == "ERROR"): + ret = res + else: + ret = res[len("STATUS "):] + + self.out("%s: %s" % (prop, ret)) + + return ret + + def isBusy(self): + ret = self.status(self.name) + + if(ret == "OFFLINE") or (ret == "IDLE") or (ret == "DISABLED"): + return False + else: + return True + + def isConnected(self): + if(self.sk): + return True + else: + return False + + def notify(self, prop): + """ + Register a notify for C{prop} + + @param prop: The property on which you want to be notified + @type prop: str + + @returns: True on success, False on error. + @see: L{Sec.unnotify} + + If C{pro} don't exists, C{self.level} equals 'control' or if C{Sec} cannot register the notify return False + Return True on success. + + """ + + if(not self.sk): + self.err("Not connected.") + return False + + if(not prop in self.props.keys()): + self.err("Unknow property %s." % prop) + return False + + if(self.level == "control"): + self.err("Level must be 'status', not 'control'.") + return False + + self.checkNotifies(buffer=True) + + self.sk.send(self.appendNULL("NOTIFY " + str(prop))) + + res = self.sk.recv(100) + res = self.removeNULL(res) + + if(res == "OK"): + return True + + elif(res == "ERROR"): + return False + + def unnotify(self, prop): + """ + Unregister a notify for C{prop} + + If I{pro} don't exists, I{self.level} equals 'control' or if Sec cannot unregister the notify return False + + @returns: True on success, False on error. + """ + + if(not self.sk): + self.err("Not connected.") + return False + + if(not prop in self.props.keys()): + self.err("Unknow property %s." % prop) + return False + + if(self.level == "control"): + self.err("Level must be 'status', not 'control'.") + return False + + self.checkNotifies(buffer=True) + + self.sk.send(self.appendNULL("UNOTIFY " + str(prop))) + + res = self.sk.recv(100) + res = self.removeNULL(res) + + if(res == "OK"): + return True + + elif(res == "ERROR"): + return False + + def checkNotifies(self, blocking = False, timeout = 60, buffer = False): + + if(not self.sk): + self.err("Not connected.") + return False + + if(self.level == "control"): + self.err("Level must be 'status', not 'control'.") + return False + + if(blocking): + wait = select.select([self.sk], [], [], timeout) + else: + wait = select.select([self.sk], [], [], 0) + + if(len(wait[0])): + data = self.sk.recv(255).split('\x00')[:-1] + + res = [] + + for i in data: + res.append(Notify(self.name, + i.split(" ")[1].strip(), + i.split(" ")[2].strip())) + + if(buffer): + self.notifies = self.notifies + res + return True + else: + ret = self.notifies + res + self.notifies = [] + + return ret + + else: + + if (buffer): + return True + + else: + ret = self.notifies + self.notifies = [] + + return ret diff --git a/src/python/uts/core/site.py b/src/python/uts/core/site.py new file mode 100644 index 00000000..392ce3f1 --- /dev/null +++ b/src/python/uts/core/site.py @@ -0,0 +1,190 @@ +#! /usr/bin/python +#! -*- coding: iso-8859-1 -*- + +from uts.core.instrument import Instrument +from uts.core.controller import Controller +from uts.core.register import Register +from uts.core.config import SiteConfiguration +from uts.core.threads import ThreadPool +from uts.core.proxy import Proxy +from uts.core.location import Location +from uts.core.manager import Manager + +from uts.core.version import _uts_version + +import signal +import os +import os.path +import distutils.sysconfig +import logging +import threading + +from optparse import OptionParser + +# FIXME: handle instruments and controllers main function error + +class Site(object): + + def __init__(self, args = []): + + self.options, self.args = self.parseArgs(args) + + # verbosity level + logging.basicConfig(level=logging.WARNING, + format='%(asctime)s %(levelname)s %(module)s:%(lineno)d %(message)s', + datefmt='%d-%m-%Y %H:%M:%S (%j)') + + if self.options.verbose: + logging.getLogger().setLevel(logging.DEBUG) + + logging.debug("Starting system.") + + # manager + self.manager = Manager() + + # directories + + for _dir in self.options.inst_dir: + self.manager.appendPath(_dir) + + for _dir in self.options.ctrl_dir: + self.manager.appendPath(_dir) + + + def parseArgs(self, args): + + parser = OptionParser(prog="UTS", version=_uts_version, + description="UTS - Unified Telescope System") + + parser.add_option("-i", "--instrument", action="append", dest="instruments", + help="Load the instrument defined by LOCATION." + "This option could be setted many times to load multiple instruments.", + metavar="LOCATION") + + parser.add_option("-c", "--controllers", action="append", dest="controllers", + help="Load the controller defined by LOCATION." + "This option could be setted many times to load multiple controllers.", + metavar="LOCATION") + + parser.add_option("-f", "--file", action="append", dest="config", + help="Load instruments and controllers defined on FILE." + "This option could be setted many times to load inst/controllers from multiple files.", + metavar="FILE") + + parser.add_option("-I", "--instruments-dir", action="append", dest="inst_dir", + help="Append PATH to instruments load path.", + metavar="PATH") + + parser.add_option("-C", "--controllers-dir", action="append", dest="ctrl_dir", + help="Append PATH to controllers load path.", + metavar="PATH") + + parser.add_option("-v", "--verbose", action="store_true", dest='verbose', + help="Increase screen log level.") + + prefix = os.path.realpath(os.path.join(os.path.abspath(__file__), '../../')) + + parser.set_defaults(instruments = [], + controllers = [], + config = [], + inst_dir = [os.path.join(prefix, 'instruments')], + ctrl_dir = [os.path.join(prefix, 'controllers')], + verbose=False) + + return parser.parse_args(args) + + def init(self): + self._pool = ThreadPool(10) + self.manager.setPool(self._pool) + + # config file + self.config = SiteConfiguration() + + for config in self.options.config: + self.config.read(config) + + for inst in self.config.getInstruments(): + l = Location(inst) + self.manager.addInstrument(l) + self.manager.initInstrument(l) + + for ctrl in self.config.getControllers(): + l = Location(ctrl) + self.manager.addController(l) + self.manager.initController(l) + + # add all instruments from config and from cmdline + for inst in self.options.instruments: + l = Location(inst) + self.manager.addInstrument(l) + self.manager.initInstrument(l) + + for ctrl in self.options.controllers: + l = Location(ctrl) + self.manager.addController(l) + self.manager.initController(l) + + def stop(self): + self.manager.stopAll() + logging.debug("Stoping system.") + +def main(args): + + def splitAndWatch(stop, finish): + + child = os.fork() + + if child == 0: + return + + def kill(): + stop() + finish.set() + os.kill(child, signal.SIGKILL) + + def sighandler(sig, frame): + kill() + + signal.signal(signal.SIGTERM, sighandler) + signal.signal(signal.SIGINT, sighandler) + + try: + os.wait() + stop() + finish.set() + + except OSError: + pass + + # ============ + + # FIXME Ugly hacks to python threading works with signal + # FIXME see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496735 + # FIXME see http://greenteapress.com/semaphores/ + + mainProcess = threading.Event() + + # only initialize, DON'T run threads here! + + s = Site(args) + + # from here we have 2 process. Child will return from splitAndWatch, + # while the main process will watch for signals and will kill the child + # process and set mainProcess event so the remaining of the code + # know what execute + + splitAndWatch(s.stop, mainProcess) + + # child run the thread + if not mainProcess.isSet(): + s.init() + else: + # run whatever you want on the main thread + pass + +if __name__ == '__main__': + + import sys + + main(sys.argv) + diff --git a/src/python/uts/core/spm.py b/src/python/uts/core/spm.py new file mode 100644 index 00000000..da4f83cc --- /dev/null +++ b/src/python/uts/core/spm.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +import sys +import logging +import commands +import socket + +class SpmNet: + + def __init__(self, server = 'localhost', port = 1750): + self.server = server + self.port = port + self.servers = {} + + self.proto = {'PM_SERVER' : '\x00\x01', 'PM_CLIENT' : '\x00\x02', + 'PM_CLOSE' : '\x00\x03', 'PM_RESEND' : '\x00\x04', + 'PM_QUIT' : '\x00\x05', 'PM_SORRY' : '\x00\x06', + 'PM_OK' : '\x00\x07', 'PM_ACCEPT' : '\x00\x08', + 'PM_TABLE' : '\x00\x09', 'PM_RMSERVER': '\x00\x10', + 'PM_FWINIT' : '\x00\x11', 'PM_SHARE' : '\x00\x12', + 'PM_OKSHARE' : '\x00\x13', 'PM_BIGBUF' : 1024, + 'PM_MAXTRY' : 20 } + + self.getServers() + + def getPort(self, server = None): + """ + Retorna a porta de um dado servidor. + @param server servidor do qual deseja saber a porta + """ + + try: + return self.servers[server] + except KeyError: + return 0 + + def getServers(self): + """ + Retorna um dictionary com os servidores e respectivas portas + ativos no momento. + """ + + sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sk.connect((self.server, self.port)) + sk.send(self.proto['PM_TABLE']) + + if sk.recv(2) == self.proto['PM_OK']: + num = sk.recv(2) + + data = sk.recv(self.proto['PM_BIGBUF']) + data = data.split('\x00') + del data[-1] + + for i in data: + item = i.split(':') + self.servers[item[0].strip()] = int(item[1]) + + sk.close() + + return self.servers + + elif sk.recv(2) == self.proto['PM_RESEND']: + sk.close() + + except socket.error, msg: + logging.exception("Error %s:" % msg[1]) + sk.close() + + def dumpTable(self): + for i,v in self.servers.items(): + print "%s %d" % (i, v) + + +class SpmCommand: + + def __init__(self, server = 'localhost', spmtable = None): + + self.server = server + self.servers = {} + + self.getServers() + + def getPort(self, server = None): + """ + Retorna a porta de um dado servidor. + @param server servidor do qual deseja saber a porta + """ + + try: + return self.servers[server] + except KeyError: + return 0 + + def getServers(self): + """ + Retorna um dictionary com os servidores e respectivas portas + ativos no momento. + """ + + try: + out = commands.getoutput("spmtable") + out = out.split('\n')[2:-1] + + for i in out: + self.servers[i.split(':')[1].strip()] = int(i.split(':')[2].strip()) + + return self.servers + except Exception, e: + logging.exception("Error getting servers.") + return False + + def dumpTable(self): + for i,v in self.servers.items(): + print "%s %d" % (i, v) + +Spm = SpmCommand + +#-- +if __name__ == '__main__': + + if(len(sys.argv) < 2): + spm = Spm() + else: + spm = Spm(sys.argv[1]) + + spm.dumpTable() + diff --git a/src/python/uts/core/threads.py b/src/python/uts/core/threads.py new file mode 100644 index 00000000..103e805d --- /dev/null +++ b/src/python/uts/core/threads.py @@ -0,0 +1,200 @@ +#! /usr/bin/python +# -*- coding: iso8859-1 -*- + +import threading +import logging +import signal +import time + +from time import sleep, time + +# Ensure booleans exist (not needed for Python 2.2.1 or higher) +try: + True +except NameError: + False = 0 + True = not False + +#threading._VERBOSE = True + +class ThreadPool: + + """Flexible thread pool class. Creates a pool of threads, then + accepts tasks that will be dispatched to the next available + thread.""" + + def __init__(self, numThreads): + + """Initialize the thread pool with numThreads workers.""" + + self.__threads = [] + self.__resizeLock = threading.Condition(threading.Lock()) + self.__taskLock = threading.Condition(threading.Lock()) + self.__tasks = [] + self.__isJoining = False + self.setThreadCount(numThreads) + + def setThreadCount(self, newNumThreads): + + """ External method to set the current pool size. Acquires + the resizing lock, then calls the internal version to do real + work.""" + + # Can't change the thread count if we're shutting down the pool! + if self.__isJoining: + return False + + self.__resizeLock.acquire() + try: + self.__setThreadCountNolock(newNumThreads) + finally: + self.__resizeLock.release() + return True + + def __setThreadCountNolock(self, newNumThreads): + + """Set the current pool size, spawning or terminating threads + if necessary. Internal use only; assumes the resizing lock is + held.""" + + # If we need to grow the pool, do so + while newNumThreads > len(self.__threads): + newThread = ThreadPoolThread(self) + self.__threads.append(newThread) + newThread.start() + # If we need to shrink the pool, do so + while newNumThreads < len(self.__threads): + self.__threads[0].goAway() + del self.__threads[0] + + def getThreadCount(self): + + """Return the number of threads in the pool.""" + + self.__resizeLock.acquire() + try: + return len(self.__threads) + finally: + self.__resizeLock.release() + + def queueTask(self, task, args=( ), kwargs = { }, taskCallback=None): + + """Insert a task into the queue. task must be callable; + args and taskCallback can be None.""" + + if self.__isJoining == True: + return False + if not callable(task): + return False + + self.__taskLock.acquire() + try: + self.__tasks.append((task, args, kwargs, taskCallback)) + return True + finally: + self.__taskLock.release() + + def getNextTask(self): + + """ Retrieve the next task from the task queue. For use + only by ThreadPoolThread objects contained in the pool.""" + + self.__taskLock.acquire() + try: + if self.__tasks == []: + return (None, None, None, None) + else: + return self.__tasks.pop(0) + finally: + self.__taskLock.release() + + def joinAll(self, waitForTasks = True, waitForThreads = True): + + """ Clear the task queue and terminate all pooled threads, + optionally allowing the tasks and threads to finish.""" + + # Mark the pool as joining to prevent any more task queueing + self.__isJoining = True + + # Wait for tasks to finish + if waitForTasks: + while self.__tasks != []: + sleep(.1) + + # Tell all the threads to quit + self.__resizeLock.acquire() + try: + self.__setThreadCountNolock(0) + self.__isJoining = True + + # Wait until all threads have exited + if waitForThreads: + for t in self.__threads: + t.join() + del t + + # Reset the pool for potential reuse + self.__isJoining = False + finally: + self.__resizeLock.release() + + + +class ThreadPoolThread(threading.Thread): + + """ Pooled thread class. """ + + threadSleepTime = 0.1 + + def __init__(self, pool): + + """ Initialize the thread and remember the pool. """ + + threading.Thread.__init__(self) + self.__pool = pool + self.__isDying = False + self.setDaemon(False) + + def run(self): + + """ Until told to quit, retrieve the next task and execute + it, calling the callback if any. """ + + while self.__isDying == False: + cmd, args, kwargs, callback = self.__pool.getNextTask() + # If there's nothing to do, just sleep a bit + if cmd is None: + sleep(ThreadPoolThread.threadSleepTime) + else: + if(hasattr(cmd, "lock")): + cmd.lock.acquire() + logging.debug("Locking %s" % cmd) + + logging.debug("Running %s" % cmd) + if callback is None: + cmd(*args, **kwargs) + else: + callback(cmd(*args, **kwargs)) + + if(hasattr(cmd, "Lock")): + cmd.lock.release() + logging.debug("unlocking %s" % cmd) + + def goAway(self): + + """ Exit the run loop next time through.""" + + self.__isDying = True + + +__tp = None + +def getThreadPool(n): + + global __tp + + if not __tp: + __tp = ThreadPool(n) + + return __tp + diff --git a/src/python/uts/core/version.py b/src/python/uts/core/version.py new file mode 100644 index 00000000..e97b99d5 --- /dev/null +++ b/src/python/uts/core/version.py @@ -0,0 +1,2 @@ +_uts_author = "P. Henrique Silva" +_uts_version = "0.1" diff --git a/src/python/uts/instruments/Makefile.am b/src/python/uts/instruments/Makefile.am new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/instruments/__init__.py b/src/python/uts/instruments/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/interfaces/Makefile b/src/python/uts/interfaces/Makefile new file mode 100644 index 00000000..5c55493a --- /dev/null +++ b/src/python/uts/interfaces/Makefile @@ -0,0 +1,291 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# src/python/uts/interfaces/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +srcdir = . +top_srcdir = ../../../.. + +pkgdatadir = $(datadir)/uts +pkglibdir = $(libdir)/uts +pkgincludedir = $(includedir)/uts +top_builddir = ../../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = /usr/bin/install -c +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = src/python/uts/interfaces +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/vela/henrique/uts-svn/missing --run aclocal-1.8 +ALLOCA = +AMDEP_FALSE = # +AMDEP_TRUE = +AMTAR = ${SHELL} /home/vela/henrique/uts-svn/missing --run tar +AUTOCONF = ${SHELL} /home/vela/henrique/uts-svn/missing --run autoconf +AUTOHEADER = ${SHELL} /home/vela/henrique/uts-svn/missing --run autoheader +AUTOMAKE = ${SHELL} /home/vela/henrique/uts-svn/missing --run automake-1.8 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CPP = gcc -E +CPPFLAGS = +CXX = g++ +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = grep -E +EXEEXT = +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s +LDFLAGS = +LIBOBJS = +LIBS = +LN_S = ln -s +LTLIBOBJS = +MAKEINFO = ${SHELL} /home/vela/henrique/uts-svn/missing --run makeinfo +OBJEXT = o +PACKAGE = uts +PACKAGE_BUGREPORT = henrique@astro.ufsc.br +PACKAGE_NAME = uts +PACKAGE_STRING = uts 1.0RC1 +PACKAGE_TARNAME = uts +PACKAGE_VERSION = 1.0RC1 +PATH_SEPARATOR = : +PYTHON = /usr/bin/python +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.3 +RANLIB = ranlib +SET_MAKE = +SHELL = /bin/sh +STRIP = +UTS_DISTRO = suse +UTS_INITCONFIG_DIR = /etc/sysconfig +VERSION = 1.0RC1 +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_RANLIB = ranlib +ac_ct_STRIP = +am__fastdepCC_FALSE = # +am__fastdepCC_TRUE = +am__fastdepCXX_FALSE = # +am__fastdepCXX_TRUE = +am__include = include +am__leading_dot = . +am__quote = +bindir = ${exec_prefix}/bin +build_alias = +datadir = ${prefix}/share +exec_prefix = ${prefix} +host_alias = +includedir = ${prefix}/include +infodir = ${prefix}/info +install_sh = /home/vela/henrique/uts-svn/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localstatedir = ${prefix}/var +mandir = ${prefix}/man +mkdir_p = mkdir -p -- . +oldincludedir = /usr/include +pkgpyexecdir = ${pyexecdir}/uts +pkgpythondir = ${pythondir}/uts +prefix = /usr/local +program_transform_name = s,x,x, +pyexecdir = ${exec_prefix}/lib/python2.3/site-packages +pythondir = ${prefix}/lib/python2.3/site-packages +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +sysconfdir = ${prefix}/etc +target_alias = +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/python/uts/interfaces/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/python/uts/interfaces/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/python/uts/interfaces/Makefile.am b/src/python/uts/interfaces/Makefile.am new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/interfaces/__init__.py b/src/python/uts/interfaces/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/interfaces/camera.py b/src/python/uts/interfaces/camera.py new file mode 100644 index 00000000..8642d404 --- /dev/null +++ b/src/python/uts/interfaces/camera.py @@ -0,0 +1,39 @@ +#! /usr/bin/python +# -*- coding: iso-8859-1 -*- + +class CameraExpose(object): + + # properties + expTime = 0 + nExp = 0 + window = None + binning = 0 + binningList = [] + gain = 0 + gainList = [] + chipSize = None + pixelSize = None + maxADU = 0 + fullWellCapacity = 0 + exposing = False + + # methods + def expose (self, expTime, nexp): + pass + + def abortExposure (self): + pass + + def stopExposure (self): + pass + + # events + def exposeComplete (self): + pass + + def exposeAborted (self): + pass + + def exposeStopped (self): + pass + diff --git a/src/python/uts/interfaces/telescope.py b/src/python/uts/interfaces/telescope.py new file mode 100644 index 00000000..0ad89569 --- /dev/null +++ b/src/python/uts/interfaces/telescope.py @@ -0,0 +1,43 @@ +#! /usr/bin/python +# -*- coding: iso-8859-1 -*- + +class TelescopeSlew(object): + + # properties + + currRA = 0 + currDec = 0 + currEphoc = 2000 + currAz = 0 + currAlt = 0 + cmdRA = 0 + cmdDec = 0 + cmdEphoc = 2000 + cmdAz = 0 + cmdAlt = 0 + axis = [] + slewRates = [] + slewRate = 0 + slewing = False + + # methods + + def slew(self, coord): + pass + + def abortSlew(self): + pass + + def moveAxis(self, axis, offset): + pass + + # events + + def slewComplete(self, position, tracking, trackingRate): + pass + + def abortComplete(self, position): + pass + + def targetChanged(self, position): + pass diff --git a/src/python/uts/util/__init__.py b/src/python/uts/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/uts/util/catalog.py b/src/python/uts/util/catalog.py new file mode 100644 index 00000000..d1c8453b --- /dev/null +++ b/src/python/uts/util/catalog.py @@ -0,0 +1,20 @@ + +class Catalog: + def __init__(self): + pass + +class Object: + + def __init__(self, name = "", ra = None, dec = None): + + self.name = name + + self.ra = ra + self.dec = dec + + self.altitude = None + self.azimuth = None + + self.ephoch = None + + self.resolvers = {} diff --git a/src/python/uts/util/etree/ElementInclude.py b/src/python/uts/util/etree/ElementInclude.py new file mode 100644 index 00000000..bac2f5e4 --- /dev/null +++ b/src/python/uts/util/etree/ElementInclude.py @@ -0,0 +1,141 @@ +# +# ElementTree +# $Id: ElementInclude.py 1862 2004-06-18 07:31:02Z Fredrik $ +# +# limited xinclude support for element trees +# +# history: +# 2003-08-15 fl created +# 2003-11-14 fl fixed default loader +# +# Copyright (c) 2003-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Limited XInclude support for the ElementTree package. +## + +import copy +import ElementTree + +XINCLUDE = "{http://www.w3.org/2001/XInclude}" + +XINCLUDE_INCLUDE = XINCLUDE + "include" +XINCLUDE_FALLBACK = XINCLUDE + "fallback" + +## +# Fatal include error. + +class FatalIncludeError(SyntaxError): + pass + +## +# Default loader. This loader reads an included resource from disk. +# +# @param href Resource reference. +# @param parse Parse mode. Either "xml" or "text". +# @param encoding Optional text encoding. +# @return The expanded resource. If the parse mode is "xml", this +# is an ElementTree instance. If the parse mode is "text", this +# is a Unicode string. If the loader fails, it can return None +# or raise an IOError exception. +# @throws IOError If the loader fails to load the resource. + +def default_loader(href, parse, encoding=None): + file = open(href) + if parse == "xml": + data = ElementTree.parse(file).getroot() + else: + data = file.read() + if encoding: + data = data.decode(encoding) + file.close() + return data + +## +# Expand XInclude directives. +# +# @param elem Root element. +# @param loader Optional resource loader. If omitted, it defaults +# to {@link default_loader}. If given, it should be a callable +# that implements the same interface as default_loader. +# @throws FatalIncludeError If the function fails to include a given +# resource, or if the tree contains malformed XInclude elements. +# @throws IOError If the function fails to load a given resource. + +def include(elem, loader=None): + if loader is None: + loader = default_loader + # look for xinclude elements + i = 0 + while i < len(elem): + e = elem[i] + if e.tag == XINCLUDE_INCLUDE: + # process xinclude directive + href = e.get("href") + parse = e.get("parse", "xml") + if parse == "xml": + node = loader(href, parse) + if node is None: + raise FatalIncludeError( + "cannot load %r as %r" % (href, parse) + ) + node = copy.copy(node) + if e.tail: + node.tail = (node.tail or "") + e.tail + elem[i] = node + elif parse == "text": + text = loader(href, parse, e.get("encoding")) + if text is None: + raise FatalIncludeError( + "cannot load %r as %r" % (href, parse) + ) + if i: + node = elem[i-1] + node.tail = (node.tail or "") + text + else: + elem.text = (elem.text or "") + text + (e.tail or "") + del elem[i] + continue + else: + raise FatalIncludeError( + "unknown parse type in xi:include tag (%r)" % parse + ) + elif e.tag == XINCLUDE_FALLBACK: + raise FatalIncludeError( + "xi:fallback tag must be child of xi:include (%r)" % e.tag + ) + else: + include(e, loader) + i = i + 1 + diff --git a/src/python/uts/util/etree/ElementPath.py b/src/python/uts/util/etree/ElementPath.py new file mode 100644 index 00000000..558b560a --- /dev/null +++ b/src/python/uts/util/etree/ElementPath.py @@ -0,0 +1,196 @@ +# +# ElementTree +# $Id: ElementPath.py 1858 2004-06-17 21:31:41Z Fredrik $ +# +# limited xpath support for element trees +# +# history: +# 2003-05-23 fl created +# 2003-05-28 fl added support for // etc +# 2003-08-27 fl fixed parsing of periods in element names +# +# Copyright (c) 2003-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Implementation module for XPath support. There's usually no reason +# to import this module directly; the ElementTree does this for +# you, if needed. +## + +import re + +xpath_tokenizer = re.compile( + "(::|\.\.|\(\)|[/.*:\[\]\(\)@=])|((?:\{[^}]+\})?[^/:\[\]\(\)@=\s]+)|\s+" + ).findall + +class xpath_descendant_or_self: + pass + +## +# Wrapper for a compiled XPath. + +class Path: + + ## + # Create an Path instance from an XPath expression. + + def __init__(self, path): + tokens = xpath_tokenizer(path) + # the current version supports 'path/path'-style expressions only + self.path = [] + self.tag = None + if tokens and tokens[0][0] == "/": + raise SyntaxError("cannot use absolute path on element") + while tokens: + op, tag = tokens.pop(0) + if tag or op == "*": + self.path.append(tag or op) + elif op == ".": + pass + elif op == "/": + self.path.append(xpath_descendant_or_self()) + continue + else: + raise SyntaxError("unsupported path syntax (%s)" % op) + if tokens: + op, tag = tokens.pop(0) + if op != "/": + raise SyntaxError( + "expected path separator (%s)" % (op or tag) + ) + if self.path and isinstance(self.path[-1], xpath_descendant_or_self): + raise SyntaxError("path cannot end with //") + if len(self.path) == 1 and isinstance(self.path[0], type("")): + self.tag = self.path[0] + + ## + # Find first matching object. + + def find(self, element): + tag = self.tag + if tag is None: + nodeset = self.findall(element) + if not nodeset: + return None + return nodeset[0] + for elem in element: + if elem.tag == tag: + return elem + return None + + ## + # Find text for first matching object. + + def findtext(self, element, default=None): + tag = self.tag + if tag is None: + nodeset = self.findall(element) + if not nodeset: + return default + return nodeset[0].text or "" + for elem in element: + if elem.tag == tag: + return elem.text or "" + return default + + ## + # Find all matching objects. + + def findall(self, element): + nodeset = [element] + index = 0 + while 1: + try: + path = self.path[index] + index = index + 1 + except IndexError: + return nodeset + set = [] + if isinstance(path, xpath_descendant_or_self): + try: + tag = self.path[index] + if not isinstance(tag, type("")): + tag = None + else: + index = index + 1 + except IndexError: + tag = None # invalid path + for node in nodeset: + new = list(node.getiterator(tag)) + if new and new[0] is node: + set.extend(new[1:]) + else: + set.extend(new) + else: + for node in nodeset: + for node in node: + if path == "*" or node.tag == path: + set.append(node) + if not set: + return [] + nodeset = set + +_cache = {} + +## +# (Internal) Compile path. + +def _compile(path): + p = _cache.get(path) + if p is not None: + return p + p = Path(path) + if len(_cache) >= 100: + _cache.clear() + _cache[path] = p + return p + +## +# Find first matching object. + +def find(element, path): + return _compile(path).find(element) + +## +# Find text for first matching object. + +def findtext(element, path, default=None): + return _compile(path).findtext(element, default) + +## +# Find all matching objects. + +def findall(element, path): + return _compile(path).findall(element) + diff --git a/src/python/uts/util/etree/ElementTree.py b/src/python/uts/util/etree/ElementTree.py new file mode 100644 index 00000000..98d02087 --- /dev/null +++ b/src/python/uts/util/etree/ElementTree.py @@ -0,0 +1,1254 @@ +# +# ElementTree +# $Id: ElementTree.py 2326 2005-03-17 07:45:21Z fredrik $ +# +# light-weight XML support for Python 1.5.2 and later. +# +# history: +# 2001-10-20 fl created (from various sources) +# 2001-11-01 fl return root from parse method +# 2002-02-16 fl sort attributes in lexical order +# 2002-04-06 fl TreeBuilder refactoring, added PythonDoc markup +# 2002-05-01 fl finished TreeBuilder refactoring +# 2002-07-14 fl added basic namespace support to ElementTree.write +# 2002-07-25 fl added QName attribute support +# 2002-10-20 fl fixed encoding in write +# 2002-11-24 fl changed default encoding to ascii; fixed attribute encoding +# 2002-11-27 fl accept file objects or file names for parse/write +# 2002-12-04 fl moved XMLTreeBuilder back to this module +# 2003-01-11 fl fixed entity encoding glitch for us-ascii +# 2003-02-13 fl added XML literal factory +# 2003-02-21 fl added ProcessingInstruction/PI factory +# 2003-05-11 fl added tostring/fromstring helpers +# 2003-05-26 fl added ElementPath support +# 2003-07-05 fl added makeelement factory method +# 2003-07-28 fl added more well-known namespace prefixes +# 2003-08-15 fl fixed typo in ElementTree.findtext (Thomas Dartsch) +# 2003-09-04 fl fall back on emulator if ElementPath is not installed +# 2003-10-31 fl markup updates +# 2003-11-15 fl fixed nested namespace bug +# 2004-03-28 fl added XMLID helper +# 2004-06-02 fl added default support to findtext +# 2004-06-08 fl fixed encoding of non-ascii element/attribute names +# 2004-08-23 fl take advantage of post-2.1 expat features +# 2005-02-01 fl added iterparse implementation +# 2005-03-02 fl fixed iterparse support for pre-2.2 versions +# +# Copyright (c) 1999-2005 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2005 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +__all__ = [ + # public symbols + "Comment", + "dump", + "Element", "ElementTree", + "fromstring", + "iselement", "iterparse", + "parse", + "PI", "ProcessingInstruction", + "QName", + "SubElement", + "tostring", + "TreeBuilder", + "VERSION", "XML", + "XMLTreeBuilder", + ] + +## +# The Element type is a flexible container object, designed to +# store hierarchical data structures in memory. The type can be +# described as a cross between a list and a dictionary. +#

+# Each element has a number of properties associated with it: +#

    +#
  • a tag. This is a string identifying what kind of data +# this element represents (the element type, in other words).
  • +#
  • a number of attributes, stored in a Python dictionary.
  • +#
  • a text string.
  • +#
  • an optional tail string.
  • +#
  • a number of child elements, stored in a Python sequence
  • +#
+# +# To create an element instance, use the {@link #Element} or {@link +# #SubElement} factory functions. +#

+# The {@link #ElementTree} class can be used to wrap an element +# structure, and convert it from and to XML. +## + +import string, sys, re + +class _SimpleElementPath: + # emulate pre-1.2 find/findtext/findall behaviour + def find(self, element, tag): + for elem in element: + if elem.tag == tag: + return elem + return None + def findtext(self, element, tag, default=None): + for elem in element: + if elem.tag == tag: + return elem.text or "" + return default + def findall(self, element, tag): + if tag[:3] == ".//": + return element.getiterator(tag[3:]) + result = [] + for elem in element: + if elem.tag == tag: + result.append(elem) + return result + +try: + import ElementPath +except ImportError: + # FIXME: issue warning in this case? + ElementPath = _SimpleElementPath() + +# TODO: add support for custom namespace resolvers/default namespaces +# TODO: add improved support for incremental parsing + +VERSION = "1.2.6" + +## +# Internal element class. This class defines the Element interface, +# and provides a reference implementation of this interface. +#

+# You should not create instances of this class directly. Use the +# appropriate factory functions instead, such as {@link #Element} +# and {@link #SubElement}. +# +# @see Element +# @see SubElement +# @see Comment +# @see ProcessingInstruction + +class _ElementInterface: + # text...tail + + ## + # (Attribute) Element tag. + + tag = None + + ## + # (Attribute) Element attribute dictionary. Where possible, use + # {@link #_ElementInterface.get}, + # {@link #_ElementInterface.set}, + # {@link #_ElementInterface.keys}, and + # {@link #_ElementInterface.items} to access + # element attributes. + + attrib = None + + ## + # (Attribute) Text before first subelement. This is either a + # string or the value None, if there was no text. + + text = None + + ## + # (Attribute) Text after this element's end tag, but before the + # next sibling element's start tag. This is either a string or + # the value None, if there was no text. + + tail = None # text after end tag, if any + + def __init__(self, tag, attrib): + self.tag = tag + self.attrib = attrib + self._children = [] + + def __repr__(self): + return "" % (self.tag, id(self)) + + ## + # Creates a new element object of the same type as this element. + # + # @param tag Element tag. + # @param attrib Element attributes, given as a dictionary. + # @return A new element instance. + + def makeelement(self, tag, attrib): + return Element(tag, attrib) + + ## + # Returns the number of subelements. + # + # @return The number of subelements. + + def __len__(self): + return len(self._children) + + ## + # Returns the given subelement. + # + # @param index What subelement to return. + # @return The given subelement. + # @exception IndexError If the given element does not exist. + + def __getitem__(self, index): + return self._children[index] + + ## + # Replaces the given subelement. + # + # @param index What subelement to replace. + # @param element The new element value. + # @exception IndexError If the given element does not exist. + # @exception AssertionError If element is not a valid object. + + def __setitem__(self, index, element): + assert iselement(element) + self._children[index] = element + + ## + # Deletes the given subelement. + # + # @param index What subelement to delete. + # @exception IndexError If the given element does not exist. + + def __delitem__(self, index): + del self._children[index] + + ## + # Returns a list containing subelements in the given range. + # + # @param start The first subelement to return. + # @param stop The first subelement that shouldn't be returned. + # @return A sequence object containing subelements. + + def __getslice__(self, start, stop): + return self._children[start:stop] + + ## + # Replaces a number of subelements with elements from a sequence. + # + # @param start The first subelement to replace. + # @param stop The first subelement that shouldn't be replaced. + # @param elements A sequence object with zero or more elements. + # @exception AssertionError If a sequence member is not a valid object. + + def __setslice__(self, start, stop, elements): + for element in elements: + assert iselement(element) + self._children[start:stop] = list(elements) + + ## + # Deletes a number of subelements. + # + # @param start The first subelement to delete. + # @param stop The first subelement to leave in there. + + def __delslice__(self, start, stop): + del self._children[start:stop] + + ## + # Adds a subelement to the end of this element. + # + # @param element The element to add. + # @exception AssertionError If a sequence member is not a valid object. + + def append(self, element): + assert iselement(element) + self._children.append(element) + + ## + # Inserts a subelement at the given position in this element. + # + # @param index Where to insert the new subelement. + # @exception AssertionError If the element is not a valid object. + + def insert(self, index, element): + assert iselement(element) + self._children.insert(index, element) + + ## + # Removes a matching subelement. Unlike the find methods, + # this method compares elements based on identity, not on tag + # value or contents. + # + # @param element What element to remove. + # @exception ValueError If a matching element could not be found. + # @exception AssertionError If the element is not a valid object. + + def remove(self, element): + assert iselement(element) + self._children.remove(element) + + ## + # Returns all subelements. The elements are returned in document + # order. + # + # @return A list of subelements. + # @defreturn list of Element instances + + def getchildren(self): + return self._children + + ## + # Finds the first matching subelement, by tag name or path. + # + # @param path What element to look for. + # @return The first matching element, or None if no element was found. + # @defreturn Element or None + + def find(self, path): + return ElementPath.find(self, path) + + ## + # Finds text for the first matching subelement, by tag name or path. + # + # @param path What element to look for. + # @param default What to return if the element was not found. + # @return The text content of the first matching element, or the + # default value no element was found. Note that if the element + # has is found, but has no text content, this method returns an + # empty string. + # @defreturn string + + def findtext(self, path, default=None): + return ElementPath.findtext(self, path, default) + + ## + # Finds all matching subelements, by tag name or path. + # + # @param path What element to look for. + # @return A list or iterator containing all matching elements, + # in document order. + # @defreturn list of Element instances + + def findall(self, path): + return ElementPath.findall(self, path) + + ## + # Resets an element. This function removes all subelements, clears + # all attributes, and sets the text and tail attributes to None. + + def clear(self): + self.attrib.clear() + self._children = [] + self.text = self.tail = None + + ## + # Gets an element attribute. + # + # @param key What attribute to look for. + # @param default What to return if the attribute was not found. + # @return The attribute value, or the default value, if the + # attribute was not found. + # @defreturn string or None + + def get(self, key, default=None): + return self.attrib.get(key, default) + + ## + # Sets an element attribute. + # + # @param key What attribute to set. + # @param value The attribute value. + + def set(self, key, value): + self.attrib[key] = value + + ## + # Gets a list of attribute names. The names are returned in an + # arbitrary order (just like for an ordinary Python dictionary). + # + # @return A list of element attribute names. + # @defreturn list of strings + + def keys(self): + return self.attrib.keys() + + ## + # Gets element attributes, as a sequence. The attributes are + # returned in an arbitrary order. + # + # @return A list of (name, value) tuples for all attributes. + # @defreturn list of (string, string) tuples + + def items(self): + return self.attrib.items() + + ## + # Creates a tree iterator. The iterator loops over this element + # and all subelements, in document order, and returns all elements + # with a matching tag. + #

+ # If the tree structure is modified during iteration, the result + # is undefined. + # + # @param tag What tags to look for (default is to return all elements). + # @return A list or iterator containing all the matching elements. + # @defreturn list or iterator + + def getiterator(self, tag=None): + nodes = [] + if tag == "*": + tag = None + if tag is None or self.tag == tag: + nodes.append(self) + for node in self._children: + nodes.extend(node.getiterator(tag)) + return nodes + +# compatibility +_Element = _ElementInterface + +## +# Element factory. This function returns an object implementing the +# standard Element interface. The exact class or type of that object +# is implementation dependent, but it will always be compatible with +# the {@link #_ElementInterface} class in this module. +#

+# The element name, attribute names, and attribute values can be +# either 8-bit ASCII strings or Unicode strings. +# +# @param tag The element name. +# @param attrib An optional dictionary, containing element attributes. +# @param **extra Additional attributes, given as keyword arguments. +# @return An element instance. +# @defreturn Element + +def Element(tag, attrib={}, **extra): + attrib = attrib.copy() + attrib.update(extra) + return _ElementInterface(tag, attrib) + +## +# Subelement factory. This function creates an element instance, and +# appends it to an existing element. +#

+# The element name, attribute names, and attribute values can be +# either 8-bit ASCII strings or Unicode strings. +# +# @param parent The parent element. +# @param tag The subelement name. +# @param attrib An optional dictionary, containing element attributes. +# @param **extra Additional attributes, given as keyword arguments. +# @return An element instance. +# @defreturn Element + +def SubElement(parent, tag, attrib={}, **extra): + attrib = attrib.copy() + attrib.update(extra) + element = parent.makeelement(tag, attrib) + parent.append(element) + return element + +## +# Comment element factory. This factory function creates a special +# element that will be serialized as an XML comment. +#

+# The comment string can be either an 8-bit ASCII string or a Unicode +# string. +# +# @param text A string containing the comment string. +# @return An element instance, representing a comment. +# @defreturn Element + +def Comment(text=None): + element = Element(Comment) + element.text = text + return element + +## +# PI element factory. This factory function creates a special element +# that will be serialized as an XML processing instruction. +# +# @param target A string containing the PI target. +# @param text A string containing the PI contents, if any. +# @return An element instance, representing a PI. +# @defreturn Element + +def ProcessingInstruction(target, text=None): + element = Element(ProcessingInstruction) + element.text = target + if text: + element.text = element.text + " " + text + return element + +PI = ProcessingInstruction + +## +# QName wrapper. This can be used to wrap a QName attribute value, in +# order to get proper namespace handling on output. +# +# @param text A string containing the QName value, in the form {uri}local, +# or, if the tag argument is given, the URI part of a QName. +# @param tag Optional tag. If given, the first argument is interpreted as +# an URI, and this argument is interpreted as a local name. +# @return An opaque object, representing the QName. + +class QName: + def __init__(self, text_or_uri, tag=None): + if tag: + text_or_uri = "{%s}%s" % (text_or_uri, tag) + self.text = text_or_uri + def __str__(self): + return self.text + def __hash__(self): + return hash(self.text) + def __cmp__(self, other): + if isinstance(other, QName): + return cmp(self.text, other.text) + return cmp(self.text, other) + +## +# ElementTree wrapper class. This class represents an entire element +# hierarchy, and adds some extra support for serialization to and from +# standard XML. +# +# @param element Optional root element. +# @keyparam file Optional file handle or name. If given, the +# tree is initialized with the contents of this XML file. + +class ElementTree: + + def __init__(self, element=None, file=None): + assert element is None or iselement(element) + self._root = element # first node + if file: + self.parse(file) + + ## + # Gets the root element for this tree. + # + # @return An element instance. + # @defreturn Element + + def getroot(self): + return self._root + + ## + # Replaces the root element for this tree. This discards the + # current contents of the tree, and replaces it with the given + # element. Use with care. + # + # @param element An element instance. + + def _setroot(self, element): + assert iselement(element) + self._root = element + + ## + # Loads an external XML document into this element tree. + # + # @param source A file name or file object. + # @param parser An optional parser instance. If not given, the + # standard {@link XMLTreeBuilder} parser is used. + # @return The document root element. + # @defreturn Element + + def parse(self, source, parser=None): + if not hasattr(source, "read"): + source = open(source, "rb") + if not parser: + parser = XMLTreeBuilder() + while 1: + data = source.read(32768) + if not data: + break + parser.feed(data) + self._root = parser.close() + return self._root + + ## + # Creates a tree iterator for the root element. The iterator loops + # over all elements in this tree, in document order. + # + # @param tag What tags to look for (default is to return all elements) + # @return An iterator. + # @defreturn iterator + + def getiterator(self, tag=None): + assert self._root is not None + return self._root.getiterator(tag) + + ## + # Finds the first toplevel element with given tag. + # Same as getroot().find(path). + # + # @param path What element to look for. + # @return The first matching element, or None if no element was found. + # @defreturn Element or None + + def find(self, path): + assert self._root is not None + if path[:1] == "/": + path = "." + path + return self._root.find(path) + + ## + # Finds the element text for the first toplevel element with given + # tag. Same as getroot().findtext(path). + # + # @param path What toplevel element to look for. + # @param default What to return if the element was not found. + # @return The text content of the first matching element, or the + # default value no element was found. Note that if the element + # has is found, but has no text content, this method returns an + # empty string. + # @defreturn string + + def findtext(self, path, default=None): + assert self._root is not None + if path[:1] == "/": + path = "." + path + return self._root.findtext(path, default) + + ## + # Finds all toplevel elements with the given tag. + # Same as getroot().findall(path). + # + # @param path What element to look for. + # @return A list or iterator containing all matching elements, + # in document order. + # @defreturn list of Element instances + + def findall(self, path): + assert self._root is not None + if path[:1] == "/": + path = "." + path + return self._root.findall(path) + + ## + # Writes the element tree to a file, as XML. + # + # @param file A file name, or a file object opened for writing. + # @param encoding Optional output encoding (default is US-ASCII). + + def write(self, file, encoding="us-ascii"): + assert self._root is not None + if not hasattr(file, "write"): + file = open(file, "wb") + if not encoding: + encoding = "us-ascii" + elif encoding != "utf-8" and encoding != "us-ascii": + file.write("\n" % encoding) + self._write(file, self._root, encoding, {}) + + def _write(self, file, node, encoding, namespaces): + # write XML to file + tag = node.tag + if tag is Comment: + file.write("" % _escape_cdata(node.text, encoding)) + elif tag is ProcessingInstruction: + file.write("" % _escape_cdata(node.text, encoding)) + else: + items = node.items() + xmlns_items = [] # new namespaces in this scope + try: + if isinstance(tag, QName) or tag[:1] == "{": + tag, xmlns = fixtag(tag, namespaces) + if xmlns: xmlns_items.append(xmlns) + except TypeError: + _raise_serialization_error(tag) + file.write("<" + _encode(tag, encoding)) + if items or xmlns_items: + items.sort() # lexical order + for k, v in items: + try: + if isinstance(k, QName) or k[:1] == "{": + k, xmlns = fixtag(k, namespaces) + if xmlns: xmlns_items.append(xmlns) + except TypeError: + _raise_serialization_error(k) + try: + if isinstance(v, QName): + v, xmlns = fixtag(v, namespaces) + if xmlns: xmlns_items.append(xmlns) + except TypeError: + _raise_serialization_error(v) + file.write(" %s=\"%s\"" % (_encode(k, encoding), + _escape_attrib(v, encoding))) + for k, v in xmlns_items: + file.write(" %s=\"%s\"" % (_encode(k, encoding), + _escape_attrib(v, encoding))) + if node.text or len(node): + file.write(">") + if node.text: + file.write(_escape_cdata(node.text, encoding)) + for n in node: + self._write(file, n, encoding, namespaces) + file.write("") + else: + file.write(" />") + for k, v in xmlns_items: + del namespaces[v] + if node.tail: + file.write(_escape_cdata(node.tail, encoding)) + +# -------------------------------------------------------------------- +# helpers + +## +# Checks if an object appears to be a valid element object. +# +# @param An element instance. +# @return A true value if this is an element object. +# @defreturn flag + +def iselement(element): + # FIXME: not sure about this; might be a better idea to look + # for tag/attrib/text attributes + return isinstance(element, _ElementInterface) or hasattr(element, "tag") + +## +# Writes an element tree or element structure to sys.stdout. This +# function should be used for debugging only. +#

+# The exact output format is implementation dependent. In this +# version, it's written as an ordinary XML file. +# +# @param elem An element tree or an individual element. + +def dump(elem): + # debugging + if not isinstance(elem, ElementTree): + elem = ElementTree(elem) + elem.write(sys.stdout) + tail = elem.getroot().tail + if not tail or tail[-1] != "\n": + sys.stdout.write("\n") + +def _encode(s, encoding): + try: + return s.encode(encoding) + except AttributeError: + return s # 1.5.2: assume the string uses the right encoding + +if sys.version[:3] == "1.5": + _escape = re.compile(r"[&<>\"\x80-\xff]+") # 1.5.2 +else: + _escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"')) + +_escape_map = { + "&": "&", + "<": "<", + ">": ">", + '"': """, +} + +_namespace_map = { + # "well-known" namespace prefixes + "http://www.w3.org/XML/1998/namespace": "xml", + "http://www.w3.org/1999/xhtml": "html", + "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf", + "http://schemas.xmlsoap.org/wsdl/": "wsdl", +} + +def _raise_serialization_error(text): + raise TypeError( + "cannot serialize %r (type %s)" % (text, type(text).__name__) + ) + +def _encode_entity(text, pattern=_escape): + # map reserved and non-ascii characters to numerical entities + def escape_entities(m, map=_escape_map): + out = [] + append = out.append + for char in m.group(): + text = map.get(char) + if text is None: + text = "&#%d;" % ord(char) + append(text) + return string.join(out, "") + try: + return _encode(pattern.sub(escape_entities, text), "ascii") + except TypeError: + _raise_serialization_error(text) + +# +# the following functions assume an ascii-compatible encoding +# (or "utf-16") + +def _escape_cdata(text, encoding=None, replace=string.replace): + # escape character data + try: + if encoding: + try: + text = _encode(text, encoding) + except UnicodeError: + return _encode_entity(text) + text = replace(text, "&", "&") + text = replace(text, "<", "<") + text = replace(text, ">", ">") + return text + except (TypeError, AttributeError): + _raise_serialization_error(text) + +def _escape_attrib(text, encoding=None, replace=string.replace): + # escape attribute value + try: + if encoding: + try: + text = _encode(text, encoding) + except UnicodeError: + return _encode_entity(text) + text = replace(text, "&", "&") + text = replace(text, "'", "'") # FIXME: overkill + text = replace(text, "\"", """) + text = replace(text, "<", "<") + text = replace(text, ">", ">") + return text + except (TypeError, AttributeError): + _raise_serialization_error(text) + +def fixtag(tag, namespaces): + # given a decorated tag (of the form {uri}tag), return prefixed + # tag and namespace declaration, if any + if isinstance(tag, QName): + tag = tag.text + namespace_uri, tag = string.split(tag[1:], "}", 1) + prefix = namespaces.get(namespace_uri) + if prefix is None: + prefix = _namespace_map.get(namespace_uri) + if prefix is None: + prefix = "ns%d" % len(namespaces) + namespaces[namespace_uri] = prefix + if prefix == "xml": + xmlns = None + else: + xmlns = ("xmlns:%s" % prefix, namespace_uri) + else: + xmlns = None + return "%s:%s" % (prefix, tag), xmlns + +## +# Parses an XML document into an element tree. +# +# @param source A filename or file object containing XML data. +# @param parser An optional parser instance. If not given, the +# standard {@link XMLTreeBuilder} parser is used. +# @return An ElementTree instance + +def parse(source, parser=None): + tree = ElementTree() + tree.parse(source, parser) + return tree + +## +# Parses an XML document into an element tree incrementally, and reports +# what's going on to the user. +# +# @param source A filename or file object containing XML data. +# @param events A list of events to report back. If omitted, only "end" +# events are reported. +# @return A (event, elem) iterator. + +class iterparse: + + def __init__(self, source, events=None): + if not hasattr(source, "read"): + source = open(source, "rb") + self._file = source + self._events = [] + self._index = 0 + self.root = self._root = None + self._parser = XMLTreeBuilder() + # wire up the parser for event reporting + parser = self._parser._parser + append = self._events.append + if events is None: + events = ["end"] + for event in events: + if event == "start": + try: + parser.ordered_attributes = 1 + parser.specified_attributes = 1 + def handler(tag, attrib_in, event=event, append=append, + start=self._parser._start_list): + append((event, start(tag, attrib_in))) + parser.StartElementHandler = handler + except AttributeError: + def handler(tag, attrib_in, event=event, append=append, + start=self._parser._start): + append((event, start(tag, attrib_in))) + parser.StartElementHandler = handler + elif event == "end": + def handler(tag, event=event, append=append, + end=self._parser._end): + append((event, end(tag))) + parser.EndElementHandler = handler + elif event == "start-ns": + def handler(prefix, uri, event=event, append=append): + try: + uri = _encode(uri, "ascii") + except UnicodeError: + pass + append((event, (prefix or "", uri))) + parser.StartNamespaceDeclHandler = handler + elif event == "end-ns": + def handler(prefix, event=event, append=append): + append((event, None)) + parser.EndNamespaceDeclHandler = handler + + def next(self): + while 1: + try: + item = self._events[self._index] + except IndexError: + if self._parser is None: + self.root = self._root + try: + raise StopIteration + except NameError: + raise IndexError + # load event buffer + del self._events[:] + self._index = 0 + data = self._file.read(16384) + if data: + self._parser.feed(data) + else: + self._root = self._parser.close() + self._parser = None + else: + self._index = self._index + 1 + return item + + try: + iter + def __iter__(self): + return self + except NameError: + def __getitem__(self, index): + return self.next() + +## +# Parses an XML document from a string constant. This function can +# be used to embed "XML literals" in Python code. +# +# @param source A string containing XML data. +# @return An Element instance. +# @defreturn Element + +def XML(text): + parser = XMLTreeBuilder() + parser.feed(text) + return parser.close() + +## +# Parses an XML document from a string constant, and also returns +# a dictionary which maps from element id:s to elements. +# +# @param source A string containing XML data. +# @return A tuple containing an Element instance and a dictionary. +# @defreturn (Element, dictionary) + +def XMLID(text): + parser = XMLTreeBuilder() + parser.feed(text) + tree = parser.close() + ids = {} + for elem in tree.getiterator(): + id = elem.get("id") + if id: + ids[id] = elem + return tree, ids + +## +# Parses an XML document from a string constant. Same as {@link #XML}. +# +# @def fromstring(text) +# @param source A string containing XML data. +# @return An Element instance. +# @defreturn Element + +fromstring = XML + +## +# Generates a string representation of an XML element, including all +# subelements. +# +# @param element An Element instance. +# @return An encoded string containing the XML data. +# @defreturn string + +def tostring(element, encoding=None): + class dummy: + pass + data = [] + file = dummy() + file.write = data.append + ElementTree(element).write(file, encoding) + return string.join(data, "") + +## +# Generic element structure builder. This builder converts a sequence +# of {@link #TreeBuilder.start}, {@link #TreeBuilder.data}, and {@link +# #TreeBuilder.end} method calls to a well-formed element structure. +#

+# You can use this class to build an element structure using a custom XML +# parser, or a parser for some other XML-like format. +# +# @param element_factory Optional element factory. This factory +# is called to create new Element instances, as necessary. + +class TreeBuilder: + + def __init__(self, element_factory=None): + self._data = [] # data collector + self._elem = [] # element stack + self._last = None # last element + self._tail = None # true if we're after an end tag + if element_factory is None: + element_factory = _ElementInterface + self._factory = element_factory + + ## + # Flushes the parser buffers, and returns the toplevel documen + # element. + # + # @return An Element instance. + # @defreturn Element + + def close(self): + assert len(self._elem) == 0, "missing end tags" + assert self._last != None, "missing toplevel element" + return self._last + + def _flush(self): + if self._data: + if self._last is not None: + text = string.join(self._data, "") + if self._tail: + assert self._last.tail is None, "internal error (tail)" + self._last.tail = text + else: + assert self._last.text is None, "internal error (text)" + self._last.text = text + self._data = [] + + ## + # Adds text to the current element. + # + # @param data A string. This should be either an 8-bit string + # containing ASCII text, or a Unicode string. + + def data(self, data): + self._data.append(data) + + ## + # Opens a new element. + # + # @param tag The element name. + # @param attrib A dictionary containing element attributes. + # @return The opened element. + # @defreturn Element + + def start(self, tag, attrs): + self._flush() + self._last = elem = self._factory(tag, attrs) + if self._elem: + self._elem[-1].append(elem) + self._elem.append(elem) + self._tail = 0 + return elem + + ## + # Closes the current element. + # + # @param tag The element name. + # @return The closed element. + # @defreturn Element + + def end(self, tag): + self._flush() + self._last = self._elem.pop() + assert self._last.tag == tag,\ + "end tag mismatch (expected %s, got %s)" % ( + self._last.tag, tag) + self._tail = 1 + return self._last + +## +# Element structure builder for XML source data, based on the +# expat parser. +# +# @keyparam target Target object. If omitted, the builder uses an +# instance of the standard {@link #TreeBuilder} class. +# @keyparam html Predefine HTML entities. This flag is not supported +# by the current implementation. +# @see #ElementTree +# @see #TreeBuilder + +class XMLTreeBuilder: + + def __init__(self, html=0, target=None): + try: + from xml.parsers import expat + except ImportError: + raise ImportError( + "No module named expat; use SimpleXMLTreeBuilder instead" + ) + self._parser = parser = expat.ParserCreate(None, "}") + if target is None: + target = TreeBuilder() + self._target = target + self._names = {} # name memo cache + # callbacks + parser.DefaultHandlerExpand = self._default + parser.StartElementHandler = self._start + parser.EndElementHandler = self._end + parser.CharacterDataHandler = self._data + # let expat do the buffering, if supported + try: + self._parser.buffer_text = 1 + except AttributeError: + pass + # use new-style attribute handling, if supported + try: + self._parser.ordered_attributes = 1 + self._parser.specified_attributes = 1 + parser.StartElementHandler = self._start_list + except AttributeError: + pass + encoding = None + if not parser.returns_unicode: + encoding = "utf-8" + # target.xml(encoding, None) + self._doctype = None + self.entity = {} + + def _fixtext(self, text): + # convert text string to ascii, if possible + try: + return _encode(text, "ascii") + except UnicodeError: + return text + + def _fixname(self, key): + # expand qname, and convert name string to ascii, if possible + try: + name = self._names[key] + except KeyError: + name = key + if "}" in name: + name = "{" + name + self._names[key] = name = self._fixtext(name) + return name + + def _start(self, tag, attrib_in): + fixname = self._fixname + tag = fixname(tag) + attrib = {} + for key, value in attrib_in.items(): + attrib[fixname(key)] = self._fixtext(value) + return self._target.start(tag, attrib) + + def _start_list(self, tag, attrib_in): + fixname = self._fixname + tag = fixname(tag) + attrib = {} + if attrib_in: + for i in range(0, len(attrib_in), 2): + attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1]) + return self._target.start(tag, attrib) + + def _data(self, text): + return self._target.data(self._fixtext(text)) + + def _end(self, tag): + return self._target.end(self._fixname(tag)) + + def _default(self, text): + prefix = text[:1] + if prefix == "&": + # deal with undefined entities + try: + self._target.data(self.entity[text[1:-1]]) + except KeyError: + from xml.parsers import expat + raise expat.error( + "undefined entity %s: line %d, column %d" % + (text, self._parser.ErrorLineNumber, + self._parser.ErrorColumnNumber) + ) + elif prefix == "<" and text[:9] == "": + self._doctype = None + return + text = string.strip(text) + if not text: + return + self._doctype.append(text) + n = len(self._doctype) + if n > 2: + type = self._doctype[1] + if type == "PUBLIC" and n == 4: + name, type, pubid, system = self._doctype + elif type == "SYSTEM" and n == 3: + name, type, system = self._doctype + pubid = None + else: + return + if pubid: + pubid = pubid[1:-1] + self.doctype(name, pubid, system[1:-1]) + self._doctype = None + + ## + # Handles a doctype declaration. + # + # @param name Doctype name. + # @param pubid Public identifier. + # @param system System identifier. + + def doctype(self, name, pubid, system): + pass + + ## + # Feeds data to the parser. + # + # @param data Encoded data. + + def feed(self, data): + self._parser.Parse(data, 0) + + ## + # Finishes feeding data to the parser. + # + # @return An element structure. + # @defreturn Element + + def close(self): + self._parser.Parse("", 1) # end of data + tree = self._target.close() + del self._target, self._parser # get rid of circular references + return tree diff --git a/src/python/uts/util/etree/HTMLTreeBuilder.py b/src/python/uts/util/etree/HTMLTreeBuilder.py new file mode 100644 index 00000000..dd9a5e2c --- /dev/null +++ b/src/python/uts/util/etree/HTMLTreeBuilder.py @@ -0,0 +1,230 @@ +# +# ElementTree +# $Id: HTMLTreeBuilder.py 2325 2005-03-16 15:50:43Z fredrik $ +# +# a simple tree builder, for HTML input +# +# history: +# 2002-04-06 fl created +# 2002-04-07 fl ignore IMG and HR end tags +# 2002-04-07 fl added support for 1.5.2 and later +# 2003-04-13 fl added HTMLTreeBuilder alias +# 2004-12-02 fl don't feed non-ASCII charrefs/entities as 8-bit strings +# 2004-12-05 fl don't feed non-ASCII CDATA as 8-bit strings +# +# Copyright (c) 1999-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Tools to build element trees from HTML files. +## + +import htmlentitydefs +import re, string, sys +import mimetools, StringIO + +import ElementTree + +AUTOCLOSE = "p", "li", "tr", "th", "td", "head", "body" +IGNOREEND = "img", "hr", "meta", "link", "br" + +if sys.version[:3] == "1.5": + is_not_ascii = re.compile(r"[\x80-\xff]").search # 1.5.2 +else: + is_not_ascii = re.compile(eval(r'u"[\u0080-\uffff]"')).search + +try: + from HTMLParser import HTMLParser +except ImportError: + from sgmllib import SGMLParser + # hack to use sgmllib's SGMLParser to emulate 2.2's HTMLParser + class HTMLParser(SGMLParser): + # the following only works as long as this class doesn't + # provide any do, start, or end handlers + def unknown_starttag(self, tag, attrs): + self.handle_starttag(tag, attrs) + def unknown_endtag(self, tag): + self.handle_endtag(tag) + +## +# ElementTree builder for HTML source code. This builder converts an +# HTML document or fragment to an ElementTree. +#

+# The parser is relatively picky, and requires balanced tags for most +# elements. However, elements belonging to the following group are +# automatically closed: P, LI, TR, TH, and TD. In addition, the +# parser automatically inserts end tags immediately after the start +# tag, and ignores any end tags for the following group: IMG, HR, +# META, and LINK. +# +# @keyparam builder Optional builder object. If omitted, the parser +# uses the standard elementtree builder. +# @keyparam encoding Optional character encoding, if known. If omitted, +# the parser looks for META tags inside the document. If no tags +# are found, the parser defaults to ISO-8859-1. Note that if your +# document uses a non-ASCII compatible encoding, you must decode +# the document before parsing. +# +# @see elementtree.ElementTree + +class HTMLTreeBuilder(HTMLParser): + + # FIXME: shouldn't this class be named Parser, not Builder? + + def __init__(self, builder=None, encoding=None): + self.__stack = [] + if builder is None: + builder = ElementTree.TreeBuilder() + self.__builder = builder + self.encoding = encoding or "iso-8859-1" + HTMLParser.__init__(self) + + ## + # Flushes parser buffers, and return the root element. + # + # @return An Element instance. + + def close(self): + HTMLParser.close(self) + return self.__builder.close() + + ## + # (Internal) Handles start tags. + + def handle_starttag(self, tag, attrs): + if tag == "meta": + # look for encoding directives + http_equiv = content = None + for k, v in attrs: + if k == "http-equiv": + http_equiv = string.lower(v) + elif k == "content": + content = v + if http_equiv == "content-type" and content: + # use mimetools to parse the http header + header = mimetools.Message( + StringIO.StringIO("%s: %s\n\n" % (http_equiv, content)) + ) + encoding = header.getparam("charset") + if encoding: + self.encoding = encoding + if tag in AUTOCLOSE: + if self.__stack and self.__stack[-1] == tag: + self.handle_endtag(tag) + self.__stack.append(tag) + attrib = {} + if attrs: + for k, v in attrs: + attrib[string.lower(k)] = v + self.__builder.start(tag, attrib) + if tag in IGNOREEND: + self.__stack.pop() + self.__builder.end(tag) + + ## + # (Internal) Handles end tags. + + def handle_endtag(self, tag): + if tag in IGNOREEND: + return + lasttag = self.__stack.pop() + if tag != lasttag and lasttag in AUTOCLOSE: + self.handle_endtag(lasttag) + self.__builder.end(tag) + + ## + # (Internal) Handles character references. + + def handle_charref(self, char): + if char[:1] == "x": + char = int(char[1:], 16) + else: + char = int(char) + if 0 <= char < 128: + self.__builder.data(chr(char)) + else: + self.__builder.data(unichr(char)) + + ## + # (Internal) Handles entity references. + + def handle_entityref(self, name): + entity = htmlentitydefs.entitydefs.get(name) + if entity: + if len(entity) == 1: + entity = ord(entity) + else: + entity = int(entity[2:-1]) + if 0 <= entity < 128: + self.__builder.data(chr(entity)) + else: + self.__builder.data(unichr(entity)) + else: + self.unknown_entityref(name) + + ## + # (Internal) Handles character data. + + def handle_data(self, data): + if isinstance(data, type('')) and is_not_ascii(data): + # convert to unicode, but only if necessary + data = unicode(data, self.encoding, "ignore") + self.__builder.data(data) + + ## + # (Hook) Handles unknown entity references. The default action + # is to ignore unknown entities. + + def unknown_entityref(self, name): + pass # ignore by default; override if necessary + +## +# An alias for the HTMLTreeBuilder class. + +TreeBuilder = HTMLTreeBuilder + +## +# Parse an HTML document or document fragment. +# +# @param source A filename or file object containing HTML data. +# @param encoding Optional character encoding, if known. If omitted, +# the parser looks for META tags inside the document. If no tags +# are found, the parser defaults to ISO-8859-1. +# @return An ElementTree instance + +def parse(source, encoding=None): + return ElementTree.parse(source, HTMLTreeBuilder(encoding=encoding)) + +if __name__ == "__main__": + import sys + ElementTree.dump(parse(open(sys.argv[1]))) diff --git a/src/python/uts/util/etree/SgmlopXMLTreeBuilder.py b/src/python/uts/util/etree/SgmlopXMLTreeBuilder.py new file mode 100644 index 00000000..44ef10ee --- /dev/null +++ b/src/python/uts/util/etree/SgmlopXMLTreeBuilder.py @@ -0,0 +1,103 @@ +# +# ElementTree +# $Id$ +# +# A simple XML tree builder, based on the sgmlop library. +# +# Note that this version does not support namespaces. This may be +# changed in future versions. +# +# history: +# 2004-03-28 fl created +# +# Copyright (c) 1999-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Tools to build element trees from XML, based on the SGMLOP parser. +#

+# The current version does not support XML namespaces. +#

+# This tree builder requires the sgmlop extension module +# (available from +# http://effbot.org/downloads). +## + +import ElementTree + +## +# ElementTree builder for XML source data, based on the SGMLOP parser. +# +# @see elementtree.ElementTree + +class TreeBuilder: + + def __init__(self, html=0): + try: + import sgmlop + except ImportError: + raise RuntimeError("sgmlop parser not available") + self.__builder = ElementTree.TreeBuilder() + if html: + import htmlentitydefs + self.entitydefs.update(htmlentitydefs.entitydefs) + self.__parser = sgmlop.XMLParser() + self.__parser.register(self) + + ## + # Feeds data to the parser. + # + # @param data Encoded data. + + def feed(self, data): + self.__parser.feed(data) + + ## + # Finishes feeding data to the parser. + # + # @return An element structure. + # @defreturn Element + + def close(self): + self.__parser.close() + self.__parser = None + return self.__builder.close() + + def finish_starttag(self, tag, attrib): + self.__builder.start(tag, attrib) + + def finish_endtag(self, tag): + self.__builder.end(tag) + + def handle_data(self, data): + self.__builder.data(data) diff --git a/src/python/uts/util/etree/SimpleXMLTreeBuilder.py b/src/python/uts/util/etree/SimpleXMLTreeBuilder.py new file mode 100644 index 00000000..d071a141 --- /dev/null +++ b/src/python/uts/util/etree/SimpleXMLTreeBuilder.py @@ -0,0 +1,144 @@ +# +# ElementTree +# $Id: SimpleXMLTreeBuilder.py 1862 2004-06-18 07:31:02Z Fredrik $ +# +# A simple XML tree builder, based on Python's xmllib +# +# Note that due to bugs in xmllib, this builder does not fully support +# namespaces (unqualified attributes are put in the default namespace, +# instead of being left as is). Run this module as a script to find +# out if this affects your Python version. +# +# history: +# 2001-10-20 fl created +# 2002-05-01 fl added namespace support for xmllib +# 2002-08-17 fl added xmllib sanity test +# +# Copyright (c) 1999-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Tools to build element trees from XML files, using xmllib. +# This module can be used instead of the standard tree builder, for +# Python versions where "expat" is not available (such as 1.5.2). +#

+# Note that due to bugs in xmllib, the namespace support is +# not reliable (you can run the module as a script to find out exactly +# how unreliable it is on your Python version). +## + +import xmllib, string + +import ElementTree + +## +# ElementTree builder for XML source data. +# +# @see elementtree.ElementTree + +class TreeBuilder(xmllib.XMLParser): + + def __init__(self, html=0): + self.__builder = ElementTree.TreeBuilder() + if html: + import htmlentitydefs + self.entitydefs.update(htmlentitydefs.entitydefs) + xmllib.XMLParser.__init__(self) + + ## + # Feeds data to the parser. + # + # @param data Encoded data. + + def feed(self, data): + xmllib.XMLParser.feed(self, data) + + ## + # Finishes feeding data to the parser. + # + # @return An element structure. + # @defreturn Element + + def close(self): + xmllib.XMLParser.close(self) + return self.__builder.close() + + def handle_data(self, data): + self.__builder.data(data) + + handle_cdata = handle_data + + def unknown_starttag(self, tag, attrs): + attrib = {} + for key, value in attrs.items(): + attrib[fixname(key)] = value + self.__builder.start(fixname(tag), attrib) + + def unknown_endtag(self, tag): + self.__builder.end(fixname(tag)) + + +def fixname(name, split=string.split): + # xmllib in 2.0 and later provides limited (and slightly broken) + # support for XML namespaces. + if " " not in name: + return name + return "{%s}%s" % tuple(split(name, " ", 1)) + + +if __name__ == "__main__": + import sys + # sanity check: look for known namespace bugs in xmllib + p = TreeBuilder() + text = """\ + + + + """ + p.feed(text) + tree = p.close() + status = [] + # check for bugs in the xmllib implementation + tag = tree.find("{default}tag") + if tag is None: + status.append("namespaces not supported") + if tag is not None and tag.get("{default}attribute"): + status.append("default namespace applied to unqualified attribute") + # report bugs + if status: + print "xmllib doesn't work properly in this Python version:" + for bug in status: + print "-", bug + else: + print "congratulations; no problems found in xmllib" + diff --git a/src/python/uts/util/etree/SimpleXMLWriter.py b/src/python/uts/util/etree/SimpleXMLWriter.py new file mode 100644 index 00000000..af3023f4 --- /dev/null +++ b/src/python/uts/util/etree/SimpleXMLWriter.py @@ -0,0 +1,279 @@ +# +# SimpleXMLWriter +# $Id: SimpleXMLWriter.py 2312 2005-03-02 18:13:39Z fredrik $ +# +# a simple XML writer +# +# history: +# 2001-12-28 fl created +# 2002-11-25 fl fixed attribute encoding +# 2002-12-02 fl minor fixes for 1.5.2 +# 2004-06-17 fl added pythondoc markup +# 2004-07-23 fl added flush method (from Jay Graves) +# 2004-10-03 fl added declaration method +# +# Copyright (c) 2001-2004 by Fredrik Lundh +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The SimpleXMLWriter module is +# +# Copyright (c) 2001-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Tools to write XML files, without having to deal with encoding +# issues, well-formedness, etc. +#

+# The current version does not provide built-in support for +# namespaces. To create files using namespaces, you have to provide +# "xmlns" attributes and explicitly add prefixes to tags and +# attributes. +# +#

Patterns

+# +# The following example generates a small XHTML document. +#
+#
+# from elementtree.SimpleXMLWriter import XMLWriter
+# import sys
+#
+# w = XMLWriter(sys.stdout)
+#
+# html = w.start("html")
+#
+# w.start("head")
+# w.element("title", "my document")
+# w.element("meta", name="generator", value="my application 1.0")
+# w.end()
+#
+# w.start("body")
+# w.element("h1", "this is a heading")
+# w.element("p", "this is a paragraph")
+#
+# w.start("p")
+# w.data("this is ")
+# w.element("b", "bold")
+# w.data(" and ")
+# w.element("i", "italic")
+# w.data(".")
+# w.end("p")
+#
+# w.close(html)
+# 
+## + +import re, sys, string + +try: + unicode("") +except NameError: + def encode(s, encoding): + # 1.5.2: application must use the right encoding + return s + _escape = re.compile(r"[&<>\"\x80-\xff]+") # 1.5.2 +else: + def encode(s, encoding): + return s.encode(encoding) + _escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"')) + +def encode_entity(text, pattern=_escape): + # map reserved and non-ascii characters to numerical entities + def escape_entities(m): + out = [] + for char in m.group(): + out.append("&#%d;" % ord(char)) + return string.join(out, "") + return encode(pattern.sub(escape_entities, text), "ascii") + +del _escape + +# +# the following functions assume an ascii-compatible encoding +# (or "utf-16") + +def escape_cdata(s, encoding=None, replace=string.replace): + s = replace(s, "&", "&") + s = replace(s, "<", "<") + s = replace(s, ">", ">") + if encoding: + try: + return encode(s, encoding) + except UnicodeError: + return encode_entity(s) + return s + +def escape_attrib(s, encoding=None, replace=string.replace): + s = replace(s, "&", "&") + s = replace(s, "'", "'") + s = replace(s, "\"", """) + s = replace(s, "<", "<") + s = replace(s, ">", ">") + if encoding: + try: + return encode(s, encoding) + except UnicodeError: + return encode_entity(s) + return s + +## +# XML writer class. +# +# @param file A file or file-like object. This object must implement +# a write method that takes an 8-bit string. +# @param encoding Optional encoding. + +class XMLWriter: + + def __init__(self, file, encoding="us-ascii"): + if not hasattr(file, "write"): + file = open(file, "w") + self.__write = file.write + if hasattr(file, "flush"): + self.flush = file.flush + self.__open = 0 # true if start tag is open + self.__tags = [] + self.__data = [] + self.__encoding = encoding + + def __flush(self): + # flush internal buffers + if self.__open: + self.__write(">") + self.__open = 0 + if self.__data: + data = string.join(self.__data, "") + self.__write(escape_cdata(data, self.__encoding)) + self.__data = [] + + ## + # Writes an XML declaration. + + def declaration(self): + encoding = self.__encoding + if encoding == "us-ascii" or encoding == "utf-8": + self.__write("\n") + else: + self.__write("\n" % encoding) + + ## + # Opens a new element. Attributes can be given as keyword + # arguments, or as a string/string dictionary. You can pass in + # 8-bit strings or Unicode strings; the former are assumed to use + # the encoding passed to the constructor. The method returns an + # opaque identifier that can be passed to the close method, + # to close all open elements up to and including this one. + # + # @param tag Element tag. + # @param attrib Attribute dictionary. Alternatively, attributes + # can be given as keyword arguments. + # @return An element identifier. + + def start(self, tag, attrib={}, **extra): + self.__flush() + tag = escape_cdata(tag, self.__encoding) + self.__data = [] + self.__tags.append(tag) + self.__write("<%s" % tag) + if attrib or extra: + attrib = attrib.copy() + attrib.update(extra) + attrib = attrib.items() + attrib.sort() + for k, v in attrib: + k = escape_cdata(k, self.__encoding) + v = escape_attrib(v, self.__encoding) + self.__write(" %s=\"%s\"" % (k, v)) + self.__open = 1 + return len(self.__tags)-1 + + ## + # Adds a comment to the output stream. + # + # @param comment Comment text, as an 8-bit string or Unicode string. + + def comment(self, comment): + self.__flush() + self.__write("\n" % escape_cdata(comment, self.__encoding)) + + ## + # Adds character data to the output stream. + # + # @param text Character data, as an 8-bit string or Unicode string. + + def data(self, text): + self.__data.append(text) + + ## + # Closes the current element (opened by the most recent call to + # start). + # + # @param tag Element tag. If given, the tag must match the start + # tag. If omitted, the current element is closed. + + def end(self, tag=None): + if tag: + assert self.__tags, "unbalanced end(%s)" % tag + assert escape_cdata(tag, self.__encoding) == self.__tags[-1],\ + "expected end(%s), got %s" % (self.__tags[-1], tag) + else: + assert self.__tags, "unbalanced end()" + tag = self.__tags.pop() + if self.__data: + self.__flush() + elif self.__open: + self.__open = 0 + self.__write(" />") + return + self.__write("" % tag) + + ## + # Closes open elements, up to (and including) the element identified + # by the given identifier. + # + # @param id Element identifier, as returned by the start method. + + def close(self, id): + while len(self.__tags) > id: + self.end() + + ## + # Adds an entire element. This is the same as calling start, + # data, and end in sequence. The text argument + # can be omitted. + + def element(self, tag, text=None, attrib={}, **extra): + apply(self.start, (tag, attrib), extra) + if text: + self.data(text) + self.end() + + ## + # Flushes the output stream. + + def flush(self): + pass # replaced by the constructor diff --git a/src/python/uts/util/etree/TidyHTMLTreeBuilder.py b/src/python/uts/util/etree/TidyHTMLTreeBuilder.py new file mode 100644 index 00000000..c851d97b --- /dev/null +++ b/src/python/uts/util/etree/TidyHTMLTreeBuilder.py @@ -0,0 +1,6 @@ +# +# ElementTree +# $Id: TidyHTMLTreeBuilder.py 2304 2005-03-01 17:42:41Z fredrik $ +# + +from elementtidy.TidyHTMLTreeBuilder import * diff --git a/src/python/uts/util/etree/TidyTools.py b/src/python/uts/util/etree/TidyTools.py new file mode 100644 index 00000000..f3a07415 --- /dev/null +++ b/src/python/uts/util/etree/TidyTools.py @@ -0,0 +1,128 @@ +# +# ElementTree +# $Id: TidyTools.py 1862 2004-06-18 07:31:02Z Fredrik $ +# +# tools to run the "tidy" command on an HTML or XHTML file, and return +# the contents as an XHTML element tree. +# +# history: +# 2002-10-19 fl added to ElementTree library; added getzonebody function +# +# Copyright (c) 1999-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# + +## +# Tools to build element trees from HTML, using the external tidy +# utility. +## + +import glob, string, os, sys + +from ElementTree import ElementTree, Element + +NS_XHTML = "{http://www.w3.org/1999/xhtml}" + +## +# Convert an HTML or HTML-like file to XHTML, using the tidy +# command line utility. +# +# @param file Filename. +# @param new_inline_tags An optional list of valid but non-standard +# inline tags. +# @return An element tree, or None if not successful. + +def tidy(file, new_inline_tags=None): + + command = ["tidy", "-qn", "-asxml"] + + if new_inline_tags: + command.append("--new-inline-tags") + command.append(string.join(new_inline_tags, ",")) + + # FIXME: support more tidy options! + + # convert + os.system( + "%s %s >%s.out 2>%s.err" % (string.join(command), file, file, file) + ) + # check that the result is valid XML + try: + tree = ElementTree() + tree.parse(file + ".out") + except: + print "*** %s:%s" % sys.exc_info()[:2] + print ("*** %s is not valid XML " + "(check %s.err for info)" % (file, file)) + tree = None + else: + if os.path.isfile(file + ".out"): + os.remove(file + ".out") + if os.path.isfile(file + ".err"): + os.remove(file + ".err") + + return tree + +## +# Get document body from a an HTML or HTML-like file. This function +# uses the tidy function to convert HTML to XHTML, and cleans +# up the resulting XML tree. +# +# @param file Filename. +# @return A body element, or None if not successful. + +def getbody(file, **options): + # get clean body from text file + + # get xhtml tree + try: + tree = apply(tidy, (file,), options) + if tree is None: + return + except IOError, v: + print "***", v + return None + + NS = NS_XHTML + + # remove namespace uris + for node in tree.getiterator(): + if node.tag.startswith(NS): + node.tag = node.tag[len(NS):] + + body = tree.getroot().find("body") + + return body + +## +# Same as getbody, but turns plain text at the start of the +# document into an H1 tag. This function can be used to parse zone +# documents. +# +# @param file Filename. +# @return A body element, or None if not successful. + +def getzonebody(file, **options): + + body = getbody(file, **options) + if body is None: + return + + if body.text and string.strip(body.text): + title = Element("h1") + title.text = string.strip(body.text) + title.tail = "\n\n" + body.insert(0, title) + + body.text = None + + return body + +if __name__ == "__main__": + + import sys + for arg in sys.argv[1:]: + for file in glob.glob(arg): + print file, "...", tidy(file) diff --git a/src/python/uts/util/etree/XMLTreeBuilder.py b/src/python/uts/util/etree/XMLTreeBuilder.py new file mode 100644 index 00000000..405a7f28 --- /dev/null +++ b/src/python/uts/util/etree/XMLTreeBuilder.py @@ -0,0 +1,113 @@ +# +# ElementTree +# $Id: XMLTreeBuilder.py 2305 2005-03-01 17:43:09Z fredrik $ +# +# an XML tree builder +# +# history: +# 2001-10-20 fl created +# 2002-05-01 fl added namespace support for xmllib +# 2002-07-27 fl require expat (1.5.2 code can use SimpleXMLTreeBuilder) +# 2002-08-17 fl use tag/attribute name memo cache +# 2002-12-04 fl moved XMLTreeBuilder to the ElementTree module +# +# Copyright (c) 1999-2004 by Fredrik Lundh. All rights reserved. +# +# fredrik@pythonware.com +# http://www.pythonware.com +# +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +## +# Tools to build element trees from XML files. +## + +import ElementTree + +## +# (obsolete) ElementTree builder for XML source data, based on the +# expat parser. +#

+# This class is an alias for ElementTree.XMLTreeBuilder. New code +# should use that version instead. +# +# @see elementtree.ElementTree + +class TreeBuilder(ElementTree.XMLTreeBuilder): + pass + +## +# (experimental) An alternate builder that supports manipulation of +# new elements. + +class FancyTreeBuilder(TreeBuilder): + + def __init__(self, html=0): + TreeBuilder.__init__(self, html) + self._parser.StartNamespaceDeclHandler = self._start_ns + self._parser.EndNamespaceDeclHandler = self._end_ns + self.namespaces = [] + + def _start(self, tag, attrib_in): + elem = TreeBuilder._start(self, tag, attrib_in) + self.start(elem) + + def _start_list(self, tag, attrib_in): + elem = TreeBuilder._start_list(self, tag, attrib_in) + self.start(elem) + + def _end(self, tag): + elem = TreeBuilder._end(self, tag) + self.end(elem) + + def _start_ns(self, prefix, value): + self.namespaces.insert(0, (prefix, value)) + + def _end_ns(self, prefix): + assert self.namespaces.pop(0)[0] == prefix, "implementation confused" + + ## + # Hook method that's called when a new element has been opened. + # May access the namespaces attribute. + # + # @param element The new element. The tag name and attributes are, + # set, but it has no children, and the text and tail attributes + # are still empty. + + def start(self, element): + pass + + ## + # Hook method that's called when a new element has been closed. + # May access the namespaces attribute. + # + # @param element The new element. + + def end(self, element): + pass diff --git a/src/python/uts/util/etree/__init__.py b/src/python/uts/util/etree/__init__.py new file mode 100644 index 00000000..cef1a6bb --- /dev/null +++ b/src/python/uts/util/etree/__init__.py @@ -0,0 +1,30 @@ +# $Id: __init__.py 1821 2004-06-03 16:57:49Z fredrik $ +# elementtree package + +# -------------------------------------------------------------------- +# The ElementTree toolkit is +# +# Copyright (c) 1999-2004 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- diff --git a/src/python/uts/util/observation.py b/src/python/uts/util/observation.py new file mode 100644 index 00000000..8814b196 --- /dev/null +++ b/src/python/uts/util/observation.py @@ -0,0 +1,47 @@ + +from catalog import Object + +class Observation(object): + + def __init__(self, target = None): + self.obj = Object() + self.nexp = 0 + self.exptime = 0 + self.filter = 0 + self.path = "" + self.filenameIndex = 0 + self.observationTime = None + self.frameType = None + + if(target): + self.fromList(target) + + def fromList(self, target): + self.obj = Object(target[1], target[2], target[3]) + self.nexp = target[4] + self.exptime = target[5] + self.filter = target[6] + self.path = target[7] + self.filenameIndex = 0 + self.observationTime = None + self.frameType = target[0] + + def __repr__(self): + s = "%s %s %s\n#%s exposures of %s seconds each." % (self.obj.name, self.obj.ra, self.obj.dec, self.nexp, self.exptime) + return s + +class ObservationPlan(object): + + def __init__(self): + + self.observations = [] + + def __len__(self): + return len(self.observations) + + def __iter__(self): + return iter(self.observations) + + def addObservation(self, obs): + self.observations.append(obs) + diff --git a/src/python/uts/util/output.py b/src/python/uts/util/output.py new file mode 100644 index 00000000..6508c229 --- /dev/null +++ b/src/python/uts/util/output.py @@ -0,0 +1,196 @@ +# Copyright 1998-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id: output.py,v 1.1 2006/03/06 18:13:31 henrique Exp $ + + +import os,sys,re + +havecolor=1 +dotitles=1 + +spinpos = 0 +spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" + +esc_seq = "\x1b[" + +g_attr = {} +g_attr["normal"] = 0 + +g_attr["bold"] = 1 +g_attr["faint"] = 2 +g_attr["standout"] = 3 +g_attr["underline"] = 4 +g_attr["blink"] = 5 +g_attr["overline"] = 6 # Why is overline actually useful? +g_attr["reverse"] = 7 +g_attr["invisible"] = 8 + +g_attr["no-attr"] = 22 +g_attr["no-standout"] = 23 +g_attr["no-underline"] = 24 +g_attr["no-blink"] = 25 +g_attr["no-overline"] = 26 +g_attr["no-reverse"] = 27 +# 28 isn't defined? +# 29 isn't defined? +g_attr["black"] = 30 +g_attr["red"] = 31 +g_attr["green"] = 32 +g_attr["yellow"] = 33 +g_attr["blue"] = 34 +g_attr["magenta"] = 35 +g_attr["cyan"] = 36 +g_attr["white"] = 37 +# 38 isn't defined? +g_attr["default"] = 39 +g_attr["bg_black"] = 40 +g_attr["bg_red"] = 41 +g_attr["bg_green"] = 42 +g_attr["bg_yellow"] = 43 +g_attr["bg_blue"] = 44 +g_attr["bg_magenta"] = 45 +g_attr["bg_cyan"] = 46 +g_attr["bg_white"] = 47 +g_attr["bg_default"] = 49 + + +# make_seq("blue", "black", "normal") +def color(fg, bg="default", attr=["normal"]): + mystr = esc_seq[:] + "%02d" % g_attr[fg] + for x in [bg]+attr: + mystr += ";%02d" % g_attr[x] + return mystr+"m" + + + +codes={} +codes["reset"] = esc_seq + "39;49;00m" + +codes["bold"] = esc_seq + "01m" +codes["faint"] = esc_seq + "02m" +codes["standout"] = esc_seq + "03m" +codes["underline"] = esc_seq + "04m" +codes["blink"] = esc_seq + "05m" +codes["overline"] = esc_seq + "06m" # Who made this up? Seriously. + +codes["teal"] = esc_seq + "36m" +codes["turquoise"] = esc_seq + "36;01m" + +codes["fuchsia"] = esc_seq + "35;01m" +codes["purple"] = esc_seq + "35m" + +codes["blue"] = esc_seq + "34;01m" +codes["darkblue"] = esc_seq + "34m" + +codes["green"] = esc_seq + "32;01m" +codes["darkgreen"] = esc_seq + "32m" + +codes["yellow"] = esc_seq + "33;01m" +codes["brown"] = esc_seq + "33m" + +codes["red"] = esc_seq + "31;01m" +codes["darkred"] = esc_seq + "31m" + +def nc_len(mystr): + tmp = re.sub(esc_seq + "^m]+m", "", mystr); + return len(tmp) + +def xtermTitle(mystr): + if havecolor and dotitles and os.environ.has_key("TERM") and sys.stderr.isatty(): + myt=os.environ["TERM"] + legal_terms = ["xterm","Eterm","aterm","rxvt","screen","kterm","rxvt-unicode"] + for term in legal_terms: + if myt.startswith(term): + sys.stderr.write("\x1b]2;"+str(mystr)+"\x07") + sys.stderr.flush() + break + +def xtermTitleReset(): + if havecolor and dotitles and os.environ.has_key("TERM"): + myt=os.environ["TERM"] + xtermTitle(os.environ["TERM"]) + + +def notitles(): + "turn off title setting" + dotitles=0 + +def nocolor(): + "turn off colorization" + havecolor=0 + for x in codes.keys(): + codes[x]="" + +def resetColor(): + return codes["reset"] + +def ctext(color,text): + return codes[ctext]+text+codes["reset"] + +def bold(text): + return codes["bold"]+text+codes["reset"] +def white(text): + return bold(text) + +def teal(text): + return codes["teal"]+text+codes["reset"] +def turquoise(text): + return codes["turquoise"]+text+codes["reset"] +def darkteal(text): + return turquoise(text) + +def fuscia(text): # Don't use this one. It's spelled wrong! + return codes["fuchsia"]+text+codes["reset"] +def fuchsia(text): + return codes["fuchsia"]+text+codes["reset"] +def purple(text): + return codes["purple"]+text+codes["reset"] + +def blue(text): + return codes["blue"]+text+codes["reset"] +def darkblue(text): + return codes["darkblue"]+text+codes["reset"] + +def green(text): + return codes["green"]+text+codes["reset"] +def darkgreen(text): + return codes["darkgreen"]+text+codes["reset"] + +def yellow(text): + return codes["yellow"]+text+codes["reset"] +def brown(text): + return codes["brown"]+text+codes["reset"] +def darkyellow(text): + return brown(text) + +def red(text): + return codes["red"]+text+codes["reset"] +def darkred(text): + return codes["darkred"]+text+codes["reset"] + + +def update_basic_spinner(): + global spinner, spinpos + spinpos = (spinpos+1) % 500 + if (spinpos % 100) == 0: + if spinpos == 0: + sys.stdout.write(". ") + else: + sys.stdout.write(".") + sys.stdout.flush() + +def update_scroll_spinner(): + global spinner, spinpos + if(spinpos >= len(spinner)): + sys.stdout.write(darkgreen(" \b\b\b"+spinner[len(spinner)-1-(spinpos%len(spinner))])) + else: + sys.stdout.write(green("\b "+spinner[spinpos])) + sys.stdout.flush() + spinpos = (spinpos+1) % (2*len(spinner)) + + +def update_spinner(): + global spinner, spinpos + spinpos = (spinpos+1) % len(spinner) + sys.stdout.write("\b\b "+spinner[spinpos]) + sys.stdout.flush() diff --git a/src/sec/Makefile.am b/src/sec/Makefile.am new file mode 100644 index 00000000..93dab490 --- /dev/null +++ b/src/sec/Makefile.am @@ -0,0 +1,13 @@ +include $(top_srcdir)/rules.make + +noinst_LIBRARIES = libsec.a + +libsec_a_SOURCES = sec.c messages.c skterror.c sktlist.c fields.c \ + sec.h messages.h skterror.h sktlist.h fields.h + +bin_PROGRAMS = sec + +sec_SOURCES = server.c sec_config.c sec_server.c main.c \ + server.h sec_config.h sec_server.h main.h + +sec_LDADD = -lsimpleskts -lsec diff --git a/src/sec/SConscript b/src/sec/SConscript new file mode 100644 index 00000000..9031a372 --- /dev/null +++ b/src/sec/SConscript @@ -0,0 +1,24 @@ +#! /usr/bin/python + +Import("env") + +_sources = Split( + +""" +server.c sec_config.c sec_server.c main.c +""" +) + +_libSources = Split( +""" +sec.c messages.c skterror.c sktlist.c fields.c +""" +) + +env.Program('sec', _sources, + CPPPATH=['.', '#contrib/include'], + LIBPATH=['#contrib/lib', '.'], + LIBS=['simpleskts', 'sec']) + +env.StaticLibrary('sec', _libSources, + CPPPATH=['.', '#contrib/include']) diff --git a/src/sec/fields.c b/src/sec/fields.c new file mode 100644 index 00000000..158f23d0 --- /dev/null +++ b/src/sec/fields.c @@ -0,0 +1,61 @@ +/*************************************************************************** + fields.c - description + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include +#include +#include "fields.h" + +int getfield(char *command, field *f, const char *flist[]) +{ + int i; + char tmp[MAX_FIELD_SIZE]; + char *ptr; + + if (command == NULL || *command == '\0') return(FEMPTY_FIELD); + if (flist == NULL) return (EOF); + + /* find field type */ + ptr = tmp; + while (isspace(*command)) command++; + if (*command == FCOMMENT_CHAR || *command == '\0') + /* Comment or empty line */ + return(FEMPTY_FIELD); + + i = 0; + while (!isspace(*command) && *command != '\0' && i++ < MAX_FIELD_SIZE) + *ptr++ = *command++; + *ptr = '\0'; + + i = -1; + /* Look for the field index, */ + /* exit if reached the end of list */ + do + if (flist[++i] == NULL) return (FNO_MATCH); + while (strncmp(tmp, flist[i], MAX_FIELD_SIZE) != 0); + + /* do not care with field contents */ + if (f == NULL) return (i); + + /* store field content */ + f->index = i; + while (isspace(*command)) command++; + /* while (*ptr++ = *command++); */ + f->contents = command; + + return(i); +} + diff --git a/src/sec/fields.h b/src/sec/fields.h new file mode 100644 index 00000000..dfb13add --- /dev/null +++ b/src/sec/fields.h @@ -0,0 +1,68 @@ +/*************************************************************************** + fields.h - command identification + ------------------- + begin : Wed Jun 7 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef FIELDS_H +#define FIELDS_H + +#define MAX_FIELD_SIZE (50) +#define MAX_FIELD_CONTENTS (255) +#define FCOMMENT_CHAR '#' + + + +#define FNO_MATCH (-10) +#define FEMPTY_FIELD (-11) + +typedef struct { + int index; /* position of field in list */ + char *contents; /* points to field contents in command */ +} field; + + +/* getfield() breaks ``command'' in a field, contained in ``flist'', + and its contents. It ignores whitespace before and after field + (see example). Also, a `#' beginning character could be used as + ``comment character''. + + Field and contents are stored in a ``field'' structure; ``index'' + is the position of the field in ``flist''. The return value is index, + if successfull, FNO_MATCH if the command isn't in ``flist'' and + FEMPTY_FIELD if command is an empty command. + If ``f'' is NULL, getfield just gets the index and returns. + + Example: + + #include "getfield.h" + + (...) + + cmd = " FIELD2 CONTENTS"; + char *fl[] = { "FIELD1", "FIELD2", "FIELD3" }; + field f; + int i; + + (...) + + i = getfield(cmd, &f, fl); // i == 1 + printf("Index: %d\n", f.index); // Index: 1 + printf("Contents: %s\n", f.contents); // Contents: CONTENTS + + */ + +int getfield(char *command, field *f, const char *flist[]); + +#endif /* FIELDS_H */ diff --git a/src/sec/main.c b/src/sec/main.c new file mode 100644 index 00000000..6fb9be19 --- /dev/null +++ b/src/sec/main.c @@ -0,0 +1,281 @@ +/*************************************************************************** + main.c - description + ------------------- + begin : Tue Jul 11 14:18:57 BRT 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "sec_server.h" + +#define FALSE (0) +#define TRUE (1) + +#define PROGRAM_NAME "Socket Secretary" +#define URL "http://www.astro.ufsc.br/~andre/" +#ifndef VERSION +#define VERSION "Beta" +#endif + +#define ROOT_DIR_ENV_VAR "UTS_DIR" +#define DEF_ROOT_DIR "/usr/local/uts" +#define DEF_CONF_FILE_NAME "/etc/sec.conf" + + +/*** Global variables filled by get_args() ***/ +char *exec_name; /* Name of executable file */ +static char *conffname; /* configuration file */ +static char *logfname; /* log file */ +static int detach = FALSE; /* should the program detach from terminal? */ + + +static void print_title(void); +static void print_help(void); +static void print_version(void); +static void print_usage(void); +static void get_args(int argc, char **argv); +static void goto_bg(void); + + +/*-------------------------------------------------------------------------*/ + +int main(int argc, char **argv) +{ + + SecServer *sec; + + /* Parse arguments */ + get_args(argc, argv); + + /* Open log file and redirect stdout, if required */ + if (logfname != NULL) { + fprintf(stderr, " -> Logging to file \"%s\".\n", logfname); + stdout = freopen(logfname, "a", stdout); + if (stdout == NULL) { + fprintf(stderr, "*** Error opening file \"%s\".\n", + logfname); + exit(1); + } + } + + /*** The function exit() is not recommended hereafter. ***/ + /*** Use abort() instead. ***/ + + sec = sec_server_new(); + if(sec == NULL) abort(); + + /* Set signal handlers and get configuration */ + fprintf(stderr, " -> Getting configuration from file \"%s\".\n", conffname); + + if(sec_server_configure(sec, conffname) == FALSE) + abort(); + + /* Open the servers */ + fprintf(stderr, " -> Opening servers for instrument %s.\n", sec->config->instname); + + sec_server_run(sec); + + fprintf(stderr, " -> OK, working.\n"); + + if (detach) { + /* Detach from terminal (daemon mode) */ + fprintf(stderr, " -> Jumping into background...\n\n"); + goto_bg(); + /* close stdout if no logfile specified */ + if (logfname == NULL) fclose(stdout); + } + + + /*** Main loop ***/ + while (sec_server_wait(sec) >= 0) { + /* Do any periodic stuff here, but don't overload. */ + /* -> check inactive sockets every */ + sec_server_check(sec); + } + + /* waitsockets failed! */ + printf("*** Program crash.\n"); + abort(); +} + +/*-------------------------------------------------------------------------*/ + +static void print_title(void) +{ + printf("%s %s\n", PROGRAM_NAME, VERSION); +} + +/*-------------------------------------------------------------------------*/ + +static void print_help(void) +{ + print_title(); + printf("This program requires Socket PortMaster (Spm) running.\n"); +#ifdef NOTIFY_ON_CHANGE + printf("This version notifies only when status changes.\n\n\n"); +#else + printf("This version notifies always.\n\n\n"); +#endif + print_usage(); + printf("\nIf no config file is specified, this program will search " + "under the environment\n" + "variable %s:\n\n" + " ${%s}%s\n\n", ROOT_DIR_ENV_VAR, ROOT_DIR_ENV_VAR, + DEF_CONF_FILE_NAME); + printf("If this file does not exists, this program will try " + "the following file:\n\n" + " %s%s\n\n\n", DEF_ROOT_DIR, DEF_CONF_FILE_NAME); + printf("Command line options:\n\n" + " -h / --help\n" + " This help screen.\n\n" + + " -v / --version\n" + " Display version and copyright " + " information.\n\n" + + " -d / --detach\n" + " Daemon mode.\n" + " Put the program in background.\n\n" + + " -o / --output \n" + " Redirect output to ,\n" + " instead of showing it on the terminal.\n\n\n" + ); + + printf("Visit the home page\n" + "%s\n" + "for more information.\n\n", URL); + exit(0); +} + +/*-------------------------------------------------------------------------*/ + +static void print_version(void) +{ + print_title(); + printf("Copyright (C) 2001 Andre Luiz de Amorim\n"); + printf("%s comes with NO WARRANTY,\n" + "to the extent permitted by law.\n", PROGRAM_NAME); + printf("You may redistribute copies of %s\n" + "under the terms of the GNU General Public License.\n" + "For more information about these matters,\n" + "see the files named COPYING.\n", PROGRAM_NAME); + + exit(0); +} + +/*-------------------------------------------------------------------------*/ + +static void print_usage(void) +{ + printf("SYNTAX:\n" + " %s [-o ] [-d] [config_file]\n\n" + " %s {-h|--help}\n\n", exec_name, exec_name); +} + +/*-------------------------------------------------------------------------*/ + +static void get_args(int argc, char **argv) +{ + int next_opt; + const char *short_options = "hvdo:"; + const struct option long_options [] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'v' }, + { "detach", 0, NULL, 'd' }, + { "output", 1, NULL, 'o' }, + { NULL, 0, NULL, 0 } + }; + + exec_name = argv[0]; + conffname = NULL; + logfname = NULL; + do { + next_opt = getopt_long(argc, argv, short_options, + long_options, NULL); + switch (next_opt) { + case 'h': + print_help(); + break; + + case 'v': + print_version(); + break; + + case 'd': + detach = TRUE; + break; + + case 'o': + /* log file name */ + logfname = optarg; + break; + + case '?': + /* Invalid option */ + print_usage(); + exit(1); + break; + + case -1: + /* end of options */ + break; + + default: + abort(); + break; + } + } while (next_opt != -1); + + if (optind < argc) + /* config file is the first non-option argument */ + conffname = argv[optind]; + + /* If config file is not specified, try to get it from environment */ + if (conffname == NULL) { + int n; + char *root_dir = getenv(ROOT_DIR_ENV_VAR); + if (root_dir == NULL) root_dir = DEF_ROOT_DIR; + + n = strlen(root_dir) + strlen(DEF_CONF_FILE_NAME) + 1; + conffname = calloc(n, sizeof(char)); + strncpy(conffname, root_dir, n); + strncat(conffname, DEF_CONF_FILE_NAME, n); + } +} + +/*-------------------------------------------------------------------------*/ + +static void goto_bg(void) +{ + int daemon = 0; + + daemon = fork(); + if (daemon < 0) fprintf(stderr, + "*** Error: Could not detach from terminal\n"); + else if (daemon) exit(0); /* We're the parent, so bye-bye! */ + + setsid(); /* release controlling terminal */ + +} + +/*-------------------------------------------------------------------------*/ diff --git a/src/sec/messages.c b/src/sec/messages.c new file mode 100644 index 00000000..13328bdd --- /dev/null +++ b/src/sec/messages.c @@ -0,0 +1,40 @@ +/*************************************************************************** + messages.c - description + ------------------- + begin : Thu Feb 1 2001 + copyright : (C) 2001 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +/* communication commands */ +const char *fcomm[] = { + "QUIT", "IDENT", "STATUS", "SETSTATUS", "NOTIFY", "UNOTIFY", + "CONTROL", "ANSWER", "RESET", "SHUTDOWN", NULL +}; /* The null pointer terminator prevents getfield() + to raise a `Segmentation fault' */ + +/* Responses */ +const char *fresponses[] = { + "HELLO", "OK", "ERROR", "ABORT","SERVER_FULL", + "STATUS", "NOTIFY", "RESET", NULL +}; + +/* instrument states */ +const char *finststatus[] = { + "OFFLINE", "BUSY", "DISABLED", "IDLE", NULL +}; + +/* TRUE & FALSE */ +#define S_TRUE "TRUE" +#define S_FALSE "FALSE" diff --git a/src/sec/messages.h b/src/sec/messages.h new file mode 100644 index 00000000..5a56ec41 --- /dev/null +++ b/src/sec/messages.h @@ -0,0 +1,40 @@ +/*************************************************************************** + messages.h - description + ------------------- + begin : Thu Feb 1 2001 + copyright : (C) 2001 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef MESSAGES_H +#define MESSAGES_H + +/* TRUE & FALSE */ +#define S_TRUE "TRUE" +#define S_FALSE "FALSE" + + +/* communication commands */ +extern const char *fcomm[]; +enum { C_QUIT, C_IDENT, C_STATUS, C_SETSTATUS, C_NOTIFY, C_UNOTIFY, + C_CONTROL, C_ANSWER, C_RESET, C_SHUTDOWN }; + +/* Responses */ +extern const char *fresponses[]; +enum { RES_HELLO, RES_OK, RES_ERROR, RES_ABORT, RES_SERVER_FULL, RES_STATUS, + RES_NOTIFY, RES_RESET }; + +/* instrument states */ +extern const char *finststatus[]; +enum { IST_OFFLINE, IST_BUSY, IST_DISABLED, IST_IDLE }; + +#endif /* MESSAGES_H */ diff --git a/src/sec/sdict-test.c b/src/sec/sdict-test.c new file mode 100644 index 00000000..da47cdef --- /dev/null +++ b/src/sec/sdict-test.c @@ -0,0 +1,56 @@ +#include "sdict.h" + +#include +#include +#include + +int main(void) { + + SDict* dict = s_dict_new(); + assert(dict != NULL); + + int i = s_dict_count(dict); + assert(i == 0); + + s_dict_add(dict, "NOME", "VALOR"); + + int j = s_dict_count(dict); + assert(j == 1); + + char* s = (char*) s_dict_get(dict, "NOME");; + assert(strcmp("VALOR", s) == 0);; + + char* keys[4] = {"NOME1", "NOME2", "NOME3", "NOME4"}; + char* values[4] = {"VALOR1", "VALOR2", "VALOR3", "VALOR4"}; + + s_dict_add_array(dict, keys, values, 4); + + char* s1 = (char*) s_dict_get(dict, "NOME1");; + assert(strcmp("VALOR1", s1) == 0);; + + char* s2 = (char*) s_dict_get(dict, "NOME2");; + assert(strcmp("VALOR2", s2) == 0);; + + char* s3 = (char*) s_dict_get(dict, "NOME3");; + assert(strcmp("VALOR3", s3) == 0);; + + char* s4 = (char*) s_dict_get(dict, "NOME4");; + assert(strcmp("VALOR4", s4) == 0);; + + s_dict_set(dict, "NOME4", "NOVO"); + + char* s5 = (char*) s_dict_get(dict, "NOME4");; + assert(strcmp("NOVO", s5) == 0);; + + assert(s_dict_has(dict, "NOME4")); + + s_dict_remove(dict, "NOME4"); + + assert(! s_dict_has(dict, "NOME4")); + + s_dict_free(dict); + assert(dict != NULL); + + return 0; + +} diff --git a/src/sec/sdict.c b/src/sec/sdict.c new file mode 100644 index 00000000..8fe46c31 --- /dev/null +++ b/src/sec/sdict.c @@ -0,0 +1,167 @@ +#include "sdict.h" + +#include +#include +#include + +static dnode_t* s_dict_get_node(SDict* dict, const void* key); + +SDict* s_dict_new(void) { + + SDict* dict = (SDict*)calloc(1, sizeof(SDict)); + + assert(dict != NULL); + + dict->priv = dict_create(DICTCOUNT_T_MAX, strcmp); + + return dict; + +} + +void s_dict_free(SDict* dict) { + + assert(dict != NULL); + + dict_free(dict->priv); + dict_destroy(dict->priv); + + free(dict); + +} + +int s_dict_add(SDict* dict, const void* key, void* value) { + + assert(dict != NULL); + assert(key != NULL); + assert(value != NULL); + + dnode_t* node = dnode_create(value); + + if(s_dict_has(dict, key)) + return FALSE; + + dict_insert(dict->priv, node, key); + + return TRUE; + +} + +int s_dict_add_array(SDict* dict, const void* keys[], void* values[], int n) { + + assert(dict != NULL); + assert(keys != NULL); + assert(values != NULL); + assert(n > 0); + + int i; + + for(i = 0; i < n; i++) + s_dict_add(dict, keys[i], values[i]); + + return TRUE; + +} + +int s_dict_remove(SDict* dict, const void* key) { + + assert(dict != NULL); + assert(key != NULL); + + dnode_t* node = s_dict_get_node(dict, key); + + if(node != NULL) { + + dict_delete(dict->priv, node); + + dnode_destroy(node); + + return TRUE; + + } else { + + return FALSE; + + } + +} + +void* s_dict_get(SDict* dict, const void* key) { + + assert(dict != NULL); + assert(key != NULL); + + dnode_t* node = s_dict_get_node(dict, key); + + if(node != NULL) { + return dnode_get(node); + }else { + return NULL; + + } + +} + +static dnode_t* s_dict_get_node(SDict* dict, const void* key) { + + assert(dict != NULL); + assert(key != NULL); + + dnode_t* found = dict_lookup(dict->priv, key); + + return found; + +} + +int s_dict_set(SDict* dict, const void* key, void* value) { + + assert(dict != NULL); + assert(key != NULL); + assert(value != NULL); + + dnode_t* node = s_dict_get_node(dict, key); + + if(node != NULL) { + + dnode_put(node, value); + return TRUE; + + } else { + + return FALSE; + + } + +} + +int s_dict_has(SDict* dict, const void* key) { + + assert(dict != NULL); + assert(key != NULL); + + dnode_t* node = s_dict_get_node(dict, key); + + if(node != NULL) { + + return TRUE; + + } else { + + return FALSE; + + } + +} + +int s_dict_foreach(SDict* dict, void* data, s_dict_clbk clbk) { + + return TRUE; + +} + +int s_dict_count(SDict* dict) { + + assert(dict != NULL); + + return (int)dict_count(dict->priv); + +} diff --git a/src/sec/sdict.h b/src/sec/sdict.h new file mode 100644 index 00000000..5f94ca24 --- /dev/null +++ b/src/sec/sdict.h @@ -0,0 +1,45 @@ +#ifndef _S_DICT_H_ +#define _S_DICT_H_ 1 + +#include + +#include "dict.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +typedef struct _SDict SDict; + +struct _SDict { + + dict_t* priv; + +}; + +typedef void (*s_dict_clbk)(SDict* dict, void* key, void* value, void* data); + +SDict* s_dict_new(void); +void s_dict_free(SDict* dict); + +int s_dict_add(SDict* dict, const void* key, void* value); +int s_dict_add_array(SDict* dict, const void* keys[], void* values[], int n); + +int s_dict_remove(SDict* dict, const void* key); + +void* s_dict_get(SDict* dict, const void* key); + +int s_dict_set(SDict* dict, const void* key, void* value); + +int s_dict_has(SDict* dict, const void* key); + +int s_dict_foreach(SDict* dict, void* data, s_dict_clbk clbk); + +int s_dict_count(SDict* dict); + + +#endif /* !_S_DICT_H */ diff --git a/src/sec/sec.c b/src/sec/sec.c new file mode 100644 index 00000000..a54e5e6f --- /dev/null +++ b/src/sec/sec.c @@ -0,0 +1,468 @@ +/*************************************************************************** + sec.c - secretary control + ------------------- + begin : Mon May 7 2001 + copyright : (C) 2001 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include "sockets.h" +#include "skterror.h" +#include "fields.h" +#include "messages.h" + +#include "sec.h" + +#define TRUE (1) +#define FALSE (0) + + +/* Read socket `skt' and put data in `buf'; wait for `timeout' seconds. + Return value: 0 if did not read anything, EOF at error, and some positive + number if there is data available. */ +static int sktread(Socket *skt, char *buf, int timeout); + +/* Read Scretary's socket to `buf'; block for SEC_READ_BLKTIMEOUT seconds. + Return value: If successfull, returns the index of the command sent by + Secretary. Returns 0 if did not read anything, EOF at error, FNO_MATCH if + the secretary sent an invalid command, FEMPTY_FIELD if th secretary sent + an empty field (see fields.h fot more details in these two). */ +static int secreadb(Socket *sec, char *buf); + +/* The same as above, but don't block. */ +static int secread(Socket *sec, char *buf); + +/* Write buf to secretary's socket. */ +static int secwrite(Socket *sec, const char *buf); + +/* Removes all status fields entries */ +static void clearstatfields(sec_t *sec); + +/* Open connetion to secretary. Mode = "r" opens sec's status port, + "w" opens control port */ +sec_t *secconnect(char *sname, char *mode, char *ident); + +/* Synchronous status reading */ +char *getstatus(sec_t *sec, int stat); + +/* Asynchronous status reading */ +int notify(sec_t *sec, int stat, notify_handler hndl); + + +/* ----------------------------------------------------------------------- */ + +static int sktread(Socket *skt, char *buf, int timeout) +{ + int res; + + if (skt == NULL || buf == NULL || timeout < 0) return (EOF); + + res = Stimeoutwait(skt, timeout, 0); + if (res == -2) return (0); /* No data */ + else if (res == -1) return (EOF); /* error */ + + /* We have data */ + if (Sgets(buf, MAXBUFLEN, skt) == NULL) return (EOF); + + return (res); +} + +/* ----------------------------------------------------------------------- */ + +static int secreadb(Socket *sec, char *buf) +{ + char tmpbuf[MAXBUFLEN]; + field f; + int res; + + if (sec == NULL || buf == NULL) return (EOF); + + res = sktread(sec, tmpbuf, SEC_READ_BLKTIMEOUT); + if (res <= 0) return (res); + + /* Identify the response */ + res = getfield(tmpbuf, &f, fresponses); + if (res < 0) return (res); + strncpy(buf, f.contents, MAXBUFLEN); + return (res); +} + +/* ----------------------------------------------------------------------- */ + +static int secread(Socket *sec, char *buf) +{ + char tmpbuf[MAXBUFLEN]; + field f; + int res; + + if (sec == NULL || buf == NULL) return (EOF); + + res = sktread(sec, tmpbuf, SEC_READ_TIMEOUT); + if (res <= 0) return (res); + + /* Identify the response */ + res = getfield(tmpbuf, &f, fresponses); + if (res < 0) return (res); + strncpy(buf, f.contents, MAXBUFLEN); + return (res); +} + +/* ----------------------------------------------------------------------- */ + +static int secwrite(Socket *sec, const char *buf) +{ + if (sec == NULL) return (SEC_ERRSOCKET); + if (buf == NULL) return (EOF); + + /* write and verify error */ + watch(sec); + Sputs(buf, sec); + if (skterror()) { /* pipe error */ + Sclose(sec); + return (SEC_ERRSOCKET); + } + return (SEC_ERROK); +} + +/* ----------------------------------------------------------------------- */ + +static void clearstatfields(sec_t *sec) +{ + int i = 0; + + if (sec == NULL || sec->status == NULL) return; + for (i = 0; i < sec->status->nstat; i++) { + unotify(sec, i); + free(sec->status->fields[i]); + free(sec->status->contents[i]); + } + free(sec->status); +} + +/* ----------------------------------------------------------------------- */ + +sec_t *secconnect(char *sname, char *mode, char *ident) +{ + char buf[MAXBUFLEN]; + sec_t *sec; + int res; + + if (sname == NULL || mode == NULL) return (NULL); + if (*mode != SEC_CLIENT_CHAR && *mode != SEC_INST_CHAR) + return (NULL); + + sec = (sec_t *) calloc(1, sizeof(sec_t)); + if (sec == NULL) return (NULL); + sec->status = (status_t *) calloc(1, sizeof(status_t)); + if (sec->status == NULL) { + free(sec); + return (NULL); + } + + + sec->skt = Sopen(sname, "c"); + if (sec->skt == NULL) { + secclose(sec); + return (NULL); + } + + /* Get initial "HELLO" */ + res = secreadb(sec->skt, buf); + if (res < 0) { + fprintf(stderr, "Read timeout or socket error\n\n"); + secclose(sec); + return (NULL); + } + if (res != RES_HELLO) { + fprintf(stderr, "Expected \"%s\", but got \"%s\"\n", + fresponses[RES_HELLO], fresponses[res]); + secclose(sec); + return (NULL); + } + + /* Send identification string */ + if (*mode == SEC_CLIENT_CHAR) { /* client connection */ + snprintf(buf, MAXBUFLEN, "%s %s", fcomm[C_IDENT], ident); + secwrite(sec->skt, buf); + } + else if (*mode == SEC_INST_CHAR) { /* instrument connection */ + snprintf(buf, MAXBUFLEN, "%s %s", + fcomm[C_IDENT], SEC_INSTCLNT_IDENT); + secwrite(sec->skt, buf); + } + + res = secreadb(sec->skt, buf); + if (res < 0) { + fprintf(stderr, "Read timeout or socket error\n\n"); + secclose(sec); + return (NULL); + } + if (res != RES_OK) { + fprintf(stderr, "Unexpected response on IDENT: \"%s\"\n", + fresponses[res]); + secclose(sec); + return (NULL); + } + + sec->enable = TRUE; + Smaskset(sec->skt); + return (sec); +} + +/* ----------------------------------------------------------------------- */ + +void secclose(sec_t *sec) +{ + if (sec == NULL) return; + + clearstatfields(sec); + if (sec->skt != NULL) { + secwrite(sec->skt, fcomm[C_QUIT]); + Smaskunset(sec->skt); + Sclose(sec->skt); + } + + free(sec); + return; +} + +/* ----------------------------------------------------------------------- */ + +int addstatus(sec_t *sec, const char *statname) +{ + char *stf, *stc; + status_t *stp; + int sz; + + if (sec == NULL || statname == NULL) return (EOF); + stp = sec->status; + sz = strlen(statname); + if (sz > MAX_FIELD_SIZE) sz = MAX_FIELD_SIZE; + stc = (char *) calloc(MAX_FIELD_CONTENTS + 1, sizeof(char)); + if (stc == NULL) return (EOF); + stf = (char *) calloc(sz + 1, sizeof(char)); + if (stf == NULL) { + free(stc); + return (EOF); + } + strncpy(stf, statname, sz); + + stp->fields[stp->nstat] = stf; + stp->contents[stp->nstat] = stc; + return (stp->nstat++); +} + +/* ----------------------------------------------------------------------- */ + +int setnstatus(sec_t *sec, int stat, float content) +{ + char buf[MAXBUFLEN]; + int res; + + res = snprintf(buf, MAXBUFLEN, "%-5.3f", content); + if (res == 0) return (EOF); + + res = setstatus(sec, stat, buf); + return (res); +} + +/* ----------------------------------------------------------------------- */ + +int setstatus(sec_t *sec, int stat, const char *content) +{ + int res; + char buf[MAXBUFLEN]; + + if (sec == NULL || content == NULL) return (EOF); + if (stat < 0 || stat > sec->status->nstat) return (EOF); + + sprintf(buf, "%s %s %s", + fcomm[C_SETSTATUS], sec->status->fields[stat], content); + // FIXME + // fcomm[C_SETSTATUS], fsyncstat[stat], content); + res = secwrite(sec->skt, buf); + + //printf("\n%s\n", buf); + if (res < 0) return (EOF); + + res = secreadb(sec->skt, buf); + if (res < 0) { + fprintf(stderr, "Read timeout or socket error\n\n"); + Sclose(sec); + return (EOF); + } + if (res != RES_OK) { + fprintf(stderr, "Error setting status %d = %s\n", + stat, content); + } + return (res); +} + +/* ----------------------------------------------------------------------- */ + +char *getstatus(sec_t *sec, int stat) +{ + int res; + char buf[MAXBUFLEN]; + + if (sec == NULL || sec->status == NULL || + stat < 0 || stat > sec->status->nstat) + return (NULL); + + // FIXME (por que nao usar?) +/* /\* If notification handling is enabled, use saved value *\/ */ +/* if (sec->status->notify[stat]) */ +/* return (sec->status->contents[stat]); */ + + // ALWAYS ASK + /* else, ask secretary */ + + sprintf(buf, "%s %s", fcomm[C_STATUS], (sec->status->fields[stat])); + + res = secwrite(sec->skt, buf); + if (res != SEC_ERROK) return (NULL); + + res = secreadb(sec->skt, sec->status->contents[stat]); + if (res != RES_STATUS) return (NULL); + + printf("%s -> %s\n", buf, sec->status->contents[stat]); + + return (sec->status->contents[stat]); +} + +/* ----------------------------------------------------------------------- */ + +float getnstatus(sec_t *sec, int stat) +{ + char *buf; + + buf = getstatus(sec, stat); + if (buf == NULL) return (HUGE_VAL); + + return(atof(buf)); +} + +/* ----------------------------------------------------------------------- */ + +int notify(sec_t *sec, int stat, notify_handler hndl) +{ + int res; + char buf[MAXBUFLEN]; + + if (sec == NULL || sec->status == NULL || + stat < 0 || stat > sec->status->nstat) + return (EOF); + + /* Exit if notification handling is already enabled */ + if (sec->status->notify[stat]) { + sec->status->handler[stat] = hndl; + return (SEC_ERROK); + } + + /* else, ask secretary */ + sprintf(buf, "%s %s", fcomm[C_NOTIFY], sec->status->fields[stat]); + res = secwrite(sec->skt, buf); + if (res != SEC_ERROK) return (EOF); + + res = secreadb(sec->skt, buf); + if (res == RES_OK) { + sec->status->notify[stat] = TRUE; + sec->status->handler[stat] = hndl; + } + + return (res); +} + +/* ----------------------------------------------------------------------- */ + +int unotify(sec_t *sec, int stat) +{ + int res; + char buf[MAXBUFLEN]; + + if (sec == NULL || sec->status == NULL || + stat < 0 || stat > sec->status->nstat) + return (EOF); + + /* Exit if notification handling is already disabled */ + if (!sec->status->notify[stat]) + return (SEC_ERROK); + + /* else, ask secretary */ + sprintf(buf, "%s %s", fcomm[C_UNOTIFY], sec->status->fields[stat]); + res = secwrite(sec->skt, buf); + if (res != SEC_ERROK) return (EOF); + + res = secreadb(sec->skt, buf); + if (res == RES_OK) sec->status->notify[stat] = FALSE; + return (res); +} + +/* ----------------------------------------------------------------------- */ + +int wait_notify(int time) +{ + Smasktime(time, 0); + return Smaskwait(); +} + +/* ----------------------------------------------------------------------- */ + +int process_notifies(sec_t *sec) +{ + int res; + field f; + status_t *st; + char buf[MAXBUFLEN]; + + if (sec == NULL || sec->status == NULL) return(EOF); + st = sec->status; + res = Stest(sec->skt); + + if (res <= 0) return (res); + + /* Data received */ + res = secread(sec->skt, buf); + if (res < 0) return (EOF); + switch (res) { + case RES_STATUS: + case RES_NOTIFY: + res = getfield(buf, &f, (const char **)st->fields); + if (res < 0) return (EOF); + strncpy(st->contents[res], f.contents, MAX_FIELD_CONTENTS); + if (!st->notify[res]) return (SEC_ERROK); + /* Call status notification handler */ + (*st->handler[res])(res, st->contents[res]); + break; + + case RES_ERROR: + case RES_OK: + return (res); + break; + + case RES_ABORT: + secclose(sec); + return (res); + break; + + default: + break; + } + + return (SEC_ERROK); +} + +/* ----------------------------------------------------------------------- */ diff --git a/src/sec/sec.h b/src/sec/sec.h new file mode 100644 index 00000000..902f24e8 --- /dev/null +++ b/src/sec/sec.h @@ -0,0 +1,120 @@ +/*************************************************************************** + sec.h - secretary control + ------------------- + begin : Mon May 7 2001 + copyright : (C) 2001 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef SEC_H +#define SEC_H + + +#include "sockets.h" +// #include "server.h" +#include "fields.h" +#include "sec_config.h" + +#define MAXBUFLEN (128) + +#define SEC_READ_TIMEOUT (0) /* seconds */ + #define SEC_READ_BLKTIMEOUT (10) /* seconds */ + +#define SEC_CTRLSERVER_STR ("control") /* String to append InstName + to form control servername */ +#define SEC_STATSERVER_STR ("status") /* String to append InstName + to form status servername */ +#define SEC_INSTCLNT_IDENT ("INSTRUMENT") /* Identification String */ +#define SEC_CLIENT_CHAR ('r') +#define SEC_INST_CHAR ('w') +#define SEC_DEF_FVALUE ("EMPTY") /* Default field value */ + +/* Error codes */ +#define SEC_ERROK (0) +#define SEC_ERRSOCKET (-10) +#define SEC_ERRMODE (-11) + + +/* --Type definitions----------------------------------------------------- */ + +/* Event handler */ +typedef int (*notify_handler)(const int, const char *); + +/* Status fields data structure */ +typedef struct { + int nstat; + char *fields[MAX_STATUS_FIELDS]; + char *contents[MAX_STATUS_FIELDS]; + /* Notification event handlers */ + notify_handler handler[MAX_STATUS_FIELDS]; + int notify[MAX_STATUS_FIELDS]; /* TRUE = notification enabled */ + int notified[MAX_STATUS_FIELDS]; +} status_t; + +/* Secretary main structure */ +typedef struct { + int enable; + Socket *skt; + status_t *status; + +// /* merged from comm.h */ +// char *instname; +// Server *statsrv; +// Server *instsrv; + +} sec_t; + + +/* --Function Prototypes-------------------------------------------------- */ + +/* secconnect() - connect to a secretary. + With `mode' == "r" (read), secconnect() connects to the Status port - + i.e "SERVERNAMEstatus" port, where "SERVERNAME" is specified by `sname'. + In this case, it is also necessary to specify `ident'. With + `mode' == "w" (write), secconcets() connects to Control port. In this case + it is possible to use the functions: + setstatus() + setnstatus() */ +sec_t *secconnect(char *sname, char *mode, char *ident); + +/* Closes an open secretary */ +void secclose(sec_t *sec); + +/* Add a staus field with name `statname' to sec. Returns status index. */ +int addstatus(sec_t *sec, const char *statname); + +/* Fill status field indexed by stat with contents. */ +int setstatus(sec_t *sec, int stat, const char *content); + +/* The same as above, but use a numeric content. */ +int setnstatus(sec_t *sec, int stat, float content); + +/* Gets the value of status field indexed by stat */ +char *getstatus(sec_t *sec, int stat); +float getnstatus(sec_t *sec, int stat); +char *status(sec_t *sec, int stat); +float nstatus(sec_t *sec, int stat); + +/* Request notification of field stat to secretary, execute + the handler function hndl() */ +int notify(sec_t *sec, int stat, notify_handler hndl); + +/* Removes notification request */ +int unotify(sec_t *sec, int stat); + +/* Wait notification fot `time' seconds */ +int wait_notify(int time); + +/* Execute pending notifications */ +int process_notifies(sec_t *sec); + +#endif /* SEC_H */ diff --git a/src/sec/sec_config.c b/src/sec/sec_config.c new file mode 100644 index 00000000..27e0cad7 --- /dev/null +++ b/src/sec/sec_config.c @@ -0,0 +1,123 @@ +/*************************************************************************** + getconf.c - description + ------------------- + begin : Thu Sep 28 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fields.h" + +#include "sec_config.h" + +/* used to scan config file */ +static const char *foptions[] = { + "NSTATCLIENTS", "INSTNAME", "STATUS", NULL +}; +enum { NSTATCLIENTS, INSTNAME, STATUS }; + +SecConfig *sec_config_new(void) { + + SecConfig* config = (SecConfig *)calloc(1, sizeof(SecConfig)); + if (config == NULL) return (NULL); + + return config; + +} + +void sec_config_free(SecConfig* config) { + + free(config); + +} + +SecConfig *sec_config_new_from_file(char *conffile) +{ + SecConfig *opts; + FILE *cfile; + char buf[MAXBUFLEN]; + char *ptr; + field f; + int i, tmp; + int line = 0; + + if (conffile == NULL) return (NULL); + + opts = sec_config_new(); + + if(opts == NULL) return NULL; + + /* Number of status fields */ + opts->nstatus = 0; + opts->maxclnt = -1; + + cfile = fopen(conffile, "r"); + if (cfile == NULL) { + free(opts); + return (NULL); + } + + while (fgets(buf, MAXBUFLEN, cfile) != NULL) { + line++; + i = getfield(buf, &f, foptions); + switch (i) { + case NSTATCLIENTS: + /* Get max. clients */ + if (sscanf(f.contents,"%d",&tmp) == EOF) + tmp = DEF_MAXCLNT; + opts->maxclnt = tmp; + break; + + case INSTNAME: + ptr = opts->instname; + /* Get instrument name */ + while (!isspace(*f.contents) && *f.contents != '\0') + *ptr++ = *f.contents++; + break; + + case STATUS: + ptr = opts->fstatus[opts->nstatus]; + tmp = 0; + /* Store in status field table */ + while (!isspace(*f.contents) && *f.contents != '\0') { + *ptr++ = *f.contents++; + if (++tmp == MAX_FIELD_SIZE) break; + } + ptr = opts->fstatus[opts->nstatus]; + /* Avoid having an empty fieldname */ + if (*ptr != '\0') opts->nstatus++; + break; + + case FEMPTY_FIELD: + /* Comment or empty line */ + break; + + case FNO_MATCH: + case EOF: + default: + fprintf(stderr, + "*** Config file: Error in line %d.\n", line); + abort(); + break; + } + } + if (*opts->instname == '\0') strcpy(opts->instname, DEF_INSTNAME); + if (opts->maxclnt == -1) opts->maxclnt = DEF_MAXCLNT; + + fclose(cfile); + return (opts); +} diff --git a/src/sec/sec_config.h b/src/sec/sec_config.h new file mode 100644 index 00000000..187f2fcf --- /dev/null +++ b/src/sec/sec_config.h @@ -0,0 +1,46 @@ +/*************************************************************************** + getconf.h - description + ------------------- + begin : Fri Sep 29 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef _SEC_CONFIG_H_ +#define _SEC_CONFIG_H_ 1 + +#include "fields.h" + +/*** Default values ***/ +#define DEF_INSTNAME "SEC" +#define DEF_MAXCLNT (10) + +#define MAXBUFLEN (128) +#define MAX_SERVERNAME (32) + +#define MAX_STATUS_FIELDS (200) +#define MAX_STATUS_CONTENTS (256) + + +typedef struct _SecConfig SecConfig; + +struct _SecConfig { + char instname[MAX_SERVERNAME]; + int maxclnt; /* maximum number of clients for status server */ + char fstatus[MAX_STATUS_FIELDS][MAX_FIELD_SIZE]; + int nstatus; +}; + +SecConfig *sec_config_new(void); +void sec_config_free(SecConfig* config); +SecConfig *sec_config_new_from_file(char *conffile); + +#endif /* !_SEC_CONFIG_H */ diff --git a/src/sec/sec_server.c b/src/sec/sec_server.c new file mode 100644 index 00000000..694df955 --- /dev/null +++ b/src/sec/sec_server.c @@ -0,0 +1,918 @@ +/*************************************************************************** + comm.c - description + ------------------- + begin : Thu Sep 28 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "sockets.h" + +#include "skterror.h" +#include "sktlist.h" +#include "server.h" +#include "fields.h" +#include "messages.h" + +#include "sec_config.h" +#include "sec_server.h" + +#define FALSE (0) +#define TRUE (1) + +#define CONTROL_STR "control" +#define STATUS_STR "status" + +#define INST_CLIENT_NAME "INSTRUMENT" + +#define DEF_STATUS_CONTENT "EMPTY" +#define DEF_INSTSTATUS_CONTENT "OFFLINE" + +#define SKT_CTRLSERVER (SKT_SERVER +1) +#define SKT_STATSERVER (SKT_SERVER +2) + +typedef struct { + char contents[MAX_STATUS_CONTENTS]; + SktList *notify_table; +}statcontents_t; + +static char *fstatus[MAX_STATUS_FIELDS]; +static statcontents_t *status_contents[MAX_STATUS_FIELDS]; + +static int statcounter = 0; + + +static void notify_internal(int i); +static void free_notify_table(SktList *list); + + +static void controlc(int sig); +void ping_sockets(SecServer *sec); + +static Server *run_status_server(SecServer* ); +static Server *run_control_server(SecServer* ); + +/* Servers, for emergency use (aborting) */ +static SecServer *sec_ptr; + +/* status server connection handlers */ +static int accept_client(SktListItem *client); +static int statsrv_answer(SktListItem *client); +static int close_client_handler(SktListItem *client); + +/* control server connection handlers */ +static int instsrv_answer(SktListItem *client); +static int close_instclient_handler(SktListItem *client); + +/* protocol handler */ +static int request_status(SktListItem *client, char *name); +static int change_status(SktListItem *client, char *statstr); +static int client_notify(SktListItem *client, char *statname); +static int client_unotify(SktListItem *client, char *statname); +static int client_ident(SktListItem *client, char *name); +static int check_ident(SktListItem *client); + + +SecServer *sec_server_new(void) { + + SecServer* sec = (SecServer *)calloc(1, sizeof(SecServer)); + assert(sec != NULL); + +/* sec->status = s_dict_new(); */ +/* sec->notify = s_dict_new(); */ + + return sec; + +} + +void sec_server_free(SecServer* sec) { + + if(sec->config != NULL) + sec_config_free(sec->config); + + if(sec->instname != NULL) + free(sec->instname); + +/* if(sec->status != NULL) */ +/* s_dict_free(sec->status) */ + +/* if(sec->notify != NULL) */ +/* s_dict_free(sec->notify) */ + + free(sec); + +} + +int sec_server_configure(SecServer* sec, const char *cfile) +{ + + /* signal handlers */ + signal(SIGINT, controlc); + signal(SIGTERM, controlc); + signal(SIGABRT, controlc); + signal(SIGPIPE, pipe_error); + + /* ignored signals */ + signal(SIGHUP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + + /*** Get custom configuration (server names and status fields) ***/ + + sec->config = sec_config_new_from_file(cfile); + + if (sec->config == NULL) { + /* Use default values */ + printf("*** Config file does not exist, using defaults.\n"); + sec->config = sec_config_new(); + strcpy(sec->config->instname, DEF_INSTNAME); + sec->config->maxclnt = DEF_MAXCLNT; + } + + return TRUE; +} + +int sec_server_run(SecServer* sec) +{ + + if(sec->config == NULL) return FALSE; + + /* Save instname */ + sec->instname = (char *) calloc(strlen(sec->config->instname) + 1, + sizeof(char)); + strcpy(sec->instname, sec->config->instname); + + /*** Status server ***/ + sec->statsrv = run_status_server(sec); + if (sec->statsrv == NULL) abort(); + + /* Configure Status Fields */ + fill_statlist(sec->config->instname, sec->config->fstatus, + sec->config->nstatus); + + /*** Instrument control server ***/ + sec->instsrv = run_control_server(sec); + if (sec->instsrv == NULL) abort(); + + /* save ``sec'' for signal handling */ + sec_ptr = sec; + + return TRUE; +} + +int sec_server_wait(SecServer *sec) +{ + int i; + + /* _MUST_ set Smasktime before Smaskwaiting */ + Smasktime(WAIT_TIME, 0); + i = Smaskwait(); + if (i > 0) { + /* Someone has new data, check it */ + server_verify(sec->statsrv); + server_verify(sec->instsrv); + } + else if (i < 0) { + /* Smaskwait crashed... fix it in the future; */ + /* by now, abort the program. */ + printf("*** Critical error: Smaskwait() failed!\n\n"); + abort(); + } + return (i); +} + + +int sec_server_check(SecServer *sec) +{ + ping_sockets(sec); + return(0); +} + +static void controlc(int sig) +{ + if (sig == SIGINT) printf("\n*** Control-C caught.\n"); + + /* Close all connections and exit. */ + printf("*** Closing servers...\n"); + if (sec_ptr != NULL) { + server_close(sec_ptr->statsrv); + server_close(sec_ptr->instsrv); + } + + sec_server_free(sec_ptr); + + exit(1); +} + + + +/* Open status server */ +Server* run_status_server(SecServer* sec) +{ + char sname[MAX_SERVER_NAME]; + Server *stsrv; + + /* build status server name based on instname */ + strcpy(sname, sec->instname); + strcat(sname, STATUS_STR); + /* e.g: instname == INST => buf == INSTstatus */ + + stsrv = server_init(sname, SKT_STATSERVER); + if (stsrv == NULL) return (NULL); + + stsrv->accept_handler = accept_client; + stsrv->answer_handler = statsrv_answer; + stsrv->close_handler = close_client_handler; + stsrv->maxclients = sec->config->maxclnt; + return (stsrv); +} + + +/* Open instrument control server */ +Server *run_control_server(SecServer* sec) +{ + char sname[MAX_SERVER_NAME]; + Server *isrv; + + /* build server name based on instname */ + strcpy(sname, sec->instname); + strcat(sname, CONTROL_STR); + /* e.g: instname == INST => buf == INSTcontrol */ + + isrv = server_init(sname, SKT_CTRLSERVER); + if (isrv == NULL) return (NULL); + + isrv->accept_handler = accept_client; + isrv->answer_handler = instsrv_answer; + isrv->close_handler = close_instclient_handler; + isrv->maxclients = 1; + return (isrv); +} + + + +/* Client will be able to ask server after identifying itself */ +static int client_ident(SktListItem *client, char *name) +{ + int i; + Server *server; + + if (client == NULL) return (EOF); + server = client->server; + if (!server_is_valid(server)) return(EOF); + + i = server_set_client_name(client, name); + if (i == EOF) { + server_write_client(fresponses[RES_ERROR], client); + server_close_client(client); + return (EOF); + } + i = server_write_client(fresponses[RES_OK], client); + if (i == EOF) return (EOF); + printf(" -> <%s> Identification: %s@%s\n", + server->name, client->name, Speername(client->skt)); + client->state = CST_IDLE; + + return (0); +} + + +static int instrument_ident(SktListItem *client, char *name) +{ + int i; + Server *server; + + if (client == NULL || name == NULL) return (EOF); + server = client->server; + if (!server_is_valid(server)) return(EOF); + + /* Verify instrument identification */ + i = strncmp(name, INST_CLIENT_NAME, MAX_CLIENT_NAME); + if (i != 0) { + /* bad identification string. */ + printf("*** <%s> Bad identification from %s, client closed\n", + server->name, Speername(client->skt)); + server_write_client(fresponses[RES_ERROR], client); + server_close_client(client); + return (EOF); + } + + /* Proceed as in client_ident() */ + + i = server_set_client_name(client, name); + if (i == EOF) { + server_write_client(fresponses[RES_ERROR], client); + server_close_client(client); + return (EOF); + } + i = server_write_client(fresponses[RES_OK], client); + if (i == EOF) return (EOF); + printf(" -> <%s> Identification: %s@%s\n", + server->name, client->name, Speername(client->skt)); + client->state = CST_IDLE; + + return (0); +} + + +static int check_ident(SktListItem *client) +{ + Server *server; + + if (client == NULL) return (EOF); + server = client->server; + if (!server_is_valid(server)) return (EOF); + + /* Only answer clients who have already identified */ + if (client->state == CST_IDENT_PENDING) { + if (server_write_client(fresponses[RES_ERROR], client) == EOF) + return (EOF); + printf("*** <%s> %s: Unidentified client, " + "access denied.\n", + server->name, Speername(client->skt)); + return (EOF); + } + return (0); +} + + +static int request_status(SktListItem *client, char *name) +{ + char buf[MAXBUFLEN]; + char *ptr; + int i; + + if (check_ident(client) == EOF) return (EOF); + ptr = get_status(name); + if (ptr == NULL) { + i = server_write_client(fresponses[RES_ERROR], client); + return (i); + } + snprintf(buf, MAXBUFLEN, "%s %s", fresponses[RES_STATUS], ptr); + i = server_write_client(buf, client); + return (i); +} + + +static int change_status(SktListItem *client, char *statstr) +{ + int i; + + i = set_status_str(statstr); + if (i == EOF) { + i = server_write_client(fresponses[RES_ERROR], client); + return (i); + } + i = server_write_client(fresponses[RES_OK], client); + return (i); +} + + +/* add client to "status"'s notification list */ +static int client_notify(SktListItem *client, char *statname) +{ + int i; + + if (check_ident(client) == EOF) return (EOF); + i = set_notify(client, statname); + if (i == EOF) { + i = server_write_client(fresponses[RES_ERROR], client); + return (i); + } + i = server_write_client(fresponses[RES_OK], client); + return (i); +} + + +/* remove client from "status"'s notification list */ +static int client_unotify(SktListItem *client, char *statname) +{ + int i; + + if (check_ident(client) == EOF) return (EOF); + i = rmv_notify(client, statname); + if (i == EOF) { + i = server_write_client(fresponses[RES_ERROR], client); + return (i); + } + i = server_write_client(fresponses[RES_OK], client); + return (i); +} + + +void ping_sockets(SecServer *sec) +{ + static int tc; + + /* Notify the special field PING every WAIT_TIME * 3 */ + if (tc % 3) return; + + /* SETSTATUS PING INSTNAME */ + set_status(STPING, sec->instname); +} + + +/* Additional proceedings after client connection */ +static int accept_client(SktListItem *client) +{ + int i; + + if (client == NULL) return (EOF); + if (!server_is_valid(client->server)) return(EOF); + + /* Tell client we accepted */ + i = server_write_client(fresponses[RES_HELLO], client); + if (i == EOF) return (EOF); + + client->state = CST_IDENT_PENDING; + return (0); +} + + +static int statsrv_answer(SktListItem *client) +{ + char buf[MAXBUFLEN]; + int fi; + field f; + Server *server; + + if (client == NULL) return (EOF); + server = client->server; + if (!server_is_valid(server)) return(EOF); + + /* Determine which command we received */ + Sgets(buf, MAXBUFLEN, client->skt); + fi = getfield(buf, &f, fcomm); + switch (fi) { + + case C_QUIT: + server_close_client(client); + return(1); + break; + + case C_IDENT: + client_ident(client, f.contents); + break; + + case C_STATUS: + if (check_ident(client) != EOF) + request_status(client, f.contents); + break; + + + case C_NOTIFY: + if (check_ident(client) != EOF) + client_notify(client, f.contents); + break; + + case C_UNOTIFY: + if (check_ident(client) != EOF) + client_unotify(client, f.contents); + break; + + case C_CONTROL: + case C_SETSTATUS: + case EOF: + default: + /* Invalid command or command unavailable */ + if (server_write_client(fresponses[RES_ERROR], client) == EOF) + return (EOF); + printf(" -> <%s> %s@%s: Invalid command - %s\n", + server->name, client->name, + Speername(client->skt), buf); + break; + } + return (0); +} + + + +static int instsrv_answer(SktListItem *client) +{ + char buf[MAXBUFLEN]; + int fi; + field f; + Server *server; + + if (client == NULL) return (EOF); + server = client->server; + if (!server_is_valid(server)) return(EOF); + + /* Determine which command we received */ + Sgets(buf, MAXBUFLEN, client->skt); + fi = getfield(buf, &f, fcomm); + switch (fi) { + + case C_QUIT: + server_close_client(client); + return(1); + break; + + case C_IDENT: + if (instrument_ident(client, f.contents) != 0) + return (1); + + break; + + case C_STATUS: + if (check_ident(client) != EOF) + request_status(client, f.contents); + break; + + case C_SETSTATUS: + change_status(client, f.contents); + break; + + case C_NOTIFY: + case C_UNOTIFY: + case EOF: + default: + /* Invalid command or command unavailable */ + if (server_write_client(fresponses[RES_ERROR], client) == EOF) + return (EOF); + printf(" -> <%s> %s@%s: Invalid command - %s\n", + server->name, client->name, + Speername(client->skt), buf); + break; + } + return (0); +} + + + +/* Things to do before closing the client */ +static int close_client_handler(SktListItem *client) +{ + clear_client_notifies(client); + return (0); +} + + +static int close_instclient_handler(SktListItem *client) +{ + clear_client_notifies(client); + + /* SETSTATUS INSTNAME OFFLINE */ + set_istatus(STATUS_INSTNAME, DEF_INSTSTATUS_CONTENT); + return (0); +} + +/* int sec_server_add_status(SecServer* sec, const char* status) { */ + +/* assert(sec != NULL); */ +/* assert(status != NULL); */ + +/* return (s_dict_add(sec->status, status, DEF_STATUS_CONTENS) && */ +/* s_dict_add(sec->notify, status, skt_list_new())); */ + +/* } */ + +/* int sec_server_free_status(SecServer* sec, const char* status) { */ + +/* assert(sec != NULL); */ +/* assert(status != NULL); */ + +/* return (s_dict_remove(sec->status, status) && */ +/* s_dict_remove(sec->notify, status)); */ + +/* } */ + +/* int sec_server_set_status(SecServer* sec, const char* status, const char* contents) { */ + +/* assert(sec != NULL); */ +/* assert(status != NULL); */ +/* assert(contents != NULL); */ + +/* return (s_dict_set(sec->status, status, contents)); */ + +/* } */ + +/* const char* sec_server_get_status(SecServer* sec, const char* status) { */ + +/* assert(sec != NULL); */ +/* assert(status != NULL); */ + +/* return (s_dict_get(sec->status, status); */ + + +/* } */ + +/* int sec_server_set_notify(SecServer* sec, SktListItem* client, const char* status) { */ + +/* assert(sec != NULL); */ +/* assert(client != NULL); */ +/* assert(status != NULL); */ + +/* SktList* list = s_dict_get(sec->notify, status); */ + +/* sktlist_add(list, client->skt); */ + +/* return RUE; */ + +/* } */ + +/* int sec_server_remove_notify(SecServer* sec, SktListItem* client, const char* status) { */ + +/* assert(sec != NULL); */ +/* assert(client != NULL); */ +/* assert(status != NULL); */ + +/* SktList* list = s_dict_get(sec->notify, status); */ + +/* sktlist_remove(list, client); */ + +/* return RUE; */ + +/* } */ + +/* Status field table */ + +/* This creates the status fields; should be avoided while runing */ +int fill_statlist(char *instname, + char fstatus[][MAX_FIELD_SIZE], int nst) +{ + int i; + + if ( instname == NULL || fstatus == NULL || nst <= 0 || + nst > MAX_STATUS_FIELDS ) + return (EOF); + + /* add a status field for instrument state */ + if (add_status(instname) < 0) return (EOF); + + /* add a status field for connection monitoring */ + if (add_status(STPING) < 0) return (EOF); + + + for (i = 0; i < nst; i++) + if (add_status((char *) fstatus[i]) < 0) return (EOF); + + return (0); +} + + +int add_status(char *name) +{ + char *status_ptr; + statcontents_t *contents_ptr; + + /* Do not allocate more than MAX_STATUS_FIELDS fields */ + if (statcounter >= MAX_STATUS_FIELDS) return (EOF); + if (name == NULL) return(EOF); + if (strlen(name) > MAX_FIELD_SIZE) return (EOF); + + /* Get memory for field stuff & notify list */ + status_ptr = (char *) calloc(strlen(name) + 1, sizeof(char)); + if (status_ptr == NULL) return(EOF); + contents_ptr = (statcontents_t *) calloc(1, sizeof(statcontents_t)); + if (contents_ptr == NULL) { + free(status_ptr); + return(EOF); + } + /* Fill the structures */ + strcpy(status_ptr, name); + if (statcounter == 0) /* INSTNAME Status field */ + strcpy(contents_ptr->contents, DEF_INSTSTATUS_CONTENT); + else + strcpy(contents_ptr->contents, DEF_STATUS_CONTENT); + + /* Create notification list */ + contents_ptr->notify_table = sktlist_new(); + if (contents_ptr->notify_table == NULL) { + free(status_ptr); + free(contents_ptr); + return (EOF); + } + + fstatus[statcounter] = status_ptr; + status_contents[statcounter] = contents_ptr; + + return(statcounter++); +} + + +/* Free _ALL_ status fields */ +void free_status(void) +{ + char **ptr1; + statcontents_t *ptr2; + + ptr1 = fstatus; + ptr2 = *status_contents; + while (statcounter > 0) { + if (ptr1 != NULL) free(ptr1++); + if (ptr2 != NULL) { + free_notify_table(ptr2->notify_table); + free(ptr2++); + } + statcounter--; + } + +} + + +/* Set status by index */ +int set_istatus(int i, char *contents) +{ + if (contents == NULL) return (EOF); + if (i < 0 || i > statcounter) return (EOF); + if (strlen(contents) > MAX_STATUS_CONTENTS) return (EOF); + + +#ifdef NOTIFY_ON_CHANGE + /* Notify clients only if status changed */ + if (strncmp(status_contents[i]->contents, + contents, MAX_STATUS_CONTENTS) != 0) { + strcpy(status_contents[i]->contents, contents); + notify_internal(i); /* FIXME */ + } +#else + /* Notify always */ + strcpy(status_contents[i]->contents, contents); + notify_internal(i); /* FIXME */ +#endif + + return (0); +} + + +/* Set status by name */ +int set_status(char *name, char *contents) +{ + int i, res; + + if (name == NULL) return (EOF); + if (contents == NULL) return (EOF); + if (strlen(contents) > MAX_STATUS_CONTENTS) return (EOF); + + i = getfield(name, NULL, (const char **) fstatus); + res = set_istatus(i, contents); + + return(res); +} + + +/* set status by string: "STATUS VALUE" */ +int set_status_str(char *statstr) +{ + int i, res; + field f; + + if (statstr == NULL) return (EOF); + + i = getfield(statstr, &f, (const char **) fstatus); + res = set_istatus(i, f.contents); + + return (res); + +} + + +/* Get status by index */ +char *get_istatus(int i) +{ + if (i < 0 || i > statcounter) return (NULL); + + return (status_contents[i]->contents); +} + + +/* Get status by name */ +char *get_status(char *name) +{ + int i; + + if (name == NULL) return (NULL); + + i = getfield(name, NULL, (const char **) fstatus); + if (i < 0 || i > statcounter) return (NULL); + + return (status_contents[i]->contents); +} + + +int set_notify(SktListItem *client, char *statfield) +{ + int i, res; + + if (client == NULL) return (EOF); + i = getfield(statfield, NULL, (const char **) fstatus); + res = set_inotify(client, i); + return (res); +} + + +int set_inotify(SktListItem *client, int i) +{ + SktListItem *item; + + if (client == NULL) return (EOF); + if (i < 0 || i > statcounter) return (EOF); + + /* Check if this client already requested notification */ + for (item = status_contents[i]->notify_table->first; + item != NULL; item = item->next) { + if (item->type == SKT_SENTINEL) continue; + if (item->id == client->id) + /* This client is already registered */ + return (0); + } + + /* Else, add client to list */ + item = sktlist_add(status_contents[i]->notify_table, + client->skt, client->type); + if (item == NULL) return (EOF); + /* Save id for future removal */ + item->id = client->id; + /* Save server for future writing */ + item->server = client->server; + return (0); + +} + + +int rmv_notify(SktListItem *client, char *statfield) +{ + int i, res; + + if (client == NULL) return (EOF); + i = getfield(statfield, NULL, (const char **) fstatus); + res = rmv_inotify(client, i); + return (res); +} + + +int rmv_inotify(SktListItem *client, int i) +{ + SktListItem *item, *tmp; + + if (client == NULL) return (EOF); + if (i < 0 || i > statcounter) return (EOF); + + /* Find who has this id */ + for (item = status_contents[i]->notify_table->first; + item != NULL; item = item->next) { + if (item->type == SKT_SENTINEL) continue; + if (item->id == client->id) { + /* id found, remove it */ + tmp = item; + item = item->previous; + sktlist_remove(status_contents[i]->notify_table, tmp); + return (0); + } + } + /* id not found */ + return (EOF); +} + +void clear_client_notifies(SktListItem *client) +{ + int i; + + /* Clear notifies for each Status entry */ + for (i = 0; i < statcounter; i++) + rmv_inotify(client, i); +} + + +static void notify_internal(int i) +{ + char buf[MAXBUFLEN]; + SktListItem *client; + + /* Notify everyone in list */ + for (client = status_contents[i]->notify_table->first; + client != NULL; client = client->next) { + if (client->type == SKT_SENTINEL) continue; + snprintf(buf, MAXBUFLEN, "NOTIFY %s %s", + fstatus[i], status_contents[i]->contents); + server_write_client(buf, client); + } +} + + +static void free_notify_table(SktList *list) +{ + if (list == NULL) return; + + while (list->first->type == SKT_CLIENT) sktlist_remove(list, list->first); + sktlist_free(list); +} + + diff --git a/src/sec/sec_server.h b/src/sec/sec_server.h new file mode 100644 index 00000000..4731dc3b --- /dev/null +++ b/src/sec/sec_server.h @@ -0,0 +1,67 @@ +#ifndef _SEC_SERVER_H_ +#define _SEC_SERVER_H_ 1 + +// #include "sdict.h" +#include "server.h" +#include "sec_config.h" + +#define WAIT_TIME (1) /* seconds */ +#define DEF_STATUS_CONTENT "EMPTY" +#define DEF_INSTSTATUS_CONTENT "OFFLINE" + +/* Field name for connection monitoring */ +#define STPING "PING" + +#define STATUS_INSTNAME (0) +#define STATUS_PING (1) + +typedef struct _SecServer SecServer; + +struct _SecServer { + char *instname; + + SecConfig *config; + +// SDict *status; +// SDict* notify; + + Server *statsrv; + Server *instsrv; + +}; + +SecServer *sec_server_new(void); + +void sec_server_free(SecServer* sec); +int sec_server_configure(SecServer* sec, const char *cfile); +int sec_server_run(SecServer* sec); +int sec_server_wait(SecServer* sec); +int sec_server_check(SecServer* sec); + +// int sec_server_add_status(SecServer* sec, const char* status); +// int sec_server_free_status(SecServer* sec, const char* status); +// int sec_server_set_status(SecServer* sec, const char* status, const char* contents); +// const char* sec_server_get_status(SecServer* sec, const char* status); + +// int sec_server_set_notify(SecServer* sec, SktListItem* client, const char* status); +// int sec_server_remove_notify(SecServer* sec, SktListItem* client, const char* status);); + +/* from status.c */ + +int fill_statlist(char *instname, + char fstatus[][MAX_FIELD_SIZE], int nst); +int add_status(char *name); +void free_status(void); +int set_istatus(int i, char *contents); +int set_status(char *name, char *contents); +int set_status_str(char *statstr); +char *get_istatus(int i); +char *get_status(char *name); + +int set_notify(SktListItem *client, char *statfield); +int set_inotify(SktListItem *client, int i); +int rmv_notify(SktListItem *client, char *statfield); +int rmv_inotify(SktListItem *client, int i); + + +#endif /* !_SEC_SERVER_H_ */ diff --git a/src/sec/server.c b/src/sec/server.c new file mode 100644 index 00000000..9c8c9662 --- /dev/null +++ b/src/sec/server.c @@ -0,0 +1,267 @@ +/*************************************************************************** + multiskt.c - description + ------------------- + begin : Tue Sep 12 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "sockets.h" + +#include "skterror.h" +#include "sktlist.h" + +#include "server.h" + +int server_is_valid(Server *srv) +{ + if (srv == NULL) return (0); + if (srv->name == NULL) return (0); + if (srv->clientlist == NULL) return (0); + if (srv->skt == NULL) return (0); + return (1); +} + + +Server *server_init(char *sname, int type) +{ + Server *srv; + + if (sname == NULL) return (NULL); + srv = (Server *) calloc(1, sizeof(Server)); + if (srv == NULL) return (NULL); + + srv->name = (char *) calloc(strlen(sname) + 1, sizeof(char)); + if (srv->name == NULL) { + free(srv); + return (NULL); + } + strcpy(srv->name, sname); + srv->skt = Sopen(sname, "s"); + if (srv->skt == NULL) { + /* force opening, remove existing server */ + Srmsrvr(sname); + srv->skt = Sopen(sname, "s"); + } + if (srv->skt == NULL) { + /* could not open server */ + printf("*** Error opening \"%s\" server.\n", sname); + printf("*** The PortMaster could be down.\n"); + free(srv); + return (NULL); + } + srv->clientlist = sktlist_new(); + if (srv->clientlist == NULL) { + printf("*** Error allocating client list.\n"); + Sclose(srv->skt); + free(srv); + return(NULL); + } + Smaskset(srv->skt); + + printf(" -> Server \"%s\" open.\n", sname); + + return (srv); +} + + +void server_close(Server *srv) +{ + SktList *tmp; + + if (srv == NULL) return; + + if (srv->name != NULL) free(srv->name); + if (srv->clientlist != NULL) { + /* disconnect all clients... */ + tmp = srv->clientlist; + while (tmp->first->type == SKT_CLIENT) { + Sputs(ABORT_MESSAGE, tmp->first->skt); + server_close_client(tmp->first); + } + sktlist_free(srv->clientlist); + } + if (srv->skt != NULL) { + Smaskunset(srv->skt); + Sclose(srv->skt); + } + free(srv); +} + + +SktListItem *server_accept(Server *srv) +{ + Socket *skt; + SktListItem *item; + + if (!server_is_valid(srv)) return(NULL); + + skt = Saccept(srv->skt); + if (skt == NULL) return (NULL); +/* if (srv->nclients >= srv->maxclients) { */ +/* /\* Deny access, server full *\/ */ +/* printf("*** <%s> %s: Connection denied.\n", */ +/* srv->name, Speername(skt)); */ +/* Sputs(SERVER_FULL_MESSAGE, skt); */ +/* Sclose(skt); */ +/* return (NULL); */ +/* } */ + item = sktlist_add(srv->clientlist, skt, SKT_CLIENT); + if (item == NULL) { + printf("*** <%s> %s: Error allocating Socket List \ + entry. Connection denied.\n", + srv->name, Speername(skt)); + Sputs(ERROR_MESSAGE, skt); + Sclose(skt); + return (NULL); + } + + Smaskset(skt); + srv->nclients++; + srv->nconn++; + + /* Save pointer to server in client */ + item->server = srv; /* e.g: srv->clientlist->last->server = srv; */ + + printf(" -> <%s> %s Connected.\n", + srv->name, Speername(skt)); + + return (item); +} + + +void server_close_client(SktListItem *clnt) +{ + Server *srv; + + if (clnt == NULL) return; + srv = clnt->server; + if (!server_is_valid(srv)) return; + + /* Execute close handler */ + if (srv->close_handler != NULL) + (*srv->close_handler) (clnt); + + if (clnt->name != NULL) free(clnt->name); + + if (clnt->skt != NULL) { + Smaskunset(clnt->skt); + Sclose(clnt->skt); + } + sktlist_remove(srv->clientlist, clnt); + + srv->nclients--; +} + + +int server_write_client(const char *buf, SktListItem *clnt) +{ + Server *srv; + + if (buf == NULL || clnt == NULL) return (EOF); + srv = clnt->server; + if (!server_is_valid(srv)) return (EOF); + + watch(clnt->skt); + Sputs((char *)buf, clnt->skt); + if (skterror()) { + server_close_client(clnt); + return (EOF); + } + return (0); +} + + +int server_set_client_name(SktListItem *clnt, char *name) +{ + char buf[MAX_CLIENT_NAME]; + char *ptr; + int i = 0; + + if (clnt == NULL) return (EOF); + if (clnt->name != NULL) free(clnt->name); + + /* Remove white space, and keep 1 char for '\0' */ + ptr = buf; + while (!isspace(*name) && (*name != '\0') && (++i < MAX_CLIENT_NAME)) + *ptr++ = *name++; + *ptr = '\0'; + + /* String size already checked, safe calling strlen and stcpy */ + clnt->name = (char *) calloc(strlen(buf) + 1, sizeof(char)); + if (clnt->name == NULL) return (EOF); + strcpy(clnt->name, buf); + return (0); +} + + +int server_answer(SktListItem *clnt) +{ + /* Dummy routine */ + return (1); +} + + +/* Look for sockets that have changed and process them */ +int server_verify(Server *srv) +{ + SktListItem *client, *tmp; + int res; + + if (!server_is_valid(srv)) return(EOF); + /*** Do not even dream calling a NULL function pointer ***/ + if (srv->accept_handler == NULL || srv->answer_handler == NULL) + return (EOF); + + /*** Process server ***/ + res = Stest(srv->skt); + if (res > 0) { + /* Accept connection (ATTENTION: call to function pointer) */ + tmp = server_accept(srv); + (*srv->accept_handler) (tmp); + } + else if (res == EOF) { + /* Socket error, must restart server */ + return (EOF); + } + + /*** Process Clients ***/ + /* seek client list */ + for (client = srv->clientlist->first; + client != NULL; client = client->next) { + if (client->type == SKT_SENTINEL) continue; + res = Stest(client->skt); + if (res > 0) { + /* Save next pointer */ + tmp = client->previous; + /* Answer the request */ + /* (ATTENTION: call to function pointer) */ + res = (*srv->answer_handler) (client); + if (res == 1) client = tmp; + } + else if (res == EOF) { + /* Socket error, close the client */ + printf("*** <%s> %s@%s - Connection broken.\n", + srv->name, client->name, Speername(client->skt)); + + tmp = client; + client = client->previous; + server_close_client(tmp); + } + } + return (0); +} diff --git a/src/sec/server.h b/src/sec/server.h new file mode 100644 index 00000000..394816ff --- /dev/null +++ b/src/sec/server.h @@ -0,0 +1,73 @@ +/*************************************************************************** + multisrv.h - description + ------------------- + begin : Tue Sep 12 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef MULTISKT_H +#define MULTISKT_H + +#include "sockets.h" + +#include "sktlist.h" + +#define ABORT_MESSAGE "ABORT" +#define ERROR_MESSAGE "ERROR" +#define SERVER_FULL_MESSAGE "SERVER_FULL" + +#define MAX_CLIENT_NAME (32) +#define MAX_SERVER_NAME (32) + +typedef struct _Server Server; + +/* pointer to handler functions */ +typedef int (*accept_hndl) (SktListItem *); +typedef int (*answer_hndl) (SktListItem *); +typedef int (*close_hndl) (SktListItem *); + +struct _Server { + char *name; + int type; + + Socket *skt; + int nconn; + int nclients; + int maxclients; + SktList *clientlist; + + /* pointer to `accept' handler */ + accept_hndl accept_handler; + /* pointer to `answer' handler */ + answer_hndl answer_handler; + /* pointer to `server_close_client' handler */ + close_hndl close_handler; + /* pointer to any useful thing */ +}; + + +Server *server_init(char *sname, int type); +void server_close(Server *srv); + +int server_is_valid(Server *srv); +int server_verify(Server *srv); + +int server_write_client(const char *buf, SktListItem *clnt); +int server_set_client_name(SktListItem *clnt, char *name); +void server_close_client(SktListItem *clnt); + +/* default accept routine */ +SktListItem *server_accept(Server *srv); +int server_answer(SktListItem *clnt); + +#endif /* MULTISKT_H */ diff --git a/src/sec/skterror.c b/src/sec/skterror.c new file mode 100644 index 00000000..caaa385f --- /dev/null +++ b/src/sec/skterror.c @@ -0,0 +1,50 @@ +/*************************************************************************** + skterror.c - description + ------------------- + begin : Tue Oct 3 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include "sockets.h" + +#include "skterror.h" + +#define TRUE (1) +#define FALSE (0) + +static Socket *watch_socket; +static int s_error; + +/* prepare to write to Status socket */ +void watch(Socket *skt) +{ + watch_socket = skt; + s_error = FALSE; +} + + +int skterror(void) +{ + if (s_error) return (1); + return (0); +} + + +void pipe_error(int sig) +{ + /* Error writing to a socket */ + printf("\n\n*** Error: Attempt to write to a broken socket.\n"); + + s_error = TRUE; + +} diff --git a/src/sec/skterror.h b/src/sec/skterror.h new file mode 100644 index 00000000..1fb97bab --- /dev/null +++ b/src/sec/skterror.h @@ -0,0 +1,30 @@ +/*************************************************************************** + skterror.h - description + ------------------- + begin : Wed Oct 4 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef SKTERROR_H +#define SKTERROR_H + +#include "sockets.h" + +/* ask if there were some error while writing to socket */ +int skterror(void); +/* Tell sigpipe() who is trying to write to socket */ +void watch(Socket *skt); + +void pipe_error(int sig); + +#endif /* STKERROR_H */ diff --git a/src/sec/sktlist.c b/src/sec/sktlist.c new file mode 100644 index 00000000..49fd9fba --- /dev/null +++ b/src/sec/sktlist.c @@ -0,0 +1,118 @@ +/*************************************************************************** + sktlist.c - description + ------------------- + begin : Tue Sep 12 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include "sockets.h" +#include "sktlist.h" + +static int id_counter = 0; + +SktList *sktlist_new(void) +{ + SktList *list; + + list = (SktList *) calloc(1, sizeof(SktList)); + if (list == NULL) return (NULL); + + /* create ``sentinels'' */ + /* Null SocketList entries, just to mark the end/beginning of the list. */ + list->head = (SktListItem *) calloc(1, sizeof(SktListItem)); + if (list->head == NULL) return (NULL); + list->tail = (SktListItem *) calloc(1, sizeof(SktListItem)); + if (list->tail == NULL) return (NULL); + + /* head points to tail */ + list->head->previous = NULL; + list->head->next = list->tail; + list->head->skt = NULL; + list->head->type = SKT_SENTINEL; + + /* tail points to head */ + list->tail->previous = list->head; + list->tail->next = NULL; + list->tail->skt = NULL; + list->tail->type = SKT_SENTINEL; + + /* `first' == `head->next' */ + list->first = list->head->next; + + return (list); +} + + +int sktlist_free(SktList *list) +{ + if (list == NULL) return (0); + + /* List must be empty */ + if (list->head->next != NULL) return (-1); + free(list->head); + free(list->tail); + free(list); + return (0); +} + + +SktListItem *sktlist_add(SktList *list, Socket *skt, int type) +{ + SktListItem *new; + + /* Add a _connected_ socket only */ + if (skt == NULL || list == NULL) return (NULL); + new = (SktListItem *) calloc(1, sizeof(SktListItem)); + if (new == NULL) return (NULL); + + /* append new item to the tail */ + list->tail->previous->next = new; + new->previous = list->tail->previous; + list->tail->previous = new; + new->next = list->tail; + new->type = type; + + /* Increment id_counter, if reached MAX_ID, restart counting */ + /* I don't know what to do when this happen, hope it won't */ + /* bring any trouble. */ + new->id = id_counter++ % MAX_ID; + + /* Point the first item to the right place */ + list->first = list->head->next; + + new->skt = skt; + + return (new); +} + + +/* this does NOT disconnect the socket! */ +void sktlist_remove(SktList *list, SktListItem *item) +{ + if (item == NULL || list == NULL) return; + + /* keep the sentinels */ + if (item->type == SKT_SENTINEL) return; + + /* link neighbors together */ + item->previous->next = item->next; + if (item->next != NULL) item->next->previous = item->previous; + + /* Point the first item to the right place */ + list->first = list->head->next; + + free(item); +} + diff --git a/src/sec/sktlist.h b/src/sec/sktlist.h new file mode 100644 index 00000000..f156cccd --- /dev/null +++ b/src/sec/sktlist.h @@ -0,0 +1,69 @@ +/*************************************************************************** + sktlist.h - description + ------------------- + begin : Tue Sep 12 2000 + copyright : (C) 2000 by Andre Luiz de Amorim + email : andre@astro.ufsc.br + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef SKTLIST_H +#define SKTLIST_H + +#include "sockets.h" + +/* socket types */ +#define SKT_SENTINEL (0) +#define SKT_CLIENT (1) +#define SKT_SERVER (2) + +/* to use static id's, start them at (MAX_ID + 1) */ +#define MAX_ID (1000000L) +#define MAXBUFLEN (128) + +/* Client states */ +/* CST_IDENT_PENDING - Server is waiting response from client, + don't send anything */ +/* CST_NOTIFY - Notify the client when an event occurs */ +/* CST_IDLE - Client is idle */ +/* CST_WAITING_NOTIFY - Client is waiting notification from server */ +enum { CST_IDENT_PENDING, CST_NOTIFY, CST_IDLE, CST_WAITING }; + +/* item of sockets linked list */ +typedef struct _SktListItem SktListItem; + +struct _SktListItem { + int id; + char *name; + void *server; /* pointer to Server structure */ + int type; + int state; + Socket *skt; + + SktListItem *next, *previous; +}; + +/* Socket linked list */ +typedef struct { + SktListItem *head; + SktListItem *first; + SktListItem *tail; +} SktList; + + +/* Socket list utilities */ +SktList *sktlist_new(void); +int sktlist_free(SktList *list); +SktListItem *sktlist_add(SktList *list, Socket *skt, int type); +void sktlist_remove(SktList *list, SktListItem *item); + + +#endif /* SKTLIST_H */ diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am new file mode 100644 index 00000000..d5ab0a3c --- /dev/null +++ b/src/tools/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = client + +bin_SCRIPTS = uts-gen-conf diff --git a/src/tools/client/Makefile.am b/src/tools/client/Makefile.am new file mode 100644 index 00000000..40b03a1c --- /dev/null +++ b/src/tools/client/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/rules.make + +bin_PROGRAMS = sclient + +sclient_SOURCES = main.c +sclient_LDADD = -lsimpleskts \ No newline at end of file diff --git a/src/tools/client/SConscript b/src/tools/client/SConscript new file mode 100644 index 00000000..e0851baa --- /dev/null +++ b/src/tools/client/SConscript @@ -0,0 +1,15 @@ +#! /usr/bin/python + +Import("env") + +_sources = Split( + +""" +main.c +""" +) + +env.Program('sclient', _sources, + CPPPATH=['.', '#contrib/include'], + LIBPATH=['#contrib/lib'], + LIBS=['simpleskts']) diff --git a/src/tools/client/main.c b/src/tools/client/main.c new file mode 100644 index 00000000..41c4863c --- /dev/null +++ b/src/tools/client/main.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include "sockets.h" + +int main (int argc, char **argv) +{ + Socket *skt; + int i, n; + char buffer[500]; + int waitresponse = 0; + + skt = Sopen(argv[1],"c"); + if (skt == NULL) exit (1); + + Smaskset(skt); + Smaskfdset(0); + + for(;;) { + // is there anything new? + i = Smaskwait(); + if (i <= 0) break; + + i = Stest(skt); + if (i <= -1) break; // socket error + else if (i > 0) { + // something new from server + Sgets(buffer, 500, skt); + printf("server> %s\n", buffer); + waitresponse = 0; + continue; + } + + // only get new command after server response + if (waitresponse) continue; + + if (Smaskfdisset(0)) { + // something new from stdin + if (fgets(buffer, 500, stdin) == NULL) break; + n = strlen(buffer); + buffer[n-1] = '\0'; + if (n > 1) { + Sputs(buffer, skt); + printf("client> %s\n", buffer); + waitresponse = 1; + } + } + } + Sputs("QUIT", skt); +} diff --git a/src/tools/client/sterm.c b/src/tools/client/sterm.c new file mode 100644 index 00000000..13856cd6 --- /dev/null +++ b/src/tools/client/sterm.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include "sockets.h" + +int main (int argc, char **argv) +{ + Socket *skt; + int i, n; + char buffer[500]; + + skt = Sopen(argv[1],"c"); + if (skt == NULL) exit (1); + + for(;;) { + printf("client> "); + fflush(stdout); + fgets(buffer, 500, stdin); + n = strlen(buffer); + buffer[n-1] = '\0'; + if (n > 1) + Sputs(buffer, skt); + usleep(100000); + i = Stest(skt); + if (i == -1) exit(-1); + else if (i > 0) { + Sgets(buffer, 500, skt); + printf("server> %s\n", buffer); + } + } +} diff --git a/src/tools/uts-gen-conf b/src/tools/uts-gen-conf new file mode 100644 index 00000000..81f90224 --- /dev/null +++ b/src/tools/uts-gen-conf @@ -0,0 +1,101 @@ +#! /usr/bin/python +# -*- coding: iso-8859-1 -*- +# +# a parser to generate .conf file to 'sec' +# + +import sys +import imp +import os.path +import glob + +daemons = {} +rpc = [] + +default_uts_etc = "/etc/uts/sec" + +# build instruments list +inst_list = [] + +for dir in sys.path: + s = os.path.join(dir, 'uts/instruments/[a-zA-Z]*.py') + inst_list += glob.glob(s) + +# look on ~/uts +dir = os.path.expanduser('~/uts') +inst_list += glob.glob(os.path.join(dir, '[a-zA-Z]*.py')) + +try: + + for d in inst_list: + + daemonFullPath = os.path.abspath(d) + + daemonPath, daemonFile = os.path.split(daemonFullPath) + + daemon = os.path.splitext(daemonFile)[0] + + sys.path.append(daemonPath) + + (f, p, d) = imp.find_module(daemon) + + mod = imp.load_module(daemon, f, p, d) + + me = "" + + if(hasattr(mod, '_me')): + me = mod._me + else: + me = mod.__name__ + + # me found + daemons[me] = {"rpc": [], "notify": []} + + if(hasattr(mod, '_rpc')): + daemons[me]["rpc"] = mod._rpc + + if(hasattr(mod, '_notify')): + daemons[me]["notify"] = mod._notify + + # make rpc list + for (d, v) in daemons.items(): + for r in v["rpc"]: + rpc.append(d+"_"+r) + + # save rpc list to file + rpc_file = file(os.path.join(default_uts_etc, "rpc.conf"), "w+") + + # header + rpc_file.write("INSTNAME RPC\n") + rpc_file.write("NSTATCLIENTS 10\n\n") + + # save each notify list to a file named daemon.conf + for (d,v) in daemons.items(): + + d_file = file(os.path.join(default_uts_etc, d.lower()+".conf"), "w+") + + # header + d_file.write("INSTNAME %s\n" % d.upper()) + d_file.write("NSTATCLIENTS 10\n\n") + + for n in v["notify"]: + d_file.write("STATUS %s\n" % n) + + # write rpc entries + for r in v["rpc"]: + rpc_file.write("STATUS %s_%s\n" % (d, r)) + + rpc_file.write("STATUS %s_END_OF_LINE\n\n" % d.upper()) + + d_file.close() + + rpc_file.close() + +except ImportError, e: + print "Cannot import module:", str(e) + +except AttributeError, e: + print "Cannot get attribute:", str(e) + +except IOError, e: + print "Cannot write file:", str(e) diff --git a/src/www/LEIAME b/src/www/LEIAME new file mode 100644 index 00000000..142bd95a --- /dev/null +++ b/src/www/LEIAME @@ -0,0 +1,71 @@ +Interface web para o UTS (e outros) - v. 0.1a + +procedimento de instalação + ++ descompactação do arquivo + + +Se você está lendo isto, esta tarefa já está concluída. :-) + ++ configuração (uts.inc.php) + + +Há algumas variáveis no arquivo uts.inc.php (o arquivo se encontra +dentro do diretório config) que devem ser editatas **ANTES** de tentar +utilizar a interface. São elas: + + +//UTS_PLATFORM//: "linux" ou "win32", logo farei o código descobrir isso por si só. + +//UTS_DB_DSN//: define a forma de acesso ao banco de dados (somente MySQL +enquanto). A URL é da forma: (os valores entre [] devem ser editados) + +``` "mysql://[usuario_mysql]:[senha_usuario_mysql]@[servidor_mysql]/[bando_de_dados]" + +//UTS_WIN_SCRIPTS_DIR//: local onde os arquivos serão gravados para o Orchestrate. **SOMENTE PARA USO COM O ORCHESTRATE.** + +//UTS_DEFAULT_SERVER//: deve conter o nome do servidor onde o UTS está sendo executado. **SOMENTE PARA O UTS.** + +//UTS_SPMTABLE_PATH//: caminho do programa (o valor padrão costuma funcionar). **SOMENTE PARA O UTS.** + + ++ criação do banco de dados + + +No diretório 'db' há um arquivo chamado 'db-schema.sql'. Este arquivo +contém as tabelas usadas pelo sistema. O arquivo está escrito na +linguagem SQL. Para criar as tabelas no MySQL você pode usar o +PHPMyAdmin, que facilitará muito sua vida (não só neste momento). A +instalação do PHPMyAdmin é muito simples, e uma vez feita, você poderá +executar arquivos SQL diretamente em um banco de dados. Ou, usar o +utilitário mysql (cliente de acesso do MySQL) para executar o arquivo +SQL. + +Mas, é **EXTREMAMENTE** recomendado, que você use o PHPMyAdmin caso seja +iniciante no MySQL. + +O PHPMyAdmin pode ser obtido em www.phpmyadmin.net + + +++ (quase) o fim. ++ + +Pronto!!! Basta acessar a URL do seu servidor web, +ex. www.observatorio.ufsc.br e entrar no diretório onde foi +instalada a interface, ex www.observatorio.ufsc.br/uts. + + ++ primeiro acesso + + +Ao acessar a tela inicial da interface, haverá um formulário para +login. Para criar um usuário é necessário acessar a tela de +administração (ex. www.observatorio.ufsc.br/uts/admin). No primeiro +acesso a esta página, será cadastrado um usuário e uma senha, que +servirão de proteção para acessos indevidos à página de +admnistração. Após cadastrar este usuário, basta adicionar +observadores, voltar a tela de login de usuários, +ex. www.observatorio.ufsc.br/uts e iniciar a observação. + + += dúvidas = + +Sugestões e dúvidas, email para [pH henrique@astro.ufsc.br], ou consulte o +código fonte. (vantagens do software livre :-) + +(copyleft) 2003-2005 - P. Henrique Silva diff --git a/src/www/LEIAME.html b/src/www/LEIAME.html new file mode 100644 index 00000000..80fff7c2 --- /dev/null +++ b/src/www/LEIAME.html @@ -0,0 +1,111 @@ + + + + +Interface web para o UTS (e outros) - v. 0.1a + +

Interface web para o UTS (e outros) - v. 0.1a

+ +procedimento de instalação +
+ +

+
+

+ + +

+
+

+ +

1. descompactação do arquivo

+

+Se você está lendo isto, esta tarefa já está concluída. :-) +

+ +

2. configuração (uts.inc.php)

+

+Há algumas variáveis no arquivo uts.inc.php (o arquivo se encontra +dentro do diretório config) que devem ser editatas ANTES de tentar +utilizar a interface. São elas: +

+

+UTS_PLATFORM: "linux" ou "win32", logo farei o código descobrir isso por si só. +

+

+UTS_DB_DSN: define a forma de acesso ao banco de dados (somente MySQL +enquanto). A URL é da forma: (os valores entre [] devem ser editados) +

+
+  "mysql://[usuario_mysql]:[senha_usuario_mysql]@[servidor_mysql]/[bando_de_dados]"
+
+

+

+UTS_WIN_SCRIPTS_DIR: local onde os arquivos serão gravados para o Orchestrate. SOMENTE PARA USO COM O ORCHESTRATE. +

+

+UTS_DEFAULT_SERVER: deve conter o nome do servidor onde o UTS está sendo executado. SOMENTE PARA O UTS. +

+

+UTS_SPMTABLE_PATH: caminho do programa (o valor padrão costuma funcionar). SOMENTE PARA O UTS. +

+ +

3. criação do banco de dados

+

+No diretório 'db' há um arquivo chamado 'db-schema.sql'. Este arquivo +contém as tabelas usadas pelo sistema. O arquivo está escrito na +linguagem SQL. Para criar as tabelas no MySQL você pode usar o +PHPMyAdmin, que facilitará muito sua vida (não só neste momento). A +instalação do PHPMyAdmin é muito simples, e uma vez feita, você poderá +executar arquivos SQL diretamente em um banco de dados. Ou, usar o +utilitário mysql (cliente de acesso do MySQL) para executar o arquivo +SQL. +

+

+Mas, é EXTREMAMENTE recomendado, que você use o PHPMyAdmin caso seja +iniciante no MySQL. +

+

+O PHPMyAdmin pode ser obtido em www.phpmyadmin.net +

+ +

3.1. (quase) o fim.

+

+Pronto!!! Basta acessar a URL do seu servidor web, +ex. www.observatorio.ufsc.br e entrar no diretório onde foi +instalada a interface, ex www.observatorio.ufsc.br/uts. +

+ +

4. primeiro acesso

+

+Ao acessar a tela inicial da interface, haverá um formulário para +login. Para criar um usuário é necessário acessar a tela de +administração (ex. www.observatorio.ufsc.br/uts/admin). No primeiro +acesso a esta página, será cadastrado um usuário e uma senha, que +servirão de proteção para acessos indevidos à página de +admnistração. Após cadastrar este usuário, basta adicionar +observadores, voltar a tela de login de usuários, +ex. www.observatorio.ufsc.br/uts e iniciar a observação. +

+ +

dúvidas

+

+Sugestões e dúvidas, email para pH, ou consulte o +código fonte. (vantagens do software livre :-) +

+

+(copyleft) 2003-2005 - P. Henrique Silva +

+ + + + diff --git a/src/www/LICENSE b/src/www/LICENSE new file mode 100644 index 00000000..5b6e7c66 --- /dev/null +++ b/src/www/LICENSE @@ -0,0 +1,340 @@ + 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) + + 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) year 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. diff --git a/src/www/admin/change-pass.php b/src/www/admin/change-pass.php new file mode 100644 index 00000000..97602543 --- /dev/null +++ b/src/www/admin/change-pass.php @@ -0,0 +1,102 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + + Header("Location: " . getMsg("home.php", "Senha alterada com sucesso.")); + +} + +?> + + + + +Observatórios Virtuais ::: Entrar + + + + + + + + +


+
+

+
"> + + + + + + + + +
Nova senha
+
+ + + diff --git a/src/www/admin/home.php b/src/www/admin/home.php new file mode 100644 index 00000000..c779baee --- /dev/null +++ b/src/www/admin/home.php @@ -0,0 +1,117 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + +?> + + + + +Telescópios na Escola ::: Administração +::: Página principal + + + + + + +
Telescópios na Escola
+
+
+
+ + + + + + + + +numRows()) { + + $i = 0; + while($res->fetchInto($data, DB_FETCHMODE_ASSOC)) { + + if($i % 2) { + +?> + + + + + + + + + + +
NomeUsuárioOpções
+ +">Editar | `');"> +Remover
Nenhum usuário +cadastrado.
+ + + diff --git a/src/www/admin/index.php b/src/www/admin/index.php new file mode 100644 index 00000000..06810e63 --- /dev/null +++ b/src/www/admin/index.php @@ -0,0 +1,215 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + +if(!$res->numRows()) { + Header("Location: setup.php"); + exit(0); +} + + +// start +session_start(); + +if($_SESSION['admin']) { + Header("Location: home.php"); + exit(0); +} + + +?> + + + + +Telescópios na Escola ::: Administração ::: +Entrada + + + + + + + + +
Telescópios na Escola
+
+
+ +
+ + + + + + + + + + + + + +
usuário
senha
 
+
+
+
+
+ + + + + + + + + +
+
+"INPE"
+INPE
+
+
+"UFRGS"
+UFRGS
+
+
+"UFRJ"
+UFRJ
+
+
+"UFRN"
+UFRN
+
+
+"UFSC"
+UFSC
+
+
+"USP"
+USP
+
+ + + + +
+

+APOIO:
+
+ + + + + + + + + +
+
+
  +
VITAE
+
+
CNPQ
+
  
+ + + +" . get_include_path() . "
"; + + foreach ($included_files as $filename) { + echo "$filename
"; + } +} + +?> + diff --git a/src/www/admin/login.php b/src/www/admin/login.php new file mode 100644 index 00000000..7bb4d6dc --- /dev/null +++ b/src/www/admin/login.php @@ -0,0 +1,70 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + +if(PEAR::isError($res)) { + Header("Location: " . getError("index.php", "Erro ao tentar acessar o banco de dados.")); + exit(0); +} + +if(!$res->numRows()) { + Header("Location: " . getError("index.php", "Usuário ou senha inválidos.")); + exit(0); +} + +$res->fetchInto($data, DB_FETCHMODE_ASSOC); + +if( ($_POST['admin'] == trim($data['admin'])) && (md5(trim($_POST['admin_pass'])) == $data['admin_pass']) ) { + + session_start(); + + $_SESSION['admin'] = 1; + $_SESSION['inicio'] = strftime("%Y%m%d-%H%M%Z", time()); + + Header("Location: home.php"); + exit(0); + +} else { + + Header("Location: " . getError("index.php", "Usuário ou senha inválidos.")); + exit(0); + +} + +?> + + + + + + + + + diff --git a/src/www/admin/logout.php b/src/www/admin/logout.php new file mode 100644 index 00000000..2af1fe50 --- /dev/null +++ b/src/www/admin/logout.php @@ -0,0 +1,40 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + + + + + + diff --git a/src/www/admin/root.php b/src/www/admin/root.php new file mode 100644 index 00000000..20385c4e --- /dev/null +++ b/src/www/admin/root.php @@ -0,0 +1,26 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> diff --git a/src/www/admin/setup.php b/src/www/admin/setup.php new file mode 100644 index 00000000..c79138ad --- /dev/null +++ b/src/www/admin/setup.php @@ -0,0 +1,202 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + +//echo $res->numRows(); + +if($res->numRows()) { + + Header("Location: index.php"); + +} + +if($_GET['action'] == "setup") { + + extract($_POST); + + $sql = "INSERT INTO setup VALUES('" . trim($admin) . "', '" . md5(trim($admin_pass)) . "')"; + $res =& $db->query($sql); + + Header("Location: index.php"); +} + +?> + + + + +Telescópios na Escola ::: Administração ::: +Setup + + + + + + + + +
Telescópios na Escola
+
+
+
+

Instrucoes:

+Digite abaixo o nome do usuário que irá administrar o +sistema de agendamento. Este nome deverá ter no mínicio 6 +e no máximo 40 caracteres. Nenhum caractere "estranho" é +aceito (@#$%&*), apenas letras (maiúsculas e +minúsculas são tratadas de forma diferente) e +números. Não use acentuação. O mesmo vale para +a senha.
+
+ + + + + + + + + + + + + +
usuário
senha
 
+
+
+
+
+ + + + + + + + + +
+
+"INPE"
+INPE
+
+
+"UFRGS"
+UFRGS
+
+
+"UFRJ"
+UFRJ
+
+
+"UFRN"
+UFRN
+
+
+"UFSC"
+UFSC
+
+
+"USP"
+USP
+
+ + + + +
+

+APOIO:
+
+ + + + + + + + + +
+
+
  +
VITAE
+
+
CNPQ
+
  
+ + diff --git a/src/www/admin/time-add.php b/src/www/admin/time-add.php new file mode 100644 index 00000000..8c97b989 --- /dev/null +++ b/src/www/admin/time-add.php @@ -0,0 +1,98 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>nextID(UTS_TIME_SEQ); + +$inicio = mktime($inicio_hora, $inicio_min, 0, $inicio_mes, $inicio_dia, $inicio_ano); +$fim = mktime($fim_hora, $fim_min, 0, $fim_mes, $fim_dia, $fim_ano); + + +if($inicio > $fim) { + Header("Location: " . getError("user.php?id=$id", "O período selecionado é inválido (ele termina antes de começar :-)")); + exit(3); +} else if($inicio == $fim) { + Header("Location: " . getError("user.php?id=$id", "O período selecionado é inválido (ele não dura nem 1 segundo :-)")); + exit(3); +} + +// checa possivel conflito + +$sql = "SELECT inicio, fim FROM user_sched WHERE ( (inicio >= $inicio AND inicio <= $fim) OR (fim >= $inicio AND fim <= $fim) )"; + +$res =& $db->query($sql); + +if (DB::isError($res)) { + Header("Location: " . getError("user.php?id=$id", "Houve um erro ao tentar alocar tempo ao usuário. Tente novamente.")); + exit(1); +} + +if($res->numRows()) { + Header("Location: " . getError("user.php?id=$id", "O período selecionado já está ocupado.")); // conflito + exit(0); +} + +// sem conflitos, continua... + +$sql = "INSERT INTO user_sched VALUES($id, $newID, $inicio, $fim)"; + +$res =& $db->query($sql); + +if (DB::isError($res)) { + Header("Location: " . getError("user.php?id=$id", "Houve um erro ao tentar alocar tempo ao usuário. Tente novamente.")); + exit(1); +} + +if($db->affectedRows()) { + Header("Location: " . getMsg("user.php?id=$id", "O período foi alocado com sucesso.")); + exit(0); +} else { + Header("Location: " . getError("user.php?id=$id", "Houve um erro ao tentar alocar tempo ao usuário. Tente novamente.")); + exit(1); +} + +?> + + + + + + + + + diff --git a/src/www/admin/time-del.php b/src/www/admin/time-del.php new file mode 100644 index 00000000..580ab6be --- /dev/null +++ b/src/www/admin/time-del.php @@ -0,0 +1,59 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query("DELETE FROM user_sched WHERE id = " . $_GET['id']); + +if (DB::isError($res)) { + + Header("Location: " . getError("user.php?id=" . $_GET['user_id'], "Houce um erro ao tentar remover o período. Tente novamente.")); + exit(1); + +} else { + + Header("Location: " . getMsg("user.php?id=" . $_GET['user_id'], "O período foi removido com sucesso.")); + exit(0); + +} + +?> + + + + + + + + + diff --git a/src/www/admin/user-add.php b/src/www/admin/user-add.php new file mode 100644 index 00000000..2562ef70 --- /dev/null +++ b/src/www/admin/user-add.php @@ -0,0 +1,130 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + + if($res->numRows() > 1) { // o usuario ja existe e nao podera ser adicionado outro + Header("Location: ". getError("user.php?id=$id", "O usuário '$username' já¡ existe.
Por favor, escolha outro nome.")); + exit(10); + } + + // checa privilegios de administrador + if(!$root) { + $root = 0; + } else { + $root = 1; + } + + if(trim($passwd)) { // trocar a senha + $sql = "UPDATE users SET nome = '$nome', username = '$username', root = $root, passwd = '" . md5($passwd) . "' WHERE id = $id"; + } else { + $sql = "UPDATE users SET nome = '$nome', username = '$username', root = $root WHERE id = $id"; + } + + $res =& $db->query($sql); + + if (DB::isError($res)) { + Header("Location: " . getError("user.php?id=$id", "Houve um erro ao tentar atualizar o registro. Tente novamente.")); + exit(4); + } + + // BUG FIXME (quando nada eh modificado, ele retorna 0 a seguir, e parece que houve um erro, qdo na verdade nao houve! + + if($db->affectedRows()) { + Header("Location: " . getMsg("user.php?id=$id", "Registro atualizado com sucesso.")); + exit(0); + } else { + Header("Location: " . getError("user.php?id=$id", "Houve um erro ao tentar atualizar o registro. Tente novamente.")); + exit(4); + } + + + +} else { // adicionar + + $sql = "SELECT username FROM users WHERE username = '$username'"; + $res =& $db->query($sql); + + $newID = $db->nextID(UTS_USER_SEQ); + + if($res->numRows()) { // o usuario ja existe e nao podera ser adicionado outro + Header("Location: ". getError("user.php?id=$id", "O usuário '$username' já existe.
Por favor, escolha outro nome.")); + exit(10); + } + + // checa privilegios de administrador + if(!$root) { + $root = 0; + } else { + $root = 1; + } + + $sql = "INSERT INTO users VALUES($newID, '$nome', '$username', $root, '" . md5($passwd) . "')"; + + $res =& $db->query($sql); + + if (DB::isError($res)) { + Header("Location: " . getError("user.php?id=$newID", "Houve um erro ao tentar adicionar o usuário. Tente novamente.")); + exit(3); + } + + if($db->affectedRows()) { + Header("Location: " . getMsg("user.php?id=$newID", "Usuário '$username' adicionado com sucesso..")); + exit(0); + } else { + Header("Location: " . getError("user.php?id=$newID", "Houve um erro ao tentar adicionar o usuário. Tente novamente.")); + exit(3); + } + +} + +?> + + + + + + + + + diff --git a/src/www/admin/user-del.php b/src/www/admin/user-del.php new file mode 100644 index 00000000..6b3be4e0 --- /dev/null +++ b/src/www/admin/user-del.php @@ -0,0 +1,57 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query("DELETE FROM users WHERE id = " . $_GET['id']); +$res2 =& $db->query("DELETE FROM user_sched WHERE user_id = " . $_GET['id']); + +if ( (PEAR::isError($res)) || (PEAR::isError($res2)) ) { + Header("Location: " . getError("home.php?erro=1", "Houve um erro ao tentar remover o usuário. Tente novamente.")); + exit(1); +} else { + Header("Location: " . getMsg("home.php", "Usuário removido com sucesso.")); + exit(0); +} + +?> + + + + + + + + + diff --git a/src/www/admin/user.php b/src/www/admin/user.php new file mode 100644 index 00000000..681e5a0a --- /dev/null +++ b/src/www/admin/user.php @@ -0,0 +1,320 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query("SELECT * FROM users WHERE id = " . intval($_GET['id'])); + + if ( (!DB::isError($res)) && ($res->numRows()) ) + $res->fetchInto($data, DB_FETCHMODE_ASSOC); + +} + +?> + + + + +Telescópios na Escola ::: Administração +::: Usuários + + + + + + + + +
Telescópios na Escola
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
Nome
Usuario
Senha
Super-usuário?>
+
+ + +
+

Tempo alocado

+
+ + + + + + + + + + + + + + + + + +
Início + + + + + + + +
Fim + + + + + + + +
+
+
+ + + + + + + + + +query("SELECT * FROM user_sched WHERE user_id = " . $_GET['id'] . " ORDER BY inicio DESC"); + +if (DB::isError($res)) { + die($res->getMessage()); +} + +if($res->numRows()) { + + $i = 0; + while($res->fetchInto($row, DB_FETCHMODE_ASSOC)) { + + if($i % 2) { + +?> + + + + + + + + + + +disconnect(); + +?>
InicioFimOpcoes
+ +Remover
Nenhum tempo alocado
+ + + + + + diff --git a/src/www/apontar-orch.php b/src/www/apontar-orch.php new file mode 100644 index 00000000..1354c1b4 --- /dev/null +++ b/src/www/apontar-orch.php @@ -0,0 +1,81 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Observatórios Virtuais ::: Apontar e Integrar + + + + + +

::: voltar :::

+ + diff --git a/src/www/apontar-uts.php b/src/www/apontar-uts.php new file mode 100644 index 00000000..a960ec01 --- /dev/null +++ b/src/www/apontar-uts.php @@ -0,0 +1,161 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>setInteractive(FALSE); + +if(!$ccd->connect()) {; + Header("Location: " . getError("formApontar.php?" . $_SERVER['QUERY_STRING'], "O Observatório não está disponível. Consulte o responsável. (SERVER_FULL)")); + exit(0); +} + +$tel = new Tel('status'); +$tel->setInteractive(FALSE); + +if(!$tel->connect()) { + Header("Location: " . getError("formApontar.php?" . $_SERVER['QUERY_STRING'], "O Observatório não está disponível. Consulte o responsável. (SERVER_FULL)")); + exit(0); +} + +$stat0 = $ccd->isBusy(); +$stat1 = $tel->isBusy(); + +if($stat0 || $stat1) { + $ccd->disconnect(); + $tel->disconnect(); + Header("Location: " . getError("formApontar.php?" . $_SERVER['QUERY_STRING'], "Há uma observa&ccdeil;ão em andamento.
Aguarde alguns instantes e tente novamente.
Para saber o quanto esperar, vá a página Estado da Observação")); + exit(0); +} + + + +$sync = new Sync(); +$sync->setInteractive(FALSE); + +if(!$sync->connect()) { + Header("Location: " . getError("formApontar.php?" . $_SERVER['QUERY_STRING'], "O Observatório não está disponível. Consulte o responsável. (SERVER_FULL)")); + exit(0); +} + +// to serialize the process +$ccd = new CCD('status'); +$ccd->setInteractive(FALSE); +$ccd->connect(); + +$tel = new Tel('status'); +$tel->setInteractive(FALSE); +$tel->connect(); + + +$ra = $_GET['ra_h'] . ":" . $_GET['ra_m'] . ":" . $_GET['ra_s']; +$dec = $_GET['dec_g'] . ":" . $_GET['dec_m'] . ":" . $_GET['dec_s']; + +updateFilename(getcwd() . "/data", $_GET['obj'] ? $_GET['obj'] : "imagem", "%Y%m%d%H%M%S"); + +//$sync->setStatus("OBJECT", $_GET['obj']); FIXME +$sync->setStatus("RA", $ra); +$sync->setStatus("DEC", $dec); +$sync->setStatus("EPOCH", $_GET['epoca']); +$sync->setStatus("FILTER", $_GET['filtro']); +$sync->setStatus("EXPTIME", $_GET['exp_time']); +$sync->setStatus("NEXP", $_GET['num_exp']); +$sync->setStatus("BFNAME", $_SESSION['bf_fullname']); + +// first slew +$sync->setStatus("TELSTART", "NOW"); + +// now wait for telescope to go offline + +while($tel->isBusy()) { + sleep(1); +} + +// ok, now take a image +$sync->setStatus("CAMSTART", "NOW"); + + +// ok +$ccd->disconnect(); +$tel->disconnect(); +$sync->disconnect(); + +// guarda o log +$i = count($_SESSION['log']); + +$_SESSION['log'][$i] = "fila"; +$_SESSION['obj'][$i] = $_GET['obj']; +$_SESSION['ra'][$i] = $ra; +$_SESSION['dec'][$i] = $dec; +$_SESSION['num_exp'][$i] = $_GET['num_exp']; +$_SESSION['exp_time'][$i] = $_GET['exp_time']; +$_SESSION['filter'][$i] = $_GET['filtro']; +$_SESSION['start_time'][$i] = time(); + +Header("Location: status.php"); + +?> + + + + +Observatórios Virtuais ::: Entrar + + + + + +

::: voltar :::

+ + diff --git a/src/www/arquivo.php b/src/www/arquivo.php new file mode 100644 index 00000000..54885510 --- /dev/null +++ b/src/www/arquivo.php @@ -0,0 +1,129 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola ::: Arquivo + + + + + +
+
Telescópios na Escola
+
+

 

+
+

As imagens também podem ser otidas /">aqui.

+
+
+
+ + + + + + + + + + + + + + + + + + + + +
ArquivoTamanhoVisualizarDownload
Nenhum objeto na lista
+ +">:: visualizar +::">:: download ::
+

 

+

::: voltar :::

+

 

+

 

+
+ + diff --git a/src/www/bin/fits2jpeg-linux b/src/www/bin/fits2jpeg-linux new file mode 100755 index 00000000..4de41474 Binary files /dev/null and b/src/www/bin/fits2jpeg-linux differ diff --git a/src/www/bin/fits2jpeg-win32 b/src/www/bin/fits2jpeg-win32 new file mode 100755 index 00000000..4de41474 Binary files /dev/null and b/src/www/bin/fits2jpeg-win32 differ diff --git a/src/www/config/uts.inc.php b/src/www/config/uts.inc.php new file mode 100644 index 00000000..3e83508b --- /dev/null +++ b/src/www/config/uts.inc.php @@ -0,0 +1,47 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + diff --git a/src/www/css/uts.css b/src/www/css/uts.css new file mode 100644 index 00000000..2266a280 --- /dev/null +++ b/src/www/css/uts.css @@ -0,0 +1,186 @@ + diff --git a/src/www/db/db-schema.sql b/src/www/db/db-schema.sql new file mode 100644 index 00000000..f0d9f4a7 --- /dev/null +++ b/src/www/db/db-schema.sql @@ -0,0 +1,77 @@ +-- phpMyAdmin SQL Dump +-- version 2.6.1 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Generation Time: Mar 10, 2005 at 09:26 PM +-- Server version: 3.23.54 +-- PHP Version: 4.2.2 +-- +-- Database: `uts` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `logged` +-- + +DROP TABLE IF EXISTS `logged`; +CREATE TABLE IF NOT EXISTS `logged` ( + `id` smallint(5) NOT NULL default '0' +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `setup` +-- + +DROP TABLE IF EXISTS `setup`; +CREATE TABLE IF NOT EXISTS `setup` ( + `admin` varchar(40) NOT NULL default '', + `admin_pass` varchar(40) NOT NULL default '' +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `user_info` +-- + +DROP TABLE IF EXISTS `user_info`; +CREATE TABLE IF NOT EXISTS `user_info` ( + `user_id` smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (`user_id`) +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `user_sched` +-- + +DROP TABLE IF EXISTS `user_sched`; +CREATE TABLE IF NOT EXISTS `user_sched` ( + `user_id` smallint(5) unsigned NOT NULL default '0', + `id` int(10) unsigned NOT NULL default '0', + `inicio` int(10) unsigned NOT NULL default '0', + `fim` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`id`) +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +CREATE TABLE IF NOT EXISTS `users` ( + `id` smallint(5) unsigned NOT NULL default '0', + `nome` varchar(255) default NULL, + `username` varchar(40) NOT NULL default '', + `root` tinyint(1) unsigned NOT NULL default '0', + `passwd` varchar(40) NOT NULL default '', + PRIMARY KEY (`id`) +) TYPE=MyISAM; diff --git a/src/www/db/db-schema.xml b/src/www/db/db-schema.xml new file mode 100644 index 00000000..bffd7e39 --- /dev/null +++ b/src/www/db/db-schema.xml @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ + + + + + + + + + +
diff --git a/src/www/db/db-user.sql b/src/www/db/db-user.sql new file mode 100644 index 00000000..9bfa815f --- /dev/null +++ b/src/www/db/db-user.sql @@ -0,0 +1,7 @@ +-- create user and give privileges + +GRANT USAGE ON * . * TO '{$uts_mysql_user}'@'{$uts_mysql_server}' IDENTIFIED BY '{$uts_mysql_user_pass}' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0; + +GRANT SELECT , INSERT , UPDATE , DELETE , CREATE , DROP , INDEX , ALTER ON '{$uts_mysql_db}' . * TO '{$uts_mysql_user}'@'{$uts_mysql_server}'; + +FLUSH PRIVILEGES; diff --git a/src/www/display.php b/src/www/display.php new file mode 100644 index 00000000..3747d0e5 --- /dev/null +++ b/src/www/display.php @@ -0,0 +1,58 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola ::: +Visualização + + + + + +
+ +

+
+

:: voltar :::

+ + diff --git a/src/www/download.php b/src/www/download.php new file mode 100644 index 00000000..f9b54f10 --- /dev/null +++ b/src/www/download.php @@ -0,0 +1,53 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + + + + + + diff --git a/src/www/formApontar.php b/src/www/formApontar.php new file mode 100644 index 00000000..e57ea6cb --- /dev/null +++ b/src/www/formApontar.php @@ -0,0 +1,257 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola ::: Apontar e integrar + + + + + + + + + +
+
Telescópios na Escola
+
+

Apontar e Integrar

+
+ +
Procedimento +

Preencha o formulário abaixo, clique em 'Observar' e +aguarde. Será exibida uma página com +informações sobre o andamento da +observação.
+Posicione o cursor sobre um dos campos abaixo par obter mais +informações.

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Objeto:
+Ascensão reta (RA) ">
+Declinação (DEC): ">
+Número de exposições::
+Tempo de exposição:
+Filtro:
 
+
+
+
+
+
+

::: voltar :::

+
+ + diff --git a/src/www/formOpcoes.php b/src/www/formOpcoes.php new file mode 100644 index 00000000..ee5a917b --- /dev/null +++ b/src/www/formOpcoes.php @@ -0,0 +1,104 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola ::: +Opções + + + + + +
+
Telescópios na Escola
+
+

Opções

+
+
+

O nome é formado da seguinte forma: +[nome_da_imagem]-[data]. Os campos cercados por [ e ] podem +ser alterados pelo formulário abaixo.

+
+
+"> > + + + + + + + + + + + + + + + + + + + + + + + + + +
Imagens e diretórios
Diretório padrão:
Nome da imagem:
Formato da data:">
 
+
+
+
+
+

::: voltar :::

+
+ + diff --git a/src/www/getStatus.php b/src/www/getStatus.php new file mode 100644 index 00000000..019ab564 --- /dev/null +++ b/src/www/getStatus.php @@ -0,0 +1,97 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>setInteractive(0); +$ccd->connect(); + +$tel = new Tel('status'); +$tel->setInteractive(0); +$tel->connect(); + +$stat0 = $tel->isBusy(); +$stat1 = $ccd->isBusy(); + +?> + + + + +Observatórios Virtuais ::: Entrar + + + + + +; "> +disconnect(); +$ccd->disconnect(); + +?> + + + + diff --git a/src/www/home.php b/src/www/home.php new file mode 100644 index 00000000..bdc186fc --- /dev/null +++ b/src/www/home.php @@ -0,0 +1,138 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola ::: Página +principal + + + + + +
+
Telescópios na Escola
+
+

+

+
+

::: apontar e integrar :::

+

::: estado da observação +:::

+

::: ver o céu :::

+

::: arquivo :::

+ +

::: opções :::

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
#ObjetoRADECTempo de exposiçãoNúmero de exposiçõesFiltro
Nenhum objeto na lista
+ + + + + + + +
+

 

+

:: sair :::

+

 

+

 

+
+ + + diff --git a/src/www/imagens/back-ajuda.png b/src/www/imagens/back-ajuda.png new file mode 100644 index 00000000..1cc73849 Binary files /dev/null and b/src/www/imagens/back-ajuda.png differ diff --git a/src/www/imagens/cnpqlogo.jpg b/src/www/imagens/cnpqlogo.jpg new file mode 100644 index 00000000..f3b8f751 Binary files /dev/null and b/src/www/imagens/cnpqlogo.jpg differ diff --git a/src/www/imagens/default.png b/src/www/imagens/default.png new file mode 100644 index 00000000..11f7c831 Binary files /dev/null and b/src/www/imagens/default.png differ diff --git a/src/www/imagens/inpelogo.jpg b/src/www/imagens/inpelogo.jpg new file mode 100644 index 00000000..9c9637b8 Binary files /dev/null and b/src/www/imagens/inpelogo.jpg differ diff --git a/src/www/imagens/ovlogo.jpg b/src/www/imagens/ovlogo.jpg new file mode 100644 index 00000000..34ecf6c2 Binary files /dev/null and b/src/www/imagens/ovlogo.jpg differ diff --git a/src/www/imagens/ufrgslogo.jpg b/src/www/imagens/ufrgslogo.jpg new file mode 100644 index 00000000..cc6c7cab Binary files /dev/null and b/src/www/imagens/ufrgslogo.jpg differ diff --git a/src/www/imagens/ufrjlogo.jpg b/src/www/imagens/ufrjlogo.jpg new file mode 100644 index 00000000..dc46f463 Binary files /dev/null and b/src/www/imagens/ufrjlogo.jpg differ diff --git a/src/www/imagens/ufrnlogo.jpg b/src/www/imagens/ufrnlogo.jpg new file mode 100644 index 00000000..3c9436d6 Binary files /dev/null and b/src/www/imagens/ufrnlogo.jpg differ diff --git a/src/www/imagens/ufsclogo.jpg b/src/www/imagens/ufsclogo.jpg new file mode 100644 index 00000000..55be6ee2 Binary files /dev/null and b/src/www/imagens/ufsclogo.jpg differ diff --git a/src/www/imagens/usplogo.jpg b/src/www/imagens/usplogo.jpg new file mode 100644 index 00000000..90751e9a Binary files /dev/null and b/src/www/imagens/usplogo.jpg differ diff --git a/src/www/imagens/vitaelogo.jpg b/src/www/imagens/vitaelogo.jpg new file mode 100644 index 00000000..e2b89f8b Binary files /dev/null and b/src/www/imagens/vitaelogo.jpg differ diff --git a/src/www/imagens/warning.gif b/src/www/imagens/warning.gif new file mode 100644 index 00000000..cf8d5718 Binary files /dev/null and b/src/www/imagens/warning.gif differ diff --git a/src/www/index.php b/src/www/index.php new file mode 100644 index 00000000..7780c4d1 --- /dev/null +++ b/src/www/index.php @@ -0,0 +1,200 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola ::: Entrada + + + + + + + + +
Telescópios na Escola
+
+
+

+ +

+
+ +
+ + + + + + + + + + + + + +
usuário
senha
 
+
+
+
+
+ + + + + + + + + +
+
INPE
+INPE
+
+
UFRGS
+UFRGS
+
+
UFRJ
+UFRJ
+
+
UFRN
+UFRN
+
+
UFSC
+UFSC
+
+
USP
+USP
+
+ + + + +
+

+APOIO:
+
+ + + + + + + + + +
+
+
  +
VITAE
+
+
CNPQ
+
  
+ + + +" . get_include_path() . "
"; + + foreach ($included_files as $filename) { + echo "$filename
"; + } +} + +?> + diff --git a/src/www/instalacao-action.php b/src/www/instalacao-action.php new file mode 100644 index 00000000..5aa52619 --- /dev/null +++ b/src/www/instalacao-action.php @@ -0,0 +1,218 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>" . $res->getMessage() . " (" . $res->getCode() . "))
"; + // $err .= nl2br($res->getUserInfo()) . "
"; + // $err .= $res->getDebugInfo() . ""; + + //return $err; + +} + + +$db =& DB::connect($dsn); + +if(DB::isError($db)) { + $err = "Erro ao tentar conectar ao MySQL.
"; + $err .= "Verifique o nome do administrador e a senha.
"; + $err .= dbErr($db); + + Header("Location: " . getError("instalacao.php", $err)); + exit(0); +} + +function back() { + +// global $db; + +// extract($_POST); + +// $sql = "REVOKE ALL PRIVILEGES ON $mysql_db . * FROM $mysql_newuser@$mysql_server;"; +// $sql .= "DROP DATABASE $mysql_db;"; +// $sql .= "DELETE FROM `columns_priv` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "DELETE FROM `user` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "DELETE FROM `db` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "DELETE FROM `tables_priv` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "FLUSH PRIVILEGES;"; + +// $db->query($sql); + +} + +// OK, we have a connection + +// // create user +// $sql = "GRANT USAGE ON * . * TO '$mysql_newuser'@'localhost' IDENTIFIED BY '$mysql_newuser_pass' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0"; + +// $result = $db->query($sql); + +// if(DB::isError($result)) { +// $err = "Erro ao tentar criar o usuÃrio.
"; +// $err .= dbErr($result); + +// $err .= "(" . $result->getMessage() . " (" . $db->getCode() . "))
"; +// $err .= "(" . $result->getUserInfo() . ")
"; + +// back(); +// Header("Location: " . getError("instalacao.php", $err)); +// exit(0); + +// } + +// create database +$sql = "CREATE DATABASE $uts_mysql_db"; +$result = $db->query($sql); + +if(DB::isError($result)) { + $err = "Erro ao tentar criar o banco de dados.
"; + $err .= dbErr($result); + + back(); + Header("Location: " . getError("instalacao.php", $err)); + exit(0); + +} + +// // grant user privileges +// $sql = "GRANT SELECT , INSERT , UPDATE , DELETE , CREATE , DROP , INDEX , ALTER ON `$mysql_db` . * TO '$mysql_newuser'@'$mysql_server'"; + +// $result = $db->query($sql); + +// if(DB::isError($result)) { +// $err = "Erro ao tentar criar o usuÃrio.
"; +// $err .= dbErr($result); + +// back(); +// Header("Location: " . getError("instalacao.php", $err)); +// exit(0); + +// } + +// // flush privileges +// $sql = "FLUSH PRIVILEGES"; +// $result = $db->query($sql); + +// // use the newly create database +// $sql = "USE '$mysql_db'"; +// $result = $db->query($sql); + +// if(DB::isError($result)) { +// $err = "Erro ao tentar criar o banco de dados.
"; +// $err .= dbErr($result); + +// back(); +// Header("Location: " . getError("instalacao.php", $err)); +// exit(0); + +// } + +// connect as the newly create user +// $dsn = "mysql://$mysql_newuser:$mysql_newuser_pass@$mysql_server/$mysql_db"; + +$db->disconnect(); +$dsn = "mysql://$mysql_admin:$mysql_admin_pass@$mysql_server/$uts_mysql_db"; +$db =& DB::connect($dsn); + +// if(DB::isError($db)) { +// $err = "Erro ao tentar conectar ao MySQL.
"; +// $err .= "Verifique o nome do administrador e a senha.
"; +// $err .= dbErr($result); + +// Header("Location: " . getError("instalacao.php", $err)); +// exit(0); +// } + + +// fill-in the newly create database +dbsource("db/db-schema.sql", array("uts_mysql_user" => $uts_mysql_user, + "uts_mysql_user_pass" => $uts_mysql_user_pass, + "uts_mysql_server" => $mysql_server, + "uts_mysql_db" => $uts_mysql_db)); + +dbsource("db/db-user.sql", array("uts_mysql_user" => $uts_mysql_user, + "uts_mysql_user_pass" => $uts_mysql_user_pass, + "uts_mysql_server" => $mysql_server, + "uts_mysql_db" => $uts_mysql_db)); + +// write configuration file +// -- + +if (strtoupper(substr(PHP_OS, 0, 3)) == "WIN") { + $os = "windows"; +} else if(strtoupper(substr(PHP_OS, 0, 5)) == "LINUX") { + $os = "linux"; +} + +$server_name = $_SERVER['SERVER_NAME']; + +$config = << + + + + + + + +CONFIG; // -- $fp = fopen("config/uts.inc.php", "w+"); fwrite($fp, +$config); fclose($fp); Header("Location: index.php"); ?> + + diff --git a/src/www/instalacao-action2.php b/src/www/instalacao-action2.php new file mode 100644 index 00000000..ddab1233 --- /dev/null +++ b/src/www/instalacao-action2.php @@ -0,0 +1,108 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>" . $res->getMessage() . " (" . $res->getCode() . "))
"; + $err .= nl2br($res->getUserInfo()) . "
"; + // $err .= $res->getDebugInfo() . ""; + + return $err; + +} + + +$db =& DB::connect($dsn); + +if(DB::isError($db)) { + $err = "Erro ao tentar conectar ao MySQL.
"; + $err .= "Verifique o nome do administrador e a senha.
"; + $err .= dbErr($db); + + Header("Location: " . getError("instalacao.php", $err)); + exit(0); +} + +function back() { + +// global $db; + +// extract($_POST); + +// $sql = "REVOKE ALL PRIVILEGES ON $mysql_db . * FROM $mysql_newuser@$mysql_server;"; +// $sql .= "DROP DATABASE $mysql_db;"; +// $sql .= "DELETE FROM `columns_priv` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "DELETE FROM `user` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "DELETE FROM `db` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "DELETE FROM `tables_priv` WHERE User = $mysql_newuser AND Host = $mysql_server;"; +// $sql .= "FLUSH PRIVILEGES;"; + +// $db->query($sql); + +} + +// OK, we have a connection + +dbsource("db/db-schema.sql", array($mysql_newuser,$mysql_newuser_pass@$mysql_server/$mysql_db"; + +$sql = file_get_contents("db/db-schema.sql"); + +$result = $db->query(mysql_real_escape_string($sql)); + +if(DB::isError($result)) { + $err = "Erro ao tentar criar o banco de dados.
"; + $err .= dbErr($result); + + back(); + Header("Location: " . getError("instalacao.php", $err)); + exit(0); + +} + +// write configuration file + + +Header("Location: admin"); + +?> + + + + + + + + + diff --git a/src/www/instalacao.php b/src/www/instalacao.php new file mode 100644 index 00000000..62c3556d --- /dev/null +++ b/src/www/instalacao.php @@ -0,0 +1,216 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Observatórios Virtuais ::: Entrar + + + + + + + + +

+""
+

+
Instalação +

Para instalar a interface, preencha os campos abaixo. +TODOS os campos são obrigatórios.

+
+
+ +
+

Verifique a permisão do diretório "config"! +É necessário permissão para escrita neste +diretório.

+
+ +
+

UTS

+ + + + + + + + + +
administrador
senha
+

MySQL

+ + + + + + + + + + + + + + + + + + +
servidor
administrador
senha
  Erro. Verifique as mensagens +acima.
+
+
+
+ + + + + + + + + +
+
INPE
+INPE
+
+
UFRGS
+UFRGS
+
+
UFRJ
+UFRJ
+
+
UFRN
+UFRN
+
+
UFSC
+UFSC
+
+
USP
+USP
+
+ + + + +
+

+APOIO:
+
+ + + + + + + + + +
+
+
  +
VITAE
+
+
CNPQ
+
  
+ + diff --git a/src/www/js/jscountdown.js b/src/www/js/jscountdown.js new file mode 100644 index 00000000..03f68a6f --- /dev/null +++ b/src/www/js/jscountdown.js @@ -0,0 +1,83 @@ + +var myCountdown = new Array(); +var repeat = false; + +function checkPlural(noun, value) { + noun = ((value == 1) || (value == 0)) ? noun : (noun += "s"); + return noun; +} + +function updateDisplay(text, id) { + var tag = document.getElementById(id); + if (tag.firstChild) { + tag.firstChild.nodeValue = text; + } + else { + textNode = document.createTextNode(text); + tag.appendChild(textNode); + } + return; +} + +function doCountdown() { + for (i = 0; i < myCountdown.length; i++) { + if (!myCountdown[i].expired) { + var currentDate = new Date(); + var eventDate = myCountdown[i].eventDate; + var timeLeft = new Date(); + timeLeft = eventDate - currentDate; + msPerDay = 24 * 60 * 60 * 1000; + msPerHour = 60 * 60 * 1000; + msPerMin = 60 * 1000; + msPerSec = 1000; + daysLeft = Math.floor(timeLeft / msPerDay); + hoursLeft = Math.floor((timeLeft % msPerDay) / msPerHour); + minsLeft = Math.floor(((timeLeft % msPerDay) % msPerHour) / msPerMin); + secsLeft = Math.floor((((timeLeft % msPerDay) % msPerHour) % msPerMin) / msPerSec); + hour = checkPlural("hora", hoursLeft); + minute = checkPlural("minuto", minsLeft); + second = checkPlural("segundo", secsLeft); + if ((daysLeft == 0) && (hoursLeft == 0) && (minsLeft == 0) && (secsLeft == 0)) { + updateDisplay(myCountdown[i].onevent, myCountdown[i].tagID); + } + else { + if (daysLeft <= -1) { + updateDisplay(myCountdown[i].afterevent, myCountdown[i].tagID); + myCountdown[i].expired = true; + } + else { + updateDisplay(hoursLeft + ":" + minsLeft + ":" + secsLeft, myCountdown[i].tagID); + repeat = true; + } + } + } + } + if (repeat) { + repeat = false; + window.setTimeout("doCountdown()", 1000); + } + else { + return; + } +} + +function setEventDate(year, month, day, hour, minute, second) { +//function setEventDate(second) { + this.eventDate = new Date(year, month - 1, day, hour, minute, second); + return; +} + +function addCountdown(countdown) { + myCountdown[myCountdown.length] = countdown; + return; +} + +function Countdown() { + this.tagID = ""; + this.eventDate = new Date(); + this.setEventDate = setEventDate; + this.event = ""; + this.onevent = ""; + this.afterevent = ""; + this.expired = false; +} \ No newline at end of file diff --git a/src/www/js/jsval.js b/src/www/js/jsval.js new file mode 100644 index 00000000..9c840f1e --- /dev/null +++ b/src/www/js/jsval.js @@ -0,0 +1,400 @@ +/* FILE HEADER ************************************************** +** JS Validate +** Author: Karl Seguin, Timo Haberkern +** Homepage: http://jsval.berlios.de/ +** Version: 1.1.0 +** Copyright 2003, 2004 Karl Seguin + + This file is part of JS Validate. + + JS Validate is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + JS Validate 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 Lesser General Public License + along with JS Validate; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +** +** END HEADER ***************************************************/ + +function validateCompleteForm (objForm, strErrorClass) { + return _validateInternal(objForm, strErrorClass, 0); +} + +function validateStandard (objForm, strErrorClass) { + return _validateInternal(objForm, strErrorClass, 1); +} + +/*************************************************************** +** Internal functions +*****************************************************************/ +function _validateInternal(form, strErrorClass, nErrorThrowType){ + var strErrorMessage = ""; var objFirstError = null; + if (nErrorThrowType == 0){ + strErrorMessage = (form.err) ? form.err : _getLanguageText("err_form"); + } + + var fields = _GenerateFormFields(form); + for (var i = 0; i < fields.length; ++i){ + + var field = fields[i]; + field.ResetClass(); + + if (!field.IsValid(fields)){ + + field.SetClass(strErrorClass); + + if (nErrorThrowType == 1) { + _throwError(field); + return false; + }else{ + if (objFirstError == null){ + objFirstError = field; + } + strErrorMessage = _handleError (field, strErrorMessage); + bError = true; + + } + } + } + if (objFirstError != null) { + alert(strErrorMessage); + objFirstError.element.focus(); + return false; + } + return true; + } + + function _getLanguageText(id){ + objTextsInternal = new _jsVal_Language(); + objTexts = null; + try { + objTexts = new jsVal_Language(); + } catch (ignored){}; + switch (id) { + case "err_form": strResult = (!objTexts || !objTexts.err_form) ? objTextsInternal.err_form : objTexts.err_form; break; + case "err_enter": strResult = (!objTexts || !objTexts.err_enter) ? objTextsInternal.err_enter : objTexts.err_enter; break; + case "err_select": strResult = (!objTexts || !objTexts.err_select) ? objTextsInternal.err_select : objTexts.err_select; break; + } + return strResult; + } + + function _GenerateFormFields(form){ + var arr = new Array(); + for (var i = 0; i < form.length; ++i){ + var element = form.elements[i]; + var index = _getElementIndex(arr,element); + //if it doesn't already exist, add it to our array, else merge the change + if (index == -1){ + arr[arr.length] = new Field(element, form); + }else{ + arr[index].Merge(element) + } + } + return arr; +} +function _getElementIndex(arr, element){ + var elementName = element.name.toLowerCase(); + for (var i = 0; i < arr.length; ++i){ + if (arr[i].element.name.toLowerCase() == elementName){ + return i; + } + } + return -1; +} + +/*************************************************************** +** Standard translation +*****************************************************************/ +function _jsVal_Language() { + this.err_form = "Please enter/select values for the following fields:\n\n"; + this.err_select = "Please select a valid \"%FIELDNAME%\""; + this.err_enter = "Please enter a valid \"%FIELDNAME%\""; +} + +/*************************************************************** +** Field Class +*****************************************************************/ +function Field(element, form){ + if (!element.oldClassName) element.oldClassName = element.className; + this.type = element.type; + this.element = element; + this.exclude = element.exclude || element.getAttribute('exclude'); + this.err = element.err || element.getAttribute('err'); + this.required = _parseBoolean(element.required || element.getAttribute('required')); + this.realname = element.realname || element.getAttribute('realname'); + this.elements = new Array(); + + switch (this.type){ + case "textarea": + case "password": + case "text": + this.value = element.value; + this.minLength = element.minlength || element.getAttribute('minlength'); + this.maxLength = element.maxlength || element.getAttribute('maxlength'); + this.regexp = this._getRegEx(element); + this.minValue = element.minvalue || element.getAttribute('minvalue'); + this.maxValue = element.maxvalue || element.getAttribute('maxvalue'); + this.equals = element.equals || element.getAttribute('equals'); + break; + case "select-one": + case "select-multiple": + this.values = new Array(); + for (var i = 0; i < element.options.length; ++i){ + if (element.options[i].selected && (!this.exclude || element.options[i].value != this.exclude)){ + this.values[this.values.length] = element.options[i].value; + } + } + this.min = element.min || element.getAttribute('min'); + this.max = element.max || element.getAttribute('max'); + this.equals = element.equals || element.getAttribute('equals'); + break; + case "checkbox": + this.min = element.min || element.getAttribute('min'); + this.max = element.max || element.getAttribute('max'); + //no break, let it fall through to radio + case "radio": + this.required = _parseBoolean(this.required || element.getAttribute('required')); + this.values = new Array(); + if (element.checked){ + this.values[0] = element.value; + } + + this.elements[0] = element; + break; + } +} +Field.prototype.Merge = function(element){ + //never negate a require field + var required = _parseBoolean(element.getAttribute('required')); + if (required){ + this.required = true; + } + //all other cases (except required) we only add if there isn't already a value (first come first served) + if (!this.err){ + this.err = element.getAttribute('err'); + } + if (!this.equals){ + this.equals = element.getAttribute('equals'); + } + if (!this.realname){ + this.realname = element.getAttribute('realname'); + } + if (!this.max){ + this.max = element.getAttribute('max'); + } + if (!this.min){ + this.min = element.getAttribute('min'); + } + if (!this.regexp){ + this.regexp = this._getRegEx(element); + } + if (element.checked){ + this.values[this.values.length] = element.value; + } + this.elements[this.elements.length] = element; +} +Field.prototype.IsValid = function(arrFields){ + switch (this.type){ + case "textarea": + case "password": + case "text": + return this._ValidateText(arrFields); + case "select-one": + case "select-multiple": + case "radio": + case "checkbox": + return this._ValidateGroup(arrFields); + default: + return true; + } +} +Field.prototype.SetClass = function(newClassName){ + if ( (this.elements) && (this.elements.length > 0)) { + for (var i = 0; i < this.elements.length; ++i){ + this.elements[i].oldClassName = this.elements[i].className; + this.elements[i].className = newClassName; + } + }else{ + this.element.oldClassName = this.element.className; + this.element.className = newClassName; + } +} +Field.prototype.ResetClass = function(){ + if ( (this.type != "button") && (this.type != "submit") && (this.type != "reset") ) { + if ( (this.elements) && (this.elements.length > 0)) { + for (var i = 0; i < this.elements.length; ++i){ + this.elements[i].className = this.elements[i].oldClassName; + } + }else{ + this.element.className = this.element.oldClassName; + } + } +} +Field.prototype._getRegEx = function(element){ + regex = element.regexp || element.getAttribute('regexp') + if (regex == null) return null; + retype = typeof(regex); + if (retype.toUpperCase() == "FUNCTION") + return regex; + else if ( (retype.toUpperCase() == "STRING") && !(regex == "email") && !(regex == "tel") + && !(regex == "pc") && !(regex == "zip") && !(regex == "money") + && !(regex == "creditcard") && !(regex == "postalzip")) + { + nBegin = 0; nEnd = regex.length-1; + if (regex.charAt(0) == "/") nBegin=1; + if (regex.charAt(regex.length-1) == "/") nEnd=regex.length-2; + + return new RegExp(regex.slice(nBegin, nEnd)); + } + else { + return regex; + } +} +Field.prototype._ValidateText = function(arrFields){ + //required value is empty + if (this.required && !this.value){ + return false; + } + //value less than minlength + if (this.value && (this.minLength && this.value.length < this.minLength)){ + return false; + } + //value is more than maxlength + if (this.value && (this.maxLength && this.value.length > this.maxLength)){ + return false; + } + //value fails regular expression + if (this.regexp){ + if (!_checkRegExp(this.regexp, this.value)) + { + //the field isn't required, but there is a value + if (!this.required && this.value){ + return false; + } + if (this.required){ + return false; + } + } + else + { + return true; + } + } + + //check equality + if (this.equals){ + for (var i = 0; i < arrFields.length; ++i){ + var field = arrFields[i]; + if ( (field.element.name == this.equals) || (field.element.id == this.equals) ) { + if (field.element.value != this.value) { + return false; + } + break; + } + } + } + + //check against minvalue and maxvalue + if (this.required){ + var fValue = parseFloat(this.value); + if ((this.minValue || this.maxValue) && isNaN(fValue)){ + return false; + } + if ( (this.minValue) && (fValue < this.minValue) ) { + return false; + } + if ( (this.maxValue) && (fValue > this.maxValue) ) { + return false + } + } + return true; +} +Field.prototype._ValidateGroup = function(arrFields){ + if (this.required && this.values.length == 0){ + return false; + } + if (this.required && this.min && this.min > this.values.length){ + return false; + } + if (this.required && this.max && this.max < this.values.length){ + return false; + } + return true; +} + +function _handleError (field, strErrorMessage) { + var obj = field.element; + strNewMessage = strErrorMessage + ( (field.realname)? field.realname : ((obj.id) ? obj.id : obj.name) ) + "\n"; + return strNewMessage; +} + +function _throwError(field){ + var obj = field.element; + switch (field.type){ + case "text": + case "password": + case "textarea": + alert(_getError(field, "err_enter")); + try { + obj.focus(); + } + catch (ignore) {} + break; + case "select-one": + case "select-multiple": + case "radio": + case "checkbox": + alert(_getError(field, "err_select")); + break; + } +} + +function _getError(field, str){ + var obj = field.element; + strErrorTemp = (field.err) ? field.err : _getLanguageText(str); + + idx = strErrorTemp.indexOf( "\\n" ); + while ( idx > -1 ) { + strErrorTemp = strErrorTemp.replace( "\\n", "\n" ); + idx = strErrorTemp.indexOf( "\\n" ); + } + + return strErrorTemp.replace("%FIELDNAME%", (field.realname)? field.realname : ((obj.id) ? obj.id : obj.name)); +} + +function _parseBoolean(value){ + return !(!value || value == 0 || value == "0" || value == "false"); +} + +function _checkRegExp(regx, value){ + switch (regx){ + case "email": + return ((/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,5})+$/).test(value)); + case "tel": + return ((/^1?[\- ]?\(?\d{3}\)?[\- ]?\d{3}[\- ]?\d{4}$/).test(value)); + case "pc": + return ((/^[a-z]\d[a-z] ?\d[a-z]\d$/i).test(value)); + case "zip": + return ((/^\d{5}$/).test(value)); + case "money": + return ((/^\d+([\.]\d\d)?$/).test(value)); + case "creditcard": + return (!isNaN(value)); + case "postalzip": + if(value.length == 6 || value.length == 7) + return((/^[a-zA-Z]\d[a-zA-Z] ?\d[a-zA-Z]\d$/).test(value)); + if(value.length == 5 || value.length == 10) + return((/^\d{5}(\-\d{4})?$/).test(value)); + break; + default: + return (regx.test(value)); + + } +} \ No newline at end of file diff --git a/src/www/js/nicetitle.js b/src/www/js/nicetitle.js new file mode 100644 index 00000000..4207a9bf --- /dev/null +++ b/src/www/js/nicetitle.js @@ -0,0 +1,220 @@ +addEvent(window, "load", makeNiceTitles); + +var XHTMLNS = "http://www.w3.org/1999/xhtml"; +var CURRENT_NICE_TITLE; +var browser = new Browser(); + +function makeNiceTitles() { + if (!document.createElement || !document.getElementsByTagName) return; + // add namespace methods to HTML DOM; this makes the script work in both + // HTML and XML contexts. + if(!document.createElementNS) + { + document.createElementNS = function(ns,elt) { + return document.createElement(elt); + } + } + + if( !document.links ) + { + document.links = document.getElementsByTagName("a"); + } + for (var ti=0;ti STD_WIDTH) { + w = h_pixels; + } else if ((STD_WIDTH>t_pixels) && (t_pixels>h_pixels)) { + w = t_pixels; + } else if ((STD_WIDTH>t_pixels) && (h_pixels>t_pixels)) { + w = h_pixels; + } else { + w = STD_WIDTH; + } + + d.style.width = w + 'px'; + + /* + mx = lnk.offsetLeft; + my = lnk.offsetTop; + */ + mpos = findPosition(lnk); + mx = mpos[0]; + my = mpos[1]; + //xy = getMousePosition(e); + //mx = xy[0]; my = xy[1]; + + d.style.left = (mx+15) + 'px'; + d.style.top = (my+35) + 'px'; + if (window.innerWidth && ((mx+w) > window.innerWidth)) { + d.style.left = (window.innerWidth - w - 25) + "px"; + } + if (document.body.scrollWidth && ((mx+w) > document.body.scrollWidth)) { + d.style.left = (document.body.scrollWidth - w - 25) + "px"; + } + + document.getElementsByTagName("body")[0].appendChild(d); + + CURRENT_NICE_TITLE = d; +} + +function hideNiceTitle(e) { + if (!document.getElementsByTagName) return; + if (CURRENT_NICE_TITLE) { + document.getElementsByTagName("body")[0].removeChild(CURRENT_NICE_TITLE); + CURRENT_NICE_TITLE = null; + } +} + +// Add an eventListener to browsers that can do it somehow. +// Originally by the amazing Scott Andrew. +function addEvent(obj, evType, fn){ + if (obj.addEventListener){ + obj.addEventListener(evType, fn, true); + return true; + } else if (obj.attachEvent){ + var r = obj.attachEvent("on"+evType, fn); + return r; + } else { + return false; + } +} + +function getParent(el, pTagName) { + if (el == null) return null; + else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase + return el; + else + return getParent(el.parentNode, pTagName); +} + +function getMousePosition(event) { + if (browser.isIE) { + x = window.event.clientX + document.documentElement.scrollLeft + + document.body.scrollLeft; + y = window.event.clientY + document.documentElement.scrollTop + + document.body.scrollTop; + } + if (browser.isNS) { + x = event.clientX + window.scrollX; + y = event.clientY + window.scrollY; + } + return [x,y]; +} + +// Determine browser and version. + +function Browser() { +// blah, browser detect, but mouse-position stuff doesn't work any other way + var ua, s, i; + + this.isIE = false; + this.isNS = false; + this.version = null; + + ua = navigator.userAgent; + + s = "MSIE"; + if ((i = ua.indexOf(s)) >= 0) { + this.isIE = true; + this.version = parseFloat(ua.substr(i + s.length)); + return; + } + + s = "Netscape6/"; + if ((i = ua.indexOf(s)) >= 0) { + this.isNS = true; + this.version = parseFloat(ua.substr(i + s.length)); + return; + } + + // Treat any other "Gecko" browser as NS 6.1. + + s = "Gecko"; + if ((i = ua.indexOf(s)) >= 0) { + this.isNS = true; + this.version = 6.1; + return; + } +} + diff --git a/src/www/js/uts.js b/src/www/js/uts.js new file mode 100644 index 00000000..8731d3d7 --- /dev/null +++ b/src/www/js/uts.js @@ -0,0 +1,82 @@ + \ No newline at end of file diff --git a/src/www/lib/Sec.php b/src/www/lib/Sec.php new file mode 100644 index 00000000..d7d2f75e --- /dev/null +++ b/src/www/lib/Sec.php @@ -0,0 +1,270 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> +socket = null; + $this->name = $name; + $this->type = $type; + $this->props = $props; + } + + function connect($addr = null, $port = null) { + if($this->socket != null) { + $this->disconnect(); + } + + $this->socket = new Socket(); + + if(!$addr || !$port) { + $addr = UTS_DEFAULT_SERVER; + $servers = getServers($addr); + $port = $servers[$this->name . $this->type]; + } + + if(!$this->socket->connect($addr, $port)) { + return FALSE; + } + + // check SERVER_FULL + $full = $this->socket->read(); + $full = trim($this->removeNULL($full)); + + if($full == "SERVER_FULL") { + return FALSE; + } + + // ident + $this->socket->write($this->appendNULL("IDENT INSTRUMENT")); + + $str = $this->socket->read(); + $str = $this->removeNULL($str); + + if($str == "ERROR") { + return FALSE; + } else { + return TRUE; + } + + } + + function getStatus($prop) { + if($this->socket == null) { + return FALSE; + } + + if(in_array($prop, $this->props)) { + $this->socket->write($this->appendNULL("STATUS " . $prop)); + + $str = $this->socket->read(); + + // format + $str = trim($this->removeNULL($str)); + + if($str == "ERROR") { + $ret = $str; + } else { + $ret = substr($str, strlen("STATUS"), strlen($str)); + } + } else { + $ret = "PROPRIEDADE INVÁLIDA"; + } + + if($this->interactive) { + printf("%s %s
", "Lendo $prop ...", "$ret"); + } + + return $ret; + + } + + function setStatus($prop, $value) { + if($this->socket == null) { + return FALSE; + } + + if(in_array($prop, $this->props)) { + $this->socket->write($this->appendNULL("SETSTATUS " . $prop . " " . ($value))); + + $str = $this->socket->read(); + $ret = trim($this->removeNULL($str)); + } else { + $ret = "PROPRIEDADE INVÁLIDA"; + } + + if($this->interactive) { + printf("%s %s
", "Setando $prop = $value ...", "$ret"); + } + + return $ret; + + } + + function notify($prop) { + + if($this->socket == null) { + return FALSE; + } + + if(in_array($prop, $this->props)) { + + $this->socket->write($this->appendNULL("NOTIFY " . $prop)); + + $str = $this->socket->read(); + $ret = trim($this->removeNULL($str)); + + // wait until notification arrive + $read = array($this->socket); + $num = socket_select($read, $write = NULL, $exp = NULL, NULL); + + if($num) { + $str = $this->socket->read(); + $ret = trim($this->removeNULL($str)); + } + + } else { + $ret = "PROPRIEDADE INVÁLIDA"; + } + + return $ret; + + } + + function isBusy() { + if($this->socket == null) { + return FALSE; + } + + $ret = $this->getStatus($this->name); + + $cmp = trim($ret); + + if($cmp == "OFFLINE" || $cmp == "IDLE" || $cmp == "DISABLED") + return FALSE; + else + return TRUE; + + } + + function appendNULL($str) { + return $str . "\x00"; + } + + function removeNULL($str) { + + return substr($str, 0, strlen($str) -1); + + } + + function disconnect() { + if($this->socket != null) { + $this->socket->write($this->appendNULL("QUIT")); + $this->socket->disconnect(); + } + + } + + function setInteractive($interactive) { + $this->interactive = $interactive; + } + +} + + +class Sync extends Sec { + + function Sync($type = 'control') { + + $props = array( + "SYNC", + "EXPTIME", + "NEXP", + "BFNAME", + "INDEX", + "TELSTART", + "CAMSTART", + "OBSERVER", + "RA", + "DEC", + "EPOCH", + "FILTER", + "TASK"); + + return parent::Sec("SYNC", $type, $props); + + } + +} + +class CCD extends Sec { + + function CCD($type = 'control') { + + $props = array( + "CCD", + "TASK", + "TYPE", + "CCD_TRIGGER", + "MOVING"); + + + $this->type = $type; + + return parent::Sec("CCD", $type, $props); + + } + +} + +class Tel extends Sec { + + function Tel($type = 'control') { + + $props = array( + "TEL", + "TASK", + "TYPE", + "CCD_TRIGGER", + "MOVING"); + + return parent::Sec("TEL", $type, $props); + + } + +} + +?> \ No newline at end of file diff --git a/src/www/lib/Socket.php b/src/www/lib/Socket.php new file mode 100644 index 00000000..75362400 --- /dev/null +++ b/src/www/lib/Socket.php @@ -0,0 +1,92 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> +fp) { + socket_shutdown($this->fp, 2); + socket_close($this->fp); + $this->fp = NULL; + } + + if (strspn($addr, '.0123456789') == strlen($addr)) { + $this->addr = $addr; + } else { + $this->addr = gethostbyname($addr); + } + + $this->port = $port; + + $this->fp = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if (!$this->fp) { + return FALSE; + } + + if(!socket_connect($this->fp, $this->addr, $this->port)) { + return FALSE; + } + + return TRUE; + } + + function disconnect() { + if($this->fp) { + socket_shutdown($this->fp, 2); + socket_close($this->fp); + $this->fp = NULL; + return TRUE; + } + + return FALSE; + } + + function read($size = 1024) { + if ($this->fp) { + return socket_read($this->fp, $size); + } + + return FALSE; + } + + function write($data) { + if ($this->fp) { + return socket_write($this->fp, $data, strlen($data)); + // $ret = socket_write($this->fp, $data, strlen($data)); + // echo "$ret
"; + // return $ret; + } + + return FALSE; + } + +} +?> diff --git a/src/www/lib/astro.php b/src/www/lib/astro.php new file mode 100644 index 00000000..31a2d18a --- /dev/null +++ b/src/www/lib/astro.php @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/src/www/lib/db.php b/src/www/lib/db.php new file mode 100644 index 00000000..b474671f --- /dev/null +++ b/src/www/lib/db.php @@ -0,0 +1,40 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> +getMessage()); +} + +?> diff --git a/src/www/lib/erro.php b/src/www/lib/erro.php new file mode 100644 index 00000000..11555fb1 --- /dev/null +++ b/src/www/lib/erro.php @@ -0,0 +1,79 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + +
+ +
+ + diff --git a/src/www/lib/pear/DB.php b/src/www/lib/pear/DB.php new file mode 100644 index 00000000..9af57b3e --- /dev/null +++ b/src/www/lib/pear/DB.php @@ -0,0 +1,1388 @@ + + * @author Tomas V.V.Cox + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: DB.php,v 1.1 2005/05/28 01:55:09 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the PEAR class so it can be extended from + */ +require_once 'PEAR.php'; + + +// {{{ constants +// {{{ error codes + +/**#@+ + * One of PEAR DB's portable error codes. + * @see DB_common::errorCode(), DB::errorMessage() + * + * {@internal If you add an error code here, make sure you also add a textual + * version of it in DB::errorMessage().}} + */ + +/** + * The code returned by many methods upon success + */ +define('DB_OK', 1); + +/** + * Unkown error + */ +define('DB_ERROR', -1); + +/** + * Syntax error + */ +define('DB_ERROR_SYNTAX', -2); + +/** + * Tried to insert a duplicate value into a primary or unique index + */ +define('DB_ERROR_CONSTRAINT', -3); + +/** + * An identifier in the query refers to a non-existant object + */ +define('DB_ERROR_NOT_FOUND', -4); + +/** + * Tried to create a duplicate object + */ +define('DB_ERROR_ALREADY_EXISTS', -5); + +/** + * The current driver does not support the action you attempted + */ +define('DB_ERROR_UNSUPPORTED', -6); + +/** + * The number of parameters does not match the number of placeholders + */ +define('DB_ERROR_MISMATCH', -7); + +/** + * A literal submitted did not match the data type expected + */ +define('DB_ERROR_INVALID', -8); + +/** + * The current DBMS does not support the action you attempted + */ +define('DB_ERROR_NOT_CAPABLE', -9); + +/** + * A literal submitted was too long so the end of it was removed + */ +define('DB_ERROR_TRUNCATED', -10); + +/** + * A literal number submitted did not match the data type expected + */ +define('DB_ERROR_INVALID_NUMBER', -11); + +/** + * A literal date submitted did not match the data type expected + */ +define('DB_ERROR_INVALID_DATE', -12); + +/** + * Attempt to divide something by zero + */ +define('DB_ERROR_DIVZERO', -13); + +/** + * A database needs to be selected + */ +define('DB_ERROR_NODBSELECTED', -14); + +/** + * Could not create the object requested + */ +define('DB_ERROR_CANNOT_CREATE', -15); + +/** + * Could not drop the database requested because it does not exist + */ +define('DB_ERROR_CANNOT_DROP', -17); + +/** + * An identifier in the query refers to a non-existant table + */ +define('DB_ERROR_NOSUCHTABLE', -18); + +/** + * An identifier in the query refers to a non-existant column + */ +define('DB_ERROR_NOSUCHFIELD', -19); + +/** + * The data submitted to the method was inappropriate + */ +define('DB_ERROR_NEED_MORE_DATA', -20); + +/** + * The attempt to lock the table failed + */ +define('DB_ERROR_NOT_LOCKED', -21); + +/** + * The number of columns doesn't match the number of values + */ +define('DB_ERROR_VALUE_COUNT_ON_ROW', -22); + +/** + * The DSN submitted has problems + */ +define('DB_ERROR_INVALID_DSN', -23); + +/** + * Could not connect to the database + */ +define('DB_ERROR_CONNECT_FAILED', -24); + +/** + * The PHP extension needed for this DBMS could not be found + */ +define('DB_ERROR_EXTENSION_NOT_FOUND',-25); + +/** + * The present user has inadequate permissions to perform the task requestd + */ +define('DB_ERROR_ACCESS_VIOLATION', -26); + +/** + * The database requested does not exist + */ +define('DB_ERROR_NOSUCHDB', -27); + +/** + * Tried to insert a null value into a column that doesn't allow nulls + */ +define('DB_ERROR_CONSTRAINT_NOT_NULL',-29); +/**#@-*/ + + +// }}} +// {{{ prepared statement-related + + +/**#@+ + * Identifiers for the placeholders used in prepared statements. + * @see DB_common::prepare() + */ + +/** + * Indicates a scalar (?) placeholder was used + * + * Quote and escape the value as necessary. + */ +define('DB_PARAM_SCALAR', 1); + +/** + * Indicates an opaque (&) placeholder was used + * + * The value presented is a file name. Extract the contents of that file + * and place them in this column. + */ +define('DB_PARAM_OPAQUE', 2); + +/** + * Indicates a misc (!) placeholder was used + * + * The value should not be quoted or escaped. + */ +define('DB_PARAM_MISC', 3); +/**#@-*/ + + +// }}} +// {{{ binary data-related + + +/**#@+ + * The different ways of returning binary data from queries. + */ + +/** + * Sends the fetched data straight through to output + */ +define('DB_BINMODE_PASSTHRU', 1); + +/** + * Lets you return data as usual + */ +define('DB_BINMODE_RETURN', 2); + +/** + * Converts the data to hex format before returning it + * + * For example the string "123" would become "313233". + */ +define('DB_BINMODE_CONVERT', 3); +/**#@-*/ + + +// }}} +// {{{ fetch modes + + +/**#@+ + * Fetch Modes. + * @see DB_common::setFetchMode() + */ + +/** + * Indicates the current default fetch mode should be used + * @see DB_common::$fetchmode + */ +define('DB_FETCHMODE_DEFAULT', 0); + +/** + * Column data indexed by numbers, ordered from 0 and up + */ +define('DB_FETCHMODE_ORDERED', 1); + +/** + * Column data indexed by column names + */ +define('DB_FETCHMODE_ASSOC', 2); + +/** + * Column data as object properties + */ +define('DB_FETCHMODE_OBJECT', 3); + +/** + * For multi-dimensional results, make the column name the first level + * of the array and put the row number in the second level of the array + * + * This is flipped from the normal behavior, which puts the row numbers + * in the first level of the array and the column names in the second level. + */ +define('DB_FETCHMODE_FLIPPED', 4); +/**#@-*/ + +/**#@+ + * Old fetch modes. Left here for compatibility. + */ +define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); +define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); +define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); +/**#@-*/ + + +// }}} +// {{{ tableInfo() && autoPrepare()-related + + +/**#@+ + * The type of information to return from the tableInfo() method. + * + * Bitwised constants, so they can be combined using | + * and removed using ^. + * + * @see DB_common::tableInfo() + * + * {@internal Since the TABLEINFO constants are bitwised, if more of them are + * added in the future, make sure to adjust DB_TABLEINFO_FULL accordingly.}} + */ +define('DB_TABLEINFO_ORDER', 1); +define('DB_TABLEINFO_ORDERTABLE', 2); +define('DB_TABLEINFO_FULL', 3); +/**#@-*/ + + +/**#@+ + * The type of query to create with the automatic query building methods. + * @see DB_common::autoPrepare(), DB_common::autoExecute() + */ +define('DB_AUTOQUERY_INSERT', 1); +define('DB_AUTOQUERY_UPDATE', 2); +/**#@-*/ + + +// }}} +// {{{ portability modes + + +/**#@+ + * Portability Modes. + * + * Bitwised constants, so they can be combined using | + * and removed using ^. + * + * @see DB_common::setOption() + * + * {@internal Since the PORTABILITY constants are bitwised, if more of them are + * added in the future, make sure to adjust DB_PORTABILITY_ALL accordingly.}} + */ + +/** + * Turn off all portability features + */ +define('DB_PORTABILITY_NONE', 0); + +/** + * Convert names of tables and fields to lower case + * when using the get*(), fetch*() and tableInfo() methods + */ +define('DB_PORTABILITY_LOWERCASE', 1); + +/** + * Right trim the data output by get*() and fetch*() + */ +define('DB_PORTABILITY_RTRIM', 2); + +/** + * Force reporting the number of rows deleted + */ +define('DB_PORTABILITY_DELETE_COUNT', 4); + +/** + * Enable hack that makes numRows() work in Oracle + */ +define('DB_PORTABILITY_NUMROWS', 8); + +/** + * Makes certain error messages in certain drivers compatible + * with those from other DBMS's + * + * + mysql, mysqli: change unique/primary key constraints + * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT + * + * + odbc(access): MS's ODBC driver reports 'no such field' as code + * 07001, which means 'too few parameters.' When this option is on + * that code gets mapped to DB_ERROR_NOSUCHFIELD. + */ +define('DB_PORTABILITY_ERRORS', 16); + +/** + * Convert null values to empty strings in data output by + * get*() and fetch*() + */ +define('DB_PORTABILITY_NULL_TO_EMPTY', 32); + +/** + * Turn on all portability features + */ +define('DB_PORTABILITY_ALL', 63); +/**#@-*/ + +// }}} + + +// }}} +// {{{ class DB + +/** + * Database independent query interface + * + * The main "DB" class is simply a container class with some static + * methods for creating DB objects as well as some utility functions + * common to all parts of DB. + * + * The object model of DB is as follows (indentation means inheritance): + *
+ * DB           The main DB class.  This is simply a utility class
+ *              with some "static" methods for creating DB objects as
+ *              well as common utility functions for other DB classes.
+ *
+ * DB_common    The base for each DB implementation.  Provides default
+ * |            implementations (in OO lingo virtual methods) for
+ * |            the actual DB implementations as well as a bunch of
+ * |            query utility functions.
+ * |
+ * +-DB_mysql   The DB implementation for MySQL.  Inherits DB_common.
+ *              When calling DB::factory or DB::connect for MySQL
+ *              connections, the object returned is an instance of this
+ *              class.
+ * 
+ * + * @category Database + * @package DB + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB +{ + // {{{ &factory() + + /** + * Create a new DB object for the specified database type but don't + * connect to the database + * + * @param string $type the database type (eg "mysql") + * @param array $options an associative array of option names and values + * + * @return object a new DB object. A DB_Error object on failure. + * + * @see DB_common::setOption() + */ + function &factory($type, $options = false) + { + if (!is_array($options)) { + $options = array('persistent' => $options); + } + + if (isset($options['debug']) && $options['debug'] >= 2) { + // expose php errors with sufficient debug level + include_once "DB/{$type}.php"; + } else { + @include_once "DB/{$type}.php"; + } + + $classname = "DB_${type}"; + + if (!class_exists($classname)) { + $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, + "Unable to include the DB/{$type}.php" + . " file for '$dsn'", + 'DB_Error', true); + return $tmp; + } + + @$obj =& new $classname; + + foreach ($options as $option => $value) { + $test = $obj->setOption($option, $value); + if (DB::isError($test)) { + return $test; + } + } + + return $obj; + } + + // }}} + // {{{ &connect() + + /** + * Create a new DB object including a connection to the specified database + * + * Example 1. + * + * require_once 'DB.php'; + * + * $dsn = 'pgsql://user:password@host/database'; + * $options = array( + * 'debug' => 2, + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * + * + * @param mixed $dsn the string "data source name" or array in the + * format returned by DB::parseDSN() + * @param array $options an associative array of option names and values + * + * @return object a new DB object. A DB_Error object on failure. + * + * @uses DB_dbase::connect(), DB_fbsql::connect(), DB_ibase::connect(), + * DB_ifx::connect(), DB_msql::connect(), DB_mssql::connect(), + * DB_mysql::connect(), DB_mysqli::connect(), DB_oci8::connect(), + * DB_odbc::connect(), DB_pgsql::connect(), DB_sqlite::connect(), + * DB_sybase::connect() + * + * @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError() + */ + function &connect($dsn, $options = array()) + { + $dsninfo = DB::parseDSN($dsn); + $type = $dsninfo['phptype']; + + if (!is_array($options)) { + /* + * For backwards compatibility. $options used to be boolean, + * indicating whether the connection should be persistent. + */ + $options = array('persistent' => $options); + } + + if (isset($options['debug']) && $options['debug'] >= 2) { + // expose php errors with sufficient debug level + include_once "DB/${type}.php"; + } else { + @include_once "DB/${type}.php"; + } + + $classname = "DB_${type}"; + if (!class_exists($classname)) { + $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, + "Unable to include the DB/{$type}.php" + . " file for '$dsn'", + 'DB_Error', true); + return $tmp; + } + + @$obj =& new $classname; + + foreach ($options as $option => $value) { + $test = $obj->setOption($option, $value); + if (DB::isError($test)) { + return $test; + } + } + + $err = $obj->connect($dsninfo, $obj->getOption('persistent')); + if (DB::isError($err)) { + $err->addUserInfo($dsn); + return $err; + } + + return $obj; + } + + // }}} + // {{{ apiVersion() + + /** + * Return the DB API version + * + * @return string the DB API version number + */ + function apiVersion() + { + return '@package_version@'; + } + + // }}} + // {{{ isError() + + /** + * Determines if a variable is a DB_Error object + * + * @param mixed $value the variable to check + * + * @return bool whether $value is DB_Error object + */ + function isError($value) + { + return is_a($value, 'DB_Error'); + } + + // }}} + // {{{ isConnection() + + /** + * Determines if a value is a DB_ object + * + * @param mixed $value the value to test + * + * @return bool whether $value is a DB_ object + */ + function isConnection($value) + { + return (is_object($value) && + is_subclass_of($value, 'db_common') && + method_exists($value, 'simpleQuery')); + } + + // }}} + // {{{ isManip() + + /** + * Tell whether a query is a data manipulation or data definition query + * + * Examples of data manipulation queries are INSERT, UPDATE and DELETE. + * Examples of data definition queries are CREATE, DROP, ALTER, GRANT, + * REVOKE. + * + * @param string $query the query + * + * @return boolean whether $query is a data manipulation query + */ + function isManip($query) + { + $manips = 'INSERT|UPDATE|DELETE|REPLACE|' + . 'CREATE|DROP|' + . 'LOAD DATA|SELECT .* INTO|COPY|' + . 'ALTER|GRANT|REVOKE|' + . 'LOCK|UNLOCK'; + if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) { + return true; + } + return false; + } + + // }}} + // {{{ errorMessage() + + /** + * Return a textual error message for a DB error code + * + * @param integer $value the DB error code + * + * @return string the error message or false if the error code was + * not recognized + */ + function errorMessage($value) + { + static $errorMessages; + if (!isset($errorMessages)) { + $errorMessages = array( + DB_ERROR => 'unknown error', + DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions', + DB_ERROR_ALREADY_EXISTS => 'already exists', + DB_ERROR_CANNOT_CREATE => 'can not create', + DB_ERROR_CANNOT_DROP => 'can not drop', + DB_ERROR_CONNECT_FAILED => 'connect failed', + DB_ERROR_CONSTRAINT => 'constraint violation', + DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', + DB_ERROR_DIVZERO => 'division by zero', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', + DB_ERROR_INVALID => 'invalid', + DB_ERROR_INVALID_DATE => 'invalid date or time', + DB_ERROR_INVALID_DSN => 'invalid DSN', + DB_ERROR_INVALID_NUMBER => 'invalid number', + DB_ERROR_MISMATCH => 'mismatch', + DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', + DB_ERROR_NODBSELECTED => 'no database selected', + DB_ERROR_NOSUCHDB => 'no such database', + DB_ERROR_NOSUCHFIELD => 'no such field', + DB_ERROR_NOSUCHTABLE => 'no such table', + DB_ERROR_NOT_CAPABLE => 'DB backend not capable', + DB_ERROR_NOT_FOUND => 'not found', + DB_ERROR_NOT_LOCKED => 'not locked', + DB_ERROR_SYNTAX => 'syntax error', + DB_ERROR_UNSUPPORTED => 'not supported', + DB_ERROR_TRUNCATED => 'truncated', + DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', + DB_OK => 'no error', + ); + } + + if (DB::isError($value)) { + $value = $value->getCode(); + } + + return isset($errorMessages[$value]) ? $errorMessages[$value] + : $errorMessages[DB_ERROR]; + } + + // }}} + // {{{ parseDSN() + + /** + * Parse a data source name + * + * Additional keys can be added by appending a URI query string to the + * end of the DSN. + * + * The format of the supplied DSN is in its fullest form: + * + * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true + * + * + * Most variations are allowed: + * + * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 + * phptype://username:password@hostspec/database_name + * phptype://username:password@hostspec + * phptype://username@hostspec + * phptype://hostspec/database + * phptype://hostspec + * phptype(dbsyntax) + * phptype + * + * + * @param string $dsn Data Source Name to be parsed + * + * @return array an associative array with the following keys: + * + phptype: Database backend used in PHP (mysql, odbc etc.) + * + dbsyntax: Database used with regards to SQL syntax etc. + * + protocol: Communication protocol to use (tcp, unix etc.) + * + hostspec: Host specification (hostname[:port]) + * + database: Database to use on the DBMS server + * + username: User name for login + * + password: Password for login + */ + function parseDSN($dsn) + { + $parsed = array( + 'phptype' => false, + 'dbsyntax' => false, + 'username' => false, + 'password' => false, + 'protocol' => false, + 'hostspec' => false, + 'port' => false, + 'socket' => false, + 'database' => false, + ); + + if (is_array($dsn)) { + $dsn = array_merge($parsed, $dsn); + if (!$dsn['dbsyntax']) { + $dsn['dbsyntax'] = $dsn['phptype']; + } + return $dsn; + } + + // Find phptype and dbsyntax + if (($pos = strpos($dsn, '://')) !== false) { + $str = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 3); + } else { + $str = $dsn; + $dsn = null; + } + + // Get phptype and dbsyntax + // $str => phptype(dbsyntax) + if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { + $parsed['phptype'] = $arr[1]; + $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; + } else { + $parsed['phptype'] = $str; + $parsed['dbsyntax'] = $str; + } + + if (!count($dsn)) { + return $parsed; + } + + // Get (if found): username and password + // $dsn => username:password@protocol+hostspec/database + if (($at = strrpos($dsn,'@')) !== false) { + $str = substr($dsn, 0, $at); + $dsn = substr($dsn, $at + 1); + if (($pos = strpos($str, ':')) !== false) { + $parsed['username'] = rawurldecode(substr($str, 0, $pos)); + $parsed['password'] = rawurldecode(substr($str, $pos + 1)); + } else { + $parsed['username'] = rawurldecode($str); + } + } + + // Find protocol and hostspec + + if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { + // $dsn => proto(proto_opts)/database + $proto = $match[1]; + $proto_opts = $match[2] ? $match[2] : false; + $dsn = $match[3]; + + } else { + // $dsn => protocol+hostspec/database (old format) + if (strpos($dsn, '+') !== false) { + list($proto, $dsn) = explode('+', $dsn, 2); + } + if (strpos($dsn, '/') !== false) { + list($proto_opts, $dsn) = explode('/', $dsn, 2); + } else { + $proto_opts = $dsn; + $dsn = null; + } + } + + // process the different protocol options + $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; + $proto_opts = rawurldecode($proto_opts); + if ($parsed['protocol'] == 'tcp') { + if (strpos($proto_opts, ':') !== false) { + list($parsed['hostspec'], + $parsed['port']) = explode(':', $proto_opts); + } else { + $parsed['hostspec'] = $proto_opts; + } + } elseif ($parsed['protocol'] == 'unix') { + $parsed['socket'] = $proto_opts; + } + + // Get dabase if any + // $dsn => database + if ($dsn) { + if (($pos = strpos($dsn, '?')) === false) { + // /database + $parsed['database'] = rawurldecode($dsn); + } else { + // /database?param1=value1¶m2=value2 + $parsed['database'] = rawurldecode(substr($dsn, 0, $pos)); + $dsn = substr($dsn, $pos + 1); + if (strpos($dsn, '&') !== false) { + $opts = explode('&', $dsn); + } else { // database?param1=value1 + $opts = array($dsn); + } + foreach ($opts as $opt) { + list($key, $value) = explode('=', $opt); + if (!isset($parsed[$key])) { + // don't allow params overwrite + $parsed[$key] = rawurldecode($value); + } + } + } + } + + return $parsed; + } + + // }}} +} + +// }}} +// {{{ class DB_Error + +/** + * DB_Error implements a class for reporting portable database error + * messages + * + * @category Database + * @package DB + * @author Stig Bakken + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_Error extends PEAR_Error +{ + // {{{ constructor + + /** + * DB_Error constructor + * + * @param mixed $code DB error code, or string with error message + * @param int $mode what "error mode" to operate in + * @param int $level what error level to use for $mode & + * PEAR_ERROR_TRIGGER + * @param mixed $debuginfo additional debug info, such as the last query + * + * @see PEAR_Error + */ + function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + if (is_int($code)) { + $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, + $mode, $level, $debuginfo); + } else { + $this->PEAR_Error("DB Error: $code", DB_ERROR, + $mode, $level, $debuginfo); + } + } + + // }}} +} + +// }}} +// {{{ class DB_result + +/** + * This class implements a wrapper for a DB result set + * + * A new instance of this class will be returned by the DB implementation + * after processing a query that returns data. + * + * @category Database + * @package DB + * @author Stig Bakken + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_result +{ + // {{{ properties + + /** + * Should results be freed automatically when there are no more rows? + * @var boolean + * @see DB_common::$options + */ + var $autofree; + + /** + * A reference to the DB_ object + * @var object + */ + var $dbh; + + /** + * The current default fetch mode + * @var integer + * @see DB_common::$fetchmode + */ + var $fetchmode; + + /** + * The name of the class into which results should be fetched when + * DB_FETCHMODE_OBJECT is in effect + * + * @var string + * @see DB_common::$fetchmode_object_class + */ + var $fetchmode_object_class; + + /** + * The number of rows to fetch from a limit query + * @var integer + */ + var $limit_count = null; + + /** + * The row to start fetching from in limit queries + * @var integer + */ + var $limit_from = null; + + /** + * The execute parameters that created this result + * @var array + * @since Property available since Release 1.7.0 + */ + var $parameters; + + /** + * The query string that created this result + * + * Copied here incase it changes in $dbh, which is referenced + * + * @var string + * @since Property available since Release 1.7.0 + */ + var $query; + + /** + * The query result resource id created by PHP + * @var resource + */ + var $result; + + /** + * The present row being dealt with + * @var integer + */ + var $row_counter = null; + + /** + * The prepared statement resource id created by PHP in $dbh + * + * This resource is only available when the result set was created using + * a driver's native execute() method, not PEAR DB's emulated one. + * + * Copied here incase it changes in $dbh, which is referenced + * + * {@internal Mainly here because the InterBase/Firebird API is only + * able to retrieve data from result sets if the statemnt handle is + * still in scope.}} + * + * @var resource + * @since Property available since Release 1.7.0 + */ + var $statement; + + + // }}} + // {{{ constructor + + /** + * This constructor sets the object's properties + * + * @param object &$dbh the DB object reference + * @param resource $result the result resource id + * @param array $options an associative array with result options + * + * @return void + */ + function DB_result(&$dbh, $result, $options = array()) + { + $this->autofree = $dbh->options['autofree']; + $this->dbh = &$dbh; + $this->fetchmode = $dbh->fetchmode; + $this->fetchmode_object_class = $dbh->fetchmode_object_class; + $this->parameters = $dbh->last_parameters; + $this->query = $dbh->last_query; + $this->result = $result; + $this->statement = empty($dbh->last_stmt) ? null : $dbh->last_stmt; + foreach ($options as $key => $value) { + $this->setOption($key, $value); + } + } + + /** + * Set options for the DB_result object + * + * @param string $key the option to set + * @param mixed $value the value to set the option to + * + * @return void + */ + function setOption($key, $value = null) + { + switch ($key) { + case 'limit_from': + $this->limit_from = $value; + break; + case 'limit_count': + $this->limit_count = $value; + } + } + + // }}} + // {{{ fetchRow() + + /** + * Fetch a row of data and return it by reference into an array + * + * The type of array returned can be controlled either by setting this + * method's $fetchmode parameter or by changing the default + * fetch mode setFetchMode() before calling this method. + * + * There are two options for standardizing the information returned + * from databases, ensuring their values are consistent when changing + * DBMS's. These portability options can be turned on when creating a + * new DB object or by using setOption(). + * + * + DB_PORTABILITY_LOWERCASE + * convert names of fields to lower case + * + * + DB_PORTABILITY_RTRIM + * right trim the data + * + * @param int $fetchmode the constant indicating how to format the data + * @param int $rownum the row number to fetch (index starts at 0) + * + * @return mixed an array or object containing the row's data, + * NULL when the end of the result set is reached + * or a DB_Error object on failure. + * + * @see DB_common::setOption(), DB_common::setFetchMode() + */ + function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) + { + if ($fetchmode === DB_FETCHMODE_DEFAULT) { + $fetchmode = $this->fetchmode; + } + if ($fetchmode === DB_FETCHMODE_OBJECT) { + $fetchmode = DB_FETCHMODE_ASSOC; + $object_class = $this->fetchmode_object_class; + } + if ($this->limit_from !== null) { + if ($this->row_counter === null) { + $this->row_counter = $this->limit_from; + // Skip rows + if ($this->dbh->features['limit'] === false) { + $i = 0; + while ($i++ < $this->limit_from) { + $this->dbh->fetchInto($this->result, $arr, $fetchmode); + } + } + } + if ($this->row_counter >= ($this->limit_from + $this->limit_count)) + { + if ($this->autofree) { + $this->free(); + } + $tmp = null; + return $tmp; + } + if ($this->dbh->features['limit'] === 'emulate') { + $rownum = $this->row_counter; + } + $this->row_counter++; + } + $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); + if ($res === DB_OK) { + if (isset($object_class)) { + // The default mode is specified in the + // DB_common::fetchmode_object_class property + if ($object_class == 'stdClass') { + $arr = (object) $arr; + } else { + $arr = &new $object_class($arr); + } + } + return $arr; + } + if ($res == null && $this->autofree) { + $this->free(); + } + return $res; + } + + // }}} + // {{{ fetchInto() + + /** + * Fetch a row of data into an array which is passed by reference + * + * The type of array returned can be controlled either by setting this + * method's $fetchmode parameter or by changing the default + * fetch mode setFetchMode() before calling this method. + * + * There are two options for standardizing the information returned + * from databases, ensuring their values are consistent when changing + * DBMS's. These portability options can be turned on when creating a + * new DB object or by using setOption(). + * + * + DB_PORTABILITY_LOWERCASE + * convert names of fields to lower case + * + * + DB_PORTABILITY_RTRIM + * right trim the data + * + * @param array &$arr the variable where the data should be placed + * @param int $fetchmode the constant indicating how to format the data + * @param int $rownum the row number to fetch (index starts at 0) + * + * @return mixed DB_OK if a row is processed, NULL when the end of the + * result set is reached or a DB_Error object on failure + * + * @see DB_common::setOption(), DB_common::setFetchMode() + */ + function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) + { + if ($fetchmode === DB_FETCHMODE_DEFAULT) { + $fetchmode = $this->fetchmode; + } + if ($fetchmode === DB_FETCHMODE_OBJECT) { + $fetchmode = DB_FETCHMODE_ASSOC; + $object_class = $this->fetchmode_object_class; + } + if ($this->limit_from !== null) { + if ($this->row_counter === null) { + $this->row_counter = $this->limit_from; + // Skip rows + if ($this->dbh->features['limit'] === false) { + $i = 0; + while ($i++ < $this->limit_from) { + $this->dbh->fetchInto($this->result, $arr, $fetchmode); + } + } + } + if ($this->row_counter >= ( + $this->limit_from + $this->limit_count)) + { + if ($this->autofree) { + $this->free(); + } + return null; + } + if ($this->dbh->features['limit'] === 'emulate') { + $rownum = $this->row_counter; + } + + $this->row_counter++; + } + $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); + if ($res === DB_OK) { + if (isset($object_class)) { + // default mode specified in the + // DB_common::fetchmode_object_class property + if ($object_class == 'stdClass') { + $arr = (object) $arr; + } else { + $arr = new $object_class($arr); + } + } + return DB_OK; + } + if ($res == null && $this->autofree) { + $this->free(); + } + return $res; + } + + // }}} + // {{{ numCols() + + /** + * Get the the number of columns in a result set + * + * @return int the number of columns. A DB_Error object on failure. + */ + function numCols() + { + return $this->dbh->numCols($this->result); + } + + // }}} + // {{{ numRows() + + /** + * Get the number of rows in a result set + * + * @return int the number of rows. A DB_Error object on failure. + */ + function numRows() + { + if ($this->dbh->features['numrows'] === 'emulate' + && $this->dbh->options['portability'] & DB_PORTABILITY_NUMROWS) + { + if ($this->dbh->features['prepare']) { + $res = $this->dbh->query($this->query, $this->parameters); + } else { + $res = $this->dbh->query($this->query); + } + if (DB::isError($res)) { + return $res; + } + $i = 0; + while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) { + $i++; + } + return $i; + } else { + return $this->dbh->numRows($this->result); + } + } + + // }}} + // {{{ nextResult() + + /** + * Get the next result if a batch of queries was executed + * + * @return bool true if a new result is available or false if not + */ + function nextResult() + { + return $this->dbh->nextResult($this->result); + } + + // }}} + // {{{ free() + + /** + * Frees the resources allocated for this result set + * + * @return bool true on success. A DB_Error object on failure. + */ + function free() + { + $err = $this->dbh->freeResult($this->result); + if (DB::isError($err)) { + return $err; + } + $this->result = false; + $this->statement = false; + return true; + } + + // }}} + // {{{ tableInfo() + + /** + * @see DB_common::tableInfo() + * @deprecated Method deprecated some time before Release 1.2 + */ + function tableInfo($mode = null) + { + if (is_string($mode)) { + return $this->dbh->raiseError(DB_ERROR_NEED_MORE_DATA); + } + return $this->dbh->tableInfo($this, $mode); + } + + // }}} + // {{{ getQuery() + + /** + * Determine the query string that created this result + * + * @return string the query string + * + * @since Method available since Release 1.7.0 + */ + function getQuery() + { + return $this->query; + } + + // }}} + // {{{ getRowCounter() + + /** + * Tells which row number is currently being processed + * + * @return integer the current row being looked at. Starts at 1. + */ + function getRowCounter() + { + return $this->row_counter; + } + + // }}} +} + +// }}} +// {{{ class DB_row + +/** + * PEAR DB Row Object + * + * The object contains a row of data from a result set. Each column's data + * is placed in a property named for the column. + * + * @category Database + * @package DB + * @author Stig Bakken + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + * @see DB_common::setFetchMode() + */ +class DB_row +{ + // {{{ constructor + + /** + * The constructor places a row's data into properties of this object + * + * @param array the array containing the row's data + * + * @return void + */ + function DB_row(&$arr) + { + foreach ($arr as $key => $value) { + $this->$key = &$arr[$key]; + } + } + + // }}} +} + +// }}} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/common.php b/src/www/lib/pear/DB/common.php new file mode 100644 index 00000000..f0b03ddc --- /dev/null +++ b/src/www/lib/pear/DB/common.php @@ -0,0 +1,2157 @@ + + * @author Tomas V.V. Cox + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: common.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the PEAR class so it can be extended from + */ +require_once 'PEAR.php'; + +/** + * DB_common is the base class from which each database driver class extends + * + * All common methods are declared here. If a given DBMS driver contains + * a particular method, that method will overload the one here. + * + * @category Database + * @package DB + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_common extends PEAR +{ + // {{{ properties + + /** + * The current default fetch mode + * @var integer + */ + var $fetchmode = DB_FETCHMODE_ORDERED; + + /** + * The name of the class into which results should be fetched when + * DB_FETCHMODE_OBJECT is in effect + * + * @var string + */ + var $fetchmode_object_class = 'stdClass'; + + /** + * Was a connection present when the object was serialized()? + * @var bool + * @see DB_common::__sleep(), DB_common::__wake() + */ + var $was_connected = null; + + /** + * The most recently executed query + * @var string + */ + var $last_query = ''; + + /** + * Run-time configuration options + * + * The 'optimize' option has been deprecated. Use the 'portability' + * option instead. + * + * @var array + * @see DB_common::setOption() + */ + var $options = array( + 'result_buffering' => 500, + 'persistent' => false, + 'ssl' => false, + 'debug' => 0, + 'seqname_format' => '%s_seq', + 'autofree' => false, + 'portability' => DB_PORTABILITY_NONE, + 'optimize' => 'performance', // Deprecated. Use 'portability'. + ); + + /** + * The parameters from the most recently executed query + * @var array + * @since Property available since Release 1.7.0 + */ + var $last_parameters = array(); + + /** + * The elements from each prepared statement + * @var array + */ + var $prepare_tokens = array(); + + /** + * The data types of the various elements in each prepared statement + * @var array + */ + var $prepare_types = array(); + + /** + * The prepared queries + * @var array + */ + var $prepared_queries = array(); + + + // }}} + // {{{ DB_common + + /** + * This constructor calls $this->PEAR('DB_Error') + * + * @return void + */ + function DB_common() + { + $this->PEAR('DB_Error'); + } + + // }}} + // {{{ __sleep() + + /** + * Automatically indicates which properties should be saved + * when PHP's serialize() function is called + * + * @return array the array of properties names that should be saved + */ + function __sleep() + { + if ($this->connection) { + // Don't disconnect(), people use serialize() for many reasons + $this->was_connected = true; + } else { + $this->was_connected = false; + } + if (isset($this->autocommit)) { + return array('autocommit', + 'dbsyntax', + 'dsn', + 'features', + 'fetchmode', + 'fetchmode_object_class', + 'options', + 'was_connected', + ); + } else { + return array('dbsyntax', + 'dsn', + 'features', + 'fetchmode', + 'fetchmode_object_class', + 'options', + 'was_connected', + ); + } + } + + // }}} + // {{{ __wakeup() + + /** + * Automatically reconnects to the database when PHP's unserialize() + * function is called + * + * The reconnection attempt is only performed if the object was connected + * at the time PHP's serialize() function was run. + * + * @return void + */ + function __wakeup() + { + if ($this->was_connected) { + $this->connect($this->dsn, $this->options); + } + } + + // }}} + // {{{ __toString() + + /** + * Automatic string conversion for PHP 5 + * + * @return string a string describing the current PEAR DB object + * + * @since Method available since Release 1.7.0 + */ + function __toString() + { + $info = strtolower(get_class($this)); + $info .= ': (phptype=' . $this->phptype . + ', dbsyntax=' . $this->dbsyntax . + ')'; + if ($this->connection) { + $info .= ' [connected]'; + } + return $info; + } + + // }}} + // {{{ toString() + + /** + * DEPRECATED: String conversion method + * + * @return string a string describing the current PEAR DB object + * + * @deprecated Method deprecated in Release 1.7.0 + */ + function toString() + { + return $this->__toString(); + } + + // }}} + // {{{ quoteString() + + /** + * DEPRECATED: Quotes a string so it can be safely used within string + * delimiters in a query + * + * @param string $string the string to be quoted + * + * @return string the quoted string + * + * @see DB_common::quoteSmart(), DB_common::escapeSimple() + * @deprecated Method deprecated some time before Release 1.2 + */ + function quoteString($string) + { + $string = $this->quote($string); + if ($string{0} == "'") { + return substr($string, 1, -1); + } + return $string; + } + + // }}} + // {{{ quote() + + /** + * DEPRECATED: Quotes a string so it can be safely used in a query + * + * @param string $string the string to quote + * + * @return string the quoted string or the string NULL + * if the value submitted is null. + * + * @see DB_common::quoteSmart(), DB_common::escapeSimple() + * @deprecated Deprecated in release 1.6.0 + */ + function quote($string = null) + { + return ($string === null) ? 'NULL' + : "'" . str_replace("'", "''", $string) . "'"; + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * Delimiting style depends on which database driver is being used. + * + * NOTE: just because you CAN use delimited identifiers doesn't mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * Portability is broken by using the following characters inside + * delimited identifiers: + * + backtick (`) -- due to MySQL + * + double quote (") -- due to Oracle + * + brackets ([ or ]) -- due to Access + * + * Delimited identifiers are known to generally work correctly under + * the following drivers: + * + mssql + * + mysql + * + mysqli + * + oci8 + * + odbc(access) + * + odbc(db2) + * + pgsql + * + sqlite + * + sybase (must execute set quoted_identifier on sometime + * prior to use) + * + * InterBase doesn't seem to be able to use delimited identifiers + * via PHP 4. They work fine under PHP 5. + * + * @param string $str the identifier name to be quoted + * + * @return string the quoted identifier + * + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + return '"' . str_replace('"', '""', $str) . '"'; + } + + // }}} + // {{{ quoteSmart() + + /** + * Formats input so it can be safely used in a query + * + * The output depends on the PHP data type of input and the database + * type being used. + * + * @param mixed $in the data to be formatted + * + * @return mixed the formatted data. The format depends on the input's + * PHP type: + *
    + *
  • + * input -> returns + *
  • + *
  • + * null -> the string NULL + *
  • + *
  • + * integer or double -> the unquoted number + *
  • + *
  • + * bool -> output depends on the driver in use + * Most drivers return integers: 1 if + * true or 0 if + * false. + * Some return strings: TRUE if + * true or FALSE if + * false. + * Finally one returns strings: T if + * true or F if + * false. Here is a list of each DBMS, + * the values returned and the suggested column type: + *
      + *
    • + * dbase -> T/F + * (Logical) + *
    • + *
    • + * fbase -> TRUE/FALSE + * (BOOLEAN) + *
    • + *
    • + * ibase -> 1/0 + * (SMALLINT) [1] + *
    • + *
    • + * ifx -> 1/0 + * (SMALLINT) [1] + *
    • + *
    • + * msql -> 1/0 + * (INTEGER) + *
    • + *
    • + * mssql -> 1/0 + * (BIT) + *
    • + *
    • + * mysql -> 1/0 + * (TINYINT(1)) + *
    • + *
    • + * mysqli -> 1/0 + * (TINYINT(1)) + *
    • + *
    • + * oci8 -> 1/0 + * (NUMBER(1)) + *
    • + *
    • + * odbc -> 1/0 + * (SMALLINT) [1] + *
    • + *
    • + * pgsql -> TRUE/FALSE + * (BOOLEAN) + *
    • + *
    • + * sqlite -> 1/0 + * (INTEGER) + *
    • + *
    • + * sybase -> 1/0 + * (TINYINT(1)) + *
    • + *
    + * [1] Accommodate the lowest common denominator because not all + * versions of have BOOLEAN. + *
  • + *
  • + * other (including strings and numeric strings) -> + * the data with single quotes escaped by preceeding + * single quotes, backslashes are escaped by preceeding + * backslashes, then the whole string is encapsulated + * between single quotes + *
  • + *
+ * + * @see DB_common::escapeSimple() + * @since Method available since Release 1.6.0 + */ + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 1 : 0; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * In SQLite, this makes things safe for inserts/updates, but may + * cause problems when performing text comparisons against columns + * containing binary data. See the + * {@link http://php.net/sqlite_escape_string PHP manual} for more info. + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + return str_replace("'", "''", $str); + } + + // }}} + // {{{ provides() + + /** + * Tells whether the present driver supports a given feature + * + * @param string $feature the feature you're curious about + * + * @return bool whether this driver supports $feature + */ + function provides($feature) + { + return $this->features[$feature]; + } + + // }}} + // {{{ setFetchMode() + + /** + * Sets the fetch mode that should be used by default for query results + * + * @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC + * or DB_FETCHMODE_OBJECT + * @param string $object_class the class name of the object to be returned + * by the fetch methods when the + * DB_FETCHMODE_OBJECT mode is selected. + * If no class is specified by default a cast + * to object from the assoc array row will be + * done. There is also the posibility to use + * and extend the 'DB_row' class. + * + * @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT + */ + function setFetchMode($fetchmode, $object_class = 'stdClass') + { + switch ($fetchmode) { + case DB_FETCHMODE_OBJECT: + $this->fetchmode_object_class = $object_class; + case DB_FETCHMODE_ORDERED: + case DB_FETCHMODE_ASSOC: + $this->fetchmode = $fetchmode; + break; + default: + return $this->raiseError('invalid fetchmode mode'); + } + } + + // }}} + // {{{ setOption() + + /** + * Sets run-time configuration options for PEAR DB + * + * Options, their data types, default values and description: + *
    + *
  • + * autofree boolean = false + *
    should results be freed automatically when there are no + * more rows? + *
  • + * result_buffering integer = 500 + *
    how many rows of the result set should be buffered? + *
    In mysql: mysql_unbuffered_query() is used instead of + * mysql_query() if this value is 0. (Release 1.7.0) + *
    In oci8: this value is passed to ocisetprefetch(). + * (Release 1.7.0) + *
  • + * debug integer = 0 + *
    debug level + *
  • + * persistent boolean = false + *
    should the connection be persistent? + *
  • + * portability integer = DB_PORTABILITY_NONE + *
    portability mode constant (see below) + *
  • + * seqname_format string = %s_seq + *
    the sprintf() format string used on sequence names. This + * format is applied to sequence names passed to + * createSequence(), nextID() and dropSequence(). + *
  • + * ssl boolean = false + *
    use ssl to connect? + *
  • + *
+ * + * ----------------------------------------- + * + * PORTABILITY MODES + * + * These modes are bitwised, so they can be combined using | + * and removed using ^. See the examples section below on how + * to do this. + * + * DB_PORTABILITY_NONE + * turn off all portability features + * + * This mode gets automatically turned on if the deprecated + * optimize option gets set to performance. + * + * + * DB_PORTABILITY_LOWERCASE + * convert names of tables and fields to lower case when using + * get*(), fetch*() and tableInfo() + * + * This mode gets automatically turned on in the following databases + * if the deprecated option optimize gets set to + * portability: + * + oci8 + * + * + * DB_PORTABILITY_RTRIM + * right trim the data output by get*() fetch*() + * + * + * DB_PORTABILITY_DELETE_COUNT + * force reporting the number of rows deleted + * + * Some DBMS's don't count the number of rows deleted when performing + * simple DELETE FROM tablename queries. This portability + * mode tricks such DBMS's into telling the count by adding + * WHERE 1=1 to the end of DELETE queries. + * + * This mode gets automatically turned on in the following databases + * if the deprecated option optimize gets set to + * portability: + * + fbsql + * + mysql + * + mysqli + * + sqlite + * + * + * DB_PORTABILITY_NUMROWS + * enable hack that makes numRows() work in Oracle + * + * This mode gets automatically turned on in the following databases + * if the deprecated option optimize gets set to + * portability: + * + oci8 + * + * + * DB_PORTABILITY_ERRORS + * makes certain error messages in certain drivers compatible + * with those from other DBMS's + * + * + mysql, mysqli: change unique/primary key constraints + * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT + * + * + odbc(access): MS's ODBC driver reports 'no such field' as code + * 07001, which means 'too few parameters.' When this option is on + * that code gets mapped to DB_ERROR_NOSUCHFIELD. + * DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD + * + * DB_PORTABILITY_NULL_TO_EMPTY + * convert null values to empty strings in data output by get*() and + * fetch*(). Needed because Oracle considers empty strings to be null, + * while most other DBMS's know the difference between empty and null. + * + * + * DB_PORTABILITY_ALL + * turn on all portability features + * + * ----------------------------------------- + * + * Example 1. Simple setOption() example + * + * $db->setOption('autofree', true); + * + * + * Example 2. Portability for lowercasing and trimming + * + * $db->setOption('portability', + * DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM); + * + * + * Example 3. All portability options except trimming + * + * $db->setOption('portability', + * DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM); + * + * + * @param string $option option name + * @param mixed $value value for the option + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::$options + */ + function setOption($option, $value) + { + if (isset($this->options[$option])) { + $this->options[$option] = $value; + + /* + * Backwards compatibility check for the deprecated 'optimize' + * option. Done here in case settings change after connecting. + */ + if ($option == 'optimize') { + if ($value == 'portability') { + switch ($this->phptype) { + case 'oci8': + $this->options['portability'] = + DB_PORTABILITY_LOWERCASE | + DB_PORTABILITY_NUMROWS; + break; + case 'fbsql': + case 'mysql': + case 'mysqli': + case 'sqlite': + $this->options['portability'] = + DB_PORTABILITY_DELETE_COUNT; + break; + } + } else { + $this->options['portability'] = DB_PORTABILITY_NONE; + } + } + + return DB_OK; + } + return $this->raiseError("unknown option $option"); + } + + // }}} + // {{{ getOption() + + /** + * Returns the value of an option + * + * @param string $option the option name you're curious about + * + * @return mixed the option's value + */ + function getOption($option) + { + if (isset($this->options[$option])) { + return $this->options[$option]; + } + return $this->raiseError("unknown option $option"); + } + + // }}} + // {{{ prepare() + + /** + * Prepares a query for multiple execution with execute() + * + * Creates a query that can be run multiple times. Each time it is run, + * the placeholders, if any, will be replaced by the contents of + * execute()'s $data argument. + * + * Three types of placeholders can be used: + * + ? scalar value (i.e. strings, integers). The system + * will automatically quote and escape the data. + * + ! value is inserted 'as is' + * + & requires a file name. The file's contents get + * inserted into the query (i.e. saving binary + * data in a db) + * + * Example 1. + * + * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); + * $data = array( + * "John's text", + * "'it''s good'", + * 'filename.txt' + * ); + * $res = $db->execute($sth, $data); + * + * + * Use backslashes to escape placeholder characters if you don't want + * them to be interpreted as placeholders: + *
+     *    "UPDATE foo SET col=? WHERE col='over \& under'"
+     * 
+ * + * With some database backends, this is emulated. + * + * {@internal ibase and oci8 have their own prepare() methods.}} + * + * @param string $query the query to be prepared + * + * @return mixed DB statement resource on success. A DB_Error object + * on failure. + * + * @see DB_common::execute() + */ + function prepare($query) + { + $tokens = preg_split('/((?prepare_tokens[] = &$newtokens; + end($this->prepare_tokens); + + $k = key($this->prepare_tokens); + $this->prepare_types[$k] = $types; + $this->prepared_queries[$k] = implode(' ', $newtokens); + + return $k; + } + + // }}} + // {{{ autoPrepare() + + /** + * Automaticaly generates an insert or update query and pass it to prepare() + * + * @param string $table the table name + * @param array $table_fields the array of field names + * @param int $mode a type of query to make: + * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + * @param string $where for update queries: the WHERE clause to + * append to the SQL statement. Don't + * include the "WHERE" keyword. + * + * @return resource the query handle + * + * @uses DB_common::prepare(), DB_common::buildManipSQL() + */ + function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, + $where = false) + { + $query = $this->buildManipSQL($table, $table_fields, $mode, $where); + if (DB::isError($query)) { + return $query; + } + return $this->prepare($query); + } + + // }}} + // {{{ autoExecute() + + /** + * Automaticaly generates an insert or update query and call prepare() + * and execute() with it + * + * @param string $table the table name + * @param array $fields_values the associative array where $key is a + * field name and $value its value + * @param int $mode a type of query to make: + * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + * @param string $where for update queries: the WHERE clause to + * append to the SQL statement. Don't + * include the "WHERE" keyword. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + * + * @uses DB_common::autoPrepare(), DB_common::execute() + */ + function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, + $where = false) + { + $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, + $where); + if (DB::isError($sth)) { + return $sth; + } + $ret =& $this->execute($sth, array_values($fields_values)); + $this->freePrepared($sth); + return $ret; + + } + + // }}} + // {{{ buildManipSQL() + + /** + * Produces an SQL query string for autoPrepare() + * + * Example: + *
+     * buildManipSQL('table_sql', array('field1', 'field2', 'field3'),
+     *               DB_AUTOQUERY_INSERT);
+     * 
+ * + * That returns + * + * INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) + * + * + * NOTES: + * - This belongs more to a SQL Builder class, but this is a simple + * facility. + * - Be carefull! If you don't give a $where param with an UPDATE + * query, all the records of the table will be updated! + * + * @param string $table the table name + * @param array $table_fields the array of field names + * @param int $mode a type of query to make: + * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + * @param string $where for update queries: the WHERE clause to + * append to the SQL statement. Don't + * include the "WHERE" keyword. + * + * @return string the sql query for autoPrepare() + */ + function buildManipSQL($table, $table_fields, $mode, $where = false) + { + if (count($table_fields) == 0) { + return $this->raiseError(DB_ERROR_NEED_MORE_DATA); + } + $first = true; + switch ($mode) { + case DB_AUTOQUERY_INSERT: + $values = ''; + $names = ''; + foreach ($table_fields as $value) { + if ($first) { + $first = false; + } else { + $names .= ','; + $values .= ','; + } + $names .= $value; + $values .= '?'; + } + return "INSERT INTO $table ($names) VALUES ($values)"; + case DB_AUTOQUERY_UPDATE: + $set = ''; + foreach ($table_fields as $value) { + if ($first) { + $first = false; + } else { + $set .= ','; + } + $set .= "$value = ?"; + } + $sql = "UPDATE $table SET $set"; + if ($where) { + $sql .= " WHERE $where"; + } + return $sql; + default: + return $this->raiseError(DB_ERROR_SYNTAX); + } + } + + // }}} + // {{{ execute() + + /** + * Executes a DB statement prepared with prepare() + * + * Example 1. + * + * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); + * $data = array( + * "John's text", + * "'it''s good'", + * 'filename.txt' + * ); + * $res =& $db->execute($sth, $data); + * + * + * @param resource $stmt a DB statement resource returned from prepare() + * @param mixed $data array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + * + * {@internal ibase and oci8 have their own execute() methods.}} + * + * @see DB_common::prepare() + */ + function &execute($stmt, $data = array()) + { + $realquery = $this->executeEmulateQuery($stmt, $data); + if (DB::isError($realquery)) { + return $realquery; + } + $result = $this->simpleQuery($realquery); + + if ($result === DB_OK || DB::isError($result)) { + return $result; + } else { + $tmp =& new DB_result($this, $result); + return $tmp; + } + } + + // }}} + // {{{ executeEmulateQuery() + + /** + * Emulates executing prepared statements if the DBMS not support them + * + * @param resource $stmt a DB statement resource returned from execute() + * @param mixed $data array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a string containing the real query run when emulating + * prepare/execute. A DB_Error object on failure. + * + * @access protected + * @see DB_common::execute() + */ + function executeEmulateQuery($stmt, $data = array()) + { + $stmt = (int)$stmt; + $data = (array)$data; + $this->last_parameters = $data; + + if (count($this->prepare_types[$stmt]) != count($data)) { + $this->last_query = $this->prepared_queries[$stmt]; + return $this->raiseError(DB_ERROR_MISMATCH); + } + + $realquery = $this->prepare_tokens[$stmt][0]; + + $i = 0; + foreach ($data as $value) { + if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) { + $realquery .= $this->quoteSmart($value); + } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) { + $fp = @fopen($value, 'rb'); + if (!$fp) { + return $this->raiseError(DB_ERROR_ACCESS_VIOLATION); + } + $realquery .= $this->quoteSmart(fread($fp, filesize($value))); + fclose($fp); + } else { + $realquery .= $value; + } + + $realquery .= $this->prepare_tokens[$stmt][++$i]; + } + + return $realquery; + } + + // }}} + // {{{ executeMultiple() + + /** + * Performs several execute() calls on the same statement handle + * + * $data must be an array indexed numerically + * from 0, one execute call is done for every "row" in the array. + * + * If an error occurs during execute(), executeMultiple() does not + * execute the unfinished rows, but rather returns that error. + * + * @param resource $stmt query handle from prepare() + * @param array $data numeric array containing the + * data to insert into the query + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::prepare(), DB_common::execute() + */ + function executeMultiple($stmt, $data) + { + foreach ($data as $value) { + $res =& $this->execute($stmt, $value); + if (DB::isError($res)) { + return $res; + } + } + return DB_OK; + } + + // }}} + // {{{ freePrepared() + + /** + * Frees the internal resources associated with a prepared query + * + * @param resource $stmt the prepared statement's PHP resource + * @param bool $free_resource should the PHP resource be freed too? + * Use false if you need to get data + * from the result set later. + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_common::prepare() + */ + function freePrepared($stmt, $free_resource = true) + { + $stmt = (int)$stmt; + if (isset($this->prepare_tokens[$stmt])) { + unset($this->prepare_tokens[$stmt]); + unset($this->prepare_types[$stmt]); + unset($this->prepared_queries[$stmt]); + return true; + } + return false; + } + + // }}} + // {{{ modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * It is defined here to ensure all drivers have this method available. + * + * @param string $query the query string to modify + * + * @return string the modified query string + * + * @access protected + * @see DB_mysql::modifyQuery(), DB_oci8::modifyQuery(), + * DB_sqlite::modifyQuery() + */ + function modifyQuery($query) + { + return $query; + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * It is defined here to assure that all implementations + * have this method defined. + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + return $query; + } + + // }}} + // {{{ query() + + /** + * Sends a query to the database server + * + * The query string can be either a normal statement to be sent directly + * to the server OR if $params are passed the query can have + * placeholders and it will be passed through prepare() and execute(). + * + * @param string $query the SQL query or the statement to prepare + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + * + * @see DB_result, DB_common::prepare(), DB_common::execute() + */ + function &query($query, $params = array()) + { + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + if (DB::isError($sth)) { + return $sth; + } + $ret =& $this->execute($sth, $params); + $this->freePrepared($sth, false); + return $ret; + } else { + $this->last_parameters = array(); + $result = $this->simpleQuery($query); + if ($result === DB_OK || DB::isError($result)) { + return $result; + } else { + $tmp =& new DB_result($this, $result); + return $tmp; + } + } + } + + // }}} + // {{{ limitQuery() + + /** + * Generates and executes a LIMIT query + * + * @param string $query the query + * @param intr $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + */ + function &limitQuery($query, $from, $count, $params = array()) + { + $query = $this->modifyLimitQuery($query, $from, $count, $params); + if (DB::isError($query)){ + return $query; + } + $result =& $this->query($query, $params); + if (is_a($result, 'DB_result')) { + $result->setOption('limit_from', $from); + $result->setOption('limit_count', $count); + } + return $result; + } + + // }}} + // {{{ getOne() + + /** + * Fetches the first column of the first row from a query result + * + * Takes care of doing the query and freeing the results when finished. + * + * @param string $query the SQL query + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed the returned value of the query. + * A DB_Error object on failure. + */ + function &getOne($query, $params = array()) + { + $params = (array)$params; + // modifyLimitQuery() would be nice here, but it causes BC issues + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + if (DB::isError($sth)) { + return $sth; + } + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + + $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED); + $res->free(); + + if ($err !== DB_OK) { + return $err; + } + + return $row[0]; + } + + // }}} + // {{{ getRow() + + /** + * Fetches the first row of data returned from a query result + * + * Takes care of doing the query and freeing the results when finished. + * + * @param string $query the SQL query + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * @param int $fetchmode the fetch mode to use + * + * @return array the first row of results as an array. + * A DB_Error object on failure. + */ + function &getRow($query, $params = array(), + $fetchmode = DB_FETCHMODE_DEFAULT) + { + // compat check, the params and fetchmode parameters used to + // have the opposite order + if (!is_array($params)) { + if (is_array($fetchmode)) { + if ($params === null) { + $tmp = DB_FETCHMODE_DEFAULT; + } else { + $tmp = $params; + } + $params = $fetchmode; + $fetchmode = $tmp; + } elseif ($params !== null) { + $fetchmode = $params; + $params = array(); + } + } + // modifyLimitQuery() would be nice here, but it causes BC issues + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + if (DB::isError($sth)) { + return $sth; + } + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + + $err = $res->fetchInto($row, $fetchmode); + + $res->free(); + + if ($err !== DB_OK) { + return $err; + } + + return $row; + } + + // }}} + // {{{ getCol() + + /** + * Fetches a single column from a query result and returns it as an + * indexed array + * + * @param string $query the SQL query + * @param mixed $col which column to return (integer [column number, + * starting at 0] or string [column name]) + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return array the results as an array. A DB_Error object on failure. + * + * @see DB_common::query() + */ + function &getCol($query, $col = 0, $params = array()) + { + $params = (array)$params; + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + + if (DB::isError($sth)) { + return $sth; + } + + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + + $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC; + + if (!is_array($row = $res->fetchRow($fetchmode))) { + $ret = array(); + } else { + if (!array_key_exists($col, $row)) { + $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD); + } else { + $ret = array($row[$col]); + while (is_array($row = $res->fetchRow($fetchmode))) { + $ret[] = $row[$col]; + } + } + } + + $res->free(); + + if (DB::isError($row)) { + $ret = $row; + } + + return $ret; + } + + // }}} + // {{{ getAssoc() + + /** + * Fetches an entire query result and returns it as an + * associative array using the first column as the key + * + * If the result set contains more than two columns, the value + * will be an array of the values from column 2-n. If the result + * set contains only two columns, the returned value will be a + * scalar with the value of the second column (unless forced to an + * array with the $force_array parameter). A DB error code is + * returned on errors. If the result set contains fewer than two + * columns, a DB_ERROR_TRUNCATED error is returned. + * + * For example, if the table "mytable" contains: + * + *
+     *  ID      TEXT       DATE
+     * --------------------------------
+     *  1       'one'      944679408
+     *  2       'two'      944679408
+     *  3       'three'    944679408
+     * 
+ * + * Then the call getAssoc('SELECT id,text FROM mytable') returns: + *
+     *   array(
+     *     '1' => 'one',
+     *     '2' => 'two',
+     *     '3' => 'three',
+     *   )
+     * 
+ * + * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: + *
+     *   array(
+     *     '1' => array('one', '944679408'),
+     *     '2' => array('two', '944679408'),
+     *     '3' => array('three', '944679408')
+     *   )
+     * 
+ * + * If the more than one row occurs with the same value in the + * first column, the last row overwrites all previous ones by + * default. Use the $group parameter if you don't want to + * overwrite like this. Example: + * + *
+     * getAssoc('SELECT category,id,name FROM mytable', false, null,
+     *          DB_FETCHMODE_ASSOC, true) returns:
+     *
+     *   array(
+     *     '1' => array(array('id' => '4', 'name' => 'number four'),
+     *                  array('id' => '6', 'name' => 'number six')
+     *            ),
+     *     '9' => array(array('id' => '4', 'name' => 'number four'),
+     *                  array('id' => '6', 'name' => 'number six')
+     *            )
+     *   )
+     * 
+ * + * Keep in mind that database functions in PHP usually return string + * values for results regardless of the database's internal type. + * + * @param string $query the SQL query + * @param bool $force_array used only when the query returns + * exactly two columns. If true, the values + * of the returned array will be one-element + * arrays instead of scalars. + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of + * items passed must match quantity of + * placeholders in query: meaning 1 + * placeholder for non-array parameters or + * 1 placeholder per array element. + * @param int $fetchmode the fetch mode to use + * @param bool $group if true, the values of the returned array + * is wrapped in another array. If the same + * key value (in the first column) repeats + * itself, the values will be appended to + * this array instead of overwriting the + * existing values. + * + * @return array the associative array containing the query results. + * A DB_Error object on failure. + */ + function &getAssoc($query, $force_array = false, $params = array(), + $fetchmode = DB_FETCHMODE_DEFAULT, $group = false) + { + $params = (array)$params; + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + + if (DB::isError($sth)) { + return $sth; + } + + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + if ($fetchmode == DB_FETCHMODE_DEFAULT) { + $fetchmode = $this->fetchmode; + } + $cols = $res->numCols(); + + if ($cols < 2) { + $tmp =& $this->raiseError(DB_ERROR_TRUNCATED); + return $tmp; + } + + $results = array(); + + if ($cols > 2 || $force_array) { + // return array values + // XXX this part can be optimized + if ($fetchmode == DB_FETCHMODE_ASSOC) { + while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) { + reset($row); + $key = current($row); + unset($row[key($row)]); + if ($group) { + $results[$key][] = $row; + } else { + $results[$key] = $row; + } + } + } elseif ($fetchmode == DB_FETCHMODE_OBJECT) { + while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) { + $arr = get_object_vars($row); + $key = current($arr); + if ($group) { + $results[$key][] = $row; + } else { + $results[$key] = $row; + } + } + } else { + while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { + // we shift away the first element to get + // indices running from 0 again + $key = array_shift($row); + if ($group) { + $results[$key][] = $row; + } else { + $results[$key] = $row; + } + } + } + if (DB::isError($row)) { + $results = $row; + } + } else { + // return scalar values + while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { + if ($group) { + $results[$row[0]][] = $row[1]; + } else { + $results[$row[0]] = $row[1]; + } + } + if (DB::isError($row)) { + $results = $row; + } + } + + $res->free(); + + return $results; + } + + // }}} + // {{{ getAll() + + /** + * Fetches all of the rows from a query result + * + * @param string $query the SQL query + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of + * items passed must match quantity of + * placeholders in query: meaning 1 + * placeholder for non-array parameters or + * 1 placeholder per array element. + * @param int $fetchmode the fetch mode to use: + * + DB_FETCHMODE_ORDERED + * + DB_FETCHMODE_ASSOC + * + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED + * + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED + * + * @return array the nested array. A DB_Error object on failure. + */ + function &getAll($query, $params = array(), + $fetchmode = DB_FETCHMODE_DEFAULT) + { + // compat check, the params and fetchmode parameters used to + // have the opposite order + if (!is_array($params)) { + if (is_array($fetchmode)) { + if ($params === null) { + $tmp = DB_FETCHMODE_DEFAULT; + } else { + $tmp = $params; + } + $params = $fetchmode; + $fetchmode = $tmp; + } elseif ($params !== null) { + $fetchmode = $params; + $params = array(); + } + } + + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + + if (DB::isError($sth)) { + return $sth; + } + + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if ($res === DB_OK || DB::isError($res)) { + return $res; + } + + $results = array(); + while (DB_OK === $res->fetchInto($row, $fetchmode)) { + if ($fetchmode & DB_FETCHMODE_FLIPPED) { + foreach ($row as $key => $val) { + $results[$key][] = $val; + } + } else { + $results[] = $row; + } + } + + $res->free(); + + if (DB::isError($row)) { + $tmp =& $this->raiseError($row); + return $tmp; + } + return $results; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ numRows() + + /** + * Determines the number of rows in a query result + * + * @param resource $result the query result idenifier produced by PHP + * + * @return int the number of rows. A DB_Error object on failure. + */ + function numRows($result) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ getSequenceName() + + /** + * Generates the name used inside the database for a sequence + * + * The createSequence() docblock contains notes about storing sequence + * names. + * + * @param string $sqn the sequence's public name + * + * @return string the sequence's name in the backend + * + * @access protected + * @see DB_common::createSequence(), DB_common::dropSequence(), + * DB_common::nextID(), DB_common::setOption() + */ + function getSequenceName($sqn) + { + return sprintf($this->getOption('seqname_format'), + preg_replace('/[^a-z0-9_.]/i', '_', $sqn)); + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::dropSequence(), + * DB_common::getSequenceName() + */ + function nextId($seq_name, $ondemand = true) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * The name of a given sequence is determined by passing the string + * provided in the $seq_name argument through PHP's sprintf() + * function using the value from the seqname_format option as + * the sprintf()'s format argument. + * + * seqname_format is set via setOption(). + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_common::nextID() + */ + function createSequence($seq_name) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_common::nextID() + */ + function dropSequence($seq_name) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ raiseError() + + /** + * Communicates an error and invoke error callbacks, etc + * + * Basically a wrapper for PEAR::raiseError without the message string. + * + * @param mixed integer error code, or a PEAR error object (all + * other parameters are ignored if this parameter is + * an object + * @param int error mode, see PEAR_Error docs + * @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the + * error level (E_USER_NOTICE etc). If error mode is + * PEAR_ERROR_CALLBACK, this is the callback function, + * either as a function name, or as an array of an + * object and method name. For other error modes this + * parameter is ignored. + * @param string extra debug information. Defaults to the last + * query and native error code. + * @param mixed native error code, integer or string depending the + * backend + * + * @return object the PEAR_Error object + * + * @see PEAR_Error + */ + function &raiseError($code = DB_ERROR, $mode = null, $options = null, + $userinfo = null, $nativecode = null) + { + // The error is yet a DB error object + if (is_object($code)) { + // because we the static PEAR::raiseError, our global + // handler should be used if it is set + if ($mode === null && !empty($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + } + $tmp = PEAR::raiseError($code, null, $mode, $options, + null, null, true); + return $tmp; + } + + if ($userinfo === null) { + $userinfo = $this->last_query; + } + + if ($nativecode) { + $userinfo .= ' [nativecode=' . trim($nativecode) . ']'; + } else { + $userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']'; + } + + $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, + 'DB_Error', true); + return $tmp; + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return mixed the DBMS' error code. A DB_Error object on failure. + */ + function errorNative() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ errorCode() + + /** + * Maps native error codes to DB's portable ones + * + * Uses the $errorcode_map property defined in each driver. + * + * @param string|int $nativecode the error code returned by the DBMS + * + * @return int the portable DB error code. Return DB_ERROR if the + * current driver doesn't have a mapping for the + * $nativecode submitted. + */ + function errorCode($nativecode) + { + if (isset($this->errorcode_map[$nativecode])) { + return $this->errorcode_map[$nativecode]; + } + // Fall back to DB_ERROR if there was no mapping. + return DB_ERROR; + } + + // }}} + // {{{ errorMessage() + + /** + * Maps a DB error code to a textual message + * + * @param integer $dbcode the DB error code + * + * @return string the error message corresponding to the error code + * submitted. FALSE if the error code is unknown. + * + * @see DB::errorMessage() + */ + function errorMessage($dbcode) + { + return DB::errorMessage($this->errorcode_map[$dbcode]); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * The format of the resulting array depends on which $mode + * you select. The sample output below is based on this query: + *
+     *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
+     *    FROM tblFoo
+     *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
+     * 
+ * + *
    + *
  • + * + * null (default) + *
    +     *   [0] => Array (
    +     *       [table] => tblFoo
    +     *       [name] => fldId
    +     *       [type] => int
    +     *       [len] => 11
    +     *       [flags] => primary_key not_null
    +     *   )
    +     *   [1] => Array (
    +     *       [table] => tblFoo
    +     *       [name] => fldPhone
    +     *       [type] => string
    +     *       [len] => 20
    +     *       [flags] =>
    +     *   )
    +     *   [2] => Array (
    +     *       [table] => tblBar
    +     *       [name] => fldId
    +     *       [type] => int
    +     *       [len] => 11
    +     *       [flags] => primary_key not_null
    +     *   )
    +     *   
    + * + *
  • + * + * DB_TABLEINFO_ORDER + * + *

    In addition to the information found in the default output, + * a notation of the number of columns is provided by the + * num_fields element while the order + * element provides an array with the column names as the keys and + * their location index number (corresponding to the keys in the + * the default output) as the values.

    + * + *

    If a result set has identical field names, the last one is + * used.

    + * + *
    +     *   [num_fields] => 3
    +     *   [order] => Array (
    +     *       [fldId] => 2
    +     *       [fldTrans] => 1
    +     *   )
    +     *   
    + * + *
  • + * + * DB_TABLEINFO_ORDERTABLE + * + *

    Similar to DB_TABLEINFO_ORDER but adds more + * dimensions to the array in which the table names are keys and + * the field names are sub-keys. This is helpful for queries that + * join tables which have identical field names.

    + * + *
    +     *   [num_fields] => 3
    +     *   [ordertable] => Array (
    +     *       [tblFoo] => Array (
    +     *           [fldId] => 0
    +     *           [fldPhone] => 1
    +     *       )
    +     *       [tblBar] => Array (
    +     *           [fldId] => 2
    +     *       )
    +     *   )
    +     *   
    + * + *
  • + *
+ * + * The flags element contains a space separated list + * of extra information about the field. This data is inconsistent + * between DBMS's due to the way each DBMS works. + * + primary_key + * + unique_key + * + multiple_key + * + not_null + * + * Most DBMS's only provide the table and flags + * elements if $result is a table name. The following DBMS's + * provide full information from queries: + * + fbsql + * + mysql + * + * If the 'portability' option has DB_PORTABILITY_LOWERCASE + * turned on, the names of tables and fields will be lowercased. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode either unused or one of the tableInfo modes: + * DB_TABLEINFO_ORDERTABLE, + * DB_TABLEINFO_ORDER or + * DB_TABLEINFO_FULL (which does both). + * These are bitwise, so the first two can be + * combined using |. + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::setOption() + */ + function tableInfo($result, $mode = null) + { + /* + * If the DB_ class has a tableInfo() method, that one + * overrides this one. But, if the driver doesn't have one, + * this method runs and tells users about that fact. + */ + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ getTables() + + /** + * Lists the tables in the current database + * + * @return array the list of tables. A DB_Error object on failure. + * + * @deprecated Method deprecated some time before Release 1.2 + */ + function getTables() + { + return $this->getListOf('tables'); + } + + // }}} + // {{{ getListOf() + + /** + * Lists internal database information + * + * @param string $type type of information being sought. + * Common items being sought are: + * tables, databases, users, views, functions + * Each DBMS's has its own capabilities. + * + * @return array an array listing the items sought. + * A DB DB_Error object on failure. + */ + function getListOf($type) + { + $sql = $this->getSpecialQuery($type); + if ($sql === null) { + $this->last_query = ''; + return $this->raiseError(DB_ERROR_UNSUPPORTED); + } elseif (is_int($sql) || DB::isError($sql)) { + // Previous error + return $this->raiseError($sql); + } elseif (is_array($sql)) { + // Already the result + return $sql; + } + // Launch this query + return $this->getCol($sql); + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + return $this->raiseError(DB_ERROR_UNSUPPORTED); + } + + // }}} + // {{{ _rtrimArrayValues() + + /** + * Right-trims all strings in an array + * + * @param array $array the array to be trimmed (passed by reference) + * + * @return void + * + * @access protected + */ + function _rtrimArrayValues(&$array) + { + foreach ($array as $key => $value) { + if (is_string($value)) { + $array[$key] = rtrim($value); + } + } + } + + // }}} + // {{{ _convertNullArrayValuesToEmpty() + + /** + * Converts all null values in an array to empty strings + * + * @param array $array the array to be de-nullified (passed by reference) + * + * @return void + * + * @access protected + */ + function _convertNullArrayValuesToEmpty(&$array) + { + foreach ($array as $key => $value) { + if (is_null($value)) { + $array[$key] = ''; + } + } + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/dbase.php b/src/www/lib/pear/DB/dbase.php new file mode 100644 index 00000000..9ec04a69 --- /dev/null +++ b/src/www/lib/pear/DB/dbase.php @@ -0,0 +1,510 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: dbase.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's dbase extension + * for interacting with dBase databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Tomas V.V. Cox + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_dbase extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'dbase'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'dbase'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => false, + 'new_link' => false, + 'numrows' => true, + 'pconnect' => false, + 'prepare' => false, + 'ssl' => false, + 'transactions' => false, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * A means of emulating result resources + * @var array + */ + var $res_row = array(); + + /** + * The quantity of results so far + * + * For emulating result resources. + * + * @var integer + */ + var $result = 0; + + /** + * Maps dbase data type id's to human readable strings + * + * The human readable values are based on the output of PHP's + * dbase_get_header_info() function. + * + * @var array + * @since Property available since Release 1.7.0 + */ + var $types = array( + 'C' => 'character', + 'D' => 'date', + 'L' => 'boolean', + 'M' => 'memo', + 'N' => 'number', + ); + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_dbase() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database and create it if it doesn't exist + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's dbase driver supports the following extra DSN options: + * + mode An integer specifying the read/write mode to use + * (0 = read only, 1 = write only, 2 = read/write). + * Available since PEAR DB 1.7.0. + * + fields An array of arrays that PHP's dbase_create() function needs + * to create a new database. This information is used if the + * dBase file specified in the "database" segment of the DSN + * does not exist. For more info, see the PHP manual's + * {@link http://php.net/dbase_create dbase_create()} page. + * Available since PEAR DB 1.7.0. + * + * Example of how to connect and establish a new dBase file if necessary: + * + * require_once 'DB.php'; + * + * $dsn = array( + * 'phptype' => 'dbase', + * 'database' => '/path/and/name/of/dbase/file', + * 'mode' => 2, + * 'fields' => array( + * array('a', 'N', 5, 0), + * array('b', 'C', 40), + * array('c', 'C', 255), + * array('d', 'C', 20), + * ), + * ); + * $options = array( + * 'debug' => 2, + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('dbase')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + /* + * Turn track_errors on for entire script since $php_errormsg + * is the only way to find errors from the dbase extension. + */ + ini_set('track_errors', 1); + $php_errormsg = ''; + + if (!file_exists($dsn['database'])) { + $this->dsn['mode'] = 2; + if (empty($dsn['fields']) || !is_array($dsn['fields'])) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + 'the dbase file does not exist and ' + . 'it could not be created because ' + . 'the "fields" element of the DSN ' + . 'is not properly set'); + } + $this->connection = @dbase_create($dsn['database'], + $dsn['fields']); + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + 'the dbase file does not exist and ' + . 'the attempt to create it failed: ' + . $php_errormsg); + } + } else { + if (!isset($this->dsn['mode'])) { + $this->dsn['mode'] = 0; + } + $this->connection = @dbase_open($dsn['database'], + $this->dsn['mode']); + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @dbase_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ &query() + + function &query($query = null) + { + // emulate result resources + $this->res_row[(int)$this->result] = 0; + $tmp =& new DB_result($this, $this->result++); + return $tmp; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum === null) { + $rownum = $this->res_row[(int)$result]++; + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @dbase_get_record_with_names($this->connection, $rownum); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @dbase_get_record($this->connection, $rownum); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($foo) + { + return @dbase_numfields($this->connection); + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($foo) + { + return @dbase_numrecords($this->connection); + } + + // }}} + // {{{ quoteSmart() + + /** + * Formats input so it can be safely used in a query + * + * @param mixed $in the data to be formatted + * + * @return mixed the formatted data. The format depends on the input's + * PHP type: + * + null = the string NULL + * + boolean = T if true or + * F if false. Use the Logical + * data type. + * + integer or double = the unquoted number + * + other (including strings and numeric strings) = + * the data with single quotes escaped by preceeding + * single quotes then the whole string is encapsulated + * between single quotes + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 'T' : 'F'; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about the current database + * + * @param mixed $result THIS IS UNUSED IN DBASE. The current database + * is examined regardless of what is provided here. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + * @since Method available since Release 1.7.0 + */ + function tableInfo($result = null, $mode = null) + { + if (function_exists('dbase_get_header_info')) { + $id = @dbase_get_header_info($this->connection); + if (!$id && $php_errormsg) { + return $this->raiseError(DB_ERROR, + null, null, null, + $php_errormsg); + } + } else { + /* + * This segment for PHP 4 is loosely based on code by + * Hadi Rusiah in the comments on + * the dBase reference page in the PHP manual. + */ + $db = @fopen($this->dsn['database'], 'r'); + if (!$db) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + + $id = array(); + $i = 0; + + $line = fread($db, 32); + while (!feof($db)) { + $line = fread($db, 32); + if (substr($line, 0, 1) == chr(13)) { + break; + } else { + $pos = strpos(substr($line, 0, 10), chr(0)); + $pos = ($pos == 0 ? 10 : $pos); + $id[$i] = array( + 'name' => substr($line, 0, $pos), + 'type' => $this->types[substr($line, 11, 1)], + 'length' => ord(substr($line, 16, 1)), + 'precision' => ord(substr($line, 17, 1)), + ); + } + $i++; + } + + fclose($db); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $res = array(); + $count = count($id); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $this->dsn['database'], + 'name' => $case_func($id[$i]['name']), + 'type' => $id[$i]['type'], + 'len' => $id[$i]['length'], + 'flags' => '' + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + return $res; + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/fbsql.php b/src/www/lib/pear/DB/fbsql.php new file mode 100644 index 00000000..49520028 --- /dev/null +++ b/src/www/lib/pear/DB/fbsql.php @@ -0,0 +1,770 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: fbsql.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's fbsql extension + * for interacting with FrontBase databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Frank M. Kromann + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + * @since Class functional since Release 1.7.0 + */ +class DB_fbsql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'fbsql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'fbsql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + 22 => DB_ERROR_SYNTAX, + 85 => DB_ERROR_ALREADY_EXISTS, + 108 => DB_ERROR_SYNTAX, + 116 => DB_ERROR_NOSUCHTABLE, + 124 => DB_ERROR_VALUE_COUNT_ON_ROW, + 215 => DB_ERROR_NOSUCHFIELD, + 217 => DB_ERROR_INVALID_NUMBER, + 226 => DB_ERROR_NOSUCHFIELD, + 231 => DB_ERROR_INVALID, + 239 => DB_ERROR_TRUNCATED, + 251 => DB_ERROR_SYNTAX, + 266 => DB_ERROR_NOT_FOUND, + 357 => DB_ERROR_CONSTRAINT_NOT_NULL, + 358 => DB_ERROR_CONSTRAINT, + 360 => DB_ERROR_CONSTRAINT, + 361 => DB_ERROR_CONSTRAINT, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_fbsql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('fbsql')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $params = array( + $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost', + $dsn['username'] ? $dsn['username'] : null, + $dsn['password'] ? $dsn['password'] : null, + ); + + $connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect'; + + $ini = ini_get('track_errors'); + $php_errormsg = ''; + if ($ini) { + $this->connection = @call_user_func_array($connect_function, + $params); + } else { + ini_set('track_errors', 1); + $this->connection = @call_user_func_array($connect_function, + $params); + ini_set('track_errors', $ini); + } + + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + + if ($dsn['database']) { + if (!@fbsql_select_db($dsn['database'], $this->connection)) { + return $this->fbsqlRaiseError(); + } + } + + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @fbsql_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $this->last_query = $query; + $query = $this->modifyQuery($query); + $result = @fbsql_query("$query;", $this->connection); + if (!$result) { + return $this->fbsqlRaiseError(); + } + // Determine which queries that should return data, and which + // should return an error code only. + if (DB::isManip($query)) { + return DB_OK; + } + return $result; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal fbsql result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return @fbsql_next_result($result); + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@fbsql_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @fbsql_fetch_array($result, FBSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @fbsql_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @fbsql_free_result($result); + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff=false) + { + if ($onoff) { + $this->query("SET COMMIT TRUE"); + } else { + $this->query("SET COMMIT FALSE"); + } + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + @fbsql_commit(); + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + @fbsql_rollback(); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @fbsql_num_fields($result); + if (!$cols) { + return $this->fbsqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @fbsql_num_rows($result); + if ($rows === null) { + return $this->fbsqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + $result = @fbsql_affected_rows($this->connection); + } else { + $result = 0; + } + return $result; + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_fbsql::createSequence(), DB_fbsql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + do { + $repeat = 0; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query('SELECT UNIQUE FROM ' . $seqname); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) { + $repeat = 1; + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $result; + } + } else { + $repeat = 0; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->fbsqlRaiseError(); + } + $result->fetchInto($tmp, DB_FETCHMODE_ORDERED); + return $tmp[0]; + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_fbsql::nextID(), DB_fbsql::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $res = $this->query('CREATE TABLE ' . $seqname + . ' (id INTEGER NOT NULL,' + . ' PRIMARY KEY(id))'); + if ($res) { + $res = $this->query('SET UNIQUE = 0 FOR ' . $seqname); + } + return $res; + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_fbsql::nextID(), DB_fbsql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name) + . ' RESTRICT'); + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + if (DB::isManip($query)) { + return preg_replace('/^([\s(])*SELECT/i', + "\\1SELECT TOP($count)", $query); + } else { + return preg_replace('/([\s(])*SELECT/i', + "\\1SELECT TOP($from, $count)", $query); + } + } + + // }}} + // {{{ quoteSmart() + + /** + * Formats input so it can be safely used in a query + * + * @param mixed $in the data to be formatted + * + * @return mixed the formatted data. The format depends on the input's + * PHP type: + * + null = the string NULL + * + boolean = string TRUE or FALSE + * + integer or double = the unquoted number + * + other (including strings and numeric strings) = + * the data escaped according to FrontBase's settings + * then encapsulated between single quotes + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 'TRUE' : 'FALSE'; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + // }}} + // {{{ fbsqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_fbsql::errorNative(), DB_common::errorCode() + */ + function fbsqlRaiseError($errno = null) + { + if ($errno === null) { + $errno = $this->errorCode(fbsql_errno($this->connection)); + } + return $this->raiseError($errno, null, null, null, + @fbsql_error($this->connection)); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code + */ + function errorNative() + { + return @fbsql_errno($this->connection); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @fbsql_list_fields($this->dsn['database'], + $result, $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @fbsql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $case_func(@fbsql_field_table($id, $i)), + 'name' => $case_func(@fbsql_field_name($id, $i)), + 'type' => @fbsql_field_type($id, $i), + 'len' => @fbsql_field_len($id, $i), + 'flags' => @fbsql_field_flags($id, $i), + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @fbsql_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SELECT "table_name" FROM information_schema.tables' + . ' t0, information_schema.schemata t1' + . ' WHERE t0.schema_pk=t1.schema_pk AND' + . ' "table_type" = \'BASE TABLE\'' + . ' AND "schema_name" = current_schema'; + case 'views': + return 'SELECT "table_name" FROM information_schema.tables' + . ' t0, information_schema.schemata t1' + . ' WHERE t0.schema_pk=t1.schema_pk AND' + . ' "table_type" = \'VIEW\'' + . ' AND "schema_name" = current_schema'; + case 'users': + return 'SELECT "user_name" from information_schema.users'; + case 'functions': + return 'SELECT "routine_name" FROM' + . ' information_schema.psm_routines' + . ' t0, information_schema.schemata t1' + . ' WHERE t0.schema_pk=t1.schema_pk' + . ' AND "routine_kind"=\'FUNCTION\'' + . ' AND "schema_name" = current_schema'; + case 'procedures': + return 'SELECT "routine_name" FROM' + . ' information_schema.psm_routines' + . ' t0, information_schema.schemata t1' + . ' WHERE t0.schema_pk=t1.schema_pk' + . ' AND "routine_kind"=\'PROCEDURE\'' + . ' AND "schema_name" = current_schema'; + default: + return null; + } + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/ibase.php b/src/www/lib/pear/DB/ibase.php new file mode 100644 index 00000000..da829dfd --- /dev/null +++ b/src/www/lib/pear/DB/ibase.php @@ -0,0 +1,1071 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: ibase.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's interbase extension + * for interacting with Interbase and Firebird databases + * + * These methods overload the ones declared in DB_common. + * + * While this class works with PHP 4, PHP's InterBase extension is + * unstable in PHP 4. Use PHP 5. + * + * NOTICE: limitQuery() only works for Firebird. + * + * @category Database + * @package DB + * @author Sterling Hughes + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + * @since Class became stable in Release 1.7.0 + */ +class DB_ibase extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'ibase'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'ibase'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * NOTE: only firebird supports limit. + * + * @var array + */ + var $features = array( + 'limit' => false, + 'new_link' => false, + 'numrows' => 'emulate', + 'pconnect' => true, + 'prepare' => true, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + -104 => DB_ERROR_SYNTAX, + -150 => DB_ERROR_ACCESS_VIOLATION, + -151 => DB_ERROR_ACCESS_VIOLATION, + -155 => DB_ERROR_NOSUCHTABLE, + -157 => DB_ERROR_NOSUCHFIELD, + -158 => DB_ERROR_VALUE_COUNT_ON_ROW, + -170 => DB_ERROR_MISMATCH, + -171 => DB_ERROR_MISMATCH, + -172 => DB_ERROR_INVALID, + // -204 => // Covers too many errors, need to use regex on msg + -205 => DB_ERROR_NOSUCHFIELD, + -206 => DB_ERROR_NOSUCHFIELD, + -208 => DB_ERROR_INVALID, + -219 => DB_ERROR_NOSUCHTABLE, + -297 => DB_ERROR_CONSTRAINT, + -303 => DB_ERROR_INVALID, + -413 => DB_ERROR_INVALID_NUMBER, + -530 => DB_ERROR_CONSTRAINT, + -551 => DB_ERROR_ACCESS_VIOLATION, + -552 => DB_ERROR_ACCESS_VIOLATION, + // -607 => // Covers too many errors, need to use regex on msg + -625 => DB_ERROR_CONSTRAINT_NOT_NULL, + -803 => DB_ERROR_CONSTRAINT, + -804 => DB_ERROR_VALUE_COUNT_ON_ROW, + -904 => DB_ERROR_CONNECT_FAILED, + -922 => DB_ERROR_NOSUCHDB, + -923 => DB_ERROR_CONNECT_FAILED, + -924 => DB_ERROR_CONNECT_FAILED + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * The number of rows affected by a data manipulation query + * @var integer + * @access private + */ + var $affected = 0; + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The prepared statement handle from the most recently executed statement + * + * {@internal Mainly here because the InterBase/Firebird API is only + * able to retrieve data from result sets if the statemnt handle is + * still in scope.}} + * + * @var resource + */ + var $last_stmt; + + /** + * Is the given prepared statement a data manipulation query? + * @var array + * @access private + */ + var $manip_query = array(); + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_ibase() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's ibase driver supports the following extra DSN options: + * + buffers The number of database buffers to allocate for the + * server-side cache. + * + charset The default character set for a database. + * + dialect The default SQL dialect for any statement + * executed within a connection. Defaults to the + * highest one supported by client libraries. + * Functional only with InterBase 6 and up. + * + role Functional only with InterBase 5 and up. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('interbase')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + if ($this->dbsyntax == 'firebird') { + $this->features['limit'] = 'alter'; + } + + $params = array( + $dsn['hostspec'] + ? ($dsn['hostspec'] . ':' . $dsn['database']) + : $dsn['database'], + $dsn['username'] ? $dsn['username'] : null, + $dsn['password'] ? $dsn['password'] : null, + isset($dsn['charset']) ? $dsn['charset'] : null, + isset($dsn['buffers']) ? $dsn['buffers'] : null, + isset($dsn['dialect']) ? $dsn['dialect'] : null, + isset($dsn['role']) ? $dsn['role'] : null, + ); + + $connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect'; + + $this->connection = @call_user_func_array($connect_function, $params); + if (!$this->connection) { + return $this->ibaseRaiseError(DB_ERROR_CONNECT_FAILED); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @ibase_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + $result = @ibase_query($this->connection, $query); + + if (!$result) { + return $this->ibaseRaiseError(); + } + if ($this->autocommit && $ismanip) { + @ibase_commit($this->connection); + } + if ($ismanip) { + $this->affected = $result; + return DB_OK; + } else { + $this->affected = 0; + return $result; + } + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * Only works with Firebird. + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + if ($this->dsn['dbsyntax'] == 'firebird') { + $query = preg_replace('/^([\s(])*SELECT/i', + "SELECT FIRST $count SKIP $from", $query); + } + return $query; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal ibase result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE); + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + if (function_exists('ibase_fetch_assoc')) { + $arr = @ibase_fetch_assoc($result); + } else { + $arr = get_object_vars(ibase_fetch_object($result)); + } + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @ibase_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @ibase_free_result($result); + } + + // }}} + // {{{ freeQuery() + + function freeQuery($query) + { + @ibase_free_query($query); + return true; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (is_integer($this->affected)) { + return $this->affected; + } + return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @ibase_num_fields($result); + if (!$cols) { + return $this->ibaseRaiseError(); + } + return $cols; + } + + // }}} + // {{{ prepare() + + /** + * Prepares a query for multiple execution with execute(). + * + * prepare() requires a generic query as string like + * INSERT INTO numbers VALUES (?, ?, ?) + * . The ? characters are placeholders. + * + * Three types of placeholders can be used: + * + ? a quoted scalar value, i.e. strings, integers + * + ! value is inserted 'as is' + * + & requires a file name. The file's contents get + * inserted into the query (i.e. saving binary + * data in a db) + * + * Use backslashes to escape placeholder characters if you don't want + * them to be interpreted as placeholders. Example: + * "UPDATE foo SET col=? WHERE col='over \& under'" + * + * + * @param string $query query to be prepared + * @return mixed DB statement resource on success. DB_Error on failure. + */ + function prepare($query) + { + $tokens = preg_split('/((? $val) { + switch ($val) { + case '?': + $types[$token++] = DB_PARAM_SCALAR; + break; + case '&': + $types[$token++] = DB_PARAM_OPAQUE; + break; + case '!': + $types[$token++] = DB_PARAM_MISC; + break; + default: + $tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val); + $newquery .= $tokens[$key] . '?'; + } + } + + $newquery = substr($newquery, 0, -1); + $this->last_query = $query; + $newquery = $this->modifyQuery($newquery); + $stmt = @ibase_prepare($this->connection, $newquery); + $this->prepare_types[(int)$stmt] = $types; + $this->manip_query[(int)$stmt] = DB::isManip($query); + return $stmt; + } + + // }}} + // {{{ execute() + + /** + * Executes a DB statement prepared with prepare(). + * + * @param resource $stmt a DB statement resource returned from prepare() + * @param mixed $data array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 for non-array items or the + * quantity of elements in the array. + * @return object a new DB_Result or a DB_Error when fail + * @see DB_ibase::prepare() + * @access public + */ + function &execute($stmt, $data = array()) + { + $data = (array)$data; + $this->last_parameters = $data; + + $types =& $this->prepare_types[(int)$stmt]; + if (count($types) != count($data)) { + $tmp =& $this->raiseError(DB_ERROR_MISMATCH); + return $tmp; + } + + $i = 0; + foreach ($data as $key => $value) { + if ($types[$i] == DB_PARAM_MISC) { + /* + * ibase doesn't seem to have the ability to pass a + * parameter along unchanged, so strip off quotes from start + * and end, plus turn two single quotes to one single quote, + * in order to avoid the quotes getting escaped by + * ibase and ending up in the database. + */ + $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]); + $data[$key] = str_replace("''", "'", $data[$key]); + } elseif ($types[$i] == DB_PARAM_OPAQUE) { + $fp = @fopen($data[$key], 'rb'); + if (!$fp) { + $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION); + return $tmp; + } + $data[$key] = fread($fp, filesize($data[$key])); + fclose($fp); + } + $i++; + } + + array_unshift($data, $stmt); + + $res = call_user_func_array('ibase_execute', $data); + if (!$res) { + $tmp =& $this->ibaseRaiseError(); + return $tmp; + } + /* XXX need this? + if ($this->autocommit && $this->manip_query[(int)$stmt]) { + @ibase_commit($this->connection); + }*/ + $this->last_stmt = $stmt; + if ($this->manip_query[(int)$stmt]) { + $tmp = DB_OK; + } else { + $tmp =& new DB_result($this, $res); + } + return $tmp; + } + + /** + * Frees the internal resources associated with a prepared query + * + * @param resource $stmt the prepared statement's PHP resource + * @param bool $free_resource should the PHP resource be freed too? + * Use false if you need to get data + * from the result set later. + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_ibase::prepare() + */ + function freePrepared($stmt, $free_resource = true) + { + if (!is_resource($stmt)) { + return false; + } + if ($free_resource) { + @ibase_free_query($stmt); + } + unset($this->prepare_tokens[(int)$stmt]); + unset($this->prepare_types[(int)$stmt]); + unset($this->manip_query[(int)$stmt]); + return true; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + $this->autocommit = $onoff ? 1 : 0; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + return @ibase_commit($this->connection); + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + return @ibase_rollback($this->connection); + } + + // }}} + // {{{ transactionInit() + + function transactionInit($trans_args = 0) + { + return $trans_args + ? @ibase_trans($trans_args, $this->connection) + : @ibase_trans(); + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_ibase::createSequence(), DB_ibase::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $sqn = strtoupper($this->getSequenceName($seq_name)); + $repeat = 0; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result =& $this->query("SELECT GEN_ID(${sqn}, 1) " + . 'FROM RDB$GENERATORS ' + . "WHERE RDB\$GENERATOR_NAME='${sqn}'"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result)) { + $repeat = 1; + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $result; + } + } else { + $repeat = 0; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $arr = $result->fetchRow(DB_FETCHMODE_ORDERED); + $result->free(); + return $arr[0]; + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_ibase::nextID(), DB_ibase::dropSequence() + */ + function createSequence($seq_name) + { + $sqn = strtoupper($this->getSequenceName($seq_name)); + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("CREATE GENERATOR ${sqn}"); + $this->popErrorHandling(); + + return $result; + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_ibase::nextID(), DB_ibase::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DELETE FROM RDB$GENERATORS ' + . "WHERE RDB\$GENERATOR_NAME='" + . strtoupper($this->getSequenceName($seq_name)) + . "'"); + } + + // }}} + // {{{ _ibaseFieldFlags() + + /** + * Get the column's flags + * + * Supports "primary_key", "unique_key", "not_null", "default", + * "computed" and "blob". + * + * @param string $field_name the name of the field + * @param string $table_name the name of the table + * + * @return string the flags + * + * @access private + */ + function _ibaseFieldFlags($field_name, $table_name) + { + $sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE' + .' FROM RDB$INDEX_SEGMENTS I' + .' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME' + .' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\'' + .' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''; + + $result = @ibase_query($this->connection, $sql); + if (!$result) { + return $this->ibaseRaiseError(); + } + + $flags = ''; + if ($obj = @ibase_fetch_object($result)) { + @ibase_free_result($result); + if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') { + $flags .= 'primary_key '; + } + if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') { + $flags .= 'unique_key '; + } + } + + $sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,' + .' R.RDB$DEFAULT_SOURCE AS DSOURCE,' + .' F.RDB$FIELD_TYPE AS FTYPE,' + .' F.RDB$COMPUTED_SOURCE AS CSOURCE' + .' FROM RDB$RELATION_FIELDS R ' + .' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME' + .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'' + .' AND R.RDB$FIELD_NAME=\'' . $field_name . '\''; + + $result = @ibase_query($this->connection, $sql); + if (!$result) { + return $this->ibaseRaiseError(); + } + if ($obj = @ibase_fetch_object($result)) { + @ibase_free_result($result); + if (isset($obj->NFLAG)) { + $flags .= 'not_null '; + } + if (isset($obj->DSOURCE)) { + $flags .= 'default '; + } + if (isset($obj->CSOURCE)) { + $flags .= 'computed '; + } + if (isset($obj->FTYPE) && $obj->FTYPE == 261) { + $flags .= 'blob '; + } + } + + return trim($flags); + } + + // }}} + // {{{ ibaseRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_ibase::errorNative(), DB_ibase::errorCode() + */ + function &ibaseRaiseError($errno = null) + { + if ($errno === null) { + $errno = $this->errorCode($this->errorNative()); + } + $tmp =& $this->raiseError($errno, null, null, null, @ibase_errmsg()); + return $tmp; + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code. NULL if there is no error code. + * + * @since Method available since Release 1.7.0 + */ + function errorNative() + { + if (function_exists('ibase_errcode')) { + return @ibase_errcode(); + } + if (preg_match('/^Dynamic SQL Error SQL error code = ([0-9-]+)/i', + @ibase_errmsg(), $m)) { + return (int)$m[1]; + } + return null; + } + + // }}} + // {{{ errorCode() + + /** + * Maps native error codes to DB's portable ones + * + * @param int $nativecode the error code returned by the DBMS + * + * @return int the portable DB error code. Return DB_ERROR if the + * current driver doesn't have a mapping for the + * $nativecode submitted. + * + * @since Method available since Release 1.7.0 + */ + function errorCode($nativecode = null) + { + if (isset($this->errorcode_map[$nativecode])) { + return $this->errorcode_map[$nativecode]; + } + + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/generator .* is not defined/' + => DB_ERROR_SYNTAX, // for compat. w ibase_errcode() + '/table.*(not exist|not found|unknown)/i' + => DB_ERROR_NOSUCHTABLE, + '/table .* already exists/i' + => DB_ERROR_ALREADY_EXISTS, + '/unsuccessful metadata update .* failed attempt to store duplicate value/i' + => DB_ERROR_ALREADY_EXISTS, + '/unsuccessful metadata update .* not found/i' + => DB_ERROR_NOT_FOUND, + '/validation error for column .* value "\*\*\* null/i' + => DB_ERROR_CONSTRAINT_NOT_NULL, + '/violation of [\w ]+ constraint/i' + => DB_ERROR_CONSTRAINT, + '/conversion error from string/i' + => DB_ERROR_INVALID_NUMBER, + '/no permission for/i' + => DB_ERROR_ACCESS_VIOLATION, + '/arithmetic exception, numeric overflow, or string truncation/i' + => DB_ERROR_INVALID, + ); + } + + $errormsg = @ibase_errmsg(); + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @ibase_query($this->connection, + "SELECT * FROM $result WHERE 1=0"); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->ibaseRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @ibase_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $info = @ibase_field_info($id, $i); + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func($info['name']), + 'type' => $info['type'], + 'len' => $info['length'], + 'flags' => ($got_string) + ? $this->_ibaseFieldFlags($info['name'], $result) + : '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @ibase_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SELECT DISTINCT R.RDB$RELATION_NAME FROM ' + . 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0'; + case 'views': + return 'SELECT DISTINCT RDB$VIEW_NAME from RDB$VIEW_RELATIONS'; + case 'users': + return 'SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/ifx.php b/src/www/lib/pear/DB/ifx.php new file mode 100644 index 00000000..0bc8727f --- /dev/null +++ b/src/www/lib/pear/DB/ifx.php @@ -0,0 +1,681 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: ifx.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's ifx extension + * for interacting with Informix databases + * + * These methods overload the ones declared in DB_common. + * + * More info on Informix errors can be found at: + * http://www.informix.com/answers/english/ierrors.htm + * + * TODO: + * - set needed env Informix vars on connect + * - implement native prepare/execute + * + * @category Database + * @package DB + * @author Tomas V.V.Cox + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_ifx extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'ifx'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'ifx'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'emulate', + 'new_link' => false, + 'numrows' => 'emulate', + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + '-201' => DB_ERROR_SYNTAX, + '-206' => DB_ERROR_NOSUCHTABLE, + '-217' => DB_ERROR_NOSUCHFIELD, + '-236' => DB_ERROR_VALUE_COUNT_ON_ROW, + '-239' => DB_ERROR_CONSTRAINT, + '-253' => DB_ERROR_SYNTAX, + '-292' => DB_ERROR_CONSTRAINT_NOT_NULL, + '-310' => DB_ERROR_ALREADY_EXISTS, + '-316' => DB_ERROR_ALREADY_EXISTS, + '-319' => DB_ERROR_NOT_FOUND, + '-329' => DB_ERROR_NODBSELECTED, + '-346' => DB_ERROR_CONSTRAINT, + '-386' => DB_ERROR_CONSTRAINT_NOT_NULL, + '-391' => DB_ERROR_CONSTRAINT_NOT_NULL, + '-554' => DB_ERROR_SYNTAX, + '-691' => DB_ERROR_CONSTRAINT, + '-692' => DB_ERROR_CONSTRAINT, + '-703' => DB_ERROR_CONSTRAINT_NOT_NULL, + '-1204' => DB_ERROR_INVALID_DATE, + '-1205' => DB_ERROR_INVALID_DATE, + '-1206' => DB_ERROR_INVALID_DATE, + '-1209' => DB_ERROR_INVALID_DATE, + '-1210' => DB_ERROR_INVALID_DATE, + '-1212' => DB_ERROR_INVALID_DATE, + '-1213' => DB_ERROR_INVALID_NUMBER, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The number of rows affected by a data manipulation query + * @var integer + * @access private + */ + var $affected = 0; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_ifx() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('informix') && + !PEAR::loadExtension('Informix')) + { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $dbhost = $dsn['hostspec'] ? '@' . $dsn['hostspec'] : ''; + $dbname = $dsn['database'] ? $dsn['database'] . $dbhost : ''; + $user = $dsn['username'] ? $dsn['username'] : ''; + $pw = $dsn['password'] ? $dsn['password'] : ''; + + $connect_function = $persistent ? 'ifx_pconnect' : 'ifx_connect'; + + $this->connection = @$connect_function($dbname, $user, $pw); + if (!is_resource($this->connection)) { + return $this->ifxRaiseError(DB_ERROR_CONNECT_FAILED); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @ifx_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $this->affected = null; + if (preg_match('/(SELECT)/i', $query)) { //TESTME: Use !DB::isManip()? + // the scroll is needed for fetching absolute row numbers + // in a select query result + $result = @ifx_query($query, $this->connection, IFX_SCROLL); + } else { + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @ifx_query('BEGIN WORK', $this->connection); + if (!$result) { + return $this->ifxRaiseError(); + } + } + $this->transaction_opcount++; + } + $result = @ifx_query($query, $this->connection); + } + if (!$result) { + return $this->ifxRaiseError(); + } + $this->affected = @ifx_affected_rows($result); + // Determine which queries should return data, and which + // should return an error code only. + if (preg_match('/(SELECT)/i', $query)) { + return $result; + } + // XXX Testme: free results inside a transaction + // may cause to stop it and commit the work? + + // Result has to be freed even with a insert or update + @ifx_free_result($result); + + return DB_OK; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal ifx result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + return $this->affected; + } else { + return 0; + } + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if (($rownum !== null) && ($rownum < 0)) { + return null; + } + if ($rownum === null) { + /* + * Even though fetch_row() should return the next row if + * $rownum is null, it doesn't in all cases. Bug 598. + */ + $rownum = 'NEXT'; + } else { + // Index starts at row 1, unlike most DBMS's starting at 0. + $rownum++; + } + if (!$arr = @ifx_fetch_row($result, $rownum)) { + return null; + } + if ($fetchmode !== DB_FETCHMODE_ASSOC) { + $i=0; + $order = array(); + foreach ($arr as $val) { + $order[$i++] = $val; + } + $arr = $order; + } elseif ($fetchmode == DB_FETCHMODE_ASSOC && + $this->options['portability'] & DB_PORTABILITY_LOWERCASE) + { + $arr = array_change_key_case($arr, CASE_LOWER); + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + if (!$cols = @ifx_num_fields($result)) { + return $this->ifxRaiseError(); + } + return $cols; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @ifx_free_result($result); + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = true) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + $result = @ifx_query('COMMIT WORK', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->ifxRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + $result = @ifx_query('ROLLBACK WORK', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->ifxRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ ifxRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_ifx::errorNative(), DB_ifx::errorCode() + */ + function ifxRaiseError($errno = null) + { + if ($errno === null) { + $errno = $this->errorCode(ifx_error()); + } + return $this->raiseError($errno, null, null, null, + $this->errorNative()); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code and message produced by the last query + * + * @return string the DBMS' error code and message + */ + function errorNative() + { + return @ifx_error() . ' ' . @ifx_errormsg(); + } + + // }}} + // {{{ errorCode() + + /** + * Maps native error codes to DB's portable ones. + * + * Requires that the DB implementation's constructor fills + * in the $errorcode_map property. + * + * @param string $nativecode error code returned by the database + * @return int a portable DB error code, or DB_ERROR if this DB + * implementation has no mapping for the given error code. + */ + function errorCode($nativecode) + { + if (ereg('SQLCODE=(.*)]', $nativecode, $match)) { + $code = $match[1]; + if (isset($this->errorcode_map[$code])) { + return $this->errorcode_map[$code]; + } + } + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' if $result is a table name. + * + * If analyzing a query result and the result has duplicate field names, + * an error will be raised saying + * can't distinguish duplicate field names. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + * @since Method available since Release 1.6.0 + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @ifx_query("SELECT * FROM $result WHERE 1=0", + $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->ifxRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + $flds = @ifx_fieldproperties($id); + $count = @ifx_num_fields($id); + + if (count($flds) != $count) { + return $this->raiseError("can't distinguish duplicate field names"); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $i = 0; + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + foreach ($flds as $key => $value) { + $props = explode(';', $value); + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func($key), + 'type' => $props[0], + 'len' => $props[1], + 'flags' => $props[4] == 'N' ? 'not_null' : '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + $i++; + } + + // free the result only if we were called on a table + if ($got_string) { + @ifx_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SELECT tabname FROM systables WHERE tabid >= 100'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/msql.php b/src/www/lib/pear/DB/msql.php new file mode 100644 index 00000000..9cab8d0e --- /dev/null +++ b/src/www/lib/pear/DB/msql.php @@ -0,0 +1,810 @@ + + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: msql.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's msql extension + * for interacting with Mini SQL databases + * + * These methods overload the ones declared in DB_common. + * + * PHP's mSQL extension did weird things with NULL values prior to PHP + * 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds + * those versions. + * + * @category Database + * @package DB + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + * @since Class not functional until Release 1.7.0 + */ +class DB_msql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'msql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'msql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'emulate', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => false, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * The query result resource created by PHP + * + * Used to make affectedRows() work. Only contains the result for + * data manipulation queries. Contains false for other queries. + * + * @var resource + * @access private + */ + var $_result; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_msql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * Example of how to connect: + * + * require_once 'DB.php'; + * + * // $dsn = 'msql://hostname/dbname'; // use a TCP connection + * $dsn = 'msql:///dbname'; // use a socket + * $options = array( + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('msql')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $params = array(); + if ($dsn['hostspec']) { + $params[] = $dsn['port'] + ? $dsn['hostspec'] . ',' . $dsn['port'] + : $dsn['hostspec']; + } + + $connect_function = $persistent ? 'msql_pconnect' : 'msql_connect'; + + $ini = ini_get('track_errors'); + $php_errormsg = ''; + if ($ini) { + $this->connection = @call_user_func_array($connect_function, + $params); + } else { + ini_set('track_errors', 1); + $this->connection = @call_user_func_array($connect_function, + $params); + ini_set('track_errors', $ini); + } + + if (!$this->connection) { + if (($err = @msql_error()) != '') { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $err); + } else { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + } + + if (!@msql_select_db($dsn['database'], $this->connection)) { + return $this->msqlRaiseError(); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @msql_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $this->last_query = $query; + $query = $this->modifyQuery($query); + $result = @msql_query($query, $this->connection); + if (!$result) { + return $this->msqlRaiseError(); + } + // Determine which queries that should return data, and which + // should return an error code only. + if (DB::isManip($query)) { + $this->_result = $result; + return DB_OK; + } else { + $this->_result = false; + return $result; + } + } + + + // }}} + // {{{ nextResult() + + /** + * Move the internal msql result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * PHP's mSQL extension did weird things with NULL values prior to PHP + * 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds + * those versions. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@msql_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @msql_fetch_array($result, MSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @msql_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @msql_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @msql_num_fields($result); + if (!$cols) { + return $this->msqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @msql_num_rows($result); + if ($rows === false) { + return $this->msqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ affected() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (!$this->_result) { + return 0; + } + return msql_affected_rows($this->_result); + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_msql::createSequence(), DB_msql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + $repeat = false; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result =& $this->query("SELECT _seq FROM ${seqname}"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) { + $repeat = true; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->createSequence($seq_name); + $this->popErrorHandling(); + if (DB::isError($result)) { + return $this->raiseError($result); + } + } else { + $repeat = false; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $arr = $result->fetchRow(DB_FETCHMODE_ORDERED); + $result->free(); + return $arr[0]; + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * Also creates a new table to associate the sequence with. Uses + * a separate table to ensure portability with other drivers. + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_msql::nextID(), DB_msql::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $res = $this->query('CREATE TABLE ' . $seqname + . ' (id INTEGER NOT NULL)'); + if (DB::isError($res)) { + return $res; + } + $res = $this->query("CREATE SEQUENCE ON ${seqname}"); + return $res; + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_msql::nextID(), DB_msql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ quoteIdentifier() + + /** + * mSQL does not support delimited identifiers + * + * @param string $str the identifier name to be quoted + * + * @return object a DB_Error object + * + * @see DB_common::quoteIdentifier() + * @since Method available since Release 1.7.0 + */ + function quoteIdentifier($str) + { + return $this->raiseError(DB_ERROR_UNSUPPORTED); + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.7.0 + */ + function escapeSimple($str) + { + return addslashes($str); + } + + // }}} + // {{{ msqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_msql::errorNative(), DB_msql::errorCode() + */ + function msqlRaiseError($errno = null) + { + $native = $this->errorNative(); + if ($errno === null) { + $errno = $this->errorCode($native); + } + return $this->raiseError($errno, null, null, null, $native); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error message produced by the last query + * + * @return string the DBMS' error message + */ + function errorNative() + { + return @msql_error(); + } + + // }}} + // {{{ errorCode() + + /** + * Determines PEAR::DB error code from the database's text error message + * + * @param string $errormsg the error message returned from the database + * + * @return integer the error number from a DB_ERROR* constant + */ + function errorCode($errormsg) + { + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/^Access to database denied/i' + => DB_ERROR_ACCESS_VIOLATION, + '/^Bad index name/i' + => DB_ERROR_ALREADY_EXISTS, + '/^Bad order field/i' + => DB_ERROR_SYNTAX, + '/^Bad type for comparison/i' + => DB_ERROR_SYNTAX, + '/^Can\'t perform LIKE on/i' + => DB_ERROR_SYNTAX, + '/^Can\'t use TEXT fields in LIKE comparison/i' + => DB_ERROR_SYNTAX, + '/^Couldn\'t create temporary table/i' + => DB_ERROR_CANNOT_CREATE, + '/^Error creating table file/i' + => DB_ERROR_CANNOT_CREATE, + '/^Field .* cannot be null$/i' + => DB_ERROR_CONSTRAINT_NOT_NULL, + '/^Index (field|condition) .* cannot be null$/i' + => DB_ERROR_SYNTAX, + '/^Invalid date format/i' + => DB_ERROR_INVALID_DATE, + '/^Invalid time format/i' + => DB_ERROR_INVALID, + '/^Literal value for .* is wrong type$/i' + => DB_ERROR_INVALID_NUMBER, + '/^No Database Selected/i' + => DB_ERROR_NODBSELECTED, + '/^No value specified for field/i' + => DB_ERROR_VALUE_COUNT_ON_ROW, + '/^Non unique value for unique index/i' + => DB_ERROR_CONSTRAINT, + '/^Out of memory for temporary table/i' + => DB_ERROR_CANNOT_CREATE, + '/^Permission denied/i' + => DB_ERROR_ACCESS_VIOLATION, + '/^Reference to un-selected table/i' + => DB_ERROR_SYNTAX, + '/^syntax error/i' + => DB_ERROR_SYNTAX, + '/^Table .* exists$/i' + => DB_ERROR_ALREADY_EXISTS, + '/^Unknown database/i' + => DB_ERROR_NOSUCHDB, + '/^Unknown field/i' + => DB_ERROR_NOSUCHFIELD, + '/^Unknown (index|system variable)/i' + => DB_ERROR_NOT_FOUND, + '/^Unknown table/i' + => DB_ERROR_NOSUCHTABLE, + '/^Unqualified field/i' + => DB_ERROR_SYNTAX, + ); + } + + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::setOption() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @msql_query("SELECT * FROM $result", + $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->raiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @msql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $tmp = @msql_fetch_field($id); + + $flags = ''; + if ($tmp->not_null) { + $flags .= 'not_null '; + } + if ($tmp->unique) { + $flags .= 'unique_key '; + } + $flags = trim($flags); + + $res[$i] = array( + 'table' => $case_func($tmp->table), + 'name' => $case_func($tmp->name), + 'type' => $tmp->type, + 'len' => msql_field_len($id, $i), + 'flags' => $flags, + ); + + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @msql_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtain a list of a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return array the array containing the list of objects requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'databases': + $id = @msql_list_dbs($this->connection); + break; + case 'tables': + $id = @msql_list_tables($this->dsn['database'], + $this->connection); + break; + default: + return null; + } + if (!$id) { + return $this->msqlRaiseError(); + } + $out = array(); + while ($row = @msql_fetch_row($id)) { + $out[] = $row[0]; + } + return $out; + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/mssql.php b/src/www/lib/pear/DB/mssql.php new file mode 100644 index 00000000..b7fb0871 --- /dev/null +++ b/src/www/lib/pear/DB/mssql.php @@ -0,0 +1,914 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: mssql.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's mssql extension + * for interacting with Microsoft SQL Server databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Sterling Hughes + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_mssql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'mssql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'mssql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'emulate', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + // XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX + var $errorcode_map = array( + 110 => DB_ERROR_VALUE_COUNT_ON_ROW, + 155 => DB_ERROR_NOSUCHFIELD, + 170 => DB_ERROR_SYNTAX, + 207 => DB_ERROR_NOSUCHFIELD, + 208 => DB_ERROR_NOSUCHTABLE, + 245 => DB_ERROR_INVALID_NUMBER, + 515 => DB_ERROR_CONSTRAINT_NOT_NULL, + 547 => DB_ERROR_CONSTRAINT, + 1913 => DB_ERROR_ALREADY_EXISTS, + 2627 => DB_ERROR_CONSTRAINT, + 2714 => DB_ERROR_ALREADY_EXISTS, + 3701 => DB_ERROR_NOSUCHTABLE, + 8134 => DB_ERROR_DIVZERO, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The database specified in the DSN + * + * It's a fix to allow calls to different databases in the same script. + * + * @var string + * @access private + */ + var $_db = null; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_mssql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase') + && !PEAR::loadExtension('sybase_ct')) + { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $params = array( + $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost', + $dsn['username'] ? $dsn['username'] : null, + $dsn['password'] ? $dsn['password'] : null, + ); + if ($dsn['port']) { + $params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':') + . $dsn['port']; + } + + $connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect'; + + $this->connection = @call_user_func_array($connect_function, $params); + + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + @mssql_get_last_message()); + } + if ($dsn['database']) { + if (!@mssql_select_db($dsn['database'], $this->connection)) { + return $this->raiseError(DB_ERROR_NODBSELECTED, + null, null, null, + @mssql_get_last_message()); + } + $this->_db = $dsn['database']; + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @mssql_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + if (!@mssql_select_db($this->_db, $this->connection)) { + return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); + } + $query = $this->modifyQuery($query); + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @mssql_query('BEGIN TRAN', $this->connection); + if (!$result) { + return $this->mssqlRaiseError(); + } + } + $this->transaction_opcount++; + } + $result = @mssql_query($query, $this->connection); + if (!$result) { + return $this->mssqlRaiseError(); + } + // Determine which queries that should return data, and which + // should return an error code only. + return $ismanip ? DB_OK : $result; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal mssql result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return @mssql_next_result($result); + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@mssql_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @mssql_fetch_array($result, MSSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @mssql_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @mssql_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @mssql_num_fields($result); + if (!$cols) { + return $this->mssqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @mssql_num_rows($result); + if ($rows === false) { + return $this->mssqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + if (!@mssql_select_db($this->_db, $this->connection)) { + return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); + } + $result = @mssql_query('COMMIT TRAN', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mssqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + if (!@mssql_select_db($this->_db, $this->connection)) { + return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); + } + $result = @mssql_query('ROLLBACK TRAN', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mssqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + $res = @mssql_query('select @@rowcount', $this->connection); + if (!$res) { + return $this->mssqlRaiseError(); + } + $ar = @mssql_fetch_row($res); + if (!$ar) { + $result = 0; + } else { + @mssql_free_result($res); + $result = $ar[0]; + } + } else { + $result = 0; + } + return $result; + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_mssql::createSequence(), DB_mssql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + if (!@mssql_select_db($this->_db, $this->connection)) { + return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); + } + $repeat = 0; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) + { + $repeat = 1; + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $this->raiseError($result); + } + } elseif (!DB::isError($result)) { + $result =& $this->query("SELECT @@IDENTITY FROM $seqname"); + $repeat = 0; + } else { + $repeat = false; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $result = $result->fetchRow(DB_FETCHMODE_ORDERED); + return $result[0]; + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_mssql::nextID(), DB_mssql::dropSequence() + */ + function createSequence($seq_name) + { + return $this->query('CREATE TABLE ' + . $this->getSequenceName($seq_name) + . ' ([id] [int] IDENTITY (1, 1) NOT NULL,' + . ' [vapor] [int] NULL)'); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_mssql::nextID(), DB_mssql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * @param string $str identifier name to be quoted + * + * @return string quoted identifier string + * + * @see DB_common::quoteIdentifier() + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + return '[' . str_replace(']', ']]', $str) . ']'; + } + + // }}} + // {{{ mssqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_mssql::errorNative(), DB_mssql::errorCode() + */ + function mssqlRaiseError($code = null) + { + $message = @mssql_get_last_message(); + if (!$code) { + $code = $this->errorNative(); + } + return $this->raiseError($this->errorCode($code, $message), + null, null, null, "$code - $message"); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code + */ + function errorNative() + { + $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection); + if (!$res) { + return DB_ERROR; + } + $row = @mssql_fetch_row($res); + return $row[0]; + } + + // }}} + // {{{ errorCode() + + /** + * Determines PEAR::DB error code from mssql's native codes. + * + * If $nativecode isn't known yet, it will be looked up. + * + * @param mixed $nativecode mssql error code, if known + * @return integer an error number from a DB error constant + * @see errorNative() + */ + function errorCode($nativecode = null, $msg = '') + { + if (!$nativecode) { + $nativecode = $this->errorNative(); + } + if (isset($this->errorcode_map[$nativecode])) { + if ($nativecode == 3701 + && preg_match('/Cannot drop the index/i', $msg)) + { + return DB_ERROR_NOT_FOUND; + } + return $this->errorcode_map[$nativecode]; + } else { + return DB_ERROR; + } + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + if (!@mssql_select_db($this->_db, $this->connection)) { + return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); + } + $id = @mssql_query("SELECT * FROM $result WHERE 1=0", + $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @mssql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func(@mssql_field_name($id, $i)), + 'type' => @mssql_field_type($id, $i), + 'len' => @mssql_field_length($id, $i), + // We only support flags for table + 'flags' => $got_string + ? $this->_mssql_field_flags($result, + @mssql_field_name($id, $i)) + : '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @mssql_free_result($id); + } + return $res; + } + + // }}} + // {{{ _mssql_field_flags() + + /** + * Get a column's flags + * + * Supports "not_null", "primary_key", + * "auto_increment" (mssql identity), "timestamp" (mssql timestamp), + * "unique_key" (mssql unique index, unique check or primary_key) and + * "multiple_key" (multikey index) + * + * mssql timestamp is NOT similar to the mysql timestamp so this is maybe + * not useful at all - is the behaviour of mysql_field_flags that primary + * keys are alway unique? is the interpretation of multiple_key correct? + * + * @param string $table the table name + * @param string $column the field name + * + * @return string the flags + * + * @access private + * @author Joern Barthel + */ + function _mssql_field_flags($table, $column) + { + static $tableName = null; + static $flags = array(); + + if ($table != $tableName) { + + $flags = array(); + $tableName = $table; + + // get unique and primary keys + $res = $this->getAll("EXEC SP_HELPINDEX[$table]", DB_FETCHMODE_ASSOC); + + foreach ($res as $val) { + $keys = explode(', ', $val['index_keys']); + + if (sizeof($keys) > 1) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'multiple_key'); + } + } + + if (strpos($val['index_description'], 'primary key')) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'primary_key'); + } + } elseif (strpos($val['index_description'], 'unique')) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'unique_key'); + } + } + } + + // get auto_increment, not_null and timestamp + $res = $this->getAll("EXEC SP_COLUMNS[$table]", DB_FETCHMODE_ASSOC); + + foreach ($res as $val) { + $val = array_change_key_case($val, CASE_LOWER); + if ($val['nullable'] == '0') { + $this->_add_flag($flags[$val['column_name']], 'not_null'); + } + if (strpos($val['type_name'], 'identity')) { + $this->_add_flag($flags[$val['column_name']], 'auto_increment'); + } + if (strpos($val['type_name'], 'timestamp')) { + $this->_add_flag($flags[$val['column_name']], 'timestamp'); + } + } + } + + if (array_key_exists($column, $flags)) { + return(implode(' ', $flags[$column])); + } + return ''; + } + + // }}} + // {{{ _add_flag() + + /** + * Adds a string to the flags array if the flag is not yet in there + * - if there is no flag present the array is created + * + * @param array &$array the reference to the flag-array + * @param string $value the flag value + * + * @return void + * + * @access private + * @author Joern Barthel + */ + function _add_flag(&$array, $value) + { + if (!is_array($array)) { + $array = array($value); + } elseif (!in_array($value, $array)) { + array_push($array, $value); + } + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return "SELECT name FROM sysobjects WHERE type = 'U'" + . ' ORDER BY name'; + case 'views': + return "SELECT name FROM sysobjects WHERE type = 'V'"; + default: + return null; + } + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/mysql.php b/src/www/lib/pear/DB/mysql.php new file mode 100644 index 00000000..f8c89ea5 --- /dev/null +++ b/src/www/lib/pear/DB/mysql.php @@ -0,0 +1,1034 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: mysql.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's mysql extension + * for interacting with MySQL databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Stig Bakken + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_mysql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'mysql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'mysql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => '4.2.0', + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + 1004 => DB_ERROR_CANNOT_CREATE, + 1005 => DB_ERROR_CANNOT_CREATE, + 1006 => DB_ERROR_CANNOT_CREATE, + 1007 => DB_ERROR_ALREADY_EXISTS, + 1008 => DB_ERROR_CANNOT_DROP, + 1022 => DB_ERROR_ALREADY_EXISTS, + 1044 => DB_ERROR_ACCESS_VIOLATION, + 1046 => DB_ERROR_NODBSELECTED, + 1048 => DB_ERROR_CONSTRAINT, + 1049 => DB_ERROR_NOSUCHDB, + 1050 => DB_ERROR_ALREADY_EXISTS, + 1051 => DB_ERROR_NOSUCHTABLE, + 1054 => DB_ERROR_NOSUCHFIELD, + 1061 => DB_ERROR_ALREADY_EXISTS, + 1062 => DB_ERROR_ALREADY_EXISTS, + 1064 => DB_ERROR_SYNTAX, + 1091 => DB_ERROR_NOT_FOUND, + 1100 => DB_ERROR_NOT_LOCKED, + 1136 => DB_ERROR_VALUE_COUNT_ON_ROW, + 1142 => DB_ERROR_ACCESS_VIOLATION, + 1146 => DB_ERROR_NOSUCHTABLE, + 1216 => DB_ERROR_CONSTRAINT, + 1217 => DB_ERROR_CONSTRAINT, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The database specified in the DSN + * + * It's a fix to allow calls to different databases in the same script. + * + * @var string + * @access private + */ + var $_db = ''; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_mysql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's mysql driver supports the following extra DSN options: + * + new_link If set to true, causes subsequent calls to connect() + * to return a new connection link instead of the + * existing one. WARNING: this is not portable to + * other DBMS's. Available since PEAR DB 1.7.0. + * + client_flags Any combination of MYSQL_CLIENT_* constants. + * Only used if PHP is at version 4.3.0 or greater. + * Available since PEAR DB 1.7.0. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('mysql')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $params = array(); + if ($dsn['protocol'] && $dsn['protocol'] == 'unix') { + $params[0] = ':' . $dsn['socket']; + } else { + $params[0] = $dsn['hostspec'] ? $dsn['hostspec'] + : 'localhost'; + if ($dsn['port']) { + $params[0] .= ':' . $dsn['port']; + } + } + $params[] = $dsn['username'] ? $dsn['username'] : null; + $params[] = $dsn['password'] ? $dsn['password'] : null; + + if (!$persistent) { + if (isset($dsn['new_link']) + && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) + { + $params[] = true; + } else { + $params[] = false; + } + } + if (version_compare(phpversion(), '4.3.0', '>=')) { + $params[] = isset($dsn['client_flags']) + ? $dsn['client_flags'] : null; + } + + $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; + + $ini = ini_get('track_errors'); + $php_errormsg = ''; + if ($ini) { + $this->connection = @call_user_func_array($connect_function, + $params); + } else { + ini_set('track_errors', 1); + $this->connection = @call_user_func_array($connect_function, + $params); + ini_set('track_errors', $ini); + } + + if (!$this->connection) { + if (($err = @mysql_error()) != '') { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $err); + } else { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + } + + if ($dsn['database']) { + if (!@mysql_select_db($dsn['database'], $this->connection)) { + return $this->mysqlRaiseError(); + } + $this->_db = $dsn['database']; + } + + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @mysql_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * Generally uses mysql_query(). If you want to use + * mysql_unbuffered_query() set the "result_buffering" option to 0 using + * setOptions(). This option was added in Release 1.7.0. + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @mysql_query('SET AUTOCOMMIT=0', $this->connection); + $result = @mysql_query('BEGIN', $this->connection); + if (!$result) { + return $this->mysqlRaiseError(); + } + } + $this->transaction_opcount++; + } + if (!$this->options['result_buffering']) { + $result = @mysql_unbuffered_query($query, $this->connection); + } else { + $result = @mysql_query($query, $this->connection); + } + if (!$result) { + return $this->mysqlRaiseError(); + } + if (is_resource($result)) { + return $result; + } + return DB_OK; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal mysql result pointer to the next available result + * + * This method has not been implemented yet. + * + * @param a valid sql result resource + * + * @return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@mysql_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @mysql_fetch_array($result, MYSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @mysql_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + /* + * Even though this DBMS already trims output, we do this because + * a field might have intentional whitespace at the end that + * gets removed by DB_PORTABILITY_RTRIM under another driver. + */ + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @mysql_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @mysql_num_fields($result); + if (!$cols) { + return $this->mysqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @mysql_num_rows($result); + if ($rows === null) { + return $this->mysqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + $result = @mysql_query('COMMIT', $this->connection); + $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mysqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + $result = @mysql_query('ROLLBACK', $this->connection); + $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mysqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + return @mysql_affected_rows($this->connection); + } else { + return 0; + } + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_mysql::createSequence(), DB_mysql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + do { + $repeat = 0; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("UPDATE ${seqname} ". + 'SET id=LAST_INSERT_ID(id+1)'); + $this->popErrorHandling(); + if ($result === DB_OK) { + // COMMON CASE + $id = @mysql_insert_id($this->connection); + if ($id != 0) { + return $id; + } + // EMPTY SEQ TABLE + // Sequence table must be empty for some reason, so fill + // it and return 1 and obtain a user-level lock + $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + if ($result == 0) { + // Failed to get the lock + return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); + } + + // add the default value + $result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + + // Release the lock + $result = $this->getOne('SELECT RELEASE_LOCK(' + . "'${seqname}_lock')"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + // We know what the result will be, so no need to try again + return 1; + + } elseif ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) + { + // ONDEMAND TABLE CREATION + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $this->raiseError($result); + } else { + $repeat = 1; + } + + } elseif (DB::isError($result) && + $result->getCode() == DB_ERROR_ALREADY_EXISTS) + { + // BACKWARDS COMPAT + // see _BCsequence() comment + $result = $this->_BCsequence($seqname); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $repeat = 1; + } + } while ($repeat); + + return $this->raiseError($result); + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_mysql::nextID(), DB_mysql::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $res = $this->query('CREATE TABLE ' . $seqname + . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' + . ' PRIMARY KEY(id))'); + if (DB::isError($res)) { + return $res; + } + // insert yields value 1, nextId call will generate ID 2 + $res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); + if (DB::isError($res)) { + return $res; + } + // so reset to zero + return $this->query("UPDATE ${seqname} SET id = 0"); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_mysql::nextID(), DB_mysql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ _BCsequence() + + /** + * Backwards compatibility with old sequence emulation implementation + * (clean up the dupes) + * + * @param string $seqname the sequence name to clean up + * + * @return bool true on success. A DB_Error object on failure. + * + * @access private + */ + function _BCsequence($seqname) + { + // Obtain a user-level lock... this will release any previous + // application locks, but unlike LOCK TABLES, it does not abort + // the current transaction and is much less frequently used. + $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); + if (DB::isError($result)) { + return $result; + } + if ($result == 0) { + // Failed to get the lock, can't do the conversion, bail + // with a DB_ERROR_NOT_LOCKED error + return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); + } + + $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); + if (DB::isError($highest_id)) { + return $highest_id; + } + // This should kill all rows except the highest + // We should probably do something if $highest_id isn't + // numeric, but I'm at a loss as how to handle that... + $result = $this->query('DELETE FROM ' . $seqname + . " WHERE id <> $highest_id"); + if (DB::isError($result)) { + return $result; + } + + // If another thread has been waiting for this lock, + // it will go thru the above procedure, but will have no + // real effect + $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); + if (DB::isError($result)) { + return $result; + } + return true; + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * MySQL can't handle the backtick character (`) in + * table or column names. + * + * @param string $str identifier name to be quoted + * + * @return string quoted identifier string + * + * @see DB_common::quoteIdentifier() + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + return '`' . $str . '`'; + } + + // }}} + // {{{ quote() + + /** + * @deprecated Deprecated in release 1.6.0 + */ + function quote($str) + { + return $this->quoteSmart($str); + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + if (function_exists('mysql_real_escape_string')) { + return @mysql_real_escape_string($str, $this->connection); + } else { + return @mysql_escape_string($str); + } + } + + // }}} + // {{{ modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * This little hack lets you know how many rows were deleted + * when running a "DELETE FROM table" query. Only implemented + * if the DB_PORTABILITY_DELETE_COUNT portability option is on. + * + * @param string $query the query string to modify + * + * @return string the modified query string + * + * @access protected + * @see DB_common::setOption() + */ + function modifyQuery($query) + { + if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { + // "DELETE FROM table" gives 0 affected rows in MySQL. + // This little hack lets you know how many rows were deleted. + if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { + $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', + 'DELETE FROM \1 WHERE 1=1', $query); + } + } + return $query; + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + if (DB::isManip($query)) { + return $query . " LIMIT $count"; + } else { + return $query . " LIMIT $from, $count"; + } + } + + // }}} + // {{{ mysqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_mysql::errorNative(), DB_common::errorCode() + */ + function mysqlRaiseError($errno = null) + { + if ($errno === null) { + if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { + $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; + $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; + $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; + } else { + // Doing this in case mode changes during runtime. + $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; + $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; + $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; + } + $errno = $this->errorCode(mysql_errno($this->connection)); + } + return $this->raiseError($errno, null, null, null, + @mysql_errno($this->connection) . ' ** ' . + @mysql_error($this->connection)); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code + */ + function errorNative() + { + return @mysql_errno($this->connection); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @mysql_list_fields($this->dsn['database'], + $result, $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @mysql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $case_func(@mysql_field_table($id, $i)), + 'name' => $case_func(@mysql_field_name($id, $i)), + 'type' => @mysql_field_type($id, $i), + 'len' => @mysql_field_len($id, $i), + 'flags' => @mysql_field_flags($id, $i), + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @mysql_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SHOW TABLES'; + case 'users': + return 'SELECT DISTINCT User FROM mysql.user'; + case 'databases': + return 'SHOW DATABASES'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/mysqli.php b/src/www/lib/pear/DB/mysqli.php new file mode 100644 index 00000000..e1e96ecc --- /dev/null +++ b/src/www/lib/pear/DB/mysqli.php @@ -0,0 +1,1076 @@ + + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: mysqli.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's mysqli extension + * for interacting with MySQL databases + * + * This is for MySQL versions 4.1 and above. Requires PHP 5. + * + * Note that persistent connections no longer exist. + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + * @since Class functional since Release 1.6.3 + */ +class DB_mysqli extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'mysqli'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'mysqli'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => false, + 'prepare' => false, + 'ssl' => true, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + 1004 => DB_ERROR_CANNOT_CREATE, + 1005 => DB_ERROR_CANNOT_CREATE, + 1006 => DB_ERROR_CANNOT_CREATE, + 1007 => DB_ERROR_ALREADY_EXISTS, + 1008 => DB_ERROR_CANNOT_DROP, + 1022 => DB_ERROR_ALREADY_EXISTS, + 1044 => DB_ERROR_ACCESS_VIOLATION, + 1046 => DB_ERROR_NODBSELECTED, + 1048 => DB_ERROR_CONSTRAINT, + 1049 => DB_ERROR_NOSUCHDB, + 1050 => DB_ERROR_ALREADY_EXISTS, + 1051 => DB_ERROR_NOSUCHTABLE, + 1054 => DB_ERROR_NOSUCHFIELD, + 1061 => DB_ERROR_ALREADY_EXISTS, + 1062 => DB_ERROR_ALREADY_EXISTS, + 1064 => DB_ERROR_SYNTAX, + 1091 => DB_ERROR_NOT_FOUND, + 1100 => DB_ERROR_NOT_LOCKED, + 1136 => DB_ERROR_VALUE_COUNT_ON_ROW, + 1142 => DB_ERROR_ACCESS_VIOLATION, + 1146 => DB_ERROR_NOSUCHTABLE, + 1216 => DB_ERROR_CONSTRAINT, + 1217 => DB_ERROR_CONSTRAINT, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The database specified in the DSN + * + * It's a fix to allow calls to different databases in the same script. + * + * @var string + * @access private + */ + var $_db = ''; + + /** + * Array for converting MYSQLI_*_FLAG constants to text values + * @var array + * @access public + * @since Property available since Release 1.6.5 + */ + var $mysqli_flags = array( + MYSQLI_NOT_NULL_FLAG => 'not_null', + MYSQLI_PRI_KEY_FLAG => 'primary_key', + MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', + MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', + MYSQLI_BLOB_FLAG => 'blob', + MYSQLI_UNSIGNED_FLAG => 'unsigned', + MYSQLI_ZEROFILL_FLAG => 'zerofill', + MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', + MYSQLI_TIMESTAMP_FLAG => 'timestamp', + MYSQLI_SET_FLAG => 'set', + // MYSQLI_NUM_FLAG => 'numeric', // unnecessary + // MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie + MYSQLI_GROUP_FLAG => 'group_by' + ); + + /** + * Array for converting MYSQLI_TYPE_* constants to text values + * @var array + * @access public + * @since Property available since Release 1.6.5 + */ + var $mysqli_types = array( + MYSQLI_TYPE_DECIMAL => 'decimal', + MYSQLI_TYPE_TINY => 'tinyint', + MYSQLI_TYPE_SHORT => 'int', + MYSQLI_TYPE_LONG => 'int', + MYSQLI_TYPE_FLOAT => 'float', + MYSQLI_TYPE_DOUBLE => 'double', + // MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it + MYSQLI_TYPE_TIMESTAMP => 'timestamp', + MYSQLI_TYPE_LONGLONG => 'bigint', + MYSQLI_TYPE_INT24 => 'mediumint', + MYSQLI_TYPE_DATE => 'date', + MYSQLI_TYPE_TIME => 'time', + MYSQLI_TYPE_DATETIME => 'datetime', + MYSQLI_TYPE_YEAR => 'year', + MYSQLI_TYPE_NEWDATE => 'date', + MYSQLI_TYPE_ENUM => 'enum', + MYSQLI_TYPE_SET => 'set', + MYSQLI_TYPE_TINY_BLOB => 'tinyblob', + MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob', + MYSQLI_TYPE_LONG_BLOB => 'longblob', + MYSQLI_TYPE_BLOB => 'blob', + MYSQLI_TYPE_VAR_STRING => 'varchar', + MYSQLI_TYPE_STRING => 'char', + MYSQLI_TYPE_GEOMETRY => 'geometry', + ); + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_mysqli() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's mysqli driver supports the following extra DSN options: + * + When the 'ssl' $option passed to DB::connect() is true: + * + key The path to the key file. + * + cert The path to the certificate file. + * + ca The path to the certificate authority file. + * + capath The path to a directory that contains trusted SSL + * CA certificates in pem format. + * + cipher The list of allowable ciphers for SSL encryption. + * + * Example of how to connect using SSL: + * + * require_once 'DB.php'; + * + * $dsn = array( + * 'phptype' => 'mysqli', + * 'username' => 'someuser', + * 'password' => 'apasswd', + * 'hostspec' => 'localhost', + * 'database' => 'thedb', + * 'key' => 'client-key.pem', + * 'cert' => 'client-cert.pem', + * 'ca' => 'cacert.pem', + * 'capath' => '/path/to/ca/dir', + * 'cipher' => 'AES', + * ); + * + * $options = array( + * 'ssl' => true, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('mysqli')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $ini = ini_get('track_errors'); + ini_set('track_errors', 1); + $php_errormsg = ''; + + if ($this->getOption('ssl') === true) { + $init = mysqli_init(); + mysqli_ssl_set( + $init, + empty($dsn['key']) ? null : $dsn['key'], + empty($dsn['cert']) ? null : $dsn['cert'], + empty($dsn['ca']) ? null : $dsn['ca'], + empty($dsn['capath']) ? null : $dsn['capath'], + empty($dsn['cipher']) ? null : $dsn['cipher'] + ); + if ($this->connection = @mysqli_real_connect( + $init, + $dsn['hostspec'], + $dsn['username'], + $dsn['password'], + $dsn['database'], + $dsn['port'], + $dsn['socket'])) + { + $this->connection = $init; + } + } else { + $this->connection = @mysqli_connect( + $dsn['hostspec'], + $dsn['username'], + $dsn['password'], + $dsn['database'], + $dsn['port'], + $dsn['socket'] + ); + } + + ini_set('track_errors', $ini); + + if (!$this->connection) { + if (($err = @mysqli_connect_error()) != '') { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $err); + } else { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + } + + if ($dsn['database']) { + $this->_db = $dsn['database']; + } + + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @mysqli_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + if ($this->_db) { + if (!@mysqli_select_db($this->connection, $this->_db)) { + return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); + } + } + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=0'); + $result = @mysqli_query($this->connection, 'BEGIN'); + if (!$result) { + return $this->mysqliRaiseError(); + } + } + $this->transaction_opcount++; + } + $result = @mysqli_query($this->connection, $query); + if (!$result) { + return $this->mysqliRaiseError(); + } + if (is_object($result)) { + return $result; + } + return DB_OK; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal mysql result pointer to the next available result. + * + * This method has not been implemented yet. + * + * @param resource $result a valid sql result resource + * @return false + * @access public + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@mysqli_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @mysqli_fetch_array($result, MYSQLI_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @mysqli_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + /* + * Even though this DBMS already trims output, we do this because + * a field might have intentional whitespace at the end that + * gets removed by DB_PORTABILITY_RTRIM under another driver. + */ + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @mysqli_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @mysqli_num_fields($result); + if (!$cols) { + return $this->mysqliRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @mysqli_num_rows($result); + if ($rows === null) { + return $this->mysqliRaiseError(); + } + return $rows; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + if ($this->_db) { + if (!@mysqli_select_db($this->connection, $this->_db)) { + return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); + } + } + $result = @mysqli_query($this->connection, 'COMMIT'); + $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1'); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mysqliRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + if ($this->_db) { + if (!@mysqli_select_db($this->connection, $this->_db)) { + return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); + } + } + $result = @mysqli_query($this->connection, 'ROLLBACK'); + $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1'); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mysqliRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + return @mysqli_affected_rows($this->connection); + } else { + return 0; + } + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_mysqli::createSequence(), DB_mysqli::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + do { + $repeat = 0; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query('UPDATE ' . $seqname + . ' SET id = LAST_INSERT_ID(id + 1)'); + $this->popErrorHandling(); + if ($result === DB_OK) { + // COMMON CASE + $id = @mysqli_insert_id($this->connection); + if ($id != 0) { + return $id; + } + + // EMPTY SEQ TABLE + // Sequence table must be empty for some reason, + // so fill it and return 1 + // Obtain a user-level lock + $result = $this->getOne('SELECT GET_LOCK(' + . "'${seqname}_lock', 10)"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + if ($result == 0) { + return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED); + } + + // add the default value + $result = $this->query('REPLACE INTO ' . $seqname + . ' (id) VALUES (0)'); + if (DB::isError($result)) { + return $this->raiseError($result); + } + + // Release the lock + $result = $this->getOne('SELECT RELEASE_LOCK(' + . "'${seqname}_lock')"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + // We know what the result will be, so no need to try again + return 1; + + } elseif ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) + { + // ONDEMAND TABLE CREATION + $result = $this->createSequence($seq_name); + + // Since createSequence initializes the ID to be 1, + // we do not need to retrieve the ID again (or we will get 2) + if (DB::isError($result)) { + return $this->raiseError($result); + } else { + // First ID of a newly created sequence is 1 + return 1; + } + + } elseif (DB::isError($result) && + $result->getCode() == DB_ERROR_ALREADY_EXISTS) + { + // BACKWARDS COMPAT + // see _BCsequence() comment + $result = $this->_BCsequence($seqname); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $repeat = 1; + } + } while ($repeat); + + return $this->raiseError($result); + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_mysqli::nextID(), DB_mysqli::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $res = $this->query('CREATE TABLE ' . $seqname + . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' + . ' PRIMARY KEY(id))'); + if (DB::isError($res)) { + return $res; + } + // insert yields value 1, nextId call will generate ID 2 + return $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_mysql::nextID(), DB_mysql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ _BCsequence() + + /** + * Backwards compatibility with old sequence emulation implementation + * (clean up the dupes) + * + * @param string $seqname the sequence name to clean up + * + * @return bool true on success. A DB_Error object on failure. + * + * @access private + */ + function _BCsequence($seqname) + { + // Obtain a user-level lock... this will release any previous + // application locks, but unlike LOCK TABLES, it does not abort + // the current transaction and is much less frequently used. + $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); + if (DB::isError($result)) { + return $result; + } + if ($result == 0) { + // Failed to get the lock, can't do the conversion, bail + // with a DB_ERROR_NOT_LOCKED error + return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED); + } + + $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); + if (DB::isError($highest_id)) { + return $highest_id; + } + + // This should kill all rows except the highest + // We should probably do something if $highest_id isn't + // numeric, but I'm at a loss as how to handle that... + $result = $this->query('DELETE FROM ' . $seqname + . " WHERE id <> $highest_id"); + if (DB::isError($result)) { + return $result; + } + + // If another thread has been waiting for this lock, + // it will go thru the above procedure, but will have no + // real effect + $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); + if (DB::isError($result)) { + return $result; + } + return true; + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * MySQL can't handle the backtick character (`) in + * table or column names. + * + * @param string $str identifier name to be quoted + * + * @return string quoted identifier string + * + * @see DB_common::quoteIdentifier() + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + return '`' . $str . '`'; + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + return @mysqli_real_escape_string($this->connection, $str); + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + if (DB::isManip($query)) { + return $query . " LIMIT $count"; + } else { + return $query . " LIMIT $from, $count"; + } + } + + // }}} + // {{{ mysqliRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_mysqli::errorNative(), DB_common::errorCode() + */ + function mysqliRaiseError($errno = null) + { + if ($errno === null) { + if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { + $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; + $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; + $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; + } else { + // Doing this in case mode changes during runtime. + $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; + $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; + $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; + } + $errno = $this->errorCode(mysqli_errno($this->connection)); + } + return $this->raiseError($errno, null, null, null, + @mysqli_errno($this->connection) . ' ** ' . + @mysqli_error($this->connection)); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code + */ + function errorNative() + { + return @mysqli_errno($this->connection); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::setOption() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @mysqli_query($this->connection, + "SELECT * FROM $result LIMIT 0"); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_a($id, 'mysqli_result')) { + return $this->mysqliRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @mysqli_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $tmp = @mysqli_fetch_field($id); + + $flags = ''; + foreach ($this->mysqli_flags as $const => $means) { + if ($tmp->flags & $const) { + $flags .= $means . ' '; + } + } + if ($tmp->def) { + $flags .= 'default_' . rawurlencode($tmp->def); + } + $flags = trim($flags); + + $res[$i] = array( + 'table' => $case_func($tmp->table), + 'name' => $case_func($tmp->name), + 'type' => isset($this->mysqli_types[$tmp->type]) + ? $this->mysqli_types[$tmp->type] + : 'unknown', + 'len' => $tmp->max_length, + 'flags' => $flags, + ); + + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @mysqli_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SHOW TABLES'; + case 'users': + return 'SELECT DISTINCT User FROM mysql.user'; + case 'databases': + return 'SHOW DATABASES'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/oci8.php b/src/www/lib/pear/DB/oci8.php new file mode 100644 index 00000000..b3638964 --- /dev/null +++ b/src/www/lib/pear/DB/oci8.php @@ -0,0 +1,1117 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: oci8.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's oci8 extension + * for interacting with Oracle databases + * + * Definitely works with versions 8 and 9 of Oracle. + * + * These methods overload the ones declared in DB_common. + * + * Be aware... OCIError() only appears to return anything when given a + * statement, so functions return the generic DB_ERROR instead of more + * useful errors that have to do with feedback from the database. + * + * @category Database + * @package DB + * @author James L. Pine + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_oci8 extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'oci8'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'oci8'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => '5.0.0', + 'numrows' => 'subquery', + 'pconnect' => true, + 'prepare' => true, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + 1 => DB_ERROR_CONSTRAINT, + 900 => DB_ERROR_SYNTAX, + 904 => DB_ERROR_NOSUCHFIELD, + 913 => DB_ERROR_VALUE_COUNT_ON_ROW, + 921 => DB_ERROR_SYNTAX, + 923 => DB_ERROR_SYNTAX, + 942 => DB_ERROR_NOSUCHTABLE, + 955 => DB_ERROR_ALREADY_EXISTS, + 1400 => DB_ERROR_CONSTRAINT_NOT_NULL, + 1401 => DB_ERROR_INVALID, + 1407 => DB_ERROR_CONSTRAINT_NOT_NULL, + 1418 => DB_ERROR_NOT_FOUND, + 1476 => DB_ERROR_DIVZERO, + 1722 => DB_ERROR_INVALID_NUMBER, + 2289 => DB_ERROR_NOSUCHTABLE, + 2291 => DB_ERROR_CONSTRAINT, + 2292 => DB_ERROR_CONSTRAINT, + 2449 => DB_ERROR_CONSTRAINT, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * Stores the $data passed to execute() in the oci8 driver + * + * Gets reset to array() when simpleQuery() is run. + * + * Needed in case user wants to call numRows() after prepare/execute + * was used. + * + * @var array + * @access private + */ + var $_data = array(); + + /** + * The result or statement handle from the most recently executed query + * @var resource + */ + var $last_stmt; + + /** + * Is the given prepared statement a data manipulation query? + * @var array + * @access private + */ + var $manip_query = array(); + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_oci8() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * If PHP is at version 5.0.0 or greater: + * + Generally, oci_connect() or oci_pconnect() are used. + * + But if the new_link DSN option is set to true, oci_new_connect() + * is used. + * + * When using PHP version 4.x, OCILogon() or OCIPLogon() are used. + * + * PEAR DB's oci8 driver supports the following extra DSN options: + * + charset The character set to be used on the connection. + * Only used if PHP is at version 5.0.0 or greater + * and the Oracle server is at 9.2 or greater. + * Available since PEAR DB 1.7.0. + * + new_link If set to true, causes subsequent calls to + * connect() to return a new connection link + * instead of the existing one. WARNING: this is + * not portable to other DBMS's. + * Available since PEAR DB 1.7.0. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('oci8')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + if (function_exists('oci_connect')) { + if (isset($dsn['new_link']) + && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) + { + $connect_function = 'oci_new_connect'; + } else { + $connect_function = $persistent ? 'oci_pconnect' + : 'oci_connect'; + } + + // Backwards compatibility with DB < 1.7.0 + if (empty($dsn['database']) && !empty($dsn['hostspec'])) { + $db = $dsn['hostspec']; + } else { + $db = $dsn['database']; + } + + $char = empty($dsn['charset']) ? null : $dsn['charset']; + $this->connection = @$connect_function($dsn['username'], + $dsn['password'], + $db, + $char); + $error = OCIError(); + if (!empty($error) && $error['code'] == 12541) { + // Couldn't find TNS listener. Try direct connection. + $this->connection = @$connect_function($dsn['username'], + $dsn['password'], + null, + $char); + } + } else { + $connect_function = $persistent ? 'OCIPLogon' : 'OCILogon'; + if ($dsn['hostspec']) { + $this->connection = @$connect_function($dsn['username'], + $dsn['password'], + $dsn['hostspec']); + } elseif ($dsn['username'] || $dsn['password']) { + $this->connection = @$connect_function($dsn['username'], + $dsn['password']); + } + } + + if (!$this->connection) { + $error = OCIError(); + $error = (is_array($error)) ? $error['message'] : null; + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $error); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + if (function_exists('oci_close')) { + $ret = @oci_close($this->connection); + } else { + $ret = @OCILogOff($this->connection); + } + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * To determine how many rows of a result set get buffered using + * ocisetprefetch(), see the "result_buffering" option in setOptions(). + * This option was added in Release 1.7.0. + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $this->_data = array(); + $this->last_parameters = array(); + $this->last_query = $query; + $query = $this->modifyQuery($query); + $result = @OCIParse($this->connection, $query); + if (!$result) { + return $this->oci8RaiseError(); + } + if ($this->autocommit) { + $success = @OCIExecute($result,OCI_COMMIT_ON_SUCCESS); + } else { + $success = @OCIExecute($result,OCI_DEFAULT); + } + if (!$success) { + return $this->oci8RaiseError($result); + } + $this->last_stmt = $result; + if (DB::isManip($query)) { + return DB_OK; + } else { + @ocisetprefetch($result, $this->options['result_buffering']); + return $result; + } + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal oracle result pointer to the next available result + * + * @param a valid oci8 result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $moredata = @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && + $moredata) + { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $moredata = OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS); + } + if (!$moredata) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @OCIFreeStatement($result); + } + + /** + * Frees the internal resources associated with a prepared query + * + * @param resource $stmt the prepared statement's resource + * @param bool $free_resource should the PHP resource be freed too? + * Use false if you need to get data + * from the result set later. + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_oci8::prepare() + */ + function freePrepared($stmt, $free_resource = true) + { + if (!is_resource($stmt)) { + return false; + } + if ($free_resource) { + @ocifreestatement($stmt); + } + if (isset($this->prepare_types[(int)$stmt])) { + unset($this->prepare_types[(int)$stmt]); + unset($this->manip_query[(int)$stmt]); + } else { + return false; + } + return true; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * Only works if the DB_PORTABILITY_NUMROWS portability option + * is turned on. + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows(), DB_common::setOption() + */ + function numRows($result) + { + // emulate numRows for Oracle. yuck. + if ($this->options['portability'] & DB_PORTABILITY_NUMROWS && + $result === $this->last_stmt) + { + $countquery = 'SELECT COUNT(*) FROM ('.$this->last_query.')'; + $save_query = $this->last_query; + $save_stmt = $this->last_stmt; + + if (count($this->_data)) { + $smt = $this->prepare('SELECT COUNT(*) FROM ('.$this->last_query.')'); + $count = $this->execute($smt, $this->_data); + } else { + $count =& $this->query($countquery); + } + + if (DB::isError($count) || + DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED))) + { + $this->last_query = $save_query; + $this->last_stmt = $save_stmt; + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + return $row[0]; + } + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @OCINumCols($result); + if (!$cols) { + return $this->oci8RaiseError($result); + } + return $cols; + } + + // }}} + // {{{ prepare() + + /** + * Prepares a query for multiple execution with execute(). + * + * With oci8, this is emulated. + * + * prepare() requires a generic query as string like + * INSERT INTO numbers VALUES (?, ?, ?) + * . The ? characters are placeholders. + * + * Three types of placeholders can be used: + * + ? a quoted scalar value, i.e. strings, integers + * + ! value is inserted 'as is' + * + & requires a file name. The file's contents get + * inserted into the query (i.e. saving binary + * data in a db) + * + * Use backslashes to escape placeholder characters if you don't want + * them to be interpreted as placeholders. Example: + * "UPDATE foo SET col=? WHERE col='over \& under'" + * + * + * @param string $query the query to be prepared + * + * @return mixed DB statement resource on success. DB_Error on failure. + * + * @see DB_oci8::execute() + */ + function prepare($query) + { + $tokens = preg_split('/((? $val) { + switch ($val) { + case '?': + $types[$token++] = DB_PARAM_SCALAR; + unset($tokens[$key]); + break; + case '&': + $types[$token++] = DB_PARAM_OPAQUE; + unset($tokens[$key]); + break; + case '!': + $types[$token++] = DB_PARAM_MISC; + unset($tokens[$key]); + break; + default: + $tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val); + if ($key != $binds) { + $newquery .= $tokens[$key] . ':bind' . $token; + } else { + $newquery .= $tokens[$key]; + } + } + } + + $this->last_query = $query; + $newquery = $this->modifyQuery($newquery); + if (!$stmt = @OCIParse($this->connection, $newquery)) { + return $this->oci8RaiseError(); + } + $this->prepare_types[(int)$stmt] = $types; + $this->manip_query[(int)$stmt] = DB::isManip($query); + return $stmt; + } + + // }}} + // {{{ execute() + + /** + * Executes a DB statement prepared with prepare(). + * + * To determine how many rows of a result set get buffered using + * ocisetprefetch(), see the "result_buffering" option in setOptions(). + * This option was added in Release 1.7.0. + * + * @param resource $stmt a DB statement resource returned from prepare() + * @param mixed $data array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 for non-array items or the + * quantity of elements in the array. + * + * @return mixed returns an oic8 result resource for successful SELECT + * queries, DB_OK for other successful queries. + * A DB error object is returned on failure. + * + * @see DB_oci8::prepare() + */ + function &execute($stmt, $data = array()) + { + $data = (array)$data; + $this->last_parameters = $data; + $this->_data = $data; + + $types =& $this->prepare_types[(int)$stmt]; + if (count($types) != count($data)) { + $tmp =& $this->raiseError(DB_ERROR_MISMATCH); + return $tmp; + } + + $i = 0; + foreach ($data as $key => $value) { + if ($types[$i] == DB_PARAM_MISC) { + /* + * Oracle doesn't seem to have the ability to pass a + * parameter along unchanged, so strip off quotes from start + * and end, plus turn two single quotes to one single quote, + * in order to avoid the quotes getting escaped by + * Oracle and ending up in the database. + */ + $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]); + $data[$key] = str_replace("''", "'", $data[$key]); + } elseif ($types[$i] == DB_PARAM_OPAQUE) { + $fp = @fopen($data[$key], 'rb'); + if (!$fp) { + $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION); + return $tmp; + } + $data[$key] = fread($fp, filesize($data[$key])); + fclose($fp); + } + if (!@OCIBindByName($stmt, ':bind' . $i, $data[$key], -1)) { + $tmp = $this->oci8RaiseError($stmt); + return $tmp; + } + $i++; + } + if ($this->autocommit) { + $success = @OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS); + } else { + $success = @OCIExecute($stmt, OCI_DEFAULT); + } + if (!$success) { + $tmp = $this->oci8RaiseError($stmt); + return $tmp; + } + $this->last_stmt = $stmt; + if ($this->manip_query[(int)$stmt]) { + $tmp = DB_OK; + } else { + @ocisetprefetch($stmt, $this->options['result_buffering']); + $tmp =& new DB_result($this, $stmt); + } + return $tmp; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + $this->autocommit = (bool)$onoff;; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + $result = @OCICommit($this->connection); + if (!$result) { + return $this->oci8RaiseError(); + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + $result = @OCIRollback($this->connection); + if (!$result) { + return $this->oci8RaiseError(); + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if ($this->last_stmt === false) { + return $this->oci8RaiseError(); + } + $result = @OCIRowCount($this->last_stmt); + if ($result === false) { + return $this->oci8RaiseError($this->last_stmt); + } + return $result; + } + + // }}} + // {{{ modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle. + * + * @param string $query the query string to modify + * + * @return string the modified query string + * + * @access protected + */ + function modifyQuery($query) + { + if (preg_match('/^\s*SELECT/i', $query) && + !preg_match('/\sFROM\s/i', $query)) { + $query .= ' FROM dual'; + } + return $query; + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + // Let Oracle return the name of the columns instead of + // coding a "home" SQL parser + + if (count($params)) { + $result = $this->prepare("SELECT * FROM ($query) " + . 'WHERE NULL = NULL'); + $tmp =& $this->execute($result, $params); + } else { + $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL"; + + if (!$result = @OCIParse($this->connection, $q_fields)) { + $this->last_query = $q_fields; + return $this->oci8RaiseError(); + } + if (!@OCIExecute($result, OCI_DEFAULT)) { + $this->last_query = $q_fields; + return $this->oci8RaiseError($result); + } + } + + $ncols = OCINumCols($result); + $cols = array(); + for ( $i = 1; $i <= $ncols; $i++ ) { + $cols[] = '"' . OCIColumnName($result, $i) . '"'; + } + $fields = implode(', ', $cols); + // XXX Test that (tip by John Lim) + //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) { + // // Introduce the FIRST_ROWS Oracle query optimizer + // $query = substr($query, strlen($match[0]), strlen($query)); + // $query = "SELECT /* +FIRST_ROWS */ " . $query; + //} + + // Construct the query + // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2 + // Perhaps this could be optimized with the use of Unions + $query = "SELECT $fields FROM". + " (SELECT rownum as linenum, $fields FROM". + " ($query)". + ' WHERE rownum <= '. ($from + $count) . + ') WHERE linenum >= ' . ++$from; + return $query; + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_oci8::createSequence(), DB_oci8::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + $repeat = 0; + do { + $this->expectError(DB_ERROR_NOSUCHTABLE); + $result =& $this->query("SELECT ${seqname}.nextval FROM dual"); + $this->popExpect(); + if ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) { + $repeat = 1; + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $this->raiseError($result); + } + } else { + $repeat = 0; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $arr = $result->fetchRow(DB_FETCHMODE_ORDERED); + return $arr[0]; + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_oci8::nextID(), DB_oci8::dropSequence() + */ + function createSequence($seq_name) + { + return $this->query('CREATE SEQUENCE ' + . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_oci8::nextID(), DB_oci8::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP SEQUENCE ' + . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ oci8RaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_oci8::errorNative(), DB_oci8::errorCode() + */ + function oci8RaiseError($errno = null) + { + if ($errno === null) { + $error = @OCIError($this->connection); + return $this->raiseError($this->errorCode($error['code']), + null, null, null, $error['message']); + } elseif (is_resource($errno)) { + $error = @OCIError($errno); + return $this->raiseError($this->errorCode($error['code']), + null, null, null, $error['message']); + } + return $this->raiseError($this->errorCode($errno)); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code. FALSE if the code could not be + * determined + */ + function errorNative() + { + if (is_resource($this->last_stmt)) { + $error = @OCIError($this->last_stmt); + } else { + $error = @OCIError($this->connection); + } + if (is_array($error)) { + return $error['code']; + } + return false; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * NOTE: flags won't contain index information. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $res = array(); + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $result = strtoupper($result); + $q_fields = 'SELECT column_name, data_type, data_length, ' + . 'nullable ' + . 'FROM user_tab_columns ' + . "WHERE table_name='$result' ORDER BY column_id"; + + $this->last_query = $q_fields; + + if (!$stmt = @OCIParse($this->connection, $q_fields)) { + return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA); + } + if (!@OCIExecute($stmt, OCI_DEFAULT)) { + return $this->oci8RaiseError($stmt); + } + + $i = 0; + while (@OCIFetch($stmt)) { + $res[$i] = array( + 'table' => $case_func($result), + 'name' => $case_func(@OCIResult($stmt, 1)), + 'type' => @OCIResult($stmt, 2), + 'len' => @OCIResult($stmt, 3), + 'flags' => (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + $i++; + } + + if ($mode) { + $res['num_fields'] = $i; + } + @OCIFreeStatement($stmt); + + } else { + if (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $result = $result->result; + } + + $res = array(); + + if ($result === $this->last_stmt) { + $count = @OCINumCols($result); + if ($mode) { + $res['num_fields'] = $count; + } + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => '', + 'name' => $case_func(@OCIColumnName($result, $i+1)), + 'type' => @OCIColumnType($result, $i+1), + 'len' => @OCIColumnSize($result, $i+1), + 'flags' => '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + } else { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SELECT table_name FROM user_tables'; + case 'synonyms': + return 'SELECT synonym_name FROM user_synonyms'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/odbc.php b/src/www/lib/pear/DB/odbc.php new file mode 100644 index 00000000..5f65b054 --- /dev/null +++ b/src/www/lib/pear/DB/odbc.php @@ -0,0 +1,883 @@ + + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: odbc.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's odbc extension + * for interacting with databases via ODBC connections + * + * These methods overload the ones declared in DB_common. + * + * More info on ODBC errors could be found here: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp + * + * @category Database + * @package DB + * @author Stig Bakken + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_odbc extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'odbc'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'sql92'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * NOTE: The feature set of the following drivers are different than + * the default: + * + solid: 'transactions' = true + * + navision: 'limit' = false + * + * @var array + */ + var $features = array( + 'limit' => 'emulate', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => false, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + '01004' => DB_ERROR_TRUNCATED, + '07001' => DB_ERROR_MISMATCH, + '21S01' => DB_ERROR_VALUE_COUNT_ON_ROW, + '21S02' => DB_ERROR_MISMATCH, + '22001' => DB_ERROR_INVALID, + '22003' => DB_ERROR_INVALID_NUMBER, + '22005' => DB_ERROR_INVALID_NUMBER, + '22008' => DB_ERROR_INVALID_DATE, + '22012' => DB_ERROR_DIVZERO, + '23000' => DB_ERROR_CONSTRAINT, + '23502' => DB_ERROR_CONSTRAINT_NOT_NULL, + '23503' => DB_ERROR_CONSTRAINT, + '23504' => DB_ERROR_CONSTRAINT, + '23505' => DB_ERROR_CONSTRAINT, + '24000' => DB_ERROR_INVALID, + '34000' => DB_ERROR_INVALID, + '37000' => DB_ERROR_SYNTAX, + '42000' => DB_ERROR_SYNTAX, + '42601' => DB_ERROR_SYNTAX, + 'IM001' => DB_ERROR_UNSUPPORTED, + 'S0000' => DB_ERROR_NOSUCHTABLE, + 'S0001' => DB_ERROR_ALREADY_EXISTS, + 'S0002' => DB_ERROR_NOSUCHTABLE, + 'S0011' => DB_ERROR_ALREADY_EXISTS, + 'S0012' => DB_ERROR_NOT_FOUND, + 'S0021' => DB_ERROR_ALREADY_EXISTS, + 'S0022' => DB_ERROR_NOSUCHFIELD, + 'S1009' => DB_ERROR_INVALID, + 'S1090' => DB_ERROR_INVALID, + 'S1C00' => DB_ERROR_NOT_CAPABLE, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * The number of rows affected by a data manipulation query + * @var integer + * @access private + */ + var $affected = 0; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_odbc() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's odbc driver supports the following extra DSN options: + * + cursor The type of cursor to be used for this connection. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('odbc')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + switch ($this->dbsyntax) { + case 'access': + case 'db2': + case 'solid': + $this->features['transactions'] = true; + break; + case 'navision': + $this->features['limit'] = false; + } + + /* + * This is hear for backwards compatibility. Should have been using + * 'database' all along, but prior to 1.6.0RC3 'hostspec' was used. + */ + if ($dsn['database']) { + $odbcdsn = $dsn['database']; + } elseif ($dsn['hostspec']) { + $odbcdsn = $dsn['hostspec']; + } else { + $odbcdsn = 'localhost'; + } + + $connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect'; + + if (empty($dsn['cursor'])) { + $this->connection = @$connect_function($odbcdsn, $dsn['username'], + $dsn['password']); + } else { + $this->connection = @$connect_function($odbcdsn, $dsn['username'], + $dsn['password'], + $dsn['cursor']); + } + + if (!is_resource($this->connection)) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $this->errorNative()); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $err = @odbc_close($this->connection); + $this->connection = null; + return $err; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $this->last_query = $query; + $query = $this->modifyQuery($query); + $result = @odbc_exec($this->connection, $query); + if (!$result) { + return $this->odbcRaiseError(); // XXX ERRORMSG + } + // Determine which queries that should return data, and which + // should return an error code only. + if (DB::isManip($query)) { + $this->affected = $result; // For affectedRows() + return DB_OK; + } + $this->affected = 0; + return $result; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal odbc result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return @odbc_next_result($result); + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + $arr = array(); + if ($rownum !== null) { + $rownum++; // ODBC first row is 1 + if (version_compare(phpversion(), '4.2.0', 'ge')) { + $cols = @odbc_fetch_into($result, $arr, $rownum); + } else { + $cols = @odbc_fetch_into($result, $rownum, $arr); + } + } else { + $cols = @odbc_fetch_into($result, $arr); + } + if (!$cols) { + return null; + } + if ($fetchmode !== DB_FETCHMODE_ORDERED) { + for ($i = 0; $i < count($arr); $i++) { + $colName = @odbc_field_name($result, $i+1); + $a[$colName] = $arr[$i]; + } + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $a = array_change_key_case($a, CASE_LOWER); + } + $arr = $a; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @odbc_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @odbc_num_fields($result); + if (!$cols) { + return $this->odbcRaiseError(); + } + return $cols; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (empty($this->affected)) { // In case of SELECT stms + return 0; + } + $nrows = @odbc_num_rows($this->affected); + if ($nrows == -1) { + return $this->odbcRaiseError(); + } + return $nrows; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * Not all ODBC drivers support this functionality. If they don't + * a DB_Error object for DB_ERROR_UNSUPPORTED is returned. + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $nrows = @odbc_num_rows($result); + if ($nrows == -1) { + return $this->odbcRaiseError(DB_ERROR_UNSUPPORTED); + } + if ($nrows === false) { + return $this->odbcRaiseError(); + } + return $nrows; + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked + * "Use ANSI quoted identifiers" when setting up the ODBC data source. + * + * @param string $str identifier name to be quoted + * + * @return string quoted identifier string + * + * @see DB_common::quoteIdentifier() + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + switch ($this->dsn['dbsyntax']) { + case 'access': + return '[' . $str . ']'; + case 'mssql': + case 'sybase': + return '[' . str_replace(']', ']]', $str) . ']'; + case 'mysql': + case 'mysqli': + return '`' . $str . '`'; + default: + return '"' . str_replace('"', '""', $str) . '"'; + } + } + + // }}} + // {{{ quote() + + /** + * @deprecated Deprecated in release 1.6.0 + * @internal + */ + function quote($str) + { + return $this->quoteSmart($str); + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_odbc::createSequence(), DB_odbc::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + $repeat = 0; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("update ${seqname} set id = id + 1"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) { + $repeat = 1; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->createSequence($seq_name); + $this->popErrorHandling(); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $result = $this->query("insert into ${seqname} (id) values(0)"); + } else { + $repeat = 0; + } + } while ($repeat); + + if (DB::isError($result)) { + return $this->raiseError($result); + } + + $result = $this->query("select id from ${seqname}"); + if (DB::isError($result)) { + return $result; + } + + $row = $result->fetchRow(DB_FETCHMODE_ORDERED); + if (DB::isError($row || !$row)) { + return $row; + } + + return $row[0]; + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_odbc::nextID(), DB_odbc::dropSequence() + */ + function createSequence($seq_name) + { + return $this->query('CREATE TABLE ' + . $this->getSequenceName($seq_name) + . ' (id integer NOT NULL,' + . ' PRIMARY KEY(id))'); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_odbc::nextID(), DB_odbc::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + if (!@odbc_autocommit($this->connection, $onoff)) { + return $this->odbcRaiseError(); + } + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if (!@odbc_commit($this->connection)) { + return $this->odbcRaiseError(); + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if (!@odbc_rollback($this->connection)) { + return $this->odbcRaiseError(); + } + return DB_OK; + } + + // }}} + // {{{ odbcRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_odbc::errorNative(), DB_common::errorCode() + */ + function odbcRaiseError($errno = null) + { + if ($errno === null) { + switch ($this->dbsyntax) { + case 'access': + if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { + $this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD; + } else { + // Doing this in case mode changes during runtime. + $this->errorcode_map['07001'] = DB_ERROR_MISMATCH; + } + + $native_code = odbc_error($this->connection); + + // S1000 is for "General Error." Let's be more specific. + if ($native_code == 'S1000') { + $errormsg = odbc_errormsg($this->connection); + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/includes related records.$/i' => DB_ERROR_CONSTRAINT, + '/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL, + ); + } + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $this->raiseError($code, + null, null, null, + $native_code . ' ' . $errormsg); + } + } + $errno = DB_ERROR; + } else { + $errno = $this->errorCode($native_code); + } + break; + default: + $errno = $this->errorCode(odbc_error($this->connection)); + } + } + return $this->raiseError($errno, null, null, null, + $this->errorNative()); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code and message produced by the last query + * + * @return string the DBMS' error code and message + */ + function errorNative() + { + if (!is_resource($this->connection)) { + return @odbc_error() . ' ' . @odbc_errormsg(); + } + return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + * @since Method available since Release 1.7.0 + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @odbc_exec($this->connection, "SELECT * FROM $result"); + if (!$id) { + return $this->odbcRaiseError(); + } + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->odbcRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @odbc_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $col = $i + 1; + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func(@odbc_field_name($id, $col)), + 'type' => @odbc_field_type($id, $col), + 'len' => @odbc_field_len($id, $col), + 'flags' => '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @odbc_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * Thanks to symbol1@gmail.com and Philippe.Jausions@11abacus.com. + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the list of objects requested + * + * @access protected + * @see DB_common::getListOf() + * @since Method available since Release 1.7.0 + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'databases': + if (!function_exists('odbc_data_source')) { + return null; + } + $res = @odbc_data_source($this->connection, SQL_FETCH_FIRST); + if (is_array($res)) { + $out = array($res['server']); + while($res = @odbc_data_source($this->connection, + SQL_FETCH_NEXT)) + { + $out[] = $res['server']; + } + return $out; + } else { + return $this->odbcRaiseError(); + } + break; + case 'tables': + case 'schema.tables': + $keep = 'TABLE'; + break; + case 'views': + $keep = 'VIEW'; + break; + default: + return null; + } + + /* + * Removing non-conforming items in the while loop rather than + * in the odbc_tables() call because some backends choke on this: + * odbc_tables($this->connection, '', '', '', 'TABLE') + */ + $res = @odbc_tables($this->connection); + if (!$res) { + return $this->odbcRaiseError(); + } + $out = array(); + while ($row = odbc_fetch_array($res)) { + if ($row['TABLE_TYPE'] != $keep) { + continue; + } + if ($type == 'schema.tables') { + $out[] = $row['TABLE_SCHEM'] . '.' . $row['TABLE_NAME']; + } else { + $out[] = $row['TABLE_NAME']; + } + } + return $out; + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/pgsql.php b/src/www/lib/pear/DB/pgsql.php new file mode 100644 index 00000000..79d6f235 --- /dev/null +++ b/src/www/lib/pear/DB/pgsql.php @@ -0,0 +1,1097 @@ + + * @author Stig Bakken + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: pgsql.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's pgsql extension + * for interacting with PostgreSQL databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Rui Hirokawa + * @author Stig Bakken + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_pgsql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'pgsql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'pgsql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => '4.3.0', + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => true, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The number of rows affected by a data manipulation query + * @var integer + */ + var $affected = 0; + + /** + * The current row being looked at in fetchInto() + * @var array + * @access private + */ + var $row = array(); + + /** + * The number of rows in a given result set + * @var array + * @access private + */ + var $_num_rows = array(); + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_pgsql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's pgsql driver supports the following extra DSN options: + * + connect_timeout How many seconds to wait for a connection to + * be established. Available since PEAR DB 1.7.0. + * + new_link If set to true, causes subsequent calls to + * connect() to return a new connection link + * instead of the existing one. WARNING: this is + * not portable to other DBMS's. Available only + * if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0. + * + options Command line options to be sent to the server. + * Available since PEAR DB 1.6.4. + * + service Specifies a service name in pg_service.conf that + * holds additional connection parameters. + * Available since PEAR DB 1.7.0. + * + sslmode How should SSL be used when connecting? Values: + * disable, allow, prefer or require. + * Available since PEAR DB 1.7.0. + * + tty This was used to specify where to send server + * debug output. Available since PEAR DB 1.6.4. + * + * Example of connecting to a new link via a socket: + * + * require_once 'DB.php'; + * + * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true'; + * $options = array( + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('pgsql')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp'; + + $params = array(''); + if ($protocol == 'tcp') { + if ($dsn['hostspec']) { + $params[0] .= 'host=' . $dsn['hostspec']; + } + if ($dsn['port']) { + $params[0] .= ' port=' . $dsn['port']; + } + } elseif ($protocol == 'unix') { + // Allow for pg socket in non-standard locations. + if ($dsn['socket']) { + $params[0] .= 'host=' . $dsn['socket']; + } + if ($dsn['port']) { + $params[0] .= ' port=' . $dsn['port']; + } + } + if ($dsn['database']) { + $params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\''; + } + if ($dsn['username']) { + $params[0] .= ' user=\'' . addslashes($dsn['username']) . '\''; + } + if ($dsn['password']) { + $params[0] .= ' password=\'' . addslashes($dsn['password']) . '\''; + } + if (!empty($dsn['options'])) { + $params[0] .= ' options=' . $dsn['options']; + } + if (!empty($dsn['tty'])) { + $params[0] .= ' tty=' . $dsn['tty']; + } + if (!empty($dsn['connect_timeout'])) { + $params[0] .= ' connect_timeout=' . $dsn['connect_timeout']; + } + if (!empty($dsn['sslmode'])) { + $params[0] .= ' sslmode=' . $dsn['sslmode']; + } + if (!empty($dsn['service'])) { + $params[0] .= ' service=' . $dsn['service']; + } + + if (isset($dsn['new_link']) + && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) + { + if (version_compare(phpversion(), '4.3.0', '>=')) { + $params[] = PGSQL_CONNECT_FORCE_NEW; + } + } + + $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect'; + + $ini = ini_get('track_errors'); + $php_errormsg = ''; + if ($ini) { + $this->connection = @call_user_func_array($connect_function, + $params); + } else { + ini_set('track_errors', 1); + $this->connection = @call_user_func_array($connect_function, + $params); + ini_set('track_errors', $ini); + } + + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @pg_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @pg_exec($this->connection, 'begin;'); + if (!$result) { + return $this->pgsqlRaiseError(); + } + } + $this->transaction_opcount++; + } + $result = @pg_exec($this->connection, $query); + if (!$result) { + return $this->pgsqlRaiseError(); + } + // Determine which queries that should return data, and which + // should return an error code only. + if ($ismanip) { + $this->affected = @pg_affected_rows($result); + return DB_OK; + } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|SHOW)\s/si', $query)) { + /* PostgreSQL commands: + ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, + CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, + GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, + REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, + UNLISTEN, UPDATE, VACUUM + */ + $this->row[(int)$result] = 0; // reset the row counter. + $numrows = $this->numRows($result); + if (is_object($numrows)) { + return $numrows; + } + $this->_num_rows[(int)$result] = $numrows; + $this->affected = 0; + return $result; + } else { + $this->affected = 0; + return DB_OK; + } + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal pgsql result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + $result_int = (int)$result; + $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int]; + if ($rownum >= $this->_num_rows[$result_int]) { + return null; + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @pg_fetch_row($result, $rownum); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + $this->row[$result_int] = ++$rownum; + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + if (is_resource($result)) { + unset($this->row[(int)$result]); + unset($this->_num_rows[(int)$result]); + $this->affected = 0; + return @pg_freeresult($result); + } + return false; + } + + // }}} + // {{{ quote() + + /** + * @deprecated Deprecated in release 1.6.0 + * @internal + */ + function quote($str) + { + return $this->quoteSmart($str); + } + + // }}} + // {{{ quoteSmart() + + /** + * Formats input so it can be safely used in a query + * + * @param mixed $in the data to be formatted + * + * @return mixed the formatted data. The format depends on the input's + * PHP type: + * + null = the string NULL + * + boolean = string TRUE or FALSE + * + integer or double = the unquoted number + * + other (including strings and numeric strings) = + * the data escaped according to MySQL's settings + * then encapsulated between single quotes + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 'TRUE' : 'FALSE'; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * {@internal PostgreSQL treats a backslash as an escape character, + * so they are escaped as well. + * + * Not using pg_escape_string() yet because it requires PostgreSQL + * to be at version 7.2 or greater.}} + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + return str_replace("'", "''", str_replace('\\', '\\\\', $str)); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @pg_numfields($result); + if (!$cols) { + return $this->pgsqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @pg_numrows($result); + if ($rows === null) { + return $this->pgsqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + // (disabled) hack to shut up error messages from libpq.a + //@fclose(@fopen("php://stderr", "w")); + $result = @pg_exec($this->connection, 'end;'); + $this->transaction_opcount = 0; + if (!$result) { + return $this->pgsqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + $result = @pg_exec($this->connection, 'abort;'); + $this->transaction_opcount = 0; + if (!$result) { + return $this->pgsqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + return $this->affected; + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_pgsql::createSequence(), DB_pgsql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + $repeat = false; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result =& $this->query("SELECT NEXTVAL('${seqname}')"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) { + $repeat = true; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->createSequence($seq_name); + $this->popErrorHandling(); + if (DB::isError($result)) { + return $this->raiseError($result); + } + } else { + $repeat = false; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $arr = $result->fetchRow(DB_FETCHMODE_ORDERED); + $result->free(); + return $arr[0]; + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_pgsql::nextID(), DB_pgsql::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $result = $this->query("CREATE SEQUENCE ${seqname}"); + return $result; + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_pgsql::nextID(), DB_pgsql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP SEQUENCE ' + . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + return "$query LIMIT $count OFFSET $from"; + } + + // }}} + // {{{ pgsqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_pgsql::errorNative(), DB_pgsql::errorCode() + */ + function pgsqlRaiseError($errno = null) + { + $native = $this->errorNative(); + if ($errno === null) { + $errno = $this->errorCode($native); + } + return $this->raiseError($errno, null, null, null, $native); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error message produced by the last query + * + * {@internal Error messages are used instead of error codes + * in order to support older versions of PostgreSQL.}} + * + * @return string the DBMS' error message + */ + function errorNative() + { + return @pg_errormessage($this->connection); + } + + // }}} + // {{{ errorCode() + + /** + * Determines PEAR::DB error code from the database's text error message. + * + * @param string $errormsg error message returned from the database + * @return integer an error number from a DB error constant + */ + function errorCode($errormsg) + { + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/(relation|sequence|table).*does not exist|class .* not found/i' + => DB_ERROR_NOSUCHTABLE, + '/index .* does not exist/' + => DB_ERROR_NOT_FOUND, + '/column .* does not exist/i' + => DB_ERROR_NOSUCHFIELD, + '/relation .* already exists/i' + => DB_ERROR_ALREADY_EXISTS, + '/(divide|division) by zero$/i' + => DB_ERROR_DIVZERO, + '/pg_atoi: error in .*: can\'t parse /i' + => DB_ERROR_INVALID_NUMBER, + '/invalid input syntax for( type)? (integer|numeric)/i' + => DB_ERROR_INVALID_NUMBER, + '/value .* is out of range for type \w*int/i' + => DB_ERROR_INVALID_NUMBER, + '/integer out of range/i' + => DB_ERROR_INVALID_NUMBER, + '/value too long for type character/i' + => DB_ERROR_INVALID, + '/attribute .* not found|relation .* does not have attribute/i' + => DB_ERROR_NOSUCHFIELD, + '/column .* specified in USING clause does not exist in (left|right) table/i' + => DB_ERROR_NOSUCHFIELD, + '/parser: parse error at or near/i' + => DB_ERROR_SYNTAX, + '/syntax error at/' + => DB_ERROR_SYNTAX, + '/column reference .* is ambiguous/i' + => DB_ERROR_SYNTAX, + '/permission denied/' + => DB_ERROR_ACCESS_VIOLATION, + '/violates not-null constraint/' + => DB_ERROR_CONSTRAINT_NOT_NULL, + '/violates [\w ]+ constraint/' + => DB_ERROR_CONSTRAINT, + '/referential integrity violation/' + => DB_ERROR_CONSTRAINT, + '/more expressions than target columns/i' + => DB_ERROR_VALUE_COUNT_ON_ROW, + ); + } + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + // Fall back to DB_ERROR if there was no mapping. + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0"); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @pg_numfields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func(@pg_fieldname($id, $i)), + 'type' => @pg_fieldtype($id, $i), + 'len' => @pg_fieldsize($id, $i), + 'flags' => $got_string + ? $this->_pgFieldFlags($id, $i, $result) + : '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @pg_freeresult($id); + } + return $res; + } + + // }}} + // {{{ _pgFieldFlags() + + /** + * Get a column's flags + * + * Supports "not_null", "default_value", "primary_key", "unique_key" + * and "multiple_key". The default value is passed through + * rawurlencode() in case there are spaces in it. + * + * @param int $resource the PostgreSQL result identifier + * @param int $num_field the field number + * + * @return string the flags + * + * @access private + */ + function _pgFieldFlags($resource, $num_field, $table_name) + { + $field_name = @pg_fieldname($resource, $num_field); + + $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef + FROM pg_attribute f, pg_class tab, pg_type typ + WHERE tab.relname = typ.typname + AND typ.typrelid = f.attrelid + AND f.attname = '$field_name' + AND tab.relname = '$table_name'"); + if (@pg_numrows($result) > 0) { + $row = @pg_fetch_row($result, 0); + $flags = ($row[0] == 't') ? 'not_null ' : ''; + + if ($row[1] == 't') { + $result = @pg_exec($this->connection, "SELECT a.adsrc + FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a + WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid + AND f.attrelid = a.adrelid AND f.attname = '$field_name' + AND tab.relname = '$table_name' AND f.attnum = a.adnum"); + $row = @pg_fetch_row($result, 0); + $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); + $flags .= 'default_' . rawurlencode($num) . ' '; + } + } else { + $flags = ''; + } + $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey + FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i + WHERE tab.relname = typ.typname + AND typ.typrelid = f.attrelid + AND f.attrelid = i.indrelid + AND f.attname = '$field_name' + AND tab.relname = '$table_name'"); + $count = @pg_numrows($result); + + for ($i = 0; $i < $count ; $i++) { + $row = @pg_fetch_row($result, $i); + $keys = explode(' ', $row[2]); + + if (in_array($num_field + 1, $keys)) { + $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : ''; + $flags .= ($row[1] == 't') ? 'primary_key ' : ''; + if (count($keys) > 1) + $flags .= 'multiple_key '; + } + } + + return trim($flags); + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SELECT c.relname AS "Name"' + . ' FROM pg_class c, pg_user u' + . ' WHERE c.relowner = u.usesysid' + . " AND c.relkind = 'r'" + . ' AND NOT EXISTS' + . ' (SELECT 1 FROM pg_views' + . ' WHERE viewname = c.relname)' + . " AND c.relname !~ '^(pg_|sql_)'" + . ' UNION' + . ' SELECT c.relname AS "Name"' + . ' FROM pg_class c' + . " WHERE c.relkind = 'r'" + . ' AND NOT EXISTS' + . ' (SELECT 1 FROM pg_views' + . ' WHERE viewname = c.relname)' + . ' AND NOT EXISTS' + . ' (SELECT 1 FROM pg_user' + . ' WHERE usesysid = c.relowner)' + . " AND c.relname !~ '^pg_'"; + case 'schema.tables': + return "SELECT schemaname || '.' || tablename" + . ' AS "Name"' + . ' FROM pg_catalog.pg_tables' + . ' WHERE schemaname NOT IN' + . " ('pg_catalog', 'information_schema', 'pg_toast')"; + case 'views': + // Table cols: viewname | viewowner | definition + return 'SELECT viewname from pg_views WHERE schemaname' + . " NOT IN ('information_schema', 'pg_catalog')"; + case 'users': + // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil + return 'SELECT usename FROM pg_user'; + case 'databases': + return 'SELECT datname FROM pg_database'; + case 'functions': + case 'procedures': + return 'SELECT proname FROM pg_proc WHERE proowner <> 1'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/sqlite.php b/src/www/lib/pear/DB/sqlite.php new file mode 100644 index 00000000..e349ec02 --- /dev/null +++ b/src/www/lib/pear/DB/sqlite.php @@ -0,0 +1,942 @@ + + * @author Mika Tuupola + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 + * @version CVS: $Id: sqlite.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's sqlite extension + * for interacting with SQLite databases + * + * These methods overload the ones declared in DB_common. + * + * NOTICE: This driver needs PHP's track_errors ini setting to be on. + * It is automatically turned on when connecting to the database. + * Make sure your scripts don't turn it off. + * + * @category Database + * @package DB + * @author Urs Gehrig + * @author Mika Tuupola + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_sqlite extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'sqlite'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'sqlite'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => false, + ); + + /** + * A mapping of native error codes to DB error codes + * + * {@internal Error codes according to sqlite_exec. See the online + * manual at http://sqlite.org/c_interface.html for info. + * This error handling based on sqlite_exec is not yet implemented.}} + * + * @var array + */ + var $errorcode_map = array( + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * SQLite data types + * + * @link http://www.sqlite.org/datatypes.html + * + * @var array + */ + var $keywords = array ( + 'BLOB' => '', + 'BOOLEAN' => '', + 'CHARACTER' => '', + 'CLOB' => '', + 'FLOAT' => '', + 'INTEGER' => '', + 'KEY' => '', + 'NATIONAL' => '', + 'NUMERIC' => '', + 'NVARCHAR' => '', + 'PRIMARY' => '', + 'TEXT' => '', + 'TIMESTAMP' => '', + 'UNIQUE' => '', + 'VARCHAR' => '', + 'VARYING' => '', + ); + + /** + * The most recent error message from $php_errormsg + * @var string + * @access private + */ + var $_lasterror = ''; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_sqlite() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's sqlite driver supports the following extra DSN options: + * + mode The permissions for the database file, in four digit + * chmod octal format (eg "0600"). + * + * Example of connecting to a database in read-only mode: + * + * require_once 'DB.php'; + * + * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400'; + * $options = array( + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('sqlite')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + if ($dsn['database']) { + if (!file_exists($dsn['database'])) { + if (!touch($dsn['database'])) { + return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); + } + if (!isset($dsn['mode']) || + !is_numeric($dsn['mode'])) + { + $mode = 0644; + } else { + $mode = octdec($dsn['mode']); + } + if (!chmod($dsn['database'], $mode)) { + return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); + } + if (!file_exists($dsn['database'])) { + return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); + } + } + if (!is_file($dsn['database'])) { + return $this->sqliteRaiseError(DB_ERROR_INVALID); + } + if (!is_readable($dsn['database'])) { + return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); + } + } else { + return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); + } + + $connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open'; + + // track_errors must remain on for simpleQuery() + ini_set('track_errors', 1); + $php_errormsg = ''; + + if (!$this->connection = @$connect_function($dsn['database'])) { + return $this->raiseError(DB_ERROR_NODBSELECTED, + null, null, null, + $php_errormsg); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @sqlite_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * NOTICE: This method needs PHP's track_errors ini setting to be on. + * It is automatically turned on when connecting to the database. + * Make sure your scripts don't turn it off. + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + + $php_errormsg = ''; + + $result = @sqlite_query($query, $this->connection); + $this->_lasterror = $php_errormsg ? $php_errormsg : ''; + + $this->result = $result; + if (!$this->result) { + return $this->sqliteRaiseError(null); + } + + // sqlite_query() seems to allways return a resource + // so cant use that. Using $ismanip instead + if (!$ismanip) { + $numRows = $this->numRows($result); + if (is_object($numRows)) { + // we've got PEAR_Error + return $numRows; + } + return $result; + } + return DB_OK; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal sqlite result pointer to the next available result + * + * @param resource $result the valid sqlite result resource + * + * @return bool true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@sqlite_seek($this->result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @sqlite_fetch_array($result, SQLITE_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @sqlite_fetch_array($result, SQLITE_NUM); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + /* + * Even though this DBMS already trims output, we do this because + * a field might have intentional whitespace at the end that + * gets removed by DB_PORTABILITY_RTRIM under another driver. + */ + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult(&$result) + { + // XXX No native free? + if (!is_resource($result)) { + return false; + } + $result = null; + return true; + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @sqlite_num_fields($result); + if (!$cols) { + return $this->sqliteRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @sqlite_num_rows($result); + if ($rows === null) { + return $this->sqliteRaiseError(); + } + return $rows; + } + + // }}} + // {{{ affected() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + return @sqlite_changes($this->connection); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_sqlite::nextID(), DB_sqlite::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_sqlite::nextID(), DB_sqlite::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $query = 'CREATE TABLE ' . $seqname . + ' (id INTEGER UNSIGNED PRIMARY KEY) '; + $result = $this->query($query); + if (DB::isError($result)) { + return($result); + } + $query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname + BEGIN + DELETE FROM $seqname WHERE idquery($query); + if (DB::isError($result)) { + return($result); + } + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_sqlite::createSequence(), DB_sqlite::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + + do { + $repeat = 0; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)"); + $this->popErrorHandling(); + if ($result === DB_OK) { + $id = @sqlite_last_insert_rowid($this->connection); + if ($id != 0) { + return $id; + } + } elseif ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) + { + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $this->raiseError($result); + } else { + $repeat = 1; + } + } + } while ($repeat); + + return $this->raiseError($result); + } + + // }}} + // {{{ getDbFileStats() + + /** + * Get the file stats for the current database + * + * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size, + * atime, mtime, ctime, blksize, blocks or a numeric key between + * 0 and 12. + * + * @param string $arg the array key for stats() + * + * @return mixed an array on an unspecified key, integer on a passed + * arg and false at a stats error + */ + function getDbFileStats($arg = '') + { + $stats = stat($this->dsn['database']); + if ($stats == false) { + return false; + } + if (is_array($stats)) { + if (is_numeric($arg)) { + if (((int)$arg <= 12) & ((int)$arg >= 0)) { + return false; + } + return $stats[$arg ]; + } + if (array_key_exists(trim($arg), $stats)) { + return $stats[$arg ]; + } + } + return $stats; + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * In SQLite, this makes things safe for inserts/updates, but may + * cause problems when performing text comparisons against columns + * containing binary data. See the + * {@link http://php.net/sqlite_escape_string PHP manual} for more info. + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @since Method available since Release 1.6.1 + * @see DB_common::escapeSimple() + */ + function escapeSimple($str) + { + return @sqlite_escape_string($str); + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + return "$query LIMIT $count OFFSET $from"; + } + + // }}} + // {{{ modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * This little hack lets you know how many rows were deleted + * when running a "DELETE FROM table" query. Only implemented + * if the DB_PORTABILITY_DELETE_COUNT portability option is on. + * + * @param string $query the query string to modify + * + * @return string the modified query string + * + * @access protected + * @see DB_common::setOption() + */ + function modifyQuery($query) + { + if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { + if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { + $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', + 'DELETE FROM \1 WHERE 1=1', $query); + } + } + return $query; + } + + // }}} + // {{{ sqliteRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_sqlite::errorNative(), DB_sqlite::errorCode() + */ + function sqliteRaiseError($errno = null) + { + $native = $this->errorNative(); + if ($errno === null) { + $errno = $this->errorCode($native); + } + + $errorcode = @sqlite_last_error($this->connection); + $userinfo = "$errorcode ** $this->last_query"; + + return $this->raiseError($errno, null, null, $userinfo, $native); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error message produced by the last query + * + * {@internal This is used to retrieve more meaningfull error messages + * because sqlite_last_error() does not provide adequate info.}} + * + * @return string the DBMS' error message + */ + function errorNative() + { + return $this->_lasterror; + } + + // }}} + // {{{ errorCode() + + /** + * Determines PEAR::DB error code from the database's text error message + * + * @param string $errormsg the error message returned from the database + * + * @return integer the DB error number + */ + function errorCode($errormsg) + { + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/^no such table:/' => DB_ERROR_NOSUCHTABLE, + '/^no such index:/' => DB_ERROR_NOT_FOUND, + '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS, + '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT, + '/is not unique/' => DB_ERROR_CONSTRAINT, + '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT, + '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT, + '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL, + '/^no such column:/' => DB_ERROR_NOSUCHFIELD, + '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD, + '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX, + '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW, + ); + } + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + // Fall back to DB_ERROR if there was no mapping. + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table + * + * @param string $result a string containing the name of a table + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + * @since Method available since Release 1.7.0 + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @sqlite_array_query($this->connection, + "PRAGMA table_info('$result');", + SQLITE_ASSOC); + $got_string = true; + } else { + $this->last_query = ''; + return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null, + 'This DBMS can not obtain tableInfo' . + ' from result sets'); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = count($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + if (strpos($id[$i]['type'], '(') !== false) { + $bits = explode('(', $id[$i]['type']); + $type = $bits[0]; + $len = rtrim($bits[1],')'); + } else { + $type = $id[$i]['type']; + $len = 0; + } + + $flags = ''; + if ($id[$i]['pk']) { + $flags .= 'primary_key '; + } + if ($id[$i]['notnull']) { + $flags .= 'not_null '; + } + if ($id[$i]['dflt_value'] !== null) { + $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']); + } + $flags = trim($flags); + + $res[$i] = array( + 'table' => $case_func($result), + 'name' => $case_func($id[$i]['name']), + 'type' => $type, + 'len' => $len, + 'flags' => $flags, + ); + + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * @param array $args SQLITE DRIVER ONLY: a private array of arguments + * used by the getSpecialQuery(). Do not use + * this directly. + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type, $args = array()) + { + if (!is_array($args)) { + return $this->raiseError('no key specified', null, null, null, + 'Argument has to be an array.'); + } + + switch ($type) { + case 'master': + return 'SELECT * FROM sqlite_master;'; + case 'tables': + return "SELECT name FROM sqlite_master WHERE type='table' " + . 'UNION ALL SELECT name FROM sqlite_temp_master ' + . "WHERE type='table' ORDER BY name;"; + case 'schema': + return 'SELECT sql FROM (SELECT * FROM sqlite_master ' + . 'UNION ALL SELECT * FROM sqlite_temp_master) ' + . "WHERE type!='meta' " + . 'ORDER BY tbl_name, type DESC, name;'; + case 'schemax': + case 'schema_x': + /* + * Use like: + * $res = $db->query($db->getSpecialQuery('schema_x', + * array('table' => 'table3'))); + */ + return 'SELECT sql FROM (SELECT * FROM sqlite_master ' + . 'UNION ALL SELECT * FROM sqlite_temp_master) ' + . "WHERE tbl_name LIKE '{$args['table']}' " + . "AND type!='meta' " + . 'ORDER BY type DESC, name;'; + case 'alter': + /* + * SQLite does not support ALTER TABLE; this is a helper query + * to handle this. 'table' represents the table name, 'rows' + * the news rows to create, 'save' the row(s) to keep _with_ + * the data. + * + * Use like: + * $args = array( + * 'table' => $table, + * 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT", + * 'save' => "NULL, titel, content, datetime" + * ); + * $res = $db->query( $db->getSpecialQuery('alter', $args)); + */ + $rows = strtr($args['rows'], $this->keywords); + + $q = array( + 'BEGIN TRANSACTION', + "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})", + "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}", + "DROP TABLE {$args['table']}", + "CREATE TABLE {$args['table']} ({$args['rows']})", + "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup", + "DROP TABLE {$args['table']}_backup", + 'COMMIT', + ); + + /* + * This is a dirty hack, since the above query will not get + * executed with a single query call so here the query method + * will be called directly and return a select instead. + */ + foreach ($q as $query) { + $this->query($query); + } + return "SELECT * FROM {$args['table']};"; + default: + return null; + } + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/storage.php b/src/www/lib/pear/DB/storage.php new file mode 100644 index 00000000..64dbc00c --- /dev/null +++ b/src/www/lib/pear/DB/storage.php @@ -0,0 +1,504 @@ + + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: storage.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB class so it can be extended from + */ +require_once 'DB.php'; + +/** + * Provides an object interface to a table row + * + * It lets you add, delete and change rows using objects rather than SQL + * statements. + * + * @category Database + * @package DB + * @author Stig Bakken + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_storage extends PEAR +{ + // {{{ properties + + /** the name of the table (or view, if the backend database supports + updates in views) we hold data from */ + var $_table = null; + + /** which column(s) in the table contains primary keys, can be a + string for single-column primary keys, or an array of strings + for multiple-column primary keys */ + var $_keycolumn = null; + + /** DB connection handle used for all transactions */ + var $_dbh = null; + + /** an assoc with the names of database fields stored as properties + in this object */ + var $_properties = array(); + + /** an assoc with the names of the properties in this object that + have been changed since they were fetched from the database */ + var $_changes = array(); + + /** flag that decides if data in this object can be changed. + objects that don't have their table's key column in their + property lists will be flagged as read-only. */ + var $_readonly = false; + + /** function or method that implements a validator for fields that + are set, this validator function returns true if the field is + valid, false if not */ + var $_validator = null; + + // }}} + // {{{ constructor + + /** + * Constructor + * + * @param $table string the name of the database table + * + * @param $keycolumn mixed string with name of key column, or array of + * strings if the table has a primary key of more than one column + * + * @param $dbh object database connection object + * + * @param $validator mixed function or method used to validate + * each new value, called with three parameters: the name of the + * field/column that is changing, a reference to the new value and + * a reference to this object + * + */ + function DB_storage($table, $keycolumn, &$dbh, $validator = null) + { + $this->PEAR('DB_Error'); + $this->_table = $table; + $this->_keycolumn = $keycolumn; + $this->_dbh = $dbh; + $this->_readonly = false; + $this->_validator = $validator; + } + + // }}} + // {{{ _makeWhere() + + /** + * Utility method to build a "WHERE" clause to locate ourselves in + * the table. + * + * XXX future improvement: use rowids? + * + * @access private + */ + function _makeWhere($keyval = null) + { + if (is_array($this->_keycolumn)) { + if ($keyval === null) { + for ($i = 0; $i < sizeof($this->_keycolumn); $i++) { + $keyval[] = $this->{$this->_keycolumn[$i]}; + } + } + $whereclause = ''; + for ($i = 0; $i < sizeof($this->_keycolumn); $i++) { + if ($i > 0) { + $whereclause .= ' AND '; + } + $whereclause .= $this->_keycolumn[$i]; + if (is_null($keyval[$i])) { + // there's not much point in having a NULL key, + // but we support it anyway + $whereclause .= ' IS NULL'; + } else { + $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]); + } + } + } else { + if ($keyval === null) { + $keyval = @$this->{$this->_keycolumn}; + } + $whereclause = $this->_keycolumn; + if (is_null($keyval)) { + // there's not much point in having a NULL key, + // but we support it anyway + $whereclause .= ' IS NULL'; + } else { + $whereclause .= ' = ' . $this->_dbh->quote($keyval); + } + } + return $whereclause; + } + + // }}} + // {{{ setup() + + /** + * Method used to initialize a DB_storage object from the + * configured table. + * + * @param $keyval mixed the key[s] of the row to fetch (string or array) + * + * @return int DB_OK on success, a DB error if not + */ + function setup($keyval) + { + $whereclause = $this->_makeWhere($keyval); + $query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause; + $sth = $this->_dbh->query($query); + if (DB::isError($sth)) { + return $sth; + } + $row = $sth->fetchRow(DB_FETCHMODE_ASSOC); + if (DB::isError($row)) { + return $row; + } + if (!$row) { + return $this->raiseError(null, DB_ERROR_NOT_FOUND, null, null, + $query, null, true); + } + foreach ($row as $key => $value) { + $this->_properties[$key] = true; + $this->$key = $value; + } + return DB_OK; + } + + // }}} + // {{{ insert() + + /** + * Create a new (empty) row in the configured table for this + * object. + */ + function insert($newpk) + { + if (is_array($this->_keycolumn)) { + $primarykey = $this->_keycolumn; + } else { + $primarykey = array($this->_keycolumn); + } + settype($newpk, "array"); + for ($i = 0; $i < sizeof($primarykey); $i++) { + $pkvals[] = $this->_dbh->quote($newpk[$i]); + } + + $sth = $this->_dbh->query("INSERT INTO $this->_table (" . + implode(",", $primarykey) . ") VALUES(" . + implode(",", $pkvals) . ")"); + if (DB::isError($sth)) { + return $sth; + } + if (sizeof($newpk) == 1) { + $newpk = $newpk[0]; + } + $this->setup($newpk); + } + + // }}} + // {{{ toString() + + /** + * Output a simple description of this DB_storage object. + * @return string object description + */ + function toString() + { + $info = strtolower(get_class($this)); + $info .= " (table="; + $info .= $this->_table; + $info .= ", keycolumn="; + if (is_array($this->_keycolumn)) { + $info .= "(" . implode(",", $this->_keycolumn) . ")"; + } else { + $info .= $this->_keycolumn; + } + $info .= ", dbh="; + if (is_object($this->_dbh)) { + $info .= $this->_dbh->toString(); + } else { + $info .= "null"; + } + $info .= ")"; + if (sizeof($this->_properties)) { + $info .= " [loaded, key="; + $keyname = $this->_keycolumn; + if (is_array($keyname)) { + $info .= "("; + for ($i = 0; $i < sizeof($keyname); $i++) { + if ($i > 0) { + $info .= ","; + } + $info .= $this->$keyname[$i]; + } + $info .= ")"; + } else { + $info .= $this->$keyname; + } + $info .= "]"; + } + if (sizeof($this->_changes)) { + $info .= " [modified]"; + } + return $info; + } + + // }}} + // {{{ dump() + + /** + * Dump the contents of this object to "standard output". + */ + function dump() + { + foreach ($this->_properties as $prop => $foo) { + print "$prop = "; + print htmlentities($this->$prop); + print "
\n"; + } + } + + // }}} + // {{{ &create() + + /** + * Static method used to create new DB storage objects. + * @param $data assoc. array where the keys are the names + * of properties/columns + * @return object a new instance of DB_storage or a subclass of it + */ + function &create($table, &$data) + { + $classname = strtolower(get_class($this)); + $obj =& new $classname($table); + foreach ($data as $name => $value) { + $obj->_properties[$name] = true; + $obj->$name = &$value; + } + return $obj; + } + + // }}} + // {{{ loadFromQuery() + + /** + * Loads data into this object from the given query. If this + * object already contains table data, changes will be saved and + * the object re-initialized first. + * + * @param $query SQL query + * + * @param $params parameter list in case you want to use + * prepare/execute mode + * + * @return int DB_OK on success, DB_WARNING_READ_ONLY if the + * returned object is read-only (because the object's specified + * key column was not found among the columns returned by $query), + * or another DB error code in case of errors. + */ +// XXX commented out for now +/* + function loadFromQuery($query, $params = null) + { + if (sizeof($this->_properties)) { + if (sizeof($this->_changes)) { + $this->store(); + $this->_changes = array(); + } + $this->_properties = array(); + } + $rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params); + if (DB::isError($rowdata)) { + return $rowdata; + } + reset($rowdata); + $found_keycolumn = false; + while (list($key, $value) = each($rowdata)) { + if ($key == $this->_keycolumn) { + $found_keycolumn = true; + } + $this->_properties[$key] = true; + $this->$key = &$value; + unset($value); // have to unset, or all properties will + // refer to the same value + } + if (!$found_keycolumn) { + $this->_readonly = true; + return DB_WARNING_READ_ONLY; + } + return DB_OK; + } + */ + + // }}} + // {{{ set() + + /** + * Modify an attriute value. + */ + function set($property, $newvalue) + { + // only change if $property is known and object is not + // read-only + if ($this->_readonly) { + return $this->raiseError(null, DB_WARNING_READ_ONLY, null, + null, null, null, true); + } + if (@isset($this->_properties[$property])) { + if (empty($this->_validator)) { + $valid = true; + } else { + $valid = @call_user_func($this->_validator, + $this->_table, + $property, + $newvalue, + $this->$property, + $this); + } + if ($valid) { + $this->$property = $newvalue; + if (empty($this->_changes[$property])) { + $this->_changes[$property] = 0; + } else { + $this->_changes[$property]++; + } + } else { + return $this->raiseError(null, DB_ERROR_INVALID, null, + null, "invalid field: $property", + null, true); + } + return true; + } + return $this->raiseError(null, DB_ERROR_NOSUCHFIELD, null, + null, "unknown field: $property", + null, true); + } + + // }}} + // {{{ &get() + + /** + * Fetch an attribute value. + * + * @param string attribute name + * + * @return attribute contents, or null if the attribute name is + * unknown + */ + function &get($property) + { + // only return if $property is known + if (isset($this->_properties[$property])) { + return $this->$property; + } + $tmp = null; + return $tmp; + } + + // }}} + // {{{ _DB_storage() + + /** + * Destructor, calls DB_storage::store() if there are changes + * that are to be kept. + */ + function _DB_storage() + { + if (sizeof($this->_changes)) { + $this->store(); + } + $this->_properties = array(); + $this->_changes = array(); + $this->_table = null; + } + + // }}} + // {{{ store() + + /** + * Stores changes to this object in the database. + * + * @return DB_OK or a DB error + */ + function store() + { + foreach ($this->_changes as $name => $foo) { + $params[] = &$this->$name; + $vars[] = $name . ' = ?'; + } + if ($vars) { + $query = 'UPDATE ' . $this->_table . ' SET ' . + implode(', ', $vars) . ' WHERE ' . + $this->_makeWhere(); + $stmt = $this->_dbh->prepare($query); + $res = $this->_dbh->execute($stmt, $params); + if (DB::isError($res)) { + return $res; + } + $this->_changes = array(); + } + return DB_OK; + } + + // }}} + // {{{ remove() + + /** + * Remove the row represented by this object from the database. + * + * @return mixed DB_OK or a DB error + */ + function remove() + { + if ($this->_readonly) { + return $this->raiseError(null, DB_WARNING_READ_ONLY, null, + null, null, null, true); + } + $query = 'DELETE FROM ' . $this->_table .' WHERE '. + $this->_makeWhere(); + $res = $this->_dbh->query($query); + if (DB::isError($res)) { + return $res; + } + foreach ($this->_properties as $prop => $foo) { + unset($this->$prop); + } + $this->_properties = array(); + $this->_changes = array(); + return DB_OK; + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/DB/sybase.php b/src/www/lib/pear/DB/sybase.php new file mode 100644 index 00000000..8091a0cc --- /dev/null +++ b/src/www/lib/pear/DB/sybase.php @@ -0,0 +1,907 @@ + + * @author Antônio Carlos Venâncio Júnior + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: sybase.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's sybase extension + * for interacting with Sybase databases + * + * These methods overload the ones declared in DB_common. + * + * WARNING: This driver may fail with multiple connections under the + * same user/pass/host and different databases. + * + * @category Database + * @package DB + * @author Sterling Hughes + * @author Antônio Carlos Venâncio Júnior + * @author Daniel Convissor + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_sybase extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'sybase'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'sybase'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'emulate', + 'new_link' => false, + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The database specified in the DSN + * + * It's a fix to allow calls to different databases in the same script. + * + * @var string + * @access private + */ + var $_db = ''; + + + // }}} + // {{{ constructor + + /** + * This constructor calls $this->DB_common() + * + * @return void + */ + function DB_sybase() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's sybase driver supports the following extra DSN options: + * + appname The application name to use on this connection. + * Available since PEAR DB 1.7.0. + * + charset The character set to use on this connection. + * Available since PEAR DB 1.7.0. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('sybase') && + !PEAR::loadExtension('sybase_ct')) + { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $dsn['hostspec'] = $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost'; + $dsn['password'] = !empty($dsn['password']) ? $dsn['password'] : false; + $dsn['charset'] = isset($dsn['charset']) ? $dsn['charset'] : false; + $dsn['appname'] = isset($dsn['appname']) ? $dsn['appname'] : false; + + $connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect'; + + if ($dsn['username']) { + $this->connection = @$connect_function($dsn['hostspec'], + $dsn['username'], + $dsn['password'], + $dsn['charset'], + $dsn['appname']); + } else { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + 'The DSN did not contain a username.'); + } + + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + @sybase_get_last_message()); + } + + if ($dsn['database']) { + if (!@sybase_select_db($dsn['database'], $this->connection)) { + return $this->raiseError(DB_ERROR_NODBSELECTED, + null, null, null, + @sybase_get_last_message()); + } + $this->_db = $dsn['database']; + } + + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @sybase_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + if (!@sybase_select_db($this->_db, $this->connection)) { + return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); + } + $query = $this->modifyQuery($query); + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @sybase_query('BEGIN TRANSACTION', $this->connection); + if (!$result) { + return $this->sybaseRaiseError(); + } + } + $this->transaction_opcount++; + } + $result = @sybase_query($query, $this->connection); + if (!$result) { + return $this->sybaseRaiseError(); + } + if (is_resource($result)) { + return $result; + } + // Determine which queries that should return data, and which + // should return an error code only. + return $ismanip ? DB_OK : $result; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal sybase result pointer to the next available result + * + * @param a valid sybase result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@sybase_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + if (function_exists('sybase_fetch_assoc')) { + $arr = @sybase_fetch_assoc($result); + } else { + if ($arr = @sybase_fetch_array($result)) { + foreach ($arr as $key => $value) { + if (is_int($key)) { + unset($arr[$key]); + } + } + } + } + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @sybase_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @sybase_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @sybase_num_fields($result); + if (!$cols) { + return $this->sybaseRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @sybase_num_rows($result); + if ($rows === false) { + return $this->sybaseRaiseError(); + } + return $rows; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + $result = @sybase_affected_rows($this->connection); + } else { + $result = 0; + } + return $result; + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_sybase::createSequence(), DB_sybase::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + if (!@sybase_select_db($this->_db, $this->connection)) { + return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); + } + $repeat = 0; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) + { + $repeat = 1; + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $this->raiseError($result); + } + } elseif (!DB::isError($result)) { + $result =& $this->query("SELECT @@IDENTITY FROM $seqname"); + $repeat = 0; + } else { + $repeat = false; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $result = $result->fetchRow(DB_FETCHMODE_ORDERED); + return $result[0]; + } + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_sybase::nextID(), DB_sybase::dropSequence() + */ + function createSequence($seq_name) + { + return $this->query('CREATE TABLE ' + . $this->getSequenceName($seq_name) + . ' (id numeric(10, 0) IDENTITY NOT NULL,' + . ' vapor int NULL)'); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_sybase::nextID(), DB_sybase::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + if (!@sybase_select_db($this->_db, $this->connection)) { + return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); + } + $result = @sybase_query('COMMIT', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->sybaseRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + if (!@sybase_select_db($this->_db, $this->connection)) { + return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); + } + $result = @sybase_query('ROLLBACK', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->sybaseRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ sybaseRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_sybase::errorNative(), DB_sybase::errorCode() + */ + function sybaseRaiseError($errno = null) + { + $native = $this->errorNative(); + if ($errno === null) { + $errno = $this->errorCode($native); + } + return $this->raiseError($errno, null, null, null, $native); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error message produced by the last query + * + * @return string the DBMS' error message + */ + function errorNative() + { + return @sybase_get_last_message(); + } + + // }}} + // {{{ errorCode() + + /** + * Determines PEAR::DB error code from the database's text error message. + * + * @param string $errormsg error message returned from the database + * @return integer an error number from a DB error constant + */ + function errorCode($errormsg) + { + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/Incorrect syntax near/' + => DB_ERROR_SYNTAX, + '/^Unclosed quote before the character string [\"\'].*[\"\']\./' + => DB_ERROR_SYNTAX, + '/Implicit conversion (from datatype|of NUMERIC value)/i' + => DB_ERROR_INVALID_NUMBER, + '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./' + => DB_ERROR_NOSUCHTABLE, + '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./' + => DB_ERROR_ACCESS_VIOLATION, + '/^.+ permission denied on object .+, database .+, owner .+/' + => DB_ERROR_ACCESS_VIOLATION, + '/^.* permission denied, database .+, owner .+/' + => DB_ERROR_ACCESS_VIOLATION, + '/[^.*] not found\./' + => DB_ERROR_NOSUCHTABLE, + '/There is already an object named/' + => DB_ERROR_ALREADY_EXISTS, + '/Invalid column name/' + => DB_ERROR_NOSUCHFIELD, + '/does not allow null values/' + => DB_ERROR_CONSTRAINT_NOT_NULL, + '/Command has been aborted/' + => DB_ERROR_CONSTRAINT, + '/^Cannot drop the index .* because it doesn\'t exist/i' + => DB_ERROR_NOT_FOUND, + '/^There is already an index/i' + => DB_ERROR_ALREADY_EXISTS, + '/^There are fewer columns in the INSERT statement than values specified/i' + => DB_ERROR_VALUE_COUNT_ON_ROW, + ); + } + + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + * @since Method available since Release 1.6.0 + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + if (!@sybase_select_db($this->_db, $this->connection)) { + return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); + } + $id = @sybase_query("SELECT * FROM $result WHERE 1=0", + $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @sybase_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $f = @sybase_fetch_field($id, $i); + // column_source is often blank + $res[$i] = array( + 'table' => $got_string + ? $case_func($result) + : $case_func($f->column_source), + 'name' => $case_func($f->name), + 'type' => $f->type, + 'len' => $f->max_length, + 'flags' => '', + ); + if ($res[$i]['table']) { + $res[$i]['flags'] = $this->_sybase_field_flags( + $res[$i]['table'], $res[$i]['name']); + } + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @sybase_free_result($id); + } + return $res; + } + + // }}} + // {{{ _sybase_field_flags() + + /** + * Get the flags for a field + * + * Currently supports: + * + unique_key (unique index, unique check or primary_key) + * + multiple_key (multi-key index) + * + * @param string $table the table name + * @param string $column the field name + * + * @return string space delimited string of flags. Empty string if none. + * + * @access private + */ + function _sybase_field_flags($table, $column) + { + static $tableName = null; + static $flags = array(); + + if ($table != $tableName) { + $flags = array(); + $tableName = $table; + + // get unique/primary keys + $res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC); + + if (!isset($res[0]['index_description'])) { + return ''; + } + + foreach ($res as $val) { + $keys = explode(', ', trim($val['index_keys'])); + + if (sizeof($keys) > 1) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'multiple_key'); + } + } + + if (strpos($val['index_description'], 'unique')) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'unique_key'); + } + } + } + + } + + if (array_key_exists($column, $flags)) { + return(implode(' ', $flags[$column])); + } + + return ''; + } + + // }}} + // {{{ _add_flag() + + /** + * Adds a string to the flags array if the flag is not yet in there + * - if there is no flag present the array is created + * + * @param array $array reference of flags array to add a value to + * @param mixed $value value to add to the flag array + * + * @return void + * + * @access private + */ + function _add_flag(&$array, $value) + { + if (!is_array($array)) { + $array = array($value); + } elseif (!in_array($value, $array)) { + array_push($array, $value); + } + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return "SELECT name FROM sysobjects WHERE type = 'U'" + . ' ORDER BY name'; + case 'views': + return "SELECT name FROM sysobjects WHERE type = 'V'"; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/src/www/lib/pear/OS/Guess.php b/src/www/lib/pear/OS/Guess.php new file mode 100644 index 00000000..39ae8ad4 --- /dev/null +++ b/src/www/lib/pear/OS/Guess.php @@ -0,0 +1,287 @@ + | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Guess.php,v 1.1 2005/05/28 01:55:11 henrique Exp $ + +// {{{ uname examples + +// php_uname() without args returns the same as 'uname -a', or a PHP-custom +// string for Windows. +// PHP versions prior to 4.3 return the uname of the host where PHP was built, +// as of 4.3 it returns the uname of the host running the PHP code. +// +// PC RedHat Linux 7.1: +// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown +// +// PC Debian Potato: +// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown +// +// PC FreeBSD 3.3: +// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.3: +// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.5: +// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.5 w/uname from GNU shellutils: +// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown +// +// HP 9000/712 HP-UX 10: +// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license +// +// HP 9000/712 HP-UX 10 w/uname from GNU shellutils: +// HP-UX host B.10.10 A 9000/712 unknown +// +// IBM RS6000/550 AIX 4.3: +// AIX host 3 4 000003531C00 +// +// AIX 4.3 w/uname from GNU shellutils: +// AIX host 3 4 000003531C00 unknown +// +// SGI Onyx IRIX 6.5 w/uname from GNU shellutils: +// IRIX64 host 6.5 01091820 IP19 mips +// +// SGI Onyx IRIX 6.5: +// IRIX64 host 6.5 01091820 IP19 +// +// SparcStation 20 Solaris 8 w/uname from GNU shellutils: +// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc +// +// SparcStation 20 Solaris 8: +// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20 +// +// Mac OS X (Darwin) +// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh +// +// Mac OS X early versions +// + +// }}} + +/* TODO: + * - define endianness, to allow matchSignature("bigend") etc. + */ + +class OS_Guess +{ + var $sysname; + var $nodename; + var $cpu; + var $release; + var $extra; + + function OS_Guess($uname = null) + { + list($this->sysname, + $this->release, + $this->cpu, + $this->extra, + $this->nodename) = $this->parseSignature($uname); + } + + function parseSignature($uname = null) + { + static $sysmap = array( + 'HP-UX' => 'hpux', + 'IRIX64' => 'irix', + ); + static $cpumap = array( + 'i586' => 'i386', + 'i686' => 'i386', + 'ppc' => 'powerpc', + ); + if ($uname === null) { + $uname = php_uname(); + } + $parts = split('[[:space:]]+', trim($uname)); + $n = count($parts); + + $release = $machine = $cpu = ''; + $sysname = $parts[0]; + $nodename = $parts[1]; + $cpu = $parts[$n-1]; + $extra = ''; + if ($cpu == 'unknown') { + $cpu = $parts[$n-2]; + } + + switch ($sysname) { + case 'AIX': + $release = "$parts[3].$parts[2]"; + break; + case 'Windows': + switch ($parts[1]) { + case '95/98': + $release = '9x'; + break; + default: + $release = $parts[1]; + break; + } + $cpu = 'i386'; + break; + case 'Linux': + $extra = $this->_detectGlibcVersion(); + // use only the first two digits from the kernel version + $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]); + break; + case 'Mac' : + $sysname = 'darwin'; + $nodename = $parts[2]; + $release = $parts[3]; + if ($cpu == 'Macintosh') { + if ($parts[$n - 2] == 'Power') { + $cpu = 'powerpc'; + } + } + break; + case 'Darwin' : + if ($cpu == 'Macintosh') { + if ($parts[$n - 2] == 'Power') { + $cpu = 'powerpc'; + } + } + $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]); + break; + default: + $release = ereg_replace('-.*', '', $parts[2]); + break; + } + + + if (isset($sysmap[$sysname])) { + $sysname = $sysmap[$sysname]; + } else { + $sysname = strtolower($sysname); + } + if (isset($cpumap[$cpu])) { + $cpu = $cpumap[$cpu]; + } + return array($sysname, $release, $cpu, $extra, $nodename); + } + + function _detectGlibcVersion() + { + // Use glibc's header file to + // get major and minor version number: + include_once "System.php"; + $tmpfile = System::mktemp("glibctest"); + $fp = fopen($tmpfile, "w"); + fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n"); + fclose($fp); + $cpp = popen("/usr/bin/cpp $tmpfile", "r"); + $major = $minor = 0; + while ($line = fgets($cpp, 1024)) { + if ($line{0} == '#' || trim($line) == '') { + continue; + } + if (list($major, $minor) = explode(' ', trim($line))) { + break; + } + } + pclose($cpp); + unlink($tmpfile); + if (!($major && $minor) && is_link('/lib/libc.so.6')) { + // Let's try reading the libc.so.6 symlink + if (ereg('^libc-([.*])\.so$', basename(readlink('/lib/libc.so.6')), $matches)) { + list($major, $minor) = explode('.', $matches); + } + } + if (!($major && $minor)) { + return ''; + } + return "glibc{$major}.{$minor}"; + } + + function getSignature() + { + if (empty($this->extra)) { + return "{$this->sysname}-{$this->release}-{$this->cpu}"; + } + return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}"; + } + + function getSysname() + { + return $this->sysname; + } + + function getNodename() + { + return $this->nodename; + } + + function getCpu() + { + return $this->cpu; + } + + function getRelease() + { + return $this->release; + } + + function getExtra() + { + return $this->extra; + } + + function matchSignature($match) + { + if (is_array($match)) { + $fragments = $match; + } else { + $fragments = explode('-', $match); + } + $n = count($fragments); + $matches = 0; + if ($n > 0) { + $matches += $this->_matchFragment($fragments[0], $this->sysname); + } + if ($n > 1) { + $matches += $this->_matchFragment($fragments[1], $this->release); + } + if ($n > 2) { + $matches += $this->_matchFragment($fragments[2], $this->cpu); + } + if ($n > 3) { + $matches += $this->_matchFragment($fragments[3], $this->extra); + } + return ($matches == $n); + } + + function _matchFragment($fragment, $value) + { + if (strcspn($fragment, '*?') < strlen($fragment)) { + $reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$'; + return eregi($reg, $value); + } + return ($fragment == '*' || !strcasecmp($fragment, $value)); + } + +} +/* + * Local Variables: + * indent-tabs-mode: nil + * c-basic-offset: 4 + * End: + */ +?> diff --git a/src/www/lib/pear/PEAR.php b/src/www/lib/pear/PEAR.php new file mode 100644 index 00000000..a02c29a2 --- /dev/null +++ b/src/www/lib/pear/PEAR.php @@ -0,0 +1,1055 @@ + | +// | Stig Bakken | +// | Tomas V.V.Cox | +// +--------------------------------------------------------------------+ +// +// $Id: PEAR.php,v 1.1 2005/05/28 01:55:09 henrique Exp $ +// + +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +// instant backwards compatibility +if (!defined('PATH_SEPARATOR')) { + if (OS_WINDOWS) { + define('PATH_SEPARATOR', ';'); + } else { + define('PATH_SEPARATOR', ':'); + } +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @since PHP 4.0.2 + * @author Stig Bakken + * @see http://pear.php.net/manual/ + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (is_a($data, 'PEAR_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } else { + return $data->getCode() == $code; + } + } + return false; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } else { + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + if ($skipmsg) { + return new $ec($code, $mode, $options, $userinfo); + } else { + return new $ec($message, $code, $mode, $options, $userinfo); + } + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + return $this->raiseError($message, $code, null, null, $userinfo); + } else { + return PEAR::raiseError($message, $code, null, null, $userinfo); + } + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + return true; + } + + // }}} +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} + +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + if (function_exists("debug_backtrace")) { + if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { + $this->backtrace = debug_backtrace(); + } + } + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + $this->level = $options; + $this->callback = null; + } + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + printf($format, $this->getMessage()); + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/src/www/lib/pear/PEAR/Autoloader.php b/src/www/lib/pear/PEAR/Autoloader.php new file mode 100644 index 00000000..abde1bf4 --- /dev/null +++ b/src/www/lib/pear/PEAR/Autoloader.php @@ -0,0 +1,208 @@ + | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Autoloader.php,v 1.1 2005/05/28 01:55:12 henrique Exp $ + +if (!extension_loaded("overload")) { + // die hard without ext/overload + die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader"); +} + +require_once "PEAR.php"; + +/** + * This class is for objects where you want to separate the code for + * some methods into separate classes. This is useful if you have a + * class with not-frequently-used methods that contain lots of code + * that you would like to avoid always parsing. + * + * The PEAR_Autoloader class provides autoloading and aggregation. + * The autoloading lets you set up in which classes the separated + * methods are found. Aggregation is the technique used to import new + * methods, an instance of each class providing separated methods is + * stored and called every time the aggregated method is called. + * + * @author Stig Sæther Bakken + */ +class PEAR_Autoloader extends PEAR +{ + // {{{ properties + + /** + * Map of methods and classes where they are defined + * + * @var array + * + * @access private + */ + var $_autoload_map = array(); + + /** + * Map of methods and aggregate objects + * + * @var array + * + * @access private + */ + var $_method_map = array(); + + // }}} + // {{{ addAutoload() + + /** + * Add one or more autoload entries. + * + * @param string $method which method to autoload + * + * @param string $classname (optional) which class to find the method in. + * If the $method parameter is an array, this + * parameter may be omitted (and will be ignored + * if not), and the $method parameter will be + * treated as an associative array with method + * names as keys and class names as values. + * + * @return void + * + * @access public + */ + function addAutoload($method, $classname = null) + { + if (is_array($method)) { + array_walk($method, create_function('$a,&$b', '$b = strtolower($b);')); + $this->_autoload_map = array_merge($this->_autoload_map, $method); + } else { + $this->_autoload_map[strtolower($method)] = $classname; + } + } + + // }}} + // {{{ removeAutoload() + + /** + * Remove an autoload entry. + * + * @param string $method which method to remove the autoload entry for + * + * @return bool TRUE if an entry was removed, FALSE if not + * + * @access public + */ + function removeAutoload($method) + { + $method = strtolower($method); + $ok = isset($this->_autoload_map[$method]); + unset($this->_autoload_map[$method]); + return $ok; + } + + // }}} + // {{{ addAggregateObject() + + /** + * Add an aggregate object to this object. If the specified class + * is not defined, loading it will be attempted following PEAR's + * file naming scheme. All the methods in the class will be + * aggregated, except private ones (name starting with an + * underscore) and constructors. + * + * @param string $classname what class to instantiate for the object. + * + * @return void + * + * @access public + */ + function addAggregateObject($classname) + { + $classname = strtolower($classname); + if (!class_exists($classname)) { + $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); + include_once $include_file; + } + $obj =& new $classname; + $methods = get_class_methods($classname); + foreach ($methods as $method) { + // don't import priviate methods and constructors + if ($method{0} != '_' && $method != $classname) { + $this->_method_map[$method] = $obj; + } + } + } + + // }}} + // {{{ removeAggregateObject() + + /** + * Remove an aggregate object. + * + * @param string $classname the class of the object to remove + * + * @return bool TRUE if an object was removed, FALSE if not + * + * @access public + */ + function removeAggregateObject($classname) + { + $ok = false; + $classname = strtolower($classname); + reset($this->_method_map); + while (list($method, $obj) = each($this->_method_map)) { + if (is_a($obj, $classname)) { + unset($this->_method_map[$method]); + $ok = true; + } + } + return $ok; + } + + // }}} + // {{{ __call() + + /** + * Overloaded object call handler, called each time an + * undefined/aggregated method is invoked. This method repeats + * the call in the right aggregate object and passes on the return + * value. + * + * @param string $method which method that was called + * + * @param string $args An array of the parameters passed in the + * original call + * + * @return mixed The return value from the aggregated method, or a PEAR + * error if the called method was unknown. + */ + function __call($method, $args, &$retval) + { + $method = strtolower($method); + if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { + $this->addAggregateObject($this->_autoload_map[$method]); + } + if (isset($this->_method_map[$method])) { + $retval = call_user_func_array(array($this->_method_map[$method], $method), $args); + return true; + } + return false; + } + + // }}} +} + +overload("PEAR_Autoloader"); + +?> diff --git a/src/www/lib/pear/PEAR/Builder.php b/src/www/lib/pear/PEAR/Builder.php new file mode 100644 index 00000000..df415d9a --- /dev/null +++ b/src/www/lib/pear/PEAR/Builder.php @@ -0,0 +1,426 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Builder.php,v 1.1 2005/05/28 01:55:12 henrique Exp $ + +require_once 'PEAR/Common.php'; + +/** + * Class to handle building (compiling) extensions. + * + * @author Stig Sæther Bakken + */ +class PEAR_Builder extends PEAR_Common +{ + // {{{ properties + + var $php_api_version = 0; + var $zend_module_api_no = 0; + var $zend_extension_api_no = 0; + + var $extensions_built = array(); + + var $current_callback = null; + + // used for msdev builds + var $_lastline = null; + var $_firstline = null; + // }}} + // {{{ constructor + + /** + * PEAR_Builder constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Builder(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + } + + // }}} + + // {{{ _build_win32() + + /** + * Build an extension from source on windows. + * requires msdev + */ + function _build_win32($descfile, $callback = null) + { + if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) { + return $info; + } + $dir = dirname($descfile); + $old_cwd = getcwd(); + + if (!@chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + $this->log(2, "building in $dir"); + + $dsp = $info['package'].'.dsp'; + if (!@is_file("$dir/$dsp")) { + return $this->raiseError("The DSP $dsp does not exist."); + } + // XXX TODO: make release build type configurable + $command = 'msdev '.$dsp.' /MAKE "'.$info['package']. ' - Release"'; + + $this->current_callback = $callback; + $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); + if (PEAR::isError($err)) { + return $err; + } + + // figure out the build platform and type + $platform = 'Win32'; + $buildtype = 'Release'; + if (preg_match('/.*?'.$info['package'].'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { + $platform = $matches[1]; + $buildtype = $matches[2]; + } + + if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/',$this->_lastline,$matches)) { + if ($matches[2]) { + // there were errors in the build + return $this->raiseError("There were errors during compilation."); + } + $out = $matches[1]; + } else { + return $this->raiseError("Did not understand the completion status returned from msdev.exe."); + } + + // msdev doesn't tell us the output directory :/ + // open the dsp, find /out and use that directory + $dsptext = join(file($dsp),''); + + // this regex depends on the build platform and type having been + // correctly identified above. + $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. + $info['package'].'\s-\s'. + $platform.'\s'. + $buildtype.'").*?'. + '\/out:"(.*?)"/is'; + + if ($dsptext && preg_match($regex,$dsptext,$matches)) { + // what we get back is a relative path to the output file itself. + $outfile = realpath($matches[2]); + } else { + return $this->raiseError("Could not retrieve output information from $dsp."); + } + if (@copy($outfile, "$dir/$out")) { + $outfile = "$dir/$out"; + } + + $built_files[] = array( + 'file' => "$outfile", + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + + return $built_files; + } + // }}} + + // {{{ msdevCallback() + function msdevCallback($what, $data) + { + if (!$this->_firstline) + $this->_firstline = $data; + $this->_lastline = $data; + } + // }}} + + // {{{ _harventInstDir + /** + * @param string + * @param string + * @param array + * @access private + */ + function _harvestInstDir($dest_prefix, $dirname, &$built_files) + { + $d = opendir($dirname); + if (!$d) + return false; + + $ret = true; + while (($ent = readdir($d)) !== false) { + if ($ent{0} == '.') + continue; + + $full = $dirname . DIRECTORY_SEPARATOR . $ent; + if (is_dir($full)) { + if (!$this->_harvestInstDir( + $dest_prefix . DIRECTORY_SEPARATOR . $ent, + $full, $built_files)) { + $ret = false; + break; + } + } else { + $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; + $built_files[] = array( + 'file' => $full, + 'dest' => $dest, + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + } + } + closedir($d); + return $ret; + } + + // }}} + + // {{{ build() + + /** + * Build an extension from source. Runs "phpize" in the source + * directory, but compiles in a temporary directory + * (/var/tmp/pear-build-USER/PACKAGE-VERSION). + * + * @param string $descfile path to XML package description file + * + * @param mixed $callback callback function used to report output, + * see PEAR_Builder::_runCommand for details + * + * @return array an array of associative arrays with built files, + * format: + * array( array( 'file' => '/path/to/ext.so', + * 'php_api' => YYYYMMDD, + * 'zend_mod_api' => YYYYMMDD, + * 'zend_ext_api' => YYYYMMDD ), + * ... ) + * + * @access public + * + * @see PEAR_Builder::_runCommand + * @see PEAR_Common::infoFromDescriptionFile + */ + function build($descfile, $callback = null) + { + if (PEAR_OS == "Windows") { + return $this->_build_win32($descfile,$callback); + } + if (PEAR_OS != 'Unix') { + return $this->raiseError("building extensions not supported on this platform"); + } + if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) { + return $info; + } + $dir = dirname($descfile); + $old_cwd = getcwd(); + if (!@chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + $vdir = "$info[package]-$info[version]"; + if (is_dir($vdir)) { + chdir($vdir); + } + $dir = getcwd(); + $this->log(2, "building in $dir"); + $this->current_callback = $callback; + putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); + $err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback')); + if (PEAR::isError($err)) { + return $err; + } + if (!$err) { + return $this->raiseError("`phpize' failed"); + } + + // {{{ start of interactive part + $configure_command = "$dir/configure"; + if (isset($info['configure_options'])) { + foreach ($info['configure_options'] as $o) { + list($r) = $this->ui->userDialog('build', + array($o['prompt']), + array('text'), + array(@$o['default'])); + if (substr($o['name'], 0, 5) == 'with-' && + ($r == 'yes' || $r == 'autodetect')) { + $configure_command .= " --$o[name]"; + } else { + $configure_command .= " --$o[name]=".trim($r); + } + } + } + // }}} end of interactive part + + // FIXME make configurable + if(!$user=getenv('USER')){ + $user='defaultuser'; + } + $build_basedir = "/var/tmp/pear-build-$user"; + $build_dir = "$build_basedir/$info[package]-$info[version]"; + $inst_dir = "$build_basedir/install-$info[package]-$info[version]"; + $this->log(1, "building in $build_dir"); + if (is_dir($build_dir)) { + System::rm('-rf', $build_dir); + } + if (!System::mkDir(array('-p', $build_dir))) { + return $this->raiseError("could not create build dir: $build_dir"); + } + $this->addTempFile($build_dir); + if (!System::mkDir(array('-p', $inst_dir))) { + return $this->raiseError("could not create temporary install dir: $inst_dir"); + } + $this->addTempFile($inst_dir); + + if (getenv('MAKE')) { + $make_command = getenv('MAKE'); + } else { + $make_command = 'make'; + } + $to_run = array( + $configure_command, + $make_command, + "$make_command INSTALL_ROOT=\"$inst_dir\" install", + "find \"$inst_dir\" -ls" + ); + if (!@chdir($build_dir)) { + return $this->raiseError("could not chdir to $build_dir"); + } + putenv('PHP_PEAR_VERSION=@PEAR-VER@'); + foreach ($to_run as $cmd) { + $err = $this->_runCommand($cmd, $callback); + if (PEAR::isError($err)) { + chdir($old_cwd); + return $err; + } + if (!$err) { + chdir($old_cwd); + return $this->raiseError("`$cmd' failed"); + } + } + if (!($dp = opendir("modules"))) { + chdir($old_cwd); + return $this->raiseError("no `modules' directory found"); + } + $built_files = array(); + $prefix = exec("php-config --prefix"); + $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); + chdir($old_cwd); + return $built_files; + } + + // }}} + // {{{ phpizeCallback() + + /** + * Message callback function used when running the "phpize" + * program. Extracts the API numbers used. Ignores other message + * types than "cmdoutput". + * + * @param string $what the type of message + * @param mixed $data the message + * + * @return void + * + * @access public + */ + function phpizeCallback($what, $data) + { + if ($what != 'cmdoutput') { + return; + } + $this->log(1, rtrim($data)); + if (preg_match('/You should update your .aclocal.m4/', $data)) { + return; + } + $matches = array(); + if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { + $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); + $apino = (int)$matches[2]; + if (isset($this->$member)) { + $this->$member = $apino; + //$msg = sprintf("%-22s : %d", $matches[1], $apino); + //$this->log(1, $msg); + } + } + } + + // }}} + // {{{ _runCommand() + + /** + * Run an external command, using a message callback to report + * output. The command will be run through popen and output is + * reported for every line with a "cmdoutput" message with the + * line string, including newlines, as payload. + * + * @param string $command the command to run + * + * @param mixed $callback (optional) function to use as message + * callback + * + * @return bool whether the command was successful (exit code 0 + * means success, any other means failure) + * + * @access private + */ + function _runCommand($command, $callback = null) + { + $this->log(1, "running: $command"); + $pp = @popen("$command 2>&1", "r"); + if (!$pp) { + return $this->raiseError("failed to run `$command'"); + } + if ($callback && $callback[0]->debug == 1) { + $olddbg = $callback[0]->debug; + $callback[0]->debug = 2; + } + + while ($line = fgets($pp, 1024)) { + if ($callback) { + call_user_func($callback, 'cmdoutput', $line); + } else { + $this->log(2, rtrim($line)); + } + } + if ($callback && isset($olddbg)) { + $callback[0]->debug = $olddbg; + } + $exitcode = @pclose($pp); + return ($exitcode == 0); + } + + // }}} + // {{{ log() + + function log($level, $msg) + { + if ($this->current_callback) { + if ($this->debug >= $level) { + call_user_func($this->current_callback, 'output', $msg); + } + return; + } + return PEAR_Common::log($level, $msg); + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Command.php b/src/www/lib/pear/PEAR/Command.php new file mode 100644 index 00000000..df18aac0 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command.php @@ -0,0 +1,398 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Command.php,v 1.1 2005/05/28 01:55:12 henrique Exp $ + + +require_once "PEAR.php"; + +/** + * List of commands and what classes they are implemented in. + * @var array command => implementing class + */ +$GLOBALS['_PEAR_Command_commandlist'] = array(); + +/** + * List of shortcuts to common commands. + * @var array shortcut => command + */ +$GLOBALS['_PEAR_Command_shortcuts'] = array(); + +/** + * Array of command objects + * @var array class => object + */ +$GLOBALS['_PEAR_Command_objects'] = array(); + +/** + * Which user interface class is being used. + * @var string class name + */ +$GLOBALS['_PEAR_Command_uiclass'] = 'PEAR_Frontend_CLI'; + +/** + * Instance of $_PEAR_Command_uiclass. + * @var object + */ +$GLOBALS['_PEAR_Command_uiobject'] = null; + +/** + * PEAR command class, a simple factory class for administrative + * commands. + * + * How to implement command classes: + * + * - The class must be called PEAR_Command_Nnn, installed in the + * "PEAR/Common" subdir, with a method called getCommands() that + * returns an array of the commands implemented by the class (see + * PEAR/Command/Install.php for an example). + * + * - The class must implement a run() function that is called with three + * params: + * + * (string) command name + * (array) assoc array with options, freely defined by each + * command, for example: + * array('force' => true) + * (array) list of the other parameters + * + * The run() function returns a PEAR_CommandResponse object. Use + * these methods to get information: + * + * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) + * *_PARTIAL means that you need to issue at least + * one more command to complete the operation + * (used for example for validation steps). + * + * string getMessage() Returns a message for the user. Remember, + * no HTML or other interface-specific markup. + * + * If something unexpected happens, run() returns a PEAR error. + * + * - DON'T OUTPUT ANYTHING! Return text for output instead. + * + * - DON'T USE HTML! The text you return will be used from both Gtk, + * web and command-line interfaces, so for now, keep everything to + * plain text. + * + * - DON'T USE EXIT OR DIE! Always use pear errors. From static + * classes do PEAR::raiseError(), from other classes do + * $this->raiseError(). + */ +class PEAR_Command +{ + // {{{ factory() + + /** + * Get the right object for executing a command. + * + * @param string $command The name of the command + * @param object $config Instance of PEAR_Config object + * + * @return object the command object or a PEAR error + * + * @access public + * @static + */ + function factory($command, &$config) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return PEAR::raiseError("unknown command `$command'"); + } + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + return PEAR::raiseError("unknown command `$command'"); + } + $ui =& PEAR_Command::getFrontendObject(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getFrontendObject() + + /** + * Get instance of frontend object. + * + * @return object + * @static + */ + function &getFrontendObject() + { + if (empty($GLOBALS['_PEAR_Command_uiobject'])) { + $GLOBALS['_PEAR_Command_uiobject'] = &new $GLOBALS['_PEAR_Command_uiclass']; + } + return $GLOBALS['_PEAR_Command_uiobject']; + } + + // }}} + // {{{ & setFrontendClass() + + /** + * Load current frontend class. + * + * @param string $uiclass Name of class implementing the frontend + * + * @return object the frontend object, or a PEAR error + * @static + */ + function &setFrontendClass($uiclass) + { + if (is_object($GLOBALS['_PEAR_Command_uiobject']) && + is_a($GLOBALS['_PEAR_Command_uiobject'], $uiclass)) { + return $GLOBALS['_PEAR_Command_uiobject']; + } + if (!class_exists($uiclass)) { + $file = str_replace('_', '/', $uiclass) . '.php'; + if (PEAR_Command::isIncludeable($file)) { + include_once $file; + } + } + if (class_exists($uiclass)) { + $obj = &new $uiclass; + // quick test to see if this class implements a few of the most + // important frontend methods + if (method_exists($obj, 'userConfirm')) { + $GLOBALS['_PEAR_Command_uiobject'] = &$obj; + $GLOBALS['_PEAR_Command_uiclass'] = $uiclass; + return $obj; + } else { + $err = PEAR::raiseError("not a frontend class: $uiclass"); + return $err; + } + } + $err = PEAR::raiseError("no such class: $uiclass"); + return $err; + } + + // }}} + // {{{ setFrontendType() + + // }}} + // {{{ isIncludeable() + + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { + return true; + } + $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($ipath as $include) { + $test = realpath($include . DIRECTORY_SEPARATOR . $path); + if (file_exists($test) && is_readable($test)) { + return true; + } + } + return false; + } + + /** + * Set current frontend. + * + * @param string $uitype Name of the frontend type (for example "CLI") + * + * @return object the frontend object, or a PEAR error + * @static + */ + function setFrontendType($uitype) + { + $uiclass = 'PEAR_Frontend_' . $uitype; + return PEAR_Command::setFrontendClass($uiclass); + } + + // }}} + // {{{ registerCommands() + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * + * @param bool (optional) if FALSE (default), the new list of + * commands should replace the current one. If TRUE, + * new entries will be merged with old. + * + * @param string (optional) where (what directory) to look for + * classes, defaults to the Command subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * + * @access public + * @static + */ + function registerCommands($merge = false, $dir = null) + { + if ($dir === null) { + $dir = dirname(__FILE__) . '/Command'; + } + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerCommands: opendir($dir) failed"); + } + if (!$merge) { + $GLOBALS['_PEAR_Command_commandlist'] = array(); + } + while ($entry = readdir($dp)) { + if ($entry{0} == '.' || substr($entry, -4) != '.php' || $entry == 'Common.php') { + continue; + } + $class = "PEAR_Command_".substr($entry, 0, -4); + $file = "$dir/$entry"; + include_once $file; + // List of commands + if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { + $GLOBALS['_PEAR_Command_objects'][$class] = &new $class($ui, $config); + } + $implements = $GLOBALS['_PEAR_Command_objects'][$class]->getCommands(); + foreach ($implements as $command => $desc) { + $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; + $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc; + } + $shortcuts = $GLOBALS['_PEAR_Command_objects'][$class]->getShortcuts(); + foreach ($shortcuts as $shortcut => $command) { + $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; + } + } + @closedir($dp); + return true; + } + + // }}} + // {{{ getCommands() + + /** + * Get the list of currently supported commands, and what + * classes implement them. + * + * @return array command => implementing class + * + * @access public + * @static + */ + function getCommands() + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_commandlist']; + } + + // }}} + // {{{ getShortcuts() + + /** + * Get the list of command shortcuts. + * + * @return array shortcut => command + * + * @access public + * @static + */ + function getShortcuts() + { + if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_shortcuts']; + } + + // }}} + // {{{ getGetoptArgs() + + /** + * Compiles arguments for getopt. + * + * @param string $command command to get optstring for + * @param string $short_args (reference) short getopt format + * @param array $long_args (reference) long getopt format + * + * @return void + * + * @access public + * @static + */ + function getGetoptArgs($command, &$short_args, &$long_args) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return null; + } + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + $obj = &$GLOBALS['_PEAR_Command_objects'][$class]; + return $obj->getGetoptArgs($command, $short_args, $long_args); + } + + // }}} + // {{{ getDescription() + + /** + * Get description for a command. + * + * @param string $command Name of the command + * + * @return string command description + * + * @access public + * @static + */ + function getDescription($command) + { + if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { + return null; + } + return $GLOBALS['_PEAR_Command_commanddesc'][$command]; + } + + // }}} + // {{{ getHelp() + + /** + * Get help for command. + * + * @param string $command Name of the command to return help for + * + * @access public + * @static + */ + function getHelp($command) + { + $cmds = PEAR_Command::getCommands(); + if (isset($cmds[$command])) { + $class = $cmds[$command]; + return $GLOBALS['_PEAR_Command_objects'][$class]->getHelp($command); + } + return false; + } + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Command/Auth.php b/src/www/lib/pear/PEAR/Command/Auth.php new file mode 100644 index 00000000..c85d685c --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Auth.php @@ -0,0 +1,155 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Auth.php,v 1.1 2005/05/28 01:55:56 henrique Exp $ + +require_once "PEAR/Command/Common.php"; +require_once "PEAR/Remote.php"; +require_once "PEAR/Config.php"; + +/** + * PEAR commands for managing configuration data. + * + */ +class PEAR_Command_Auth extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'login' => array( + 'summary' => 'Connects and authenticates to remote server', + 'shortcut' => 'li', + 'function' => 'doLogin', + 'options' => array(), + 'doc' => ' +Log in to the remote server. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server.', + ), + 'logout' => array( + 'summary' => 'Logs out from the remote server', + 'shortcut' => 'lo', + 'function' => 'doLogout', + 'options' => array(), + 'doc' => ' +Logs out from the remote server. This command does not actually +connect to the remote server, it only deletes the stored username and +password from your user configuration.', + ) + + ); + + // }}} + + // {{{ constructor + + /** + * PEAR_Command_Auth constructor. + * + * @access public + */ + function PEAR_Command_Auth(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doLogin() + + /** + * Execute the 'login' command. + * + * @param string $command command name + * + * @param array $options option_name => value + * + * @param array $params list of additional parameters + * + * @return bool TRUE on success, FALSE for unknown commands, or + * a PEAR error on failure + * + * @access public + */ + function doLogin($command, $options, $params) + { + $server = $this->config->get('master_server'); + $remote = new PEAR_Remote($this->config); + $username = $this->config->get('username'); + if (empty($username)) { + $username = @$_ENV['USER']; + } + $this->ui->outputData("Logging in to $server.", $command); + + list($username, $password) = $this->ui->userDialog( + $command, + array('Username', 'Password'), + array('text', 'password'), + array($username, '') + ); + $username = trim($username); + $password = trim($password); + + $this->config->set('username', $username); + $this->config->set('password', $password); + + $remote->expectError(401); + $ok = $remote->call('logintest'); + $remote->popExpect(); + if ($ok === true) { + $this->ui->outputData("Logged in.", $command); + $this->config->store(); + } else { + return $this->raiseError("Login failed!"); + } + + } + + // }}} + // {{{ doLogout() + + /** + * Execute the 'logout' command. + * + * @param string $command command name + * + * @param array $options option_name => value + * + * @param array $params list of additional parameters + * + * @return bool TRUE on success, FALSE for unknown commands, or + * a PEAR error on failure + * + * @access public + */ + function doLogout($command, $options, $params) + { + $server = $this->config->get('master_server'); + $this->ui->outputData("Logging out from $server.", $command); + $this->config->remove('username'); + $this->config->remove('password'); + $this->config->store(); + } + + // }}} +} + +?> \ No newline at end of file diff --git a/src/www/lib/pear/PEAR/Command/Build.php b/src/www/lib/pear/PEAR/Command/Build.php new file mode 100644 index 00000000..75536509 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Build.php @@ -0,0 +1,89 @@ + | +// | Tomas V.V.Cox | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Build.php,v 1.1 2005/05/28 01:55:56 henrique Exp $ + +require_once "PEAR/Command/Common.php"; +require_once "PEAR/Builder.php"; + +/** + * PEAR commands for building extensions. + * + */ +class PEAR_Command_Build extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'build' => array( + 'summary' => 'Build an Extension From C Source', + 'function' => 'doBuild', + 'shortcut' => 'b', + 'options' => array(), + 'doc' => '[package.xml] +Builds one or more extensions contained in a package.' + ), + ); + + // }}} + + // {{{ constructor + + /** + * PEAR_Command_Build constructor. + * + * @access public + */ + function PEAR_Command_Build(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doBuild() + + function doBuild($command, $options, $params) + { + if (sizeof($params) < 1) { + $params[0] = 'package.xml'; + } + $builder = &new PEAR_Builder($this->ui); + $this->debug = $this->config->get('verbose'); + $err = $builder->build($params[0], array(&$this, 'buildCallback')); + if (PEAR::isError($err)) { + return $err; + } + return true; + } + + // }}} + // {{{ buildCallback() + + function buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } + + // }}} +} diff --git a/src/www/lib/pear/PEAR/Command/Common.php b/src/www/lib/pear/PEAR/Command/Common.php new file mode 100644 index 00000000..bb4d5ec9 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Common.php @@ -0,0 +1,249 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.1 2005/05/28 01:55:56 henrique Exp $ + +require_once "PEAR.php"; + +class PEAR_Command_Common extends PEAR +{ + // {{{ properties + + /** + * PEAR_Config object used to pass user system and configuration + * on when executing commands + * + * @var object + */ + var $config; + + /** + * User Interface object, for all interaction with the user. + * @var object + */ + var $ui; + + var $_deps_rel_trans = array( + 'lt' => '<', + 'le' => '<=', + 'eq' => '=', + 'ne' => '!=', + 'gt' => '>', + 'ge' => '>=', + 'has' => '==' + ); + + var $_deps_type_trans = array( + 'pkg' => 'package', + 'extension' => 'extension', + 'php' => 'PHP', + 'prog' => 'external program', + 'ldlib' => 'external library for linking', + 'rtlib' => 'external runtime library', + 'os' => 'operating system', + 'websrv' => 'web server', + 'sapi' => 'SAPI backend' + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Common constructor. + * + * @access public + */ + function PEAR_Command_Common(&$ui, &$config) + { + parent::PEAR(); + $this->config = &$config; + $this->ui = &$ui; + } + + // }}} + + // {{{ getCommands() + + /** + * Return a list of all the commands defined by this class. + * @return array list of commands + * @access public + */ + function getCommands() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + $ret[$command] = $this->commands[$command]['summary']; + } + return $ret; + } + + // }}} + // {{{ getShortcuts() + + /** + * Return a list of all the command shortcuts defined by this class. + * @return array shortcut => command + * @access public + */ + function getShortcuts() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + if (isset($this->commands[$command]['shortcut'])) { + $ret[$this->commands[$command]['shortcut']] = $command; + } + } + return $ret; + } + + // }}} + // {{{ getOptions() + + function getOptions($command) + { + return @$this->commands[$command]['options']; + } + + // }}} + // {{{ getGetoptArgs() + + function getGetoptArgs($command, &$short_args, &$long_args) + { + $short_args = ""; + $long_args = array(); + if (empty($this->commands[$command])) { + return; + } + reset($this->commands[$command]); + while (list($option, $info) = each($this->commands[$command]['options'])) { + $larg = $sarg = ''; + if (isset($info['arg'])) { + if ($info['arg']{0} == '(') { + $larg = '=='; + $sarg = '::'; + $arg = substr($info['arg'], 1, -1); + } else { + $larg = '='; + $sarg = ':'; + $arg = $info['arg']; + } + } + if (isset($info['shortopt'])) { + $short_args .= $info['shortopt'] . $sarg; + } + $long_args[] = $option . $larg; + } + } + + // }}} + // {{{ getHelp() + /** + * Returns the help message for the given command + * + * @param string $command The command + * @return mixed A fail string if the command does not have help or + * a two elements array containing [0]=>help string, + * [1]=> help string for the accepted cmd args + */ + function getHelp($command) + { + $config = &PEAR_Config::singleton(); + $help = @$this->commands[$command]['doc']; + if (empty($help)) { + // XXX (cox) Fallback to summary if there is no doc (show both?) + if (!$help = @$this->commands[$command]['summary']) { + return "No help for command \"$command\""; + } + } + if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { + foreach($matches[0] as $k => $v) { + $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); + } + } + return array($help, $this->getHelpArgs($command)); + } + + // }}} + // {{{ getHelpArgs() + /** + * Returns the help for the accepted arguments of a command + * + * @param string $command + * @return string The help string + */ + function getHelpArgs($command) + { + if (isset($this->commands[$command]['options']) && + count($this->commands[$command]['options'])) + { + $help = "Options:\n"; + foreach ($this->commands[$command]['options'] as $k => $v) { + if (isset($v['arg'])) { + if ($v['arg']{0} == '(') { + $arg = substr($v['arg'], 1, -1); + $sapp = " [$arg]"; + $lapp = "[=$arg]"; + } else { + $sapp = " $v[arg]"; + $lapp = "=$v[arg]"; + } + } else { + $sapp = $lapp = ""; + } + if (isset($v['shortopt'])) { + $s = $v['shortopt']; + @$help .= " -$s$sapp, --$k$lapp\n"; + } else { + @$help .= " --$k$lapp\n"; + } + $p = " "; + $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); + $help .= " $doc\n"; + } + return $help; + } + return null; + } + + // }}} + // {{{ run() + + function run($command, $options, $params) + { + $func = @$this->commands[$command]['function']; + if (empty($func)) { + // look for shortcuts + foreach (array_keys($this->commands) as $cmd) { + if (@$this->commands[$cmd]['shortcut'] == $command) { + $command = $cmd; + $func = @$this->commands[$command]['function']; + if (empty($func)) { + return $this->raiseError("unknown command `$command'"); + } + break; + } + } + } + return $this->$func($command, $options, $params); + } + + // }}} +} + +?> \ No newline at end of file diff --git a/src/www/lib/pear/PEAR/Command/Config.php b/src/www/lib/pear/PEAR/Command/Config.php new file mode 100644 index 00000000..21b75403 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Config.php @@ -0,0 +1,225 @@ + | +// | Tomas V.V.Cox | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Config.php,v 1.1 2005/05/28 01:55:57 henrique Exp $ + +require_once "PEAR/Command/Common.php"; +require_once "PEAR/Config.php"; + +/** + * PEAR commands for managing configuration data. + * + */ +class PEAR_Command_Config extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'config-show' => array( + 'summary' => 'Show All Settings', + 'function' => 'doConfigShow', + 'shortcut' => 'csh', + 'options' => array(), + 'doc' => ' +Displays all configuration values. An optional argument +may be used to tell which configuration layer to display. Valid +configuration layers are "user", "system" and "default". +', + ), + 'config-get' => array( + 'summary' => 'Show One Setting', + 'function' => 'doConfigGet', + 'shortcut' => 'cg', + 'options' => array(), + 'doc' => ' [layer] +Displays the value of one configuration parameter. The +first argument is the name of the parameter, an optional second argument +may be used to tell which configuration layer to look in. Valid configuration +layers are "user", "system" and "default". If no layer is specified, a value +will be picked from the first layer that defines the parameter, in the order +just specified. +', + ), + 'config-set' => array( + 'summary' => 'Change Setting', + 'function' => 'doConfigSet', + 'shortcut' => 'cs', + 'options' => array(), + 'doc' => ' [layer] +Sets the value of one configuration parameter. The first argument is +the name of the parameter, the second argument is the new value. Some +parameters are subject to validation, and the command will fail with +an error message if the new value does not make sense. An optional +third argument may be used to specify in which layer to set the +configuration parameter. The default layer is "user". +', + ), + 'config-help' => array( + 'summary' => 'Show Information About Setting', + 'function' => 'doConfigHelp', + 'shortcut' => 'ch', + 'options' => array(), + 'doc' => '[parameter] +Displays help for a configuration parameter. Without arguments it +displays help for all configuration parameters. +', + ), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Config constructor. + * + * @access public + */ + function PEAR_Command_Config(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doConfigShow() + + function doConfigShow($command, $options, $params) + { + // $params[0] -> the layer + if ($error = $this->_checkLayer(@$params[0])) { + return $this->raiseError($error); + } + $keys = $this->config->getKeys(); + sort($keys); + $data = array('caption' => 'Configuration:'); + foreach ($keys as $key) { + $type = $this->config->getType($key); + $value = $this->config->get($key, @$params[0]); + if ($type == 'password' && $value) { + $value = '********'; + } + if ($value === false) { + $value = 'false'; + } elseif ($value === true) { + $value = 'true'; + } + $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value); + } + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doConfigGet() + + function doConfigGet($command, $options, $params) + { + // $params[0] -> the parameter + // $params[1] -> the layer + if ($error = $this->_checkLayer(@$params[1])) { + return $this->raiseError($error); + } + if (sizeof($params) < 1 || sizeof($params) > 2) { + return $this->raiseError("config-get expects 1 or 2 parameters"); + } elseif (sizeof($params) == 1) { + $this->ui->outputData($this->config->get($params[0]), $command); + } else { + $data = $this->config->get($params[0], $params[1]); + $this->ui->outputData($data, $command); + } + return true; + } + + // }}} + // {{{ doConfigSet() + + function doConfigSet($command, $options, $params) + { + // $param[0] -> a parameter to set + // $param[1] -> the value for the parameter + // $param[2] -> the layer + $failmsg = ''; + if (sizeof($params) < 2 || sizeof($params) > 3) { + $failmsg .= "config-set expects 2 or 3 parameters"; + return PEAR::raiseError($failmsg); + } + if ($error = $this->_checkLayer(@$params[2])) { + $failmsg .= $error; + return PEAR::raiseError($failmsg); + } + if (!call_user_func_array(array(&$this->config, 'set'), $params)) + { + $failmsg = "config-set (" . implode(", ", $params) . ") failed"; + } else { + $this->config->store(); + } + if ($failmsg) { + return $this->raiseError($failmsg); + } + return true; + } + + // }}} + // {{{ doConfigHelp() + + function doConfigHelp($command, $options, $params) + { + if (empty($params)) { + $params = $this->config->getKeys(); + } + $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : ''); + $data['headline'] = array('Name', 'Type', 'Description'); + $data['border'] = true; + foreach ($params as $name) { + $type = $this->config->getType($name); + $docs = $this->config->getDocs($name); + if ($type == 'set') { + $docs = rtrim($docs) . "\nValid set: " . + implode(' ', $this->config->getSetValues($name)); + } + $data['data'][] = array($name, $type, $docs); + } + $this->ui->outputData($data, $command); + } + + // }}} + // {{{ _checkLayer() + + /** + * Checks if a layer is defined or not + * + * @param string $layer The layer to search for + * @return mixed False on no error or the error message + */ + function _checkLayer($layer = null) + { + if (!empty($layer) && $layer != 'default') { + $layers = $this->config->getLayers(); + if (!in_array($layer, $layers)) { + return " only the layers: \"" . implode('" or "', $layers) . "\" are supported"; + } + } + return false; + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Command/Install.php b/src/www/lib/pear/PEAR/Command/Install.php new file mode 100644 index 00000000..e6d352a4 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Install.php @@ -0,0 +1,470 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Install.php,v 1.1 2005/05/28 01:55:57 henrique Exp $ + +require_once "PEAR/Command/Common.php"; +require_once "PEAR/Installer.php"; + +/** + * PEAR commands for installation or deinstallation/upgrading of + * packages. + * + */ +class PEAR_Command_Install extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'install' => array( + 'summary' => 'Install Package', + 'function' => 'doInstall', + 'shortcut' => 'i', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'will overwrite newer installed packages', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, install anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as installed', + ), + 'soft' => array( + 'shortopt' => 's', + 'doc' => 'soft install, fail silently, or upgrade if already installed', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + ), + 'doc' => ' ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: + +"Package-1.0.tgz" : installs from a local file + +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. + +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. + +"Package" : queries your configured server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). + +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. +'), + 'upgrade' => array( + 'summary' => 'Upgrade Package', + 'function' => 'doInstall', + 'shortcut' => 'up', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'overwrite newer installed packages', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + ), + 'doc' => ' ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. + +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). + +More than one package may be specified at once. +'), + 'upgrade-all' => array( + 'summary' => 'Upgrade All Packages', + 'function' => 'doInstall', + 'shortcut' => 'ua', + 'options' => array( + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + ), + 'doc' => ' +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. +'), + 'uninstall' => array( + 'summary' => 'Un-install Package', + 'function' => 'doUninstall', + 'shortcut' => 'un', + 'options' => array( + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, uninstall anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not remove files, only register the packages as not installed', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + ), + 'doc' => ' ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. +'), + 'bundle' => array( + 'summary' => 'Unpacks a Pecl Package', + 'function' => 'doBundle', + 'shortcut' => 'bun', + 'options' => array( + 'destination' => array( + 'shortopt' => 'd', + 'arg' => 'DIR', + 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', + ), + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'Force the unpacking even if there were errors in the package', + ), + ), + 'doc' => ' +Unpacks a Pecl Package into the selected location. It will download the +package if needed. +'), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Install constructor. + * + * @access public + */ + function PEAR_Command_Install(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doInstall() + + function doInstall($command, $options, $params) + { + require_once 'PEAR/Downloader.php'; + if (empty($this->installer)) { + $this->installer = &new PEAR_Installer($this->ui); + } + if ($command == 'upgrade') { + $options['upgrade'] = true; + } + if ($command == 'upgrade-all') { + include_once "PEAR/Remote.php"; + $options['upgrade'] = true; + $remote = &new PEAR_Remote($this->config); + $state = $this->config->get('preferred_state'); + if (empty($state) || $state == 'any') { + $latest = $remote->call("package.listLatestReleases"); + } else { + $latest = $remote->call("package.listLatestReleases", $state); + } + if (PEAR::isError($latest)) { + return $latest; + } + $reg = new PEAR_Registry($this->config->get('php_dir')); + $installed = array_flip($reg->listPackages()); + $params = array(); + foreach ($latest as $package => $info) { + $package = strtolower($package); + if (!isset($installed[$package])) { + // skip packages we don't have installed + continue; + } + $inst_version = $reg->packageInfo($package, 'version'); + if (version_compare("$info[version]", "$inst_version", "le")) { + // installed version is up-to-date + continue; + } + $params[] = $package; + $this->ui->outputData(array('data' => "Will upgrade $package"), $command); + } + } + $this->downloader = &new PEAR_Downloader($this->ui, $options, $this->config); + $errors = array(); + $downloaded = array(); + $this->downloader->download($params); + $errors = $this->downloader->getErrorMsgs(); + if (count($errors)) { + $err['data'] = array($errors); + $err['headline'] = 'Install Errors'; + $this->ui->outputData($err); + return $this->raiseError("$command failed"); + } + $downloaded = $this->downloader->getDownloadedPackages(); + $this->installer->sortPkgDeps($downloaded); + foreach ($downloaded as $pkg) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->install($pkg['file'], $options, $this->config); + PEAR::popErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData('ERROR: ' .$info->getMessage()); + continue; + } + if (is_array($info)) { + if ($this->config->get('verbose') > 0) { + $label = "$info[package] $info[version]"; + $out = array('data' => "$command ok: $label"); + if (isset($info['release_warnings'])) { + $out['release_warnings'] = $info['release_warnings']; + } + $this->ui->outputData($out, $command); + } + } else { + return $this->raiseError("$command failed"); + } + } + return true; + } + + // }}} + // {{{ doUninstall() + + function doUninstall($command, $options, $params) + { + if (empty($this->installer)) { + $this->installer = &new PEAR_Installer($this->ui); + } + if (sizeof($params) < 1) { + return $this->raiseError("Please supply the package(s) you want to uninstall"); + } + include_once 'PEAR/Registry.php'; + $reg = new PEAR_Registry($this->config->get('php_dir')); + $newparams = array(); + $badparams = array(); + foreach ($params as $pkg) { + $info = $reg->packageInfo($pkg); + if ($info === null) { + $badparams[] = $pkg; + } else { + $newparams[] = $info; + } + } + $this->installer->sortPkgDeps($newparams, true); + $params = array(); + foreach($newparams as $info) { + $params[] = $info['info']['package']; + } + $params = array_merge($params, $badparams); + foreach ($params as $pkg) { + if ($this->installer->uninstall($pkg, $options)) { + if ($this->config->get('verbose') > 0) { + $this->ui->outputData("uninstall ok: $pkg", $command); + } + } else { + return $this->raiseError("uninstall failed: $pkg"); + } + } + return true; + } + + // }}} + + + // }}} + // {{{ doBundle() + /* + (cox) It just downloads and untars the package, does not do + any check that the PEAR_Installer::_installFile() does. + */ + + function doBundle($command, $options, $params) + { + if (empty($this->installer)) { + $this->installer = &new PEAR_Downloader($this->ui); + } + $installer = &$this->installer; + if (sizeof($params) < 1) { + return $this->raiseError("Please supply the package you want to bundle"); + } + $pkgfile = $params[0]; + $need_download = false; + if (preg_match('#^(http|ftp)://#', $pkgfile)) { + $need_download = true; + } elseif (!@is_file($pkgfile)) { + if ($installer->validPackageName($pkgfile)) { + $pkgfile = $installer->getPackageDownloadUrl($pkgfile); + $need_download = true; + } else { + if (strlen($pkgfile)) { + return $this->raiseError("Could not open the package file: $pkgfile"); + } else { + return $this->raiseError("No package file given"); + } + } + } + + // Download package ----------------------------------------------- + if ($need_download) { + $downloaddir = $installer->config->get('download_dir'); + if (empty($downloaddir)) { + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; + } + $installer->log(2, '+ tmp dir created at ' . $downloaddir); + } + $callback = $this->ui ? array(&$installer, '_downloadCallback') : null; + $file = $installer->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback); + if (PEAR::isError($file)) { + return $this->raiseError($file); + } + $pkgfile = $file; + } + + // Parse xml file ----------------------------------------------- + $pkginfo = $installer->infoFromTgzFile($pkgfile); + if (PEAR::isError($pkginfo)) { + return $this->raiseError($pkginfo); + } + $installer->validatePackageInfo($pkginfo, $errors, $warnings); + // XXX We allow warnings, do we have to do it? + if (count($errors)) { + if (empty($options['force'])) { + return $this->raiseError("The following errors where found:\n". + implode("\n", $errors)); + } else { + $this->log(0, "warning : the following errors were found:\n". + implode("\n", $errors)); + } + } + $pkgname = $pkginfo['package']; + + // Unpacking ------------------------------------------------- + + if (isset($options['destination'])) { + if (!is_dir($options['destination'])) { + System::mkdir('-p ' . $options['destination']); + } + $dest = realpath($options['destination']); + } else { + $pwd = getcwd(); + if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) { + $dest = $pwd . DIRECTORY_SEPARATOR . 'ext'; + } else { + $dest = $pwd; + } + } + $dest .= DIRECTORY_SEPARATOR . $pkgname; + $orig = $pkgname . '-' . $pkginfo['version']; + + $tar = new Archive_Tar($pkgfile); + if (!@$tar->extractModify($dest, $orig)) { + return $this->raiseError("unable to unpack $pkgfile"); + } + $this->ui->outputData("Package ready at '$dest'"); + // }}} + } + + // }}} + +} +?> diff --git a/src/www/lib/pear/PEAR/Command/Mirror.php b/src/www/lib/pear/PEAR/Command/Mirror.php new file mode 100644 index 00000000..4c269dd5 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Mirror.php @@ -0,0 +1,101 @@ + | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Mirror.php,v 1.1 2005/05/28 01:55:57 henrique Exp $ + +require_once "PEAR/Command/Common.php"; +require_once "PEAR/Command.php"; +require_once "PEAR/Remote.php"; +require_once "PEAR.php"; + +/** + * PEAR commands for providing file mirrors + * + */ +class PEAR_Command_Mirror extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'download-all' => array( + 'summary' => 'Downloads each available package from master_server', + 'function' => 'doDownloadAll', + 'shortcut' => 'da', + 'options' => array(), + 'doc' => ' + Requests a list of available packages from the package server + (master_server) and downloads them to current working directory' + ), + ); + + // }}} + + // {{{ constructor + + /** + * PEAR_Command_Mirror constructor. + * + * @access public + * @param object PEAR_Frontend a reference to an frontend + * @param object PEAR_Config a reference to the configuration data + */ + function PEAR_Command_Mirror(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doDownloadAll() + /** + * retrieves a list of avaible Packages from master server + * and downloads them + * + * @access public + * @param string $command the command + * @param array $options the command options before the command + * @param array $params the stuff after the command name + * @return bool true if succesful + * @throw PEAR_Error + */ + function doDownloadAll($command, $options, $params) + { + $this->config->set("php_dir", "."); + $remote = &new PEAR_Remote($this->config); + $remoteInfo = $remote->call("package.listAll"); + if (PEAR::isError($remoteInfo)) { + return $remoteInfo; + } + $cmd = &PEAR_Command::factory("download", $this->config); + if (PEAR::isError($cmd)) { + return $cmd; + } + foreach ($remoteInfo as $pkgn => $pkg) { + /** + * Error handling not neccesary, because already done by + * the download command + */ + $cmd->run("download", array(), array($pkgn)); + } + + return true; + } + + // }}} +} diff --git a/src/www/lib/pear/PEAR/Command/Package.php b/src/www/lib/pear/PEAR/Command/Package.php new file mode 100644 index 00000000..494680dc --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Package.php @@ -0,0 +1,819 @@ + | +// | Martin Jansen | +// | Greg Beaver | +// +----------------------------------------------------------------------+ +// +// $Id: Package.php,v 1.1 2005/05/28 01:55:57 henrique Exp $ + +require_once 'PEAR/Common.php'; +require_once 'PEAR/Command/Common.php'; + +class PEAR_Command_Package extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'package' => array( + 'summary' => 'Build Package', + 'function' => 'doPackage', + 'shortcut' => 'p', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'Do not gzip the package file' + ), + 'showname' => array( + 'shortopt' => 'n', + 'doc' => 'Print the name of the packaged file.', + ), + ), + 'doc' => '[descfile] +Creates a PEAR package from its description file (usually called +package.xml). +' + ), + 'package-validate' => array( + 'summary' => 'Validate Package Consistency', + 'function' => 'doPackageValidate', + 'shortcut' => 'pv', + 'options' => array(), + 'doc' => ' +', + ), + 'cvsdiff' => array( + 'summary' => 'Run a "cvs diff" for all files in a package', + 'function' => 'doCvsDiff', + 'shortcut' => 'cd', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'date' => array( + 'shortopt' => 'D', + 'doc' => 'Diff against revision of DATE', + 'arg' => 'DATE', + ), + 'release' => array( + 'shortopt' => 'R', + 'doc' => 'Diff against tag for package release REL', + 'arg' => 'REL', + ), + 'revision' => array( + 'shortopt' => 'r', + 'doc' => 'Diff against revision REV', + 'arg' => 'REV', + ), + 'context' => array( + 'shortopt' => 'c', + 'doc' => 'Generate context diff', + ), + 'unified' => array( + 'shortopt' => 'u', + 'doc' => 'Generate unified diff', + ), + 'ignore-case' => array( + 'shortopt' => 'i', + 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent', + ), + 'ignore-whitespace' => array( + 'shortopt' => 'b', + 'doc' => 'Ignore changes in amount of white space', + ), + 'ignore-blank-lines' => array( + 'shortopt' => 'B', + 'doc' => 'Ignore changes that insert or delete blank lines', + ), + 'brief' => array( + 'doc' => 'Report only whether the files differ, no details', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. +', + ), + 'cvstag' => array( + 'summary' => 'Set CVS Release Tag', + 'function' => 'doCvsTag', + 'shortcut' => 'ct', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'slide' => array( + 'shortopt' => 'F', + 'doc' => 'Move (slide) tag if it exists', + ), + 'delete' => array( + 'shortopt' => 'd', + 'doc' => 'Remove tag', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. +', + ), + 'run-tests' => array( + 'summary' => 'Run Regression Tests', + 'function' => 'doRunTests', + 'shortcut' => 'rt', + 'options' => array( + 'recur' => array( + 'shortopt' => 'r', + 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum', + ), + 'ini' => array( + 'shortopt' => 'i', + 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"', + 'arg' => 'SETTINGS' + ), + 'realtimelog' => array( + 'shortopt' => 'l', + 'doc' => 'Log test runs/results as they are run', + ), + ), + 'doc' => '[testfile|dir ...] +Run regression tests with PHP\'s regression testing script (run-tests.php).', + ), + 'package-dependencies' => array( + 'summary' => 'Show package dependencies', + 'function' => 'doPackageDependencies', + 'shortcut' => 'pd', + 'options' => array(), + 'doc' => ' +List all depencies the package has.' + ), + 'sign' => array( + 'summary' => 'Sign a package distribution file', + 'function' => 'doSign', + 'shortcut' => 'si', + 'options' => array(), + 'doc' => ' +Signs a package distribution (.tar or .tgz) file with GnuPG.', + ), + 'makerpm' => array( + 'summary' => 'Builds an RPM spec file from a PEAR package', + 'function' => 'doMakeRPM', + 'shortcut' => 'rpm', + 'options' => array( + 'spec-template' => array( + 'shortopt' => 't', + 'arg' => 'FILE', + 'doc' => 'Use FILE as RPM spec file template' + ), + 'rpm-pkgname' => array( + 'shortopt' => 'p', + 'arg' => 'FORMAT', + 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced +by the PEAR package name, defaults to "PEAR::%s".', + ), + ), + 'doc' => ' + +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm +', + ), + ); + + var $output; + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Package constructor. + * + * @access public + */ + function PEAR_Command_Package(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ _displayValidationResults() + + function _displayValidationResults($err, $warn, $strict = false) + { + foreach ($err as $e) { + $this->output .= "Error: $e\n"; + } + foreach ($warn as $w) { + $this->output .= "Warning: $w\n"; + } + $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n", + sizeof($err), sizeof($warn)); + if ($strict && sizeof($err) > 0) { + $this->output .= "Fix these errors and try again."; + return false; + } + return true; + } + + // }}} + // {{{ doPackage() + + function doPackage($command, $options, $params) + { + $this->output = ''; + include_once 'PEAR/Packager.php'; + if (sizeof($params) < 1) { + $params[0] = "package.xml"; + } + $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; + $packager =& new PEAR_Packager(); + $err = $warn = array(); + $dir = dirname($pkginfofile); + $compress = empty($options['nocompress']) ? true : false; + $result = $packager->package($pkginfofile, $compress); + if (PEAR::isError($result)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError($result); + } + // Don't want output, only the package file name just created + if (isset($options['showname'])) { + $this->output = $result; + } + if (PEAR::isError($result)) { + $this->output .= "Package failed: ".$result->getMessage(); + } + $this->ui->outputData($this->output, $command); + return true; + } + + // }}} + // {{{ doPackageValidate() + + function doPackageValidate($command, $options, $params) + { + $this->output = ''; + if (sizeof($params) < 1) { + $params[0] = "package.xml"; + } + $obj = new PEAR_Common; + $info = null; + if ($fp = @fopen($params[0], "r")) { + $test = fread($fp, 5); + fclose($fp); + if ($test == "infoFromDescriptionFile($params[0]); + } + } + if (empty($info)) { + $info = $obj->infoFromTgzFile($params[0]); + } + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $obj->validatePackageInfo($info, $err, $warn); + $this->_displayValidationResults($err, $warn); + $this->ui->outputData($this->output, $command); + return true; + } + + // }}} + // {{{ doCvsTag() + + function doCvsTag($command, $options, $params) + { + $this->output = ''; + $_cmd = $command; + if (sizeof($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + $obj = new PEAR_Common; + $info = $obj->infoFromDescriptionFile($params[0]); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $err = $warn = array(); + $obj->validatePackageInfo($info, $err, $warn); + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + break; + } + $version = $info['version']; + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); + $cvstag = "RELEASE_$cvsversion"; + $files = array_keys($info['filelist']); + $command = "cvs"; + if (isset($options['quiet'])) { + $command .= ' -q'; + } + if (isset($options['reallyquiet'])) { + $command .= ' -Q'; + } + $command .= ' tag'; + if (isset($options['slide'])) { + $command .= ' -F'; + } + if (isset($options['delete'])) { + $command .= ' -d'; + } + $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); + foreach ($files as $file) { + $command .= ' ' . escapeshellarg($file); + } + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $command\n"; + } + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + $this->ui->outputData($this->output, $_cmd); + return true; + } + + // }}} + // {{{ doCvsDiff() + + function doCvsDiff($command, $options, $params) + { + $this->output = ''; + if (sizeof($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + $obj = new PEAR_Common; + $info = $obj->infoFromDescriptionFile($params[0]); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $files = array_keys($info['filelist']); + $cmd = "cvs"; + if (isset($options['quiet'])) { + $cmd .= ' -q'; + unset($options['quiet']); + } + if (isset($options['reallyquiet'])) { + $cmd .= ' -Q'; + unset($options['reallyquiet']); + } + if (isset($options['release'])) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']); + $cvstag = "RELEASE_$cvsversion"; + $options['revision'] = $cvstag; + unset($options['release']); + } + $execute = true; + if (isset($options['dry-run'])) { + $execute = false; + unset($options['dry-run']); + } + $cmd .= ' diff'; + // the rest of the options are passed right on to "cvs diff" + foreach ($options as $option => $optarg) { + $arg = @$this->commands[$command]['options'][$option]['arg']; + $short = @$this->commands[$command]['options'][$option]['shortopt']; + $cmd .= $short ? " -$short" : " --$option"; + if ($arg && $optarg) { + $cmd .= ($short ? '' : '=') . escapeshellarg($optarg); + } + } + foreach ($files as $file) { + $cmd .= ' ' . escapeshellarg($file); + } + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $cmd\n"; + } + if ($execute) { + $fp = popen($cmd, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + $this->ui->outputData($this->output, $command); + return true; + } + + // }}} + // {{{ doRunTests() + + function doRunTests($command, $options, $params) + { + include_once 'PEAR/RunTest.php'; + $log = new PEAR_Common; + $log->ui = &$this->ui; // slightly hacky, but it will work + $run = new PEAR_RunTest($log); + $tests = array(); + if (isset($options['recur'])) { + $depth = 4; + } else { + $depth = 1; + } + if (!count($params)) { + $params[] = '.'; + } + foreach ($params as $p) { + if (is_dir($p)) { + $dir = System::find(array($p, '-type', 'f', + '-maxdepth', $depth, + '-name', '*.phpt')); + $tests = array_merge($tests, $dir); + } else { + if (!@file_exists($p)) { + if (!preg_match('/\.phpt$/', $p)) { + $p .= '.phpt'; + } + $dir = System::find(array(dirname($p), '-type', 'f', + '-maxdepth', $depth, + '-name', $p)); + $tests = array_merge($tests, $dir); + } else { + $tests[] = $p; + } + } + } + $ini_settings = ''; + if (isset($options['ini'])) { + $ini_settings .= $options['ini']; + } + if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) { + $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}"; + } + if ($ini_settings) { + $this->ui->outputData('Using INI settings: "' . $ini_settings . '"'); + } + $skipped = $passed = $failed = array(); + $this->ui->outputData('Running ' . count($tests) . ' tests', $command); + $start = time(); + if (isset($options['realtimelog'])) { + @unlink('run-tests.log'); + } + foreach ($tests as $t) { + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "Running test $t..."); + fclose($fp); + } + } + $result = $run->run($t, $ini_settings); + if (OS_WINDOWS) { + for($i=0;$i<2000;$i++) { + $i = $i; // delay - race conditions on windows + } + } + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "$result\n"); + fclose($fp); + } + } + if ($result == 'FAILED') { + $failed[] = $t; + } + if ($result == 'PASSED') { + $passed[] = $t; + } + if ($result == 'SKIPPED') { + $skipped[] = $t; + } + } + $total = date('i:s', time() - $start); + if (count($failed)) { + $output = "TOTAL TIME: $total\n"; + $output .= count($passed) . " PASSED TESTS\n"; + $output .= count($skipped) . " SKIPPED TESTS\n"; + $output .= count($failed) . " FAILED TESTS:\n"; + foreach ($failed as $failure) { + $output .= $failure . "\n"; + } + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + } else { + $fp = @fopen('run-tests.log', 'w'); + } + if ($fp) { + fwrite($fp, $output, strlen($output)); + fclose($fp); + $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command); + } + } elseif (@file_exists('run-tests.log') && !@is_dir('run-tests.log')) { + @unlink('run-tests.log'); + } + $this->ui->outputData('TOTAL TIME: ' . $total); + $this->ui->outputData(count($passed) . ' PASSED TESTS', $command); + $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command); + if (count($failed)) { + $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command); + foreach ($failed as $failure) { + $this->ui->outputData($failure, $command); + } + } + + return true; + } + + // }}} + // {{{ doPackageDependencies() + + function doPackageDependencies($command, $options, $params) + { + // $params[0] -> the PEAR package to list its information + if (sizeof($params) != 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + + $obj = new PEAR_Common(); + if (PEAR::isError($info = $obj->infoFromAny($params[0]))) { + return $this->raiseError($info); + } + + if (is_array($info['release_deps'])) { + $data = array( + 'caption' => 'Dependencies for ' . $info['package'], + 'border' => true, + 'headline' => array("Type", "Name", "Relation", "Version"), + ); + + foreach ($info['release_deps'] as $d) { + + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + + if (isset($d['name'])) { + $name = $d['name']; + } else { + $name = ''; + } + + if (isset($d['version'])) { + $version = $d['version']; + } else { + $version = ''; + } + + $data['data'][] = array($type, $name, $rel, $version); + } + + $this->ui->outputData($data, $command); + return true; + } + + // Fallback + $this->ui->outputData("This package does not have any dependencies.", $command); + } + + // }}} + // {{{ doSign() + + function doSign($command, $options, $params) + { + // should move most of this code into PEAR_Packager + // so it'll be easy to implement "pear package --sign" + if (sizeof($params) != 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + if (!file_exists($params[0])) { + return $this->raiseError("file does not exist: $params[0]"); + } + $obj = new PEAR_Common; + $info = $obj->infoFromTgzFile($params[0]); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + include_once "Archive/Tar.php"; + include_once "System.php"; + $tar = new Archive_Tar($params[0]); + $tmpdir = System::mktemp('-d pearsign'); + if (!$tar->extractList('package.xml package.sig', $tmpdir)) { + return $this->raiseError("failed to extract tar file"); + } + if (file_exists("$tmpdir/package.sig")) { + return $this->raiseError("package already signed"); + } + @unlink("$tmpdir/package.sig"); + $input = $this->ui->userDialog($command, + array('GnuPG Passphrase'), + array('password')); + $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/package.xml 2>/dev/null", "w"); + if (!$gpg) { + return $this->raiseError("gpg command failed"); + } + fwrite($gpg, "$input[0]\r"); + if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) { + return $this->raiseError("gpg sign failed"); + } + $tar->addModify("$tmpdir/package.sig", '', $tmpdir); + return true; + } + + // }}} + // {{{ doMakeRPM() + + /* + + (cox) + + TODO: + + - Fill the rpm dependencies in the template file. + + IDEAS: + + - Instead of mapping the role to rpm vars, perhaps it's better + + to use directly the pear cmd to install the files by itself + + in %postrun so: + + pear -d php_dir=%{_libdir}/php/pear -d test_dir=.. + + */ + + function doMakeRPM($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + if (!file_exists($params[0])) { + return $this->raiseError("file does not exist: $params[0]"); + } + include_once "Archive/Tar.php"; + include_once "PEAR/Installer.php"; + include_once "System.php"; + $tar = new Archive_Tar($params[0]); + $tmpdir = System::mktemp('-d pear2rpm'); + $instroot = System::mktemp('-d pear2rpm'); + $tmp = $this->config->get('verbose'); + $this->config->set('verbose', 0); + $installer = new PEAR_Installer($this->ui); + $info = $installer->install($params[0], + array('installroot' => $instroot, + 'nodeps' => true)); + $pkgdir = "$info[package]-$info[version]"; + $info['rpm_xml_dir'] = '/var/lib/pear'; + $this->config->set('verbose', $tmp); + if (!$tar->extractList("package.xml", $tmpdir, $pkgdir)) { + return $this->raiseError("failed to extract $params[0]"); + } + if (!file_exists("$tmpdir/package.xml")) { + return $this->raiseError("no package.xml found in $params[0]"); + } + if (isset($options['spec-template'])) { + $spec_template = $options['spec-template']; + } else { + $spec_template = $this->config->get('data_dir') . + '/PEAR/template.spec'; + } + if (isset($options['rpm-pkgname'])) { + $rpm_pkgname_format = $options['rpm-pkgname']; + } else { + $rpm_pkgname_format = "PEAR::%s"; + } + + $info['extra_headers'] = ''; + $info['doc_files'] = ''; + $info['files'] = ''; + $info['rpm_package'] = sprintf($rpm_pkgname_format, $info['package']); + $srcfiles = 0; + foreach ($info['filelist'] as $name => $attr) { + + if (!isset($attr['role'])) { + continue; + } + $name = preg_replace('![/:\\\\]!', '/', $name); + if ($attr['role'] == 'doc') { + $info['doc_files'] .= " $name"; + + // Map role to the rpm vars + } else { + + $c_prefix = '%{_libdir}/php/pear'; + + switch ($attr['role']) { + + case 'php': + + $prefix = $c_prefix; break; + + case 'ext': + + $prefix = '%{_libdir}/php'; break; // XXX good place? + + case 'src': + + $srcfiles++; + + $prefix = '%{_includedir}/php'; break; // XXX good place? + + case 'test': + + $prefix = "$c_prefix/tests/" . $info['package']; break; + + case 'data': + + $prefix = "$c_prefix/data/" . $info['package']; break; + + case 'script': + + $prefix = '%{_bindir}'; break; + + } + + $name = str_replace('\\', '/', $name); + $info['files'] .= "$prefix/$name\n"; + + } + } + if ($srcfiles > 0) { + include_once "OS/Guess.php"; + $os = new OS_Guess; + $arch = $os->getCpu(); + } else { + $arch = 'noarch'; + } + $cfg = array('master_server', 'php_dir', 'ext_dir', 'doc_dir', + 'bin_dir', 'data_dir', 'test_dir'); + foreach ($cfg as $k) { + $info[$k] = $this->config->get($k); + } + $info['arch'] = $arch; + $fp = @fopen($spec_template, "r"); + if (!$fp) { + return $this->raiseError("could not open RPM spec file template $spec_template: $php_errormsg"); + } + $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\1"]', fread($fp, filesize($spec_template))); + fclose($fp); + $spec_file = "$info[rpm_package]-$info[version].spec"; + $wp = fopen($spec_file, "wb"); + if (!$wp) { + return $this->raiseError("could not write RPM spec file $spec_file: $php_errormsg"); + } + fwrite($wp, $spec_contents); + fclose($wp); + $this->ui->outputData("Wrote RPM spec file $spec_file", $command); + + return true; + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Command/Registry.php b/src/www/lib/pear/PEAR/Command/Registry.php new file mode 100644 index 00000000..557bd308 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Registry.php @@ -0,0 +1,351 @@ + | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Registry.php,v 1.1 2005/05/28 01:55:58 henrique Exp $ + +require_once 'PEAR/Command/Common.php'; +require_once 'PEAR/Registry.php'; +require_once 'PEAR/Config.php'; + +class PEAR_Command_Registry extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'list' => array( + 'summary' => 'List Installed Packages', + 'function' => 'doList', + 'shortcut' => 'l', + 'options' => array(), + 'doc' => '[package] +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir)). With a parameter, it +lists the files in that package. +', + ), + 'shell-test' => array( + 'summary' => 'Shell Script Test', + 'function' => 'doShellTest', + 'shortcut' => 'st', + 'options' => array(), + 'doc' => ' [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + The version to compare with +'), + 'info' => array( + 'summary' => 'Display information about a package', + 'function' => 'doInfo', + 'shortcut' => 'in', + 'options' => array(), + 'doc' => ' +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package.' + ) + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Registry constructor. + * + * @access public + */ + function PEAR_Command_Registry(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doList() + + function _sortinfo($a, $b) + { + return strcmp($a['package'], $b['package']); + } + + function doList($command, $options, $params) + { + $reg = new PEAR_Registry($this->config->get('php_dir')); + if (sizeof($params) == 0) { + $installed = $reg->packageInfo(); + usort($installed, array(&$this, '_sortinfo')); + $i = $j = 0; + $data = array( + 'caption' => 'Installed packages:', + 'border' => true, + 'headline' => array('Package', 'Version', 'State') + ); + foreach ($installed as $package) { + $data['data'][] = array($package['package'], + $package['version'], + @$package['release_state']); + } + if (count($installed)==0) { + $data = '(no packages installed)'; + } + $this->ui->outputData($data, $command); + } else { + if (file_exists($params[0]) && !is_dir($params[0])) { + include_once "PEAR/Common.php"; + $obj = &new PEAR_Common; + $info = $obj->infoFromAny($params[0]); + $headings = array('Package File', 'Install Path'); + $installed = false; + } else { + $info = $reg->packageInfo($params[0]); + $headings = array('Type', 'Install Path'); + $installed = true; + } + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + if ($info === null) { + return $this->raiseError("`$params[0]' not installed"); + } + $list = $info['filelist']; + if ($installed) { + $caption = 'Installed Files For ' . $params[0]; + } else { + $caption = 'Contents of ' . basename($params[0]); + } + $data = array( + 'caption' => $caption, + 'border' => true, + 'headline' => $headings); + foreach ($list as $file => $att) { + if ($installed) { + if (empty($att['installed_as'])) { + continue; + } + $data['data'][] = array($att['role'], $att['installed_as']); + } else { + if (isset($att['baseinstalldir'])) { + $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR . + $file; + } else { + $dest = $file; + } + switch ($att['role']) { + case 'test': + case 'data': + if ($installed) { + break 2; + } + $dest = '-- will not be installed --'; + break; + case 'doc': + $dest = $this->config->get('doc_dir') . DIRECTORY_SEPARATOR . + $dest; + break; + case 'php': + default: + $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR . + $dest; + } + $dest = preg_replace('!/+!', '/', $dest); + $file = preg_replace('!/+!', '/', $file); + $data['data'][] = array($file, $dest); + } + } + $this->ui->outputData($data, $command); + + + } + return true; + } + + // }}} + // {{{ doShellTest() + + function doShellTest($command, $options, $params) + { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $reg = &new PEAR_Registry($this->config->get('php_dir')); + // "pear shell-test Foo" + if (sizeof($params) == 1) { + if (!$reg->packageExists($params[0])) { + exit(1); + } + // "pear shell-test Foo 1.0" + } elseif (sizeof($params) == 2) { + $v = $reg->packageInfo($params[0], 'version'); + if (!$v || !version_compare("$v", "{$params[1]}", "ge")) { + exit(1); + } + // "pear shell-test Foo ge 1.0" + } elseif (sizeof($params) == 3) { + $v = $reg->packageInfo($params[0], 'version'); + if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) { + exit(1); + } + } else { + $this->popErrorHandling(); + $this->raiseError("$command: expects 1 to 3 parameters"); + exit(1); + } + } + + // }}} + // {{{ doInfo + + function doInfo($command, $options, $params) + { + // $params[0] The package for showing info + if (sizeof($params) != 1) { + return $this->raiseError("This command only accepts one param: ". + "the package you want information"); + } + if (@is_file($params[0])) { + $obj = &new PEAR_Common(); + $info = $obj->infoFromAny($params[0]); + } else { + $reg = &new PEAR_Registry($this->config->get('php_dir')); + $info = $reg->packageInfo($params[0]); + } + if (PEAR::isError($info)) { + return $info; + } + if (empty($info)) { + $this->raiseError("Nothing found for `$params[0]'"); + return; + } + unset($info['filelist']); + unset($info['changelog']); + $keys = array_keys($info); + $longtext = array('description', 'summary'); + foreach ($keys as $key) { + if (is_array($info[$key])) { + switch ($key) { + case 'maintainers': { + $i = 0; + $mstr = ''; + foreach ($info[$key] as $m) { + if ($i++ > 0) { + $mstr .= "\n"; + } + $mstr .= $m['name'] . " <"; + if (isset($m['email'])) { + $mstr .= $m['email']; + } else { + $mstr .= $m['handle'] . '@php.net'; + } + $mstr .= "> ($m[role])"; + } + $info[$key] = $mstr; + break; + } + case 'release_deps': { + $i = 0; + $dstr = ''; + foreach ($info[$key] as $d) { + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + if (isset($d['name'])) { + $name = $d['name'] . ' '; + } else { + $name = ''; + } + if (isset($d['version'])) { + $version = $d['version'] . ' '; + } else { + $version = ''; + } + $dstr .= "$type $name$rel $version\n"; + } + $info[$key] = $dstr; + break; + } + case 'provides' : { + $debug = $this->config->get('verbose'); + if ($debug < 2) { + $pstr = 'Classes: '; + } else { + $pstr = ''; + } + $i = 0; + foreach ($info[$key] as $p) { + if ($debug < 2 && $p['type'] != "class") { + continue; + } + // Only print classes when verbosity mode is < 2 + if ($debug < 2) { + if ($i++ > 0) { + $pstr .= ", "; + } + $pstr .= $p['name']; + } else { + if ($i++ > 0) { + $pstr .= "\n"; + } + $pstr .= ucfirst($p['type']) . " " . $p['name']; + if (isset($p['explicit']) && $p['explicit'] == 1) { + $pstr .= " (explicit)"; + } + } + } + $info[$key] = $pstr; + break; + } + default: { + $info[$key] = implode(", ", $info[$key]); + break; + } + } + } + if ($key == '_lastmodified') { + $hdate = date('Y-m-d', $info[$key]); + unset($info[$key]); + $info['Last Modified'] = $hdate; + } else { + $info[$key] = trim($info[$key]); + if (in_array($key, $longtext)) { + $info[$key] = preg_replace('/ +/', ' ', $info[$key]); + } + } + } + $caption = 'About ' . $info['package'] . '-' . $info['version']; + $data = array( + 'caption' => $caption, + 'border' => true); + foreach ($info as $key => $value) { + $key = ucwords(trim(str_replace('_', ' ', $key))); + $data['data'][] = array($key, $value); + } + $data['raw'] = $info; + + $this->ui->outputData($data, 'package-info'); + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Command/Remote.php b/src/www/lib/pear/PEAR/Command/Remote.php new file mode 100644 index 00000000..111d6328 --- /dev/null +++ b/src/www/lib/pear/PEAR/Command/Remote.php @@ -0,0 +1,435 @@ + | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Remote.php,v 1.1 2005/05/28 01:55:58 henrique Exp $ + +require_once 'PEAR/Command/Common.php'; +require_once 'PEAR/Common.php'; +require_once 'PEAR/Remote.php'; +require_once 'PEAR/Registry.php'; + +class PEAR_Command_Remote extends PEAR_Command_Common +{ + // {{{ command definitions + + var $commands = array( + 'remote-info' => array( + 'summary' => 'Information About Remote Packages', + 'function' => 'doRemoteInfo', + 'shortcut' => 'ri', + 'options' => array(), + 'doc' => ' +Get details on a package from the server.', + ), + 'list-upgrades' => array( + 'summary' => 'List Available Upgrades', + 'function' => 'doListUpgrades', + 'shortcut' => 'lu', + 'options' => array(), + 'doc' => ' +List releases on the server of packages you have installed where +a newer version is available with the same release state (stable etc.).' + ), + 'remote-list' => array( + 'summary' => 'List Remote Packages', + 'function' => 'doRemoteList', + 'shortcut' => 'rl', + 'options' => array(), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', + ), + 'search' => array( + 'summary' => 'Search remote package database', + 'function' => 'doSearch', + 'shortcut' => 'sp', + 'options' => array(), + 'doc' => ' +Lists all packages which match the search parameters (first param +is package name, second package info)', + ), + 'list-all' => array( + 'summary' => 'List All Packages', + 'function' => 'doListAll', + 'shortcut' => 'la', + 'options' => array(), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', + ), + 'download' => array( + 'summary' => 'Download Package', + 'function' => 'doDownload', + 'shortcut' => 'd', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'download an uncompressed (.tar) file', + ), + ), + 'doc' => '{package|package-version} +Download a package tarball. The file will be named as suggested by the +server, for example if you download the DB package and the latest stable +version of DB is 1.2, the downloaded file will be DB-1.2.tgz.', + ), + 'clear-cache' => array( + 'summary' => 'Clear XML-RPC Cache', + 'function' => 'doClearCache', + 'shortcut' => 'cc', + 'options' => array(), + 'doc' => ' +Clear the XML-RPC cache. See also the cache_ttl configuration +parameter. +', + ), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Remote constructor. + * + * @access public + */ + function PEAR_Command_Remote(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doRemoteInfo() + + function doRemoteInfo($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError("$command expects one param: the remote package name"); + } + $r = new PEAR_Remote($this->config); + $info = $r->call('package.info', $params[0]); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $reg = new PEAR_Registry($this->config->get('php_dir')); + $installed = $reg->packageInfo($info['name']); + $info['installed'] = $installed['version'] ? $installed['version'] : '- no -'; + + $this->ui->outputData($info, $command); + + return true; + } + + // }}} + // {{{ doRemoteList() + + function doRemoteList($command, $options, $params) + { + $r = new PEAR_Remote($this->config); + $list_options = false; + if ($this->config->get('preferred_state') == 'stable') + $list_options = true; + $available = $r->call('package.listAll', $list_options); + if (PEAR::isError($available)) { + return $this->raiseError($available); + } + $i = $j = 0; + $data = array( + 'caption' => 'Available packages:', + 'border' => true, + 'headline' => array('Package', 'Version'), + ); + foreach ($available as $name => $info) { + $data['data'][] = array($name, isset($info['stable']) ? $info['stable'] : '-n/a-'); + } + if (count($available)==0) { + $data = '(no packages installed yet)'; + } + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doListAll() + + function doListAll($command, $options, $params) + { + $r = new PEAR_Remote($this->config); + $reg = new PEAR_Registry($this->config->get('php_dir')); + $list_options = false; + if ($this->config->get('preferred_state') == 'stable') + $list_options = true; + $available = $r->call('package.listAll', $list_options); + if (PEAR::isError($available)) { + return $this->raiseError($available); + } + if (!is_array($available)) { + return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "'.$available.'")'); + } + $data = array( + 'caption' => 'All packages:', + 'border' => true, + 'headline' => array('Package', 'Latest', 'Local'), + ); + $local_pkgs = $reg->listPackages(); + + foreach ($available as $name => $info) { + $installed = $reg->packageInfo($name); + $desc = $info['summary']; + if (isset($params[$name])) + $desc .= "\n\n".$info['description']; + + if (isset($options['mode'])) + { + if ($options['mode'] == 'installed' && !isset($installed['version'])) + continue; + if ($options['mode'] == 'notinstalled' && isset($installed['version'])) + continue; + if ($options['mode'] == 'upgrades' + && (!isset($installed['version']) || $installed['version'] == $info['stable'])) + { + continue; + } + } + $pos = array_search(strtolower($name), $local_pkgs); + if ($pos !== false) { + unset($local_pkgs[$pos]); + } + + $data['data'][$info['category']][] = array( + $name, + @$info['stable'], + @$installed['version'], + @$desc, + @$info['deps'], + ); + } + + foreach ($local_pkgs as $name) { + $info = $reg->packageInfo($name); + $data['data']['Local'][] = array( + $info['package'], + '', + $info['version'], + $info['summary'], + @$info['release_deps'] + ); + } + + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doSearch() + + function doSearch($command, $options, $params) + { + if ((!isset($params[0]) || empty($params[0])) + && (!isset($params[1]) || empty($params[1]))) + { + return $this->raiseError('no valid search string supplied'); + }; + + $r = new PEAR_Remote($this->config); + $reg = new PEAR_Registry($this->config->get('php_dir')); + $available = $r->call('package.listAll', true, false); + if (PEAR::isError($available)) { + return $this->raiseError($available); + } + $data = array( + 'caption' => 'Matched packages:', + 'border' => true, + 'headline' => array('Package', 'Stable/(Latest)', 'Local'), + ); + + foreach ($available as $name => $info) { + $found = (!empty($params[0]) && stristr($name, $params[0]) !== false); + if (!$found && !(isset($params[1]) && !empty($params[1]) + && (stristr($info['summary'], $params[1]) !== false + || stristr($info['description'], $params[1]) !== false))) + { + continue; + }; + + $installed = $reg->packageInfo($name); + $desc = $info['summary']; + if (isset($params[$name])) + $desc .= "\n\n".$info['description']; + + $unstable = ''; + if ($info['unstable']) { + $unstable = '/(' . $info['unstable'] . $info['state'] . ')'; + } + if (!isset($info['stable']) || !$info['stable']) { + $info['stable'] = 'none'; + } + $data['data'][$info['category']][] = array( + $name, + $info['stable'] . $unstable, + $installed['version'], + $desc, + ); + } + if (!isset($data['data'])) { + return $this->raiseError('no packages found'); + } + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doDownload() + + function doDownload($command, $options, $params) + { + //$params[0] -> The package to download + if (count($params) != 1) { + return PEAR::raiseError("download expects one argument: the package to download"); + } + $server = $this->config->get('master_server'); + if (!ereg('^http://', $params[0])) { + $getoption = isset($options['nocompress'])&&$options['nocompress']==1?'?uncompress=on':''; + $pkgfile = "http://$server/get/$params[0]".$getoption; + } else { + $pkgfile = $params[0]; + } + $this->bytes_downloaded = 0; + $saved = PEAR_Common::downloadHttp($pkgfile, $this->ui, '.', + array(&$this, 'downloadCallback')); + if (PEAR::isError($saved)) { + return $this->raiseError($saved); + } + $fname = basename($saved); + $this->ui->outputData("File $fname downloaded ($this->bytes_downloaded bytes)", $command); + return true; + } + + function downloadCallback($msg, $params = null) + { + if ($msg == 'done') { + $this->bytes_downloaded = $params; + } + } + + // }}} + // {{{ doListUpgrades() + + function doListUpgrades($command, $options, $params) + { + include_once "PEAR/Registry.php"; + $remote = new PEAR_Remote($this->config); + if (empty($params[0])) { + $state = $this->config->get('preferred_state'); + } else { + $state = $params[0]; + } + $caption = 'Available Upgrades'; + if (empty($state) || $state == 'any') { + $latest = $remote->call("package.listLatestReleases"); + } else { + $latest = $remote->call("package.listLatestReleases", $state); + $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')'; + } + $caption .= ':'; + if (PEAR::isError($latest)) { + return $latest; + } + $reg = new PEAR_Registry($this->config->get('php_dir')); + $inst = array_flip($reg->listPackages()); + $data = array( + 'caption' => $caption, + 'border' => 1, + 'headline' => array('Package', 'Local', 'Remote', 'Size'), + ); + foreach ((array)$latest as $pkg => $info) { + $package = strtolower($pkg); + if (!isset($inst[$package])) { + // skip packages we don't have installed + continue; + } + extract($info); + $pkginfo = $reg->packageInfo($package); + $inst_version = $pkginfo['version']; + $inst_state = $pkginfo['release_state']; + if (version_compare("$version", "$inst_version", "le")) { + // installed version is up-to-date + continue; + } + if ($filesize >= 20480) { + $filesize += 1024 - ($filesize % 1024); + $fs = sprintf("%dkB", $filesize / 1024); + } elseif ($filesize > 0) { + $filesize += 103 - ($filesize % 103); + $fs = sprintf("%.1fkB", $filesize / 1024.0); + } else { + $fs = " -"; // XXX center instead + } + $data['data'][] = array($pkg, "$inst_version ($inst_state)", "$version ($state)", $fs); + } + if (empty($data['data'])) { + $this->ui->outputData('No upgrades available'); + } else { + $this->ui->outputData($data, $command); + } + return true; + } + + // }}} + // {{{ doClearCache() + + function doClearCache($command, $options, $params) + { + $cache_dir = $this->config->get('cache_dir'); + $verbose = $this->config->get('verbose'); + $output = ''; + if (!($dp = @opendir($cache_dir))) { + return $this->raiseError("opendir($cache_dir) failed: $php_errormsg"); + } + if ($verbose >= 1) { + $output .= "reading directory $cache_dir\n"; + } + $num = 0; + while ($ent = readdir($dp)) { + if (preg_match('/^xmlrpc_cache_[a-z0-9]{32}$/', $ent)) { + $path = $cache_dir . DIRECTORY_SEPARATOR . $ent; + $ok = @unlink($path); + if ($ok) { + if ($verbose >= 2) { + $output .= "deleted $path\n"; + } + $num++; + } elseif ($verbose >= 1) { + $output .= "failed to delete $path\n"; + } + } + } + closedir($dp); + if ($verbose >= 1) { + $output .= "$num cache entries cleared\n"; + } + $this->ui->outputData(rtrim($output), $command); + return $num; + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Common.php b/src/www/lib/pear/PEAR/Common.php new file mode 100644 index 00000000..ff1a26a3 --- /dev/null +++ b/src/www/lib/pear/PEAR/Common.php @@ -0,0 +1,2094 @@ + | +// | Tomas V.V.Cox | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.1 2005/05/28 01:55:12 henrique Exp $ + +require_once 'PEAR.php'; +require_once 'Archive/Tar.php'; +require_once 'System.php'; +require_once 'PEAR/Config.php'; + +// {{{ constants and globals + +/** + * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() + */ +define('PEAR_COMMON_ERROR_INVALIDPHP', 1); +define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); +define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/'); + +// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 +define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); +define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '$/i'); + +// XXX far from perfect :-) +define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^(' . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?$/'); + +/** + * List of temporary files and directories registered by + * PEAR_Common::addTempFile(). + * @var array + */ +$GLOBALS['_PEAR_Common_tempfiles'] = array(); + +/** + * Valid maintainer roles + * @var array + */ +$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); + +/** + * Valid release states + * @var array + */ +$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); + +/** + * Valid dependency types + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); + +/** + * Valid dependency relations + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); + +/** + * Valid file roles + * @var array + */ +$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); + +/** + * Valid replacement types + * @var array + */ +$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); + +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); + +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); + +// }}} + +/** + * Class providing common functionality for PEAR administration classes. + * @deprecated This class will disappear, and its components will be spread + * into smaller classes, like the AT&T breakup + */ +class PEAR_Common extends PEAR +{ + // {{{ properties + + /** stack of elements, gives some sort of XML context */ + var $element_stack = array(); + + /** name of currently parsed XML element */ + var $current_element; + + /** array of attributes of the currently parsed XML element */ + var $current_attributes = array(); + + /** assoc with information about a package */ + var $pkginfo = array(); + + /** + * User Interface object (PEAR_Frontend_* class). If null, + * the log() method uses print. + * @var object + */ + var $ui = null; + + /** + * Configuration object (PEAR_Config). + * @var object + */ + var $config = null; + + var $current_path = null; + + /** + * PEAR_SourceAnalyzer instance + * @var object + */ + var $source_analyzer = null; + /** + * Flag variable used to mark a valid package file + * @var boolean + * @access private + */ + var $_validPackageFile; + + // }}} + + // {{{ constructor + + /** + * PEAR_Common constructor + * + * @access public + */ + function PEAR_Common() + { + parent::PEAR(); + $this->config = &PEAR_Config::singleton(); + $this->debug = $this->config->get('verbose'); + } + + // }}} + // {{{ destructor + + /** + * PEAR_Common destructor + * + * @access private + */ + function _PEAR_Common() + { + // doesn't work due to bug #14744 + //$tempfiles = $this->_tempfiles; + $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; + while ($file = array_shift($tempfiles)) { + if (@is_dir($file)) { + System::rm(array('-rf', $file)); + } elseif (file_exists($file)) { + unlink($file); + } + } + } + + // }}} + // {{{ addTempFile() + + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string $file name of file or directory + * + * @return void + * + * @access public + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } + + // }}} + // {{{ mkDirHier() + + /** + * Wrapper to System::mkDir(), creates a directory as well as + * any necessary parent directories. + * + * @param string $dir directory name + * + * @return bool TRUE on success, or a PEAR error + * + * @access public + */ + function mkDirHier($dir) + { + $this->log(2, "+ create dir $dir"); + return System::mkDir(array('-p', $dir)); + } + + // }}} + // {{{ log() + + /** + * Logging method. + * + * @param int $level log level (0 is quiet, higher is noisier) + * @param string $msg message to write to the log + * + * @return void + * + * @access public + */ + function log($level, $msg, $append_crlf = true) + { + if ($this->debug >= $level) { + if (is_object($this->ui)) { + $this->ui->log($msg, $append_crlf); + } else { + print "$msg\n"; + } + } + } + + // }}} + // {{{ mkTempDir() + + /** + * Create and register a temporary directory. + * + * @param string $tmpdir (optional) Directory to use as tmpdir. + * Will use system defaults (for example + * /tmp or c:\windows\temp) if not specified + * + * @return string name of created directory + * + * @access public + */ + function mkTempDir($tmpdir = '') + { + if ($tmpdir) { + $topt = array('-t', $tmpdir); + } else { + $topt = array(); + } + $topt = array_merge($topt, array('-d', 'pear')); + if (!$tmpdir = System::mktemp($topt)) { + return false; + } + $this->addTempFile($tmpdir); + return $tmpdir; + } + + // }}} + // {{{ setFrontendObject() + + /** + * Set object that represents the frontend to be used. + * + * @param object Reference of the frontend object + * @return void + * @access public + */ + function setFrontendObject(&$ui) + { + $this->ui = &$ui; + } + + // }}} + + // {{{ _unIndent() + + /** + * Unindent given string (?) + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } + } + return $data; + } + + // }}} + // {{{ _element_start() + + /** + * XML parser callback for starting elements. Used while package + * format version is not yet known. + * + * @param resource $xp XML parser resource + * @param string $name name of starting element + * @param array $attribs element attributes, name => value + * + * @return void + * + * @access private + */ + function _element_start($xp, $name, $attribs) + { + array_push($this->element_stack, $name); + $this->current_element = $name; + $spos = sizeof($this->element_stack) - 2; + $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; + $this->current_attributes = $attribs; + switch ($name) { + case 'package': { + $this->_validPackageFile = true; + if (isset($attribs['version'])) { + $vs = preg_replace('/[^0-9a-z]/', '_', $attribs['version']); + } else { + $vs = '1_0'; + } + $elem_start = '_element_start_'. $vs; + $elem_end = '_element_end_'. $vs; + $cdata = '_pkginfo_cdata_'. $vs; + if (!method_exists($this, $elem_start) || + !method_exists($this, $elem_end) || + !method_exists($this, $cdata)) { + $this->raiseError("No handlers for package.xml version $attribs[version]"); + return; + } + xml_set_element_handler($xp, $elem_start, $elem_end); + xml_set_character_data_handler($xp, $cdata); + break; + } + } + } + + // }}} + // {{{ _element_end() + + /** + * XML parser callback for ending elements. Used while package + * format version is not yet known. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_end($xp, $name) + { + } + + // }}} + + // Support for package DTD v1.0: + // {{{ _element_start_1_0() + + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_start_1_0($xp, $name, $attribs) + { + array_push($this->element_stack, $name); + $this->current_element = $name; + $spos = sizeof($this->element_stack) - 2; + $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; + $this->current_attributes = $attribs; + $this->cdata = ''; + switch ($name) { + case 'dir': + if ($this->in_changelog) { + break; + } + if ($attribs['name'] != '/') { + $this->dir_names[] = $attribs['name']; + } + if (isset($attribs['baseinstalldir'])) { + $this->dir_install = $attribs['baseinstalldir']; + } + if (isset($attribs['role'])) { + $this->dir_role = $attribs['role']; + } + break; + case 'file': + if ($this->in_changelog) { + break; + } + if (isset($attribs['name'])) { + $path = ''; + if (count($this->dir_names)) { + foreach ($this->dir_names as $dir) { + $path .= $dir . DIRECTORY_SEPARATOR; + } + } + $path .= $attribs['name']; + unset($attribs['name']); + $this->current_path = $path; + $this->filelist[$path] = $attribs; + // Set the baseinstalldir only if the file don't have this attrib + if (!isset($this->filelist[$path]['baseinstalldir']) && + isset($this->dir_install)) + { + $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + } + // Set the Role + if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { + $this->filelist[$path]['role'] = $this->dir_role; + } + } + break; + case 'replace': + if (!$this->in_changelog) { + $this->filelist[$this->current_path]['replacements'][] = $attribs; + } + break; + case 'maintainers': + $this->pkginfo['maintainers'] = array(); + $this->m_i = 0; // maintainers array index + break; + case 'maintainer': + // compatibility check + if (!isset($this->pkginfo['maintainers'])) { + $this->pkginfo['maintainers'] = array(); + $this->m_i = 0; + } + $this->pkginfo['maintainers'][$this->m_i] = array(); + $this->current_maintainer =& $this->pkginfo['maintainers'][$this->m_i]; + break; + case 'changelog': + $this->pkginfo['changelog'] = array(); + $this->c_i = 0; // changelog array index + $this->in_changelog = true; + break; + case 'release': + if ($this->in_changelog) { + $this->pkginfo['changelog'][$this->c_i] = array(); + $this->current_release = &$this->pkginfo['changelog'][$this->c_i]; + } else { + $this->current_release = &$this->pkginfo; + } + break; + case 'deps': + if (!$this->in_changelog) { + $this->pkginfo['release_deps'] = array(); + } + break; + case 'dep': + // dependencies array index + if (!$this->in_changelog) { + $this->d_i++; + $this->pkginfo['release_deps'][$this->d_i] = $attribs; + } + break; + case 'configureoptions': + if (!$this->in_changelog) { + $this->pkginfo['configure_options'] = array(); + } + break; + case 'configureoption': + if (!$this->in_changelog) { + $this->pkginfo['configure_options'][] = $attribs; + } + break; + case 'provides': + if (empty($attribs['type']) || empty($attribs['name'])) { + break; + } + $attribs['explicit'] = true; + $this->pkginfo['provides']["$attribs[type];$attribs[name]"] = $attribs; + break; + } + } + + // }}} + // {{{ _element_end_1_0() + + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_end_1_0($xp, $name) + { + $data = trim($this->cdata); + switch ($name) { + case 'name': + switch ($this->prev_element) { + case 'package': + // XXX should we check the package name here? + $this->pkginfo['package'] = ereg_replace('[^a-zA-Z0-9._]', '_', $data); + break; + case 'maintainer': + $this->current_maintainer['name'] = $data; + break; + } + break; + case 'summary': + $this->pkginfo['summary'] = $data; + break; + case 'description': + $data = $this->_unIndent($this->cdata); + $this->pkginfo['description'] = $data; + break; + case 'user': + $this->current_maintainer['handle'] = $data; + break; + case 'email': + $this->current_maintainer['email'] = $data; + break; + case 'role': + $this->current_maintainer['role'] = $data; + break; + case 'version': + $data = ereg_replace ('[^a-zA-Z0-9._\-]', '_', $data); + if ($this->in_changelog) { + $this->current_release['version'] = $data; + } else { + $this->pkginfo['version'] = $data; + } + break; + case 'date': + if ($this->in_changelog) { + $this->current_release['release_date'] = $data; + } else { + $this->pkginfo['release_date'] = $data; + } + break; + case 'notes': + // try to "de-indent" release notes in case someone + // has been over-indenting their xml ;-) + $data = $this->_unIndent($this->cdata); + if ($this->in_changelog) { + $this->current_release['release_notes'] = $data; + } else { + $this->pkginfo['release_notes'] = $data; + } + break; + case 'warnings': + if ($this->in_changelog) { + $this->current_release['release_warnings'] = $data; + } else { + $this->pkginfo['release_warnings'] = $data; + } + break; + case 'state': + if ($this->in_changelog) { + $this->current_release['release_state'] = $data; + } else { + $this->pkginfo['release_state'] = $data; + } + break; + case 'license': + if ($this->in_changelog) { + $this->current_release['release_license'] = $data; + } else { + $this->pkginfo['release_license'] = $data; + } + break; + case 'dep': + if ($data && !$this->in_changelog) { + $this->pkginfo['release_deps'][$this->d_i]['name'] = $data; + } + break; + case 'dir': + if ($this->in_changelog) { + break; + } + array_pop($this->dir_names); + break; + case 'file': + if ($this->in_changelog) { + break; + } + if ($data) { + $path = ''; + if (count($this->dir_names)) { + foreach ($this->dir_names as $dir) { + $path .= $dir . DIRECTORY_SEPARATOR; + } + } + $path .= $data; + $this->filelist[$path] = $this->current_attributes; + // Set the baseinstalldir only if the file don't have this attrib + if (!isset($this->filelist[$path]['baseinstalldir']) && + isset($this->dir_install)) + { + $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + } + // Set the Role + if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { + $this->filelist[$path]['role'] = $this->dir_role; + } + } + break; + case 'maintainer': + if (empty($this->pkginfo['maintainers'][$this->m_i]['role'])) { + $this->pkginfo['maintainers'][$this->m_i]['role'] = 'lead'; + } + $this->m_i++; + break; + case 'release': + if ($this->in_changelog) { + $this->c_i++; + } + break; + case 'changelog': + $this->in_changelog = false; + break; + } + array_pop($this->element_stack); + $spos = sizeof($this->element_stack) - 1; + $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : ''; + $this->cdata = ''; + } + + // }}} + // {{{ _pkginfo_cdata_1_0() + + /** + * XML parser callback for character data. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name character data + * + * @return void + * + * @access private + */ + function _pkginfo_cdata_1_0($xp, $data) + { + if (isset($this->cdata)) { + $this->cdata .= $data; + } + } + + // }}} + + // {{{ infoFromTgzFile() + + /** + * Returns information about a package file. Expects the name of + * a gzipped tar file as input. + * + * @param string $file name of .tgz file + * + * @return array array with package information + * + * @access public + * + */ + function infoFromTgzFile($file) + { + if (!@is_file($file)) { + return $this->raiseError("could not open file \"$file\""); + } + $tar = new Archive_Tar($file); + if ($this->debug <= 1) { + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + } + $content = $tar->listContent(); + if ($this->debug <= 1) { + $tar->popErrorHandling(); + } + if (!is_array($content)) { + $file = realpath($file); + return $this->raiseError("Could not get contents of package \"$file\"". + '. Invalid tgz file.'); + } + $xml = null; + foreach ($content as $file) { + $name = $file['filename']; + if ($name == 'package.xml') { + $xml = $name; + break; + } elseif (ereg('package.xml$', $name, $match)) { + $xml = $match[0]; + break; + } + } + $tmpdir = System::mkTemp(array('-d', 'pear')); + $this->addTempFile($tmpdir); + if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { + return $this->raiseError('could not extract the package.xml file'); + } + return $this->infoFromDescriptionFile("$tmpdir/$xml"); + } + + // }}} + // {{{ infoFromDescriptionFile() + + /** + * Returns information about a package file. Expects the name of + * a package xml file as input. + * + * @param string $descfile name of package xml file + * + * @return array array with package information + * + * @access public + * + */ + function infoFromDescriptionFile($descfile) + { + if (!@is_file($descfile) || !is_readable($descfile) || + (!$fp = @fopen($descfile, 'r'))) { + return $this->raiseError("Unable to open $descfile"); + } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + $data = fread($fp, filesize($descfile)); + return $this->infoFromString($data); + } + + // }}} + // {{{ infoFromString() + + /** + * Returns information about a package file. Expects the contents + * of a package xml file as input. + * + * @param string $data name of package xml file + * + * @return array array with package information + * + * @access public + * + */ + function infoFromString($data) + { + require_once('PEAR/Dependency.php'); + if (PEAR_Dependency::checkExtension($error, 'xml')) { + return $this->raiseError($error); + } + $xp = @xml_parser_create(); + if (!$xp) { + return $this->raiseError('Unable to create XML parser'); + } + xml_set_object($xp, $this); + xml_set_element_handler($xp, '_element_start', '_element_end'); + xml_set_character_data_handler($xp, '_pkginfo_cdata'); + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); + + $this->element_stack = array(); + $this->pkginfo = array('provides' => array()); + $this->current_element = false; + unset($this->dir_install); + $this->pkginfo['filelist'] = array(); + $this->filelist =& $this->pkginfo['filelist']; + $this->dir_names = array(); + $this->in_changelog = false; + $this->d_i = 0; + $this->cdata = ''; + $this->_validPackageFile = false; + + if (!xml_parse($xp, $data, 1)) { + $code = xml_get_error_code($xp); + $msg = sprintf("XML error: %s at line %d", + xml_error_string($code), + xml_get_current_line_number($xp)); + xml_parser_free($xp); + return $this->raiseError($msg, $code); + } + + xml_parser_free($xp); + + if (!$this->_validPackageFile) { + return $this->raiseError('Invalid Package File, no tag'); + } + foreach ($this->pkginfo as $k => $v) { + if (!is_array($v)) { + $this->pkginfo[$k] = trim($v); + } + } + return $this->pkginfo; + } + // }}} + // {{{ infoFromAny() + + /** + * Returns package information from different sources + * + * This method is able to extract information about a package + * from a .tgz archive or from a XML package definition file. + * + * @access public + * @param string Filename of the source ('package.xml', '.tgz') + * @return string + */ + function infoFromAny($info) + { + if (is_string($info) && file_exists($info)) { + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = $this->infoFromDescriptionFile($info); + } elseif ($tmp == '.tar' || $tmp == '.tgz') { + $info = $this->infoFromTgzFile($info); + } else { + $fp = fopen($info, "r"); + $test = fread($fp, 5); + fclose($fp); + if ($test == "infoFromDescriptionFile($info); + } else { + $info = $this->infoFromTgzFile($info); + } + } + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + } + return $info; + } + + // }}} + // {{{ xmlFromInfo() + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @param array $pkginfo package info + * + * @return string XML data + * + * @access public + */ + function xmlFromInfo($pkginfo) + { + static $maint_map = array( + "handle" => "user", + "name" => "name", + "email" => "email", + "role" => "role", + ); + $ret = "\n"; + $ret .= "\n"; + $ret .= " + $pkginfo[package] + ".htmlspecialchars($pkginfo['summary'])." + ".htmlspecialchars($pkginfo['description'])." + +"; + foreach ($pkginfo['maintainers'] as $maint) { + $ret .= " \n"; + foreach ($maint_map as $idx => $elm) { + $ret .= " <$elm>"; + $ret .= htmlspecialchars($maint[$idx]); + $ret .= "\n"; + } + $ret .= " \n"; + } + $ret .= " \n"; + $ret .= $this->_makeReleaseXml($pkginfo); + if (@sizeof($pkginfo['changelog']) > 0) { + $ret .= " \n"; + foreach ($pkginfo['changelog'] as $oldrelease) { + $ret .= $this->_makeReleaseXml($oldrelease, true); + } + $ret .= " \n"; + } + $ret .= "\n"; + return $ret; + } + + // }}} + // {{{ _makeReleaseXml() + + /** + * Generate part of an XML description with release information. + * + * @param array $pkginfo array with release information + * @param bool $changelog whether the result will be in a changelog element + * + * @return string XML data + * + * @access private + */ + function _makeReleaseXml($pkginfo, $changelog = false) + { + // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! + $indent = $changelog ? " " : ""; + $ret = "$indent \n"; + if (!empty($pkginfo['version'])) { + $ret .= "$indent $pkginfo[version]\n"; + } + if (!empty($pkginfo['release_date'])) { + $ret .= "$indent $pkginfo[release_date]\n"; + } + if (!empty($pkginfo['release_license'])) { + $ret .= "$indent $pkginfo[release_license]\n"; + } + if (!empty($pkginfo['release_state'])) { + $ret .= "$indent $pkginfo[release_state]\n"; + } + if (!empty($pkginfo['release_notes'])) { + $ret .= "$indent ".htmlspecialchars($pkginfo['release_notes'])."\n"; + } + if (!empty($pkginfo['release_warnings'])) { + $ret .= "$indent ".htmlspecialchars($pkginfo['release_warnings'])."\n"; + } + if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { + $ret .= "$indent \n"; + foreach ($pkginfo['release_deps'] as $dep) { + $ret .= "$indent $what) { + $ret .= "$indent $fa) { + @$ret .= "$indent $v) { + $ret .= " $k=\"" . htmlspecialchars($v) .'"'; + } + $ret .= "/>\n"; + } + @$ret .= "$indent \n"; + } + } + $ret .= "$indent \n"; + } + $ret .= "$indent \n"; + return $ret; + } + + // }}} + // {{{ validatePackageInfo() + + /** + * Validate XML package definition file. + * + * @param string $info Filename of the package archive or of the + * package definition file + * @param array $errors Array that will contain the errors + * @param array $warnings Array that will contain the warnings + * @param string $dir_prefix (optional) directory where source files + * may be found, or empty if they are not available + * @access public + * @return boolean + */ + function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') + { + if (PEAR::isError($info = $this->infoFromAny($info))) { + return $this->raiseError($info); + } + if (!is_array($info)) { + return false; + } + + $errors = array(); + $warnings = array(); + if (!isset($info['package'])) { + $errors[] = 'missing package name'; + } elseif (!$this->validPackageName($info['package'])) { + $errors[] = 'invalid package name'; + } + $this->_packageName = $pn = $info['package']; + + if (empty($info['summary'])) { + $errors[] = 'missing summary'; + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $warnings[] = 'summary should be on a single line'; + } + if (empty($info['description'])) { + $errors[] = 'missing description'; + } + if (empty($info['release_license'])) { + $errors[] = 'missing license'; + } + if (!isset($info['version'])) { + $errors[] = 'missing version'; + } elseif (!$this->validPackageVersion($info['version'])) { + $errors[] = 'invalid package release version'; + } + if (empty($info['release_state'])) { + $errors[] = 'missing release state'; + } elseif (!in_array($info['release_state'], PEAR_Common::getReleaseStates())) { + $errors[] = "invalid release state `$info[release_state]', should be one of: " + . implode(' ', PEAR_Common::getReleaseStates()); + } + if (empty($info['release_date'])) { + $errors[] = 'missing release date'; + } elseif (!preg_match('/^\d{4}-\d\d-\d\d$/', $info['release_date'])) { + $errors[] = "invalid release date `$info[release_date]', format is YYYY-MM-DD"; + } + if (empty($info['release_notes'])) { + $errors[] = "missing release notes"; + } + if (empty($info['maintainers'])) { + $errors[] = 'no maintainer(s)'; + } else { + $i = 1; + foreach ($info['maintainers'] as $m) { + if (empty($m['handle'])) { + $errors[] = "maintainer $i: missing handle"; + } + if (empty($m['role'])) { + $errors[] = "maintainer $i: missing role"; + } elseif (!in_array($m['role'], PEAR_Common::getUserRoles())) { + $errors[] = "maintainer $i: invalid role `$m[role]', should be one of: " + . implode(' ', PEAR_Common::getUserRoles()); + } + if (empty($m['name'])) { + $errors[] = "maintainer $i: missing name"; + } + if (empty($m['email'])) { + $errors[] = "maintainer $i: missing email"; + } + $i++; + } + } + if (!empty($info['release_deps'])) { + $i = 1; + foreach ($info['release_deps'] as $d) { + if (empty($d['type'])) { + $errors[] = "dependency $i: missing type"; + } elseif (!in_array($d['type'], PEAR_Common::getDependencyTypes())) { + $errors[] = "dependency $i: invalid type '$d[type]', should be one of: " . + implode(' ', PEAR_Common::getDependencyTypes()); + } + if (empty($d['rel'])) { + $errors[] = "dependency $i: missing relation"; + } elseif (!in_array($d['rel'], PEAR_Common::getDependencyRelations())) { + $errors[] = "dependency $i: invalid relation '$d[rel]', should be one of: " + . implode(' ', PEAR_Common::getDependencyRelations()); + } + if (!empty($d['optional'])) { + if (!in_array($d['optional'], array('yes', 'no'))) { + $errors[] = "dependency $i: invalid relation optional attribute '$d[optional]', should be one of: yes no"; + } else { + if (($d['rel'] == 'not' || $d['rel'] == 'ne') && $d['optional'] == 'yes') { + $errors[] = "dependency $i: 'not' and 'ne' dependencies cannot be " . + "optional"; + } + } + } + if ($d['rel'] != 'not' && $d['rel'] != 'has' && empty($d['version'])) { + $warnings[] = "dependency $i: missing version"; + } elseif (($d['rel'] == 'not' || $d['rel'] == 'has') && !empty($d['version'])) { + $warnings[] = "dependency $i: version ignored for `$d[rel]' dependencies"; + } + if ($d['rel'] == 'not' && !empty($d['version'])) { + $warnings[] = "dependency $i: 'not' defines a total conflict, to exclude " . + "specific versions, use 'ne'"; + } + if ($d['type'] == 'php' && !empty($d['name'])) { + $warnings[] = "dependency $i: name ignored for php type dependencies"; + } elseif ($d['type'] != 'php' && empty($d['name'])) { + $errors[] = "dependency $i: missing name"; + } + if ($d['type'] == 'php' && $d['rel'] == 'not') { + $errors[] = "dependency $i: PHP dependencies cannot use 'not' " . + "rel, use 'ne' to exclude versions"; + } + $i++; + } + } + if (!empty($info['configure_options'])) { + $i = 1; + foreach ($info['configure_options'] as $c) { + if (empty($c['name'])) { + $errors[] = "configure option $i: missing name"; + } + if (empty($c['prompt'])) { + $errors[] = "configure option $i: missing prompt"; + } + $i++; + } + } + if (empty($info['filelist'])) { + $errors[] = 'no files'; + } else { + foreach ($info['filelist'] as $file => $fa) { + if (empty($fa['role'])) { + $errors[] = "file $file: missing role"; + continue; + } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { + $errors[] = "file $file: invalid role, should be one of: " + . implode(' ', PEAR_Common::getFileRoles()); + } + if ($fa['role'] == 'php' && $dir_prefix) { + $this->log(1, "Analyzing $file"); + $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $this->buildProvidesArray($srcinfo); + } + } + + // (ssb) Any checks we can do for baseinstalldir? + // (cox) Perhaps checks that either the target dir and + // baseInstall doesn't cointain "../../" + } + } + $this->_packageName = $pn = $info['package']; + $pnl = strlen($pn); + foreach ((array)$this->pkginfo['provides'] as $key => $what) { + if (isset($what['explicit'])) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; + } + $warnings[] = "in $file: class \"$name\" not prefixed with package name \"$pn\""; + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; + } + $warnings[] = "in $file: function \"$name\" not prefixed with package name \"$pn\""; + } + } + + + return true; + } + + // }}} + // {{{ buildProvidesArray() + + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access public + * + */ + function buildProvidesArray($srcinfo) + { + $file = basename($srcinfo['source_file']); + $pn = ''; + if (isset($this->_packageName)) { + $pn = $this->_packageName; + } + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->pkginfo['provides'][$key])) { + continue; + } + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->pkginfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->pkginfo['provides'][$key])) { + continue; + } + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { + continue; + } + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + // }}} + // {{{ analyzeSourceCode() + + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access public + */ + function analyzeSourceCode($file) + { + if (!function_exists("token_get_all")) { + return false; + } + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); + } + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + if (!$fp = @fopen($file, "r")) { + return false; + } + $contents = fread($fp, filesize($file)); + $tokens = token_get_all($contents); +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); + } + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + if ($inquote) { + if ($token != '"') { + continue; + } else { + $inquote = false; + } + } + switch ($token) { + case T_WHITESPACE: + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; + } + break; + case '"': + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; + } + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + PEAR::raiseError("Parser error: Invalid PHP file $file", + PEAR_COMMON_ERROR_INVALIDPHP); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'clone', 'throw') + )) { + PEAR::raiseError('Error: PHP5 packages must be packaged by php 5 PEAR'); + return false; + } + } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; + } + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { + PEAR::raiseError("Parser error: Invalid PHP file $file", + PEAR_COMMON_ERROR_INVALIDPHP); + return false; + } + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } + continue 2; + } + } + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); + } + + // }}} + // {{{ betterStates() + + /** + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state + */ + function betterStates($state, $include = false) + { + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; + } + if ($include) { + $i--; + } + return array_slice($states, $i + 1); + } + + // }}} + // {{{ detectDependencies() + + function detectDependencies($any, $status_callback = null) + { + if (!function_exists("token_get_all")) { + return false; + } + if (PEAR::isError($info = $this->infoFromAny($any))) { + return $this->raiseError($info); + } + if (!is_array($info)) { + return false; + } + $deps = array(); + $used_c = $decl_c = $decl_f = $decl_m = array(); + foreach ($info['filelist'] as $file => $fa) { + $tmp = $this->analyzeSourceCode($file); + $used_c = @array_merge($used_c, $tmp['used_classes']); + $decl_c = @array_merge($decl_c, $tmp['declared_classes']); + $decl_f = @array_merge($decl_f, $tmp['declared_functions']); + $decl_m = @array_merge($decl_m, $tmp['declared_methods']); + $inheri = @array_merge($inheri, $tmp['inheritance']); + } + $used_c = array_unique($used_c); + $decl_c = array_unique($decl_c); + $undecl_c = array_diff($used_c, $decl_c); + return array('used_classes' => $used_c, + 'declared_classes' => $decl_c, + 'declared_methods' => $decl_m, + 'declared_functions' => $decl_f, + 'undeclared_classes' => $undecl_c, + 'inheritance' => $inheri, + ); + } + + // }}} + // {{{ getUserRoles() + + /** + * Get the valid roles for a PEAR package maintainer + * + * @return array + * @static + */ + function getUserRoles() + { + return $GLOBALS['_PEAR_Common_maintainer_roles']; + } + + // }}} + // {{{ getReleaseStates() + + /** + * Get the valid package release states of packages + * + * @return array + * @static + */ + function getReleaseStates() + { + return $GLOBALS['_PEAR_Common_release_states']; + } + + // }}} + // {{{ getDependencyTypes() + + /** + * Get the implemented dependency types (php, ext, pkg etc.) + * + * @return array + * @static + */ + function getDependencyTypes() + { + return $GLOBALS['_PEAR_Common_dependency_types']; + } + + // }}} + // {{{ getDependencyRelations() + + /** + * Get the implemented dependency relations (has, lt, ge etc.) + * + * @return array + * @static + */ + function getDependencyRelations() + { + return $GLOBALS['_PEAR_Common_dependency_relations']; + } + + // }}} + // {{{ getFileRoles() + + /** + * Get the implemented file roles + * + * @return array + * @static + */ + function getFileRoles() + { + return $GLOBALS['_PEAR_Common_file_roles']; + } + + // }}} + // {{{ getReplacementTypes() + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getReplacementTypes() + { + return $GLOBALS['_PEAR_Common_replacement_types']; + } + + // }}} + // {{{ getProvideTypes() + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getProvideTypes() + { + return $GLOBALS['_PEAR_Common_provide_types']; + } + + // }}} + // {{{ getScriptPhases() + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getScriptPhases() + { + return $GLOBALS['_PEAR_Common_script_phases']; + } + + // }}} + // {{{ validPackageName() + + /** + * Test whether a string contains a valid package name. + * + * @param string $name the package name to test + * + * @return bool + * + * @access public + */ + function validPackageName($name) + { + return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); + } + + + // }}} + // {{{ validPackageVersion() + + /** + * Test whether a string contains a valid package version. + * + * @param string $ver the package version to test + * + * @return bool + * + * @access public + */ + function validPackageVersion($ver) + { + return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + + // }}} + + // {{{ downloadHttp() + + /** + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: + * + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir (optional) directory to save file in + * @param mixed $callback (optional) function/method to call for status + * updates + * + * @return string Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). + * + * @access public + */ + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) + { + if ($callback) { + call_user_func($callback, 'setup', array(&$ui)); + } + if (preg_match('!^http://([^/:?#]*)(:(\d+))?(/.*)!', $url, $matches)) { + list(,$host,,$port,$path) = $matches; + } + if (isset($this)) { + $config = &$this->config; + } else { + $config = &PEAR_Config::singleton(); + } + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($proxy = parse_url($config->get('http_proxy'))) { + $proxy_host = @$proxy['host']; + $proxy_port = @$proxy['port']; + $proxy_user = @$proxy['user']; + $proxy_pass = @$proxy['pass']; + + if ($proxy_port == '') { + $proxy_port = 8080; + } + if ($callback) { + call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); + } + } + if (empty($port)) { + $port = 80; + } + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); + } + $request = "GET $url HTTP/1.0\r\n"; + } else { + $fp = @fsockopen($host, $port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($host, $port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + $request = "GET $path HTTP/1.0\r\n"; + } + $request .= "Host: $host:$port\r\n". + "User-Agent: PHP/".PHP_VERSION."\r\n"; + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } + $request .= "\r\n"; + fwrite($fp, $request); + $headers = array(); + while (trim($line = fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*$/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + if ($matches[1] != 200) { + return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)"); + } + } + } + if (isset($headers['content-disposition']) && + preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|$)/', $headers['content-disposition'], $matches)) { + $save_as = basename($matches[1]); + } else { + $save_as = basename($url); + } + if ($callback) { + $tmp = call_user_func($callback, 'saveas', $save_as); + if ($tmp) { + $save_as = $tmp; + } + } + $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; + if (!$wp = @fopen($dest_file, 'wb')) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("could not open $dest_file for writing"); + } + if (isset($headers['content-length'])) { + $length = $headers['content-length']; + } else { + $length = -1; + } + $bytes = 0; + if ($callback) { + call_user_func($callback, 'start', array(basename($dest_file), $length)); + } + while ($data = @fread($fp, 1024)) { + $bytes += strlen($data); + if ($callback) { + call_user_func($callback, 'bytesread', $bytes); + } + if (!@fwrite($wp, $data)) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); + } + } + fclose($fp); + fclose($wp); + if ($callback) { + call_user_func($callback, 'done', $bytes); + } + return $dest_file; + } + + // }}} + // {{{ sortPkgDeps() + + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * + * It also removes duplicate dependencies + * @param array + * @param boolean Sort packages in reverse order if true + * @return array array of array(packagefilename, package.xml contents) + */ + function sortPkgDeps(&$packages, $uninstall = false) + { + $ret = array(); + if ($uninstall) { + foreach($packages as $packageinfo) { + $ret[] = array('info' => $packageinfo); + } + } else { + foreach($packages as $packagefile) { + if (!is_array($packagefile)) { + $ret[] = array('file' => $packagefile, + 'info' => $a = $this->infoFromAny($packagefile), + 'pkg' => $a['package']); + } else { + $ret[] = $packagefile; + } + } + } + $checkdupes = array(); + $newret = array(); + foreach($ret as $i => $p) { + if (!isset($checkdupes[$p['info']['package']])) { + $checkdupes[$p['info']['package']][] = $i; + $newret[] = $p; + } + } + $this->_packageSortTree = $this->_getPkgDepTree($newret); + + $func = $uninstall ? '_sortPkgDepsRev' : '_sortPkgDeps'; + usort($newret, array(&$this, $func)); + $this->_packageSortTree = null; + $packages = $newret; + } + + // }}} + // {{{ _sortPkgDeps() + + /** + * Compare two package's package.xml, and sort + * so that dependencies are installed first + * + * This is a crude compare, real dependency checking is done on install. + * The only purpose this serves is to make the command-line + * order-independent (you can list a dependent package first, and + * installation occurs in the order required) + * @access private + */ + function _sortPkgDeps($p1, $p2) + { + $p1name = $p1['info']['package']; + $p2name = $p2['info']['package']; + $p1deps = $this->_getPkgDeps($p1); + $p2deps = $this->_getPkgDeps($p2); + if (!count($p1deps) && !count($p2deps)) { + return 0; // order makes no difference + } + if (!count($p1deps)) { + return -1; // package 2 has dependencies, package 1 doesn't + } + if (!count($p2deps)) { + return 1; // package 1 has dependencies, package 2 doesn't + } + // both have dependencies + if (in_array($p1name, $p2deps)) { + return -1; // put package 1 first: package 2 depends on package 1 + } + if (in_array($p2name, $p1deps)) { + return 1; // put package 2 first: package 1 depends on package 2 + } + if ($this->_removedDependency($p1name, $p2name)) { + return -1; // put package 1 first: package 2 depends on packages that depend on package 1 + } + if ($this->_removedDependency($p2name, $p1name)) { + return 1; // put package 2 first: package 1 depends on packages that depend on package 2 + } + // doesn't really matter if neither depends on the other + return 0; + } + + // }}} + // {{{ _sortPkgDepsRev() + + /** + * Compare two package's package.xml, and sort + * so that dependencies are uninstalled last + * + * This is a crude compare, real dependency checking is done on uninstall. + * The only purpose this serves is to make the command-line + * order-independent (you can list a dependency first, and + * uninstallation occurs in the order required) + * @access private + */ + function _sortPkgDepsRev($p1, $p2) + { + $p1name = $p1['info']['package']; + $p2name = $p2['info']['package']; + $p1deps = $this->_getRevPkgDeps($p1); + $p2deps = $this->_getRevPkgDeps($p2); + if (!count($p1deps) && !count($p2deps)) { + return 0; // order makes no difference + } + if (!count($p1deps)) { + return 1; // package 2 has dependencies, package 1 doesn't + } + if (!count($p2deps)) { + return -1; // package 2 has dependencies, package 1 doesn't + } + // both have dependencies + if (in_array($p1name, $p2deps)) { + return 1; // put package 1 last + } + if (in_array($p2name, $p1deps)) { + return -1; // put package 2 last + } + if ($this->_removedDependency($p1name, $p2name)) { + return 1; // put package 1 last: package 2 depends on packages that depend on package 1 + } + if ($this->_removedDependency($p2name, $p1name)) { + return -1; // put package 2 last: package 1 depends on packages that depend on package 2 + } + // doesn't really matter if neither depends on the other + return 0; + } + + // }}} + // {{{ _getPkgDeps() + + /** + * get an array of package dependency names + * @param array + * @return array + * @access private + */ + function _getPkgDeps($p) + { + if (!isset($p['info']['releases'])) { + return $this->_getRevPkgDeps($p); + } + $rel = array_shift($p['info']['releases']); + if (!isset($rel['deps'])) { + return array(); + } + $ret = array(); + foreach($rel['deps'] as $dep) { + if ($dep['type'] == 'pkg') { + $ret[] = $dep['name']; + } + } + return $ret; + } + + // }}} + // {{{ _getPkgDeps() + + /** + * get an array representation of the package dependency tree + * @return array + * @access private + */ + function _getPkgDepTree($packages) + { + $tree = array(); + foreach ($packages as $p) { + $package = $p['info']['package']; + $deps = $this->_getPkgDeps($p); + $tree[$package] = $deps; + } + return $tree; + } + + // }}} + // {{{ _removedDependency($p1, $p2) + + /** + * get an array of package dependency names for uninstall + * @param string package 1 name + * @param string package 2 name + * @return bool + * @access private + */ + function _removedDependency($p1, $p2) + { + if (empty($this->_packageSortTree[$p2])) { + return false; + } + if (!in_array($p1, $this->_packageSortTree[$p2])) { + foreach ($this->_packageSortTree[$p2] as $potential) { + if ($this->_removedDependency($p1, $potential)) { + return true; + } + } + return false; + } + return true; + } + + // }}} + // {{{ _getRevPkgDeps() + + /** + * get an array of package dependency names for uninstall + * @param array + * @return array + * @access private + */ + function _getRevPkgDeps($p) + { + if (!isset($p['info']['release_deps'])) { + return array(); + } + $ret = array(); + foreach($p['info']['release_deps'] as $dep) { + if ($dep['type'] == 'pkg') { + $ret[] = $dep['name']; + } + } + return $ret; + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Config.php b/src/www/lib/pear/PEAR/Config.php new file mode 100644 index 00000000..83d8b5a7 --- /dev/null +++ b/src/www/lib/pear/PEAR/Config.php @@ -0,0 +1,1169 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Config.php,v 1.1 2005/05/28 01:55:12 henrique Exp $ + +require_once 'PEAR.php'; +require_once 'System.php'; + +/** + * Last created PEAR_Config instance. + * @var object + */ +$GLOBALS['_PEAR_Config_instance'] = null; +if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { + $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; +} else { + $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; +} + +// Below we define constants with default values for all configuration +// parameters except username/password. All of them can have their +// defaults set through environment variables. The reason we use the +// PHP_ prefix is for some security, PHP protects environment +// variables starting with PHP_*. + +if (getenv('PHP_PEAR_SYSCONF_DIR')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); +} elseif (getenv('SystemRoot')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); +} else { + define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); +} + +// Default for master_server +if (getenv('PHP_PEAR_MASTER_SERVER')) { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); +} else { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); +} + +// Default for http_proxy +if (getenv('PHP_PEAR_HTTP_PROXY')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); +} elseif (getenv('http_proxy')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); +} else { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); +} + +// Default for php_dir +if (getenv('PHP_PEAR_INSTALL_DIR')) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); +} else { + if (@is_dir($PEAR_INSTALL_DIR)) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', + $PEAR_INSTALL_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } +} + +// Default for ext_dir +if (getenv('PHP_PEAR_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); +} else { + if (ini_get('extension_dir')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); + } elseif (defined('PEAR_EXTENSION_DIR') && @is_dir(PEAR_EXTENSION_DIR)) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); + } elseif (defined('PHP_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); + } +} + +// Default for doc_dir +if (getenv('PHP_PEAR_DOC_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); +} + +// Default for bin_dir +if (getenv('PHP_PEAR_BIN_DIR')) { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); +} + +// Default for data_dir +if (getenv('PHP_PEAR_DATA_DIR')) { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); +} + +// Default for test_dir +if (getenv('PHP_PEAR_TEST_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); +} + +// Default for cache_dir +if (getenv('PHP_PEAR_CACHE_DIR')) { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'cache'); +} + +// Default for php_bin +if (getenv('PHP_PEAR_PHP_BIN')) { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. + DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); +} + +// Default for verbose +if (getenv('PHP_PEAR_VERBOSE')) { + define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); +} else { + define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); +} + +// Default for preferred_state +if (getenv('PHP_PEAR_PREFERRED_STATE')) { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); +} else { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); +} + +// Default for umask +if (getenv('PHP_PEAR_UMASK')) { + define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); +} else { + define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); +} + +// Default for cache_ttl +if (getenv('PHP_PEAR_CACHE_TTL')) { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); +} + +// Default for sig_type +if (getenv('PHP_PEAR_SIG_TYPE')) { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); +} + +// Default for sig_bin +if (getenv('PHP_PEAR_SIG_BIN')) { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', + System::which( + 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); +} + +// Default for sig_keydir +if (getenv('PHP_PEAR_SIG_KEYDIR')) { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', + PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); +} + +/** + * This is a class for storing configuration data, keeping track of + * which are system-defined, user-defined or defaulted. + */ +class PEAR_Config extends PEAR +{ + // {{{ properties + + /** + * Array of config files used. + * + * @var array layer => config file + */ + var $files = array( + 'system' => '', + 'user' => '', + ); + + var $layers = array(); + + /** + * Configuration data, two-dimensional array where the first + * dimension is the config layer ('user', 'system' and 'default'), + * and the second dimension is keyname => value. + * + * The order in the first dimension is important! Earlier + * layers will shadow later ones when a config value is + * requested (if a 'user' value exists, it will be returned first, + * then 'system' and finally 'default'). + * + * @var array layer => array(keyname => value, ...) + */ + var $configuration = array( + 'user' => array(), + 'system' => array(), + 'default' => array(), + ); + + /** + * Information about the configuration data. Stores the type, + * default value and a documentation string for each configuration + * value. + * + * @var array layer => array(infotype => value, ...) + */ + var $configuration_info = array( + // Internet Access + 'master_server' => array( + 'type' => 'string', + 'default' => 'pear.php.net', + 'doc' => 'name of the main PEAR server', + 'prompt' => 'PEAR server', + 'group' => 'Internet Access', + ), + 'http_proxy' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, + 'doc' => 'HTTP proxy (host:port) to use when downloading packages', + 'prompt' => 'HTTP Proxy Server Address', + 'group' => 'Internet Access', + ), + // File Locations + 'php_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, + 'doc' => 'directory where .php files are installed', + 'prompt' => 'PEAR directory', + 'group' => 'File Locations', + ), + 'ext_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, + 'doc' => 'directory where loadable extensions are installed', + 'prompt' => 'PHP extension directory', + 'group' => 'File Locations', + ), + 'doc_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, + 'doc' => 'directory where documentation is installed', + 'prompt' => 'PEAR documentation directory', + 'group' => 'File Locations', + ), + 'bin_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, + 'doc' => 'directory where executables are installed', + 'prompt' => 'PEAR executables directory', + 'group' => 'File Locations', + ), + 'data_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, + 'doc' => 'directory where data files are installed', + 'prompt' => 'PEAR data directory', + 'group' => 'File Locations (Advanced)', + ), + 'test_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, + 'doc' => 'directory where regression tests are installed', + 'prompt' => 'PEAR test directory', + 'group' => 'File Locations (Advanced)', + ), + 'cache_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, + 'doc' => 'directory which is used for XMLRPC cache', + 'prompt' => 'PEAR Installer cache directory', + 'group' => 'File Locations (Advanced)', + ), + 'php_bin' => array( + 'type' => 'file', + 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, + 'doc' => 'PHP CLI/CGI binary for executing scripts', + 'prompt' => 'PHP CLI/CGI binary', + 'group' => 'File Locations (Advanced)', + ), + // Maintainers + 'username' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '(maintainers) your PEAR account name', + 'prompt' => 'PEAR username (for maintainers)', + 'group' => 'Maintainers', + ), + 'password' => array( + 'type' => 'password', + 'default' => '', + 'doc' => '(maintainers) your PEAR account password', + 'prompt' => 'PEAR password (for maintainers)', + 'group' => 'Maintainers', + ), + // Advanced + 'verbose' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, + 'doc' => 'verbosity level +0: really quiet +1: somewhat quiet +2: verbose +3: debug', + 'prompt' => 'Debug Log Level', + 'group' => 'Advanced', + ), + 'preferred_state' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, + 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', + 'valid_set' => array( + 'stable', 'beta', 'alpha', 'devel', 'snapshot'), + 'prompt' => 'Preferred Package State', + 'group' => 'Advanced', + ), + 'umask' => array( + 'type' => 'mask', + 'default' => PEAR_CONFIG_DEFAULT_UMASK, + 'doc' => 'umask used when creating files (Unix-like systems only)', + 'prompt' => 'Unix file mask', + 'group' => 'Advanced', + ), + 'cache_ttl' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, + 'doc' => 'amount of secs where the local cache is used and not updated', + 'prompt' => 'Cache TimeToLive', + 'group' => 'Advanced', + ), + 'sig_type' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, + 'doc' => 'which package signature mechanism to use', + 'valid_set' => array('gpg'), + 'prompt' => 'Package Signature Type', + 'group' => 'Maintainers', + ), + 'sig_bin' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, + 'doc' => 'which package signature mechanism to use', + 'prompt' => 'Signature Handling Program', + 'group' => 'Maintainers', + ), + 'sig_keyid' => array( + 'type' => 'string', + 'default' => '', + 'doc' => 'which key to use for signing with', + 'prompt' => 'Signature Key Id', + 'group' => 'Maintainers', + ), + 'sig_keydir' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, + 'doc' => 'which package signature mechanism to use', + 'prompt' => 'Signature Key Directory', + 'group' => 'Maintainers', + ), + ); + + // }}} + + // {{{ PEAR_Config([file], [defaults_file]) + + /** + * Constructor. + * + * @param string (optional) file to read user-defined options from + * @param string (optional) file to read system-wide defaults from + * + * @access public + * + * @see PEAR_Config::singleton + */ + function PEAR_Config($user_file = '', $system_file = '') + { + $this->PEAR(); + $sl = DIRECTORY_SEPARATOR; + if (empty($user_file)) { + if (OS_WINDOWS) { + $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; + } else { + $user_file = getenv('HOME') . $sl . '.pearrc'; + } + } + if (empty($system_file)) { + if (OS_WINDOWS) { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'; + } else { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'; + } + } + $this->layers = array_keys($this->configuration); + $this->files['user'] = $user_file; + $this->files['system'] = $system_file; + if ($user_file && file_exists($user_file)) { + $this->readConfigFile($user_file); + } + if ($system_file && file_exists($system_file)) { + $this->mergeConfigFile($system_file, false, 'system'); + } + foreach ($this->configuration_info as $key => $info) { + $this->configuration['default'][$key] = $info['default']; + } + //$GLOBALS['_PEAR_Config_instance'] = &$this; + } + + // }}} + // {{{ singleton([file], [defaults_file]) + + /** + * Static singleton method. If you want to keep only one instance + * of this class in use, this method will give you a reference to + * the last created PEAR_Config object if one exists, or create a + * new object. + * + * @param string (optional) file to read user-defined options from + * @param string (optional) file to read system-wide defaults from + * + * @return object an existing or new PEAR_Config instance + * + * @access public + * + * @see PEAR_Config::PEAR_Config + */ + function &singleton($user_file = '', $system_file = '') + { + if (is_object($GLOBALS['_PEAR_Config_instance'])) { + return $GLOBALS['_PEAR_Config_instance']; + } + $GLOBALS['_PEAR_Config_instance'] = + &new PEAR_Config($user_file, $system_file); + return $GLOBALS['_PEAR_Config_instance']; + } + + // }}} + // {{{ readConfigFile([file], [layer]) + + /** + * Reads configuration data from a file. All existing values in + * the config layer are discarded and replaced with data from the + * file. + * + * @param string (optional) file to read from, if NULL or not + * specified, the last-used file for the same layer (second param) + * is used + * + * @param string (optional) config layer to insert data into + * ('user' or 'system') + * + * @return bool TRUE on success or a PEAR error on failure + * + * @access public + */ + function readConfigFile($file = null, $layer = 'user') + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); + } + if ($file === null) { + $file = $this->files[$layer]; + } + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + return $data; + } + $this->_decodeInput($data); + $this->configuration[$layer] = $data; + return true; + } + + // }}} + // {{{ mergeConfigFile(file, [override], [layer]) + + /** + * Merges data into a config layer from a file. Does the same + * thing as readConfigFile, except it does not replace all + * existing values in the config layer. + * + * @param string file to read from + * + * @param bool (optional) whether to overwrite existing data + * (default TRUE) + * + * @param string config layer to insert data into ('user' or + * 'system') + * + * @return bool TRUE on success or a PEAR error on failure + * + * @access public. + */ + function mergeConfigFile($file, $override = true, $layer = 'user') + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); + } + if ($file === null) { + $file = $this->files[$layer]; + } + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + return $data; + } + $this->_decodeInput($data); + if ($override) { + $this->configuration[$layer] = array_merge($this->configuration[$layer], $data); + } else { + $this->configuration[$layer] = array_merge($data, $this->configuration[$layer]); + } + return true; + } + + // }}} + // {{{ writeConfigFile([file], [layer]) + + /** + * Writes data into a config layer from a file. + * + * @param string file to read from + * + * @param bool (optional) whether to overwrite existing data + * (default TRUE) + * + * @param string config layer to insert data into ('user' or + * 'system') + * + * @return bool TRUE on success or a PEAR error on failure + * + * @access public. + */ + function writeConfigFile($file = null, $layer = 'user', $data = null) + { + if ($layer == 'both' || $layer == 'all') { + foreach ($this->files as $type => $file) { + $err = $this->writeConfigFile($file, $type, $data); + if (PEAR::isError($err)) { + return $err; + } + } + return true; + } + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); + } + if ($file === null) { + $file = $this->files[$layer]; + } + $data = ($data === null) ? $this->configuration[$layer] : $data; + $this->_encodeOutput($data); + $opt = array('-p', dirname($file)); + if (!@System::mkDir($opt)) { + return $this->raiseError("could not create directory: " . dirname($file)); + } + if (@is_file($file) && !@is_writeable($file)) { + return $this->raiseError("no write access to $file!"); + } + $fp = @fopen($file, "w"); + if (!$fp) { + return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed"); + } + $contents = "#PEAR_Config 0.9\n" . serialize($data); + if (!@fwrite($fp, $contents)) { + return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed"); + } + return true; + } + + // }}} + // {{{ _readConfigDataFrom(file) + + /** + * Reads configuration data from a file and returns the parsed data + * in an array. + * + * @param string file to read from + * + * @return array configuration data or a PEAR error on failure + * + * @access private + */ + function _readConfigDataFrom($file) + { + $fp = @fopen($file, "r"); + if (!$fp) { + return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); + } + $size = filesize($file); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $contents = fread($fp, $size); + set_magic_quotes_runtime($rt); + fclose($fp); + $version = '0.1'; + if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { + $version = $matches[1]; + $contents = substr($contents, strlen($matches[0])); + } + if (version_compare("$version", '1', '<')) { + $data = unserialize($contents); + if (!is_array($data)) { + if (strlen(trim($contents)) > 0) { + $error = "PEAR_Config: bad data in $file"; +// if (isset($this)) { + return $this->raiseError($error); +// } else { +// return PEAR::raiseError($error); + } else { + $data = array(); + } + } + // add parsing of newer formats here... + } else { + return $this->raiseError("$file: unknown version `$version'"); + } + return $data; + } + + // }}} + // {{{ getConfFile(layer) + /** + * Gets the file used for storing the config for a layer + * + * @param string $layer 'user' or 'system' + */ + + function getConfFile($layer) + { + return $this->files[$layer]; + } + + // }}} + // {{{ _encodeOutput(&data) + + /** + * Encodes/scrambles configuration data before writing to files. + * Currently, 'password' values will be base64-encoded as to avoid + * that people spot cleartext passwords by accident. + * + * @param array (reference) array to encode values in + * + * @return bool TRUE on success + * + * @access private + */ + function _encodeOutput(&$data) + { + foreach ($data as $key => $value) { + if (!isset($this->configuration_info[$key])) { + continue; + } + $type = $this->configuration_info[$key]['type']; + switch ($type) { + // we base64-encode passwords so they are at least + // not shown in plain by accident + case 'password': { + $data[$key] = base64_encode($data[$key]); + break; + } + case 'mask': { + $data[$key] = octdec($data[$key]); + break; + } + } + } + return true; + } + + // }}} + // {{{ _decodeInput(&data) + + /** + * Decodes/unscrambles configuration data after reading from files. + * + * @param array (reference) array to encode values in + * + * @return bool TRUE on success + * + * @access private + * + * @see PEAR_Config::_encodeOutput + */ + function _decodeInput(&$data) + { + if (!is_array($data)) { + return true; + } + foreach ($data as $key => $value) { + if (!isset($this->configuration_info[$key])) { + continue; + } + $type = $this->configuration_info[$key]['type']; + switch ($type) { + case 'password': { + $data[$key] = base64_decode($data[$key]); + break; + } + case 'mask': { + $data[$key] = decoct($data[$key]); + break; + } + } + } + return true; + } + + // }}} + // {{{ get(key, [layer]) + + /** + * Returns a configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * + * @return mixed the config value, or NULL if not found + * + * @access public + */ + function get($key, $layer = null) + { + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return $this->configuration[$layer][$key]; + } + } + } elseif (isset($this->configuration[$layer][$key])) { + return $this->configuration[$layer][$key]; + } + return null; + } + + // }}} + // {{{ set(key, value, [layer]) + + /** + * Set a config value in a specific layer (defaults to 'user'). + * Enforces the types defined in the configuration_info array. An + * integer config variable will be cast to int, and a set config + * variable will be validated against its legal values. + * + * @param string config key + * + * @param string config value + * + * @param string (optional) config layer + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function set($key, $value, $layer = 'user') + { + if (empty($this->configuration_info[$key])) { + return false; + } + extract($this->configuration_info[$key]); + switch ($type) { + case 'integer': + $value = (int)$value; + break; + case 'set': { + // If a valid_set is specified, require the value to + // be in the set. If there is no valid_set, accept + // any value. + if ($valid_set) { + reset($valid_set); + if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || + (key($valid_set) !== 0 && empty($valid_set[$value]))) + { + return false; + } + } + break; + } + } + $this->configuration[$layer][$key] = $value; + return true; + } + + // }}} + // {{{ getType(key) + + /** + * Get the type of a config value. + * + * @param string config key + * + * @return string type, one of "string", "integer", "file", + * "directory", "set" or "password". + * + * @access public + * + */ + function getType($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['type']; + } + return false; + } + + // }}} + // {{{ getDocs(key) + + /** + * Get the documentation for a config value. + * + * @param string config key + * + * @return string documentation string + * + * @access public + * + */ + function getDocs($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['doc']; + } + return false; + } + // }}} + // {{{ getPrompt(key) + + /** + * Get the short documentation for a config value. + * + * @param string config key + * + * @return string short documentation string + * + * @access public + * + */ + function getPrompt($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['prompt']; + } + return false; + } + // }}} + // {{{ getGroup(key) + + /** + * Get the parameter group for a config key. + * + * @param string config key + * + * @return string parameter group + * + * @access public + * + */ + function getGroup($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['group']; + } + return false; + } + + // }}} + // {{{ getGroups() + + /** + * Get the list of parameter groups. + * + * @return array list of parameter groups + * + * @access public + * + */ + function getGroups() + { + $tmp = array(); + foreach ($this->configuration_info as $key => $info) { + $tmp[$info['group']] = 1; + } + return array_keys($tmp); + } + + // }}} + // {{{ getGroupKeys() + + /** + * Get the list of the parameters in a group. + * + * @param string $group parameter group + * + * @return array list of parameters in $group + * + * @access public + * + */ + function getGroupKeys($group) + { + $keys = array(); + foreach ($this->configuration_info as $key => $info) { + if ($info['group'] == $group) { + $keys[] = $key; + } + } + return $keys; + } + + // }}} + // {{{ getSetValues(key) + + /** + * Get the list of allowed set values for a config value. Returns + * NULL for config values that are not sets. + * + * @param string config key + * + * @return array enumerated array of set values, or NULL if the + * config key is unknown or not a set + * + * @access public + * + */ + function getSetValues($key) + { + if (isset($this->configuration_info[$key]) && + isset($this->configuration_info[$key]['type']) && + $this->configuration_info[$key]['type'] == 'set') + { + $valid_set = $this->configuration_info[$key]['valid_set']; + reset($valid_set); + if (key($valid_set) === 0) { + return $valid_set; + } + return array_keys($valid_set); + } + return false; + } + + // }}} + // {{{ getKeys() + + /** + * Get all the current config keys. + * + * @return array simple array of config keys + * + * @access public + */ + function getKeys() + { + $keys = array(); + foreach ($this->layers as $layer) { + $keys = array_merge($keys, $this->configuration[$layer]); + } + return array_keys($keys); + } + + // }}} + // {{{ remove(key, [layer]) + + /** + * Remove the a config key from a specific config layer. + * + * @param string config key + * + * @param string (optional) config layer + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function remove($key, $layer = 'user') + { + if (isset($this->configuration[$layer][$key])) { + unset($this->configuration[$layer][$key]); + return true; + } + return false; + } + + // }}} + // {{{ removeLayer(layer) + + /** + * Temporarily remove an entire config layer. USE WITH CARE! + * + * @param string config key + * + * @param string (optional) config layer + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function removeLayer($layer) + { + if (isset($this->configuration[$layer])) { + $this->configuration[$layer] = array(); + return true; + } + return false; + } + + // }}} + // {{{ store([layer]) + + /** + * Stores configuration data in a layer. + * + * @param string config layer to store + * + * @return bool TRUE on success, or PEAR error on failure + * + * @access public + */ + function store($layer = 'user', $data = null) + { + return $this->writeConfigFile(null, $layer, $data); + } + + // }}} + // {{{ toDefault(key) + + /** + * Unset the user-defined value of a config key, reverting the + * value to the system-defined one. + * + * @param string config key + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function toDefault($key) + { + trigger_error("PEAR_Config::toDefault() deprecated, use PEAR_Config::remove() instead", E_USER_NOTICE); + return $this->remove($key, 'user'); + } + + // }}} + // {{{ definedBy(key) + + /** + * Tells what config layer that gets to define a key. + * + * @param string config key + * + * @return string the config layer, or an empty string if not found + * + * @access public + */ + function definedBy($key) + { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return $layer; + } + } + return ''; + } + + // }}} + // {{{ isDefaulted(key) + + /** + * Tells whether a config value has a system-defined value. + * + * @param string config key + * + * @return bool + * + * @access public + * + * @deprecated + */ + function isDefaulted($key) + { + trigger_error("PEAR_Config::isDefaulted() deprecated, use PEAR_Config::definedBy() instead", E_USER_NOTICE); + return $this->definedBy($key) == 'system'; + } + + // }}} + // {{{ isDefined(key) + + /** + * Tells whether a given key exists as a config value. + * + * @param string config key + * + * @return bool whether exists in this object + * + * @access public + */ + function isDefined($key) + { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return true; + } + } + return false; + } + + // }}} + // {{{ isDefinedLayer(key) + + /** + * Tells whether a given config layer exists. + * + * @param string config layer + * + * @return bool whether exists in this object + * + * @access public + */ + function isDefinedLayer($layer) + { + return isset($this->configuration[$layer]); + } + + // }}} + // {{{ getLayers() + + /** + * Returns the layers defined (except the 'default' one) + * + * @return array of the defined layers + */ + function getLayers() + { + $cf = $this->configuration; + unset($cf['default']); + return array_keys($cf); + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Dependency.php b/src/www/lib/pear/PEAR/Dependency.php new file mode 100644 index 00000000..aec1fb1e --- /dev/null +++ b/src/www/lib/pear/PEAR/Dependency.php @@ -0,0 +1,487 @@ + | +// | Stig Bakken | +// +----------------------------------------------------------------------+ +// +// $Id: Dependency.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + +require_once "PEAR.php"; + +define('PEAR_DEPENDENCY_MISSING', -1); +define('PEAR_DEPENDENCY_CONFLICT', -2); +define('PEAR_DEPENDENCY_UPGRADE_MINOR', -3); +define('PEAR_DEPENDENCY_UPGRADE_MAJOR', -4); +define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5); +define('PEAR_DEPENDENCY_MISSING_OPTIONAL', -6); +define('PEAR_DEPENDENCY_CONFLICT_OPTIONAL', -7); +define('PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL', -8); +define('PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL', -9); + +/** + * Dependency check for PEAR packages + * + * The class is based on the dependency RFC that can be found at + * http://cvs.php.net/cvs.php/pearweb/rfc. It requires PHP >= 4.1 + * + * @author Tomas V.V.Vox + * @author Stig Bakken + */ +class PEAR_Dependency +{ + // {{{ constructor + /** + * Constructor + * + * @access public + * @param object Registry object + * @return void + */ + function PEAR_Dependency(&$registry) + { + $this->registry = &$registry; + } + + // }}} + // {{{ callCheckMethod() + + /** + * This method maps the XML dependency definition to the + * corresponding one from PEAR_Dependency + * + *
+    * $opts => Array
+    *    (
+    *        [type] => pkg
+    *        [rel] => ge
+    *        [version] => 3.4
+    *        [name] => HTML_Common
+    *        [optional] => false
+    *    )
+    * 
+ * + * @param string Error message + * @param array Options + * @return boolean + */ + function callCheckMethod(&$errmsg, $opts) + { + $rel = isset($opts['rel']) ? $opts['rel'] : 'has'; + $req = isset($opts['version']) ? $opts['version'] : null; + $name = isset($opts['name']) ? $opts['name'] : null; + $opt = (isset($opts['optional']) && $opts['optional'] == 'yes') ? + $opts['optional'] : null; + $errmsg = ''; + switch ($opts['type']) { + case 'pkg': + return $this->checkPackage($errmsg, $name, $req, $rel, $opt); + break; + case 'ext': + return $this->checkExtension($errmsg, $name, $req, $rel, $opt); + break; + case 'php': + return $this->checkPHP($errmsg, $req, $rel); + break; + case 'prog': + return $this->checkProgram($errmsg, $name); + break; + case 'os': + return $this->checkOS($errmsg, $name); + break; + case 'sapi': + return $this->checkSAPI($errmsg, $name); + break; + case 'zend': + return $this->checkZend($errmsg, $name); + break; + default: + return "'{$opts['type']}' dependency type not supported"; + } + } + + // }}} + // {{{ checkPackage() + + /** + * Package dependencies check method + * + * @param string $errmsg Empty string, it will be populated with an error message, if any + * @param string $name Name of the package to test + * @param string $req The package version required + * @param string $relation How to compare versions with each other + * @param bool $opt Whether the relationship is optional + * + * @return mixed bool false if no error or the error string + */ + function checkPackage(&$errmsg, $name, $req = null, $relation = 'has', + $opt = false) + { + if (is_string($req) && substr($req, 0, 2) == 'v.') { + $req = substr($req, 2); + } + switch ($relation) { + case 'has': + if (!$this->registry->packageExists($name)) { + if ($opt) { + $errmsg = "package `$name' is recommended to utilize some features."; + return PEAR_DEPENDENCY_MISSING_OPTIONAL; + } + $errmsg = "requires package `$name'"; + return PEAR_DEPENDENCY_MISSING; + } + return false; + case 'not': + if ($this->registry->packageExists($name)) { + $errmsg = "conflicts with package `$name'"; + return PEAR_DEPENDENCY_CONFLICT; + } + return false; + case 'lt': + case 'le': + case 'eq': + case 'ne': + case 'ge': + case 'gt': + $version = $this->registry->packageInfo($name, 'version'); + if (!$this->registry->packageExists($name) + || !version_compare("$version", "$req", $relation)) + { + $code = $this->codeFromRelation($relation, $version, $req, $opt); + if ($opt) { + $errmsg = "package `$name' version " . $this->signOperator($relation) . + " $req is recommended to utilize some features."; + if ($version) { + $errmsg .= " Installed version is $version"; + } + return $code; + } + $errmsg = "requires package `$name' " . + $this->signOperator($relation) . " $req"; + return $code; + } + return false; + } + $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$name)"; + return PEAR_DEPENDENCY_BAD_DEPENDENCY; + } + + // }}} + // {{{ checkPackageUninstall() + + /** + * Check package dependencies on uninstall + * + * @param string $error The resultant error string + * @param string $warning The resultant warning string + * @param string $name Name of the package to test + * + * @return bool true if there were errors + */ + function checkPackageUninstall(&$error, &$warning, $package) + { + $error = null; + $packages = $this->registry->listPackages(); + foreach ($packages as $pkg) { + if ($pkg == $package) { + continue; + } + $deps = $this->registry->packageInfo($pkg, 'release_deps'); + if (empty($deps)) { + continue; + } + foreach ($deps as $dep) { + if ($dep['type'] == 'pkg' && strcasecmp($dep['name'], $package) == 0) { + if ($dep['rel'] == 'ne' || $dep['rel'] == 'not') { + continue; + } + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + $warning .= "\nWarning: Package '$pkg' optionally depends on '$package'"; + } else { + $error .= "Package '$pkg' depends on '$package'\n"; + } + } + } + } + return ($error) ? true : false; + } + + // }}} + // {{{ checkExtension() + + /** + * Extension dependencies check method + * + * @param string $name Name of the extension to test + * @param string $req_ext_ver Required extension version to compare with + * @param string $relation How to compare versions with eachother + * @param bool $opt Whether the relationship is optional + * + * @return mixed bool false if no error or the error string + */ + function checkExtension(&$errmsg, $name, $req = null, $relation = 'has', + $opt = false) + { + if ($relation == 'not') { + if (extension_loaded($name)) { + $errmsg = "conflicts with PHP extension '$name'"; + return PEAR_DEPENDENCY_CONFLICT; + } else { + return false; + } + } + + if (!extension_loaded($name)) { + if ($relation == 'not') { + return false; + } + if ($opt) { + $errmsg = "'$name' PHP extension is recommended to utilize some features"; + return PEAR_DEPENDENCY_MISSING_OPTIONAL; + } + $errmsg = "'$name' PHP extension is not installed"; + return PEAR_DEPENDENCY_MISSING; + } + if ($relation == 'has') { + return false; + } + $code = false; + if (is_string($req) && substr($req, 0, 2) == 'v.') { + $req = substr($req, 2); + } + $ext_ver = phpversion($name); + $operator = $relation; + // Force params to be strings, otherwise the comparation will fail (ex. 0.9==0.90) + if (!version_compare("$ext_ver", "$req", $operator)) { + $errmsg = "'$name' PHP extension version " . + $this->signOperator($operator) . " $req is required"; + $code = $this->codeFromRelation($relation, $ext_ver, $req, $opt); + if ($opt) { + $errmsg = "'$name' PHP extension version " . $this->signOperator($operator) . + " $req is recommended to utilize some features"; + return $code; + } + } + return $code; + } + + // }}} + // {{{ checkOS() + + /** + * Operating system dependencies check method + * + * @param string $os Name of the operating system + * + * @return mixed bool false if no error or the error string + */ + function checkOS(&$errmsg, $os) + { + // XXX Fixme: Implement a more flexible way, like + // comma separated values or something similar to PEAR_OS + static $myos; + if (empty($myos)) { + include_once "OS/Guess.php"; + $myos = new OS_Guess(); + } + // only 'has' relation is currently supported + if ($myos->matchSignature($os)) { + return false; + } + $errmsg = "'$os' operating system not supported"; + return PEAR_DEPENDENCY_CONFLICT; + } + + // }}} + // {{{ checkPHP() + + /** + * PHP version check method + * + * @param string $req which version to compare + * @param string $relation how to compare the version + * + * @return mixed bool false if no error or the error string + */ + function checkPHP(&$errmsg, $req, $relation = 'ge') + { + // this would be a bit stupid, but oh well :) + if ($relation == 'has') { + return false; + } + if ($relation == 'not') { + $errmsg = 'Invalid dependency - "not" is not allowed for php dependencies, ' . + 'php cannot conflict with itself'; + return PEAR_DEPENDENCY_BAD_DEPENDENCY; + } + if (substr($req, 0, 2) == 'v.') { + $req = substr($req,2, strlen($req) - 2); + } + $php_ver = phpversion(); + $operator = $relation; + if (!version_compare("$php_ver", "$req", $operator)) { + $errmsg = "PHP version " . $this->signOperator($operator) . + " $req is required"; + return PEAR_DEPENDENCY_CONFLICT; + } + return false; + } + + // }}} + // {{{ checkProgram() + + /** + * External program check method. Looks for executable files in + * directories listed in the PATH environment variable. + * + * @param string $program which program to look for + * + * @return mixed bool false if no error or the error string + */ + function checkProgram(&$errmsg, $program) + { + // XXX FIXME honor safe mode + $exe_suffix = OS_WINDOWS ? '.exe' : ''; + $path_elements = explode(PATH_SEPARATOR, getenv('PATH')); + foreach ($path_elements as $dir) { + $file = $dir . DIRECTORY_SEPARATOR . $program . $exe_suffix; + if (@file_exists($file) && @is_executable($file)) { + return false; + } + } + $errmsg = "'$program' program is not present in the PATH"; + return PEAR_DEPENDENCY_MISSING; + } + + // }}} + // {{{ checkSAPI() + + /** + * SAPI backend check method. Version comparison is not yet + * available here. + * + * @param string $name name of SAPI backend + * @param string $req which version to compare + * @param string $relation how to compare versions (currently + * hardcoded to 'has') + * @return mixed bool false if no error or the error string + */ + function checkSAPI(&$errmsg, $name, $req = null, $relation = 'has') + { + // XXX Fixme: There is no way to know if the user has or + // not other SAPI backends installed than the installer one + + $sapi_backend = php_sapi_name(); + // Version comparisons not supported, sapi backends don't have + // version information yet. + if ($sapi_backend == $name) { + return false; + } + $errmsg = "'$sapi_backend' SAPI backend not supported"; + return PEAR_DEPENDENCY_CONFLICT; + } + + // }}} + // {{{ checkZend() + + /** + * Zend version check method + * + * @param string $req which version to compare + * @param string $relation how to compare the version + * + * @return mixed bool false if no error or the error string + */ + function checkZend(&$errmsg, $req, $relation = 'ge') + { + if (substr($req, 0, 2) == 'v.') { + $req = substr($req,2, strlen($req) - 2); + } + $zend_ver = zend_version(); + $operator = substr($relation,0,2); + if (!version_compare("$zend_ver", "$req", $operator)) { + $errmsg = "Zend version " . $this->signOperator($operator) . + " $req is required"; + return PEAR_DEPENDENCY_CONFLICT; + } + return false; + } + + // }}} + // {{{ signOperator() + + /** + * Converts text comparing operators to them sign equivalents + * + * Example: 'ge' to '>=' + * + * @access public + * @param string Operator + * @return string Sign equivalent + */ + function signOperator($operator) + { + switch($operator) { + case 'lt': return '<'; + case 'le': return '<='; + case 'gt': return '>'; + case 'ge': return '>='; + case 'eq': return '=='; + case 'ne': return '!='; + default: + return $operator; + } + } + + // }}} + // {{{ codeFromRelation() + + /** + * Convert relation into corresponding code + * + * @access public + * @param string Relation + * @param string Version + * @param string Requirement + * @param bool Optional dependency indicator + * @return integer + */ + function codeFromRelation($relation, $version, $req, $opt = false) + { + $code = PEAR_DEPENDENCY_BAD_DEPENDENCY; + switch ($relation) { + case 'gt': case 'ge': case 'eq': + // upgrade + $have_major = preg_replace('/\D.*/', '', $version); + $need_major = preg_replace('/\D.*/', '', $req); + if ($need_major > $have_major) { + $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL : + PEAR_DEPENDENCY_UPGRADE_MAJOR; + } else { + $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL : + PEAR_DEPENDENCY_UPGRADE_MINOR; + } + break; + case 'lt': case 'le': case 'ne': + $code = $opt ? PEAR_DEPENDENCY_CONFLICT_OPTIONAL : + PEAR_DEPENDENCY_CONFLICT; + break; + } + return $code; + } + + // }}} +} +?> diff --git a/src/www/lib/pear/PEAR/Downloader.php b/src/www/lib/pear/PEAR/Downloader.php new file mode 100644 index 00000000..e6339a23 --- /dev/null +++ b/src/www/lib/pear/PEAR/Downloader.php @@ -0,0 +1,680 @@ + | +// | Tomas V.V.Cox | +// | Martin Jansen | +// +----------------------------------------------------------------------+ +// +// $Id: Downloader.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + +require_once 'PEAR/Common.php'; +require_once 'PEAR/Registry.php'; +require_once 'PEAR/Dependency.php'; +require_once 'PEAR/Remote.php'; +require_once 'System.php'; + + +define('PEAR_INSTALLER_OK', 1); +define('PEAR_INSTALLER_FAILED', 0); +define('PEAR_INSTALLER_SKIPPED', -1); +define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); + +/** + * Administration class used to download PEAR packages and maintain the + * installed package database. + * + * @since PEAR 1.4 + * @author Greg Beaver + */ +class PEAR_Downloader extends PEAR_Common +{ + /** + * @var PEAR_Config + * @access private + */ + var $_config; + + /** + * @var PEAR_Registry + * @access private + */ + var $_registry; + + /** + * @var PEAR_Remote + * @access private + */ + var $_remote; + + /** + * Preferred Installation State (snapshot, devel, alpha, beta, stable) + * @var string|null + * @access private + */ + var $_preferredState; + + /** + * Options from command-line passed to Install. + * + * Recognized options:
+ * - onlyreqdeps : install all required dependencies as well + * - alldeps : install all dependencies, including optional + * - installroot : base relative path to install files in + * - force : force a download even if warnings would prevent it + * @see PEAR_Command_Install + * @access private + * @var array + */ + var $_options; + + /** + * Downloaded Packages after a call to download(). + * + * Format of each entry: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @access private + * @var array + */ + var $_downloadedPackages = array(); + + /** + * Packages slated for download. + * + * This is used to prevent downloading a package more than once should it be a dependency + * for two packages to be installed. + * Format of each entry: + * + *
+     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
+     * );
+     * 
+ * @access private + * @var array + */ + var $_toDownload = array(); + + /** + * Array of every package installed, with names lower-cased. + * + * Format: + * + * array('package1' => 0, 'package2' => 1, ); + * + * @var array + */ + var $_installed = array(); + + /** + * @var array + * @access private + */ + var $_errorStack = array(); + + // {{{ PEAR_Downloader() + + function PEAR_Downloader(&$ui, $options, &$config) + { + $this->_options = $options; + $this->_config = &$config; + $this->_preferredState = $this->_config->get('preferred_state'); + $this->ui = &$ui; + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + + $php_dir = $this->_config->get('php_dir'); + if (isset($this->_options['installroot'])) { + if (substr($this->_options['installroot'], -1) == DIRECTORY_SEPARATOR) { + $this->_options['installroot'] = substr($this->_options['installroot'], 0, -1); + } + $php_dir = $this->_prependPath($php_dir, $this->_options['installroot']); + } + $this->_registry = &new PEAR_Registry($php_dir); + $this->_remote = &new PEAR_Remote($config); + + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + $this->_installed = $this->_registry->listPackages(); + array_walk($this->_installed, create_function('&$v,$k','$v = strtolower($v);')); + $this->_installed = array_flip($this->_installed); + } + parent::PEAR_Common(); + } + + // }}} + // {{{ configSet() + function configSet($key, $value, $layer = 'user') + { + $this->_config->set($key, $value, $layer); + $this->_preferredState = $this->_config->get('preferred_state'); + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + } + + // }}} + // {{{ setOptions() + function setOptions($options) + { + $this->_options = $options; + } + + // }}} + // {{{ _downloadFile() + /** + * @param string filename to download + * @param string version/state + * @param string original value passed to command-line + * @param string|null preferred state (snapshot/devel/alpha/beta/stable) + * Defaults to configuration preferred state + * @return null|PEAR_Error|string + * @access private + */ + function _downloadFile($pkgfile, $version, $origpkgfile, $state = null) + { + if (is_null($state)) { + $state = $this->_preferredState; + } + // {{{ check the package filename, and whether it's already installed + $need_download = false; + if (preg_match('#^(http|ftp)://#', $pkgfile)) { + $need_download = true; + } elseif (!@is_file($pkgfile)) { + if ($this->validPackageName($pkgfile)) { + if ($this->_registry->packageExists($pkgfile)) { + if (empty($this->_options['upgrade']) && empty($this->_options['force'])) { + $errors[] = "$pkgfile already installed"; + return; + } + } + $pkgfile = $this->getPackageDownloadUrl($pkgfile, $version); + $need_download = true; + } else { + if (strlen($pkgfile)) { + $errors[] = "Could not open the package file: $pkgfile"; + } else { + $errors[] = "No package file given"; + } + return; + } + } + // }}} + + // {{{ Download package ----------------------------------------------- + if ($need_download) { + $downloaddir = $this->_config->get('download_dir'); + if (empty($downloaddir)) { + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; + } + $this->log(3, '+ tmp dir created at ' . $downloaddir); + } + $callback = $this->ui ? array(&$this, '_downloadCallback') : null; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $file = $this->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback); + $this->popErrorHandling(); + if (PEAR::isError($file)) { + if ($this->validPackageName($origpkgfile)) { + if (!PEAR::isError($info = $this->_remote->call('package.info', + $origpkgfile))) { + if (!count($info['releases'])) { + return $this->raiseError('Package ' . $origpkgfile . + ' has no releases'); + } else { + return $this->raiseError('No releases of preferred state "' + . $state . '" exist for package ' . $origpkgfile . + '. Use ' . $origpkgfile . '-state to install another' . + ' state (like ' . $origpkgfile .'-beta)', + PEAR_INSTALLER_ERROR_NO_PREF_STATE); + } + } else { + return $pkgfile; + } + } else { + return $this->raiseError($file); + } + } + $pkgfile = $file; + } + // }}} + return $pkgfile; + } + // }}} + // {{{ getPackageDownloadUrl() + + function getPackageDownloadUrl($package, $version = null) + { + if ($version) { + $package .= "-$version"; + } + if ($this === null || $this->_config === null) { + $package = "http://pear.php.net/get/$package"; + } else { + $package = "http://" . $this->_config->get('master_server') . + "/get/$package"; + } + if (!extension_loaded("zlib")) { + $package .= '?uncompress=yes'; + } + return $package; + } + + // }}} + // {{{ extractDownloadFileName($pkgfile, &$version) + + function extractDownloadFileName($pkgfile, &$version) + { + if (@is_file($pkgfile)) { + return $pkgfile; + } + // regex defined in Common.php + if (preg_match(PEAR_COMMON_PACKAGE_DOWNLOAD_PREG, $pkgfile, $m)) { + $version = (isset($m[3])) ? $m[3] : null; + return $m[1]; + } + $version = null; + return $pkgfile; + } + + // }}} + + // }}} + // {{{ getDownloadedPackages() + + /** + * Retrieve a list of downloaded packages after a call to {@link download()}. + * + * Also resets the list of downloaded packages. + * @return array + */ + function getDownloadedPackages() + { + $ret = $this->_downloadedPackages; + $this->_downloadedPackages = array(); + $this->_toDownload = array(); + return $ret; + } + + // }}} + // {{{ download() + + /** + * Download any files and their dependencies, if necessary + * + * BC-compatible method name + * @param array a mixed list of package names, local files, or package.xml + */ + function download($packages) + { + return $this->doDownload($packages); + } + + // }}} + // {{{ doDownload() + + /** + * Download any files and their dependencies, if necessary + * + * @param array a mixed list of package names, local files, or package.xml + */ + function doDownload($packages) + { + $mywillinstall = array(); + $state = $this->_preferredState; + + // {{{ download files in this list if necessary + foreach($packages as $pkgfile) { + $need_download = false; + if (!is_file($pkgfile)) { + if (preg_match('#^(http|ftp)://#', $pkgfile)) { + $need_download = true; + } + $pkgfile = $this->_downloadNonFile($pkgfile); + if (PEAR::isError($pkgfile)) { + return $pkgfile; + } + if ($pkgfile === false) { + continue; + } + } // end is_file() + + $tempinfo = $this->infoFromAny($pkgfile); + if ($need_download) { + $this->_toDownload[] = $tempinfo['package']; + } + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + // ignore dependencies if there are any errors + if (!PEAR::isError($tempinfo)) { + $mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps']; + } + } + $this->_downloadedPackages[] = array('pkg' => $tempinfo['package'], + 'file' => $pkgfile, 'info' => $tempinfo); + } // end foreach($packages) + // }}} + + // {{{ extract dependencies from downloaded files and then download + // them if necessary + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + $deppackages = array(); + foreach ($mywillinstall as $package => $alldeps) { + if (!is_array($alldeps)) { + // there are no dependencies + continue; + } + $fail = false; + foreach ($alldeps as $info) { + if ($info['type'] != 'pkg') { + continue; + } + $ret = $this->_processDependency($package, $info, $mywillinstall); + if ($ret === false) { + continue; + } + if ($ret === 0) { + $fail = true; + continue; + } + if (PEAR::isError($ret)) { + return $ret; + } + $deppackages[] = $ret; + } // foreach($alldeps + if ($fail) { + $deppackages = array(); + } + } + + if (count($deppackages)) { + $this->doDownload($deppackages); + } + } // }}} if --alldeps or --onlyreqdeps + } + + // }}} + // {{{ _downloadNonFile($pkgfile) + + /** + * @return false|PEAR_Error|string false if loop should be broken out of, + * string if the file was downloaded, + * PEAR_Error on exception + * @access private + */ + function _downloadNonFile($pkgfile) + { + $origpkgfile = $pkgfile; + $state = null; + $pkgfile = $this->extractDownloadFileName($pkgfile, $version); + if (preg_match('#^(http|ftp)://#', $pkgfile)) { + return $this->_downloadFile($pkgfile, $version, $origpkgfile); + } + if (!$this->validPackageName($pkgfile)) { + return $this->raiseError("Package name '$pkgfile' not valid"); + } + // ignore packages that are installed unless we are upgrading + $curinfo = $this->_registry->packageInfo($pkgfile); + if ($this->_registry->packageExists($pkgfile) + && empty($this->_options['upgrade']) && empty($this->_options['force'])) { + $this->log(0, "Package '{$curinfo['package']}' already installed, skipping"); + return false; + } + if (in_array($pkgfile, $this->_toDownload)) { + return false; + } + $releases = $this->_remote->call('package.info', $pkgfile, 'releases', true); + if (!count($releases)) { + return $this->raiseError("No releases found for package '$pkgfile'"); + } + // Want a specific version/state + if ($version !== null) { + // Passed Foo-1.2 + if ($this->validPackageVersion($version)) { + if (!isset($releases[$version])) { + return $this->raiseError("No release with version '$version' found for '$pkgfile'"); + } + // Passed Foo-alpha + } elseif (in_array($version, $this->getReleaseStates())) { + $state = $version; + $version = 0; + foreach ($releases as $ver => $inf) { + if ($inf['state'] == $state && version_compare("$version", "$ver") < 0) { + $version = $ver; + break; + } + } + if ($version == 0) { + return $this->raiseError("No release with state '$state' found for '$pkgfile'"); + } + // invalid suffix passed + } else { + return $this->raiseError("Invalid suffix '-$version', be sure to pass a valid PEAR ". + "version number or release state"); + } + // Guess what to download + } else { + $states = $this->betterStates($this->_preferredState, true); + $possible = false; + $version = 0; + $higher_version = 0; + $prev_hi_ver = 0; + foreach ($releases as $ver => $inf) { + if (in_array($inf['state'], $states) && version_compare("$version", "$ver") < 0) { + $version = $ver; + break; + } else { + $ver = (string)$ver; + if (version_compare($prev_hi_ver, $ver) < 0) { + $prev_hi_ver = $higher_version = $ver; + } + } + } + if ($version === 0 && !isset($this->_options['force'])) { + return $this->raiseError('No release with state equal to: \'' . implode(', ', $states) . + "' found for '$pkgfile'"); + } elseif ($version === 0) { + $this->log(0, "Warning: $pkgfile is state '" . $releases[$higher_version]['state'] . "' which is less stable " . + "than state '$this->_preferredState'"); + } + } + // Check if we haven't already the version + if (empty($this->_options['force']) && !is_null($curinfo)) { + if ($curinfo['version'] == $version) { + $this->log(0, "Package '{$curinfo['package']}-{$curinfo['version']}' already installed, skipping"); + return false; + } elseif (version_compare("$version", "{$curinfo['version']}") < 0) { + $this->log(0, "Package '{$curinfo['package']}' version '{$curinfo['version']}' " . + " is installed and {$curinfo['version']} is > requested '$version', skipping"); + return false; + } + } + $this->_toDownload[] = $pkgfile; + return $this->_downloadFile($pkgfile, $version, $origpkgfile, $state); + } + + // }}} + // {{{ _processDependency($package, $info, $mywillinstall) + + /** + * Process a dependency, download if necessary + * @param array dependency information from PEAR_Remote call + * @param array packages that will be installed in this iteration + * @return false|string|PEAR_Error + * @access private + * @todo Add test for relation 'lt'/'le' -> make sure that the dependency requested is + * in fact lower than the required value. This will be very important for BC dependencies + */ + function _processDependency($package, $info, $mywillinstall) + { + $state = $this->_preferredState; + if (!isset($this->_options['alldeps']) && isset($info['optional']) && + $info['optional'] == 'yes') { + // skip optional deps + $this->log(0, "skipping Package '$package' optional dependency '$info[name]'"); + return false; + } + // {{{ get releases + $releases = $this->_remote->call('package.info', $info['name'], 'releases', true); + if (PEAR::isError($releases)) { + return $releases; + } + if (!count($releases)) { + if (!isset($this->_installed[strtolower($info['name'])])) { + $this->pushError("Package '$package' dependency '$info[name]' ". + "has no releases"); + } + return false; + } + $found = false; + $save = $releases; + while(count($releases) && !$found) { + if (!empty($state) && $state != 'any') { + list($release_version, $release) = each($releases); + if ($state != $release['state'] && + !in_array($release['state'], $this->betterStates($state))) + { + // drop this release - it ain't stable enough + array_shift($releases); + } else { + $found = true; + } + } else { + $found = true; + } + } + if (!count($releases) && !$found) { + $get = array(); + foreach($save as $release) { + $get = array_merge($get, + $this->betterStates($release['state'], true)); + } + $savestate = array_shift($get); + $this->pushError( "Release for '$package' dependency '$info[name]' " . + "has state '$savestate', requires '$state'"); + return 0; + } + if (in_array(strtolower($info['name']), $this->_toDownload) || + isset($mywillinstall[strtolower($info['name'])])) { + // skip upgrade check for packages we will install + return false; + } + if (!isset($this->_installed[strtolower($info['name'])])) { + // check to see if we can install the specific version required + if ($info['rel'] == 'eq') { + return $info['name'] . '-' . $info['version']; + } + // skip upgrade check for packages we don't have installed + return $info['name']; + } + // }}} + + // {{{ see if a dependency must be upgraded + $inst_version = $this->_registry->packageInfo($info['name'], 'version'); + if (!isset($info['version'])) { + // this is a rel='has' dependency, check against latest + if (version_compare($release_version, $inst_version, 'le')) { + return false; + } else { + return $info['name']; + } + } + if (version_compare($info['version'], $inst_version, 'le')) { + // installed version is up-to-date + return false; + } + return $info['name']; + } + + // }}} + // {{{ _downloadCallback() + + function _downloadCallback($msg, $params = null) + { + switch ($msg) { + case 'saveas': + $this->log(1, "downloading $params ..."); + break; + case 'done': + $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); + break; + case 'bytesread': + static $bytes; + if (empty($bytes)) { + $bytes = 0; + } + if (!($bytes % 10240)) { + $this->log(1, '.', false); + } + $bytes += $params; + break; + case 'start': + $this->log(1, "Starting to download {$params[0]} (".number_format($params[1], 0, '', ',')." bytes)"); + break; + } + if (method_exists($this->ui, '_downloadCallback')) + $this->ui->_downloadCallback($msg, $params); + } + + // }}} + // {{{ _prependPath($path, $prepend) + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + $path = $prepend . substr($path, 2); + } else { + $path = $prepend . $path; + } + } + return $path; + } + // }}} + // {{{ pushError($errmsg, $code) + + /** + * @param string + * @param integer + */ + function pushError($errmsg, $code = -1) + { + array_push($this->_errorStack, array($errmsg, $code)); + } + + // }}} + // {{{ getErrorMsgs() + + function getErrorMsgs() + { + $msgs = array(); + $errs = $this->_errorStack; + foreach ($errs as $err) { + $msgs[] = $err[0]; + } + $this->_errorStack = array(); + return $msgs; + } + + // }}} +} +// }}} + +?> diff --git a/src/www/lib/pear/PEAR/ErrorStack.php b/src/www/lib/pear/PEAR/ErrorStack.php new file mode 100644 index 00000000..5ac000fd --- /dev/null +++ b/src/www/lib/pear/PEAR/ErrorStack.php @@ -0,0 +1,981 @@ + | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: ErrorStack.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + +/** + * Error Stack Implementation + * + * This is an incredibly simple implementation of a very complex error handling + * facility. It contains the ability + * to track multiple errors from multiple packages simultaneously. In addition, + * it can track errors of many levels, save data along with the error, context + * information such as the exact file, line number, class and function that + * generated the error, and if necessary, it can raise a traditional PEAR_Error. + * It has built-in support for PEAR::Log, to log errors as they occur + * + * Since version 0.2alpha, it is also possible to selectively ignore errors, + * through the use of an error callback, see {@link pushCallback()} + * + * Since version 0.3alpha, it is possible to specify the exception class + * returned from {@link push()} + * + * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can + * still be done quite handily in an error callback or by manipulating the returned array + * @author Greg Beaver + * @version PEAR1.3.2 (beta) + * @package PEAR_ErrorStack + * @category Debugging + * @license http://www.php.net/license/3_0.txt PHP License v3.0 + */ + +/** + * Singleton storage + * + * Format: + *
+ * array(
+ *  'package1' => PEAR_ErrorStack object,
+ *  'package2' => PEAR_ErrorStack object,
+ *  ...
+ * )
+ * 
+ * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] + */ +$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); + +/** + * Global error callback (default) + * + * This is only used if set to non-false. * is the default callback for + * all packages, whereas specific packages may set a default callback + * for all instances, regardless of whether they are a singleton or not. + * + * To exclude non-singletons, only set the local callback for the singleton + * @see PEAR_ErrorStack::setDefaultCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( + '*' => false, +); + +/** + * Global Log object (default) + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; + +/** + * Global Overriding Callback + * + * This callback will override any error callbacks that specific loggers have set. + * Use with EXTREME caution + * @see PEAR_ErrorStack::staticPushCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + +/**#@+ + * One of four possible return values from the error Callback + * @see PEAR_ErrorStack::_errorCallback() + */ +/** + * If this is returned, then the error will be both pushed onto the stack + * and logged. + */ +define('PEAR_ERRORSTACK_PUSHANDLOG', 1); +/** + * If this is returned, then the error will only be pushed onto the stack, + * and not logged. + */ +define('PEAR_ERRORSTACK_PUSH', 2); +/** + * If this is returned, then the error will only be logged, but not pushed + * onto the error stack. + */ +define('PEAR_ERRORSTACK_LOG', 3); +/** + * If this is returned, then the error is completely ignored. + */ +define('PEAR_ERRORSTACK_IGNORE', 4); +/** + * If this is returned, then the error is logged and die() is called. + */ +define('PEAR_ERRORSTACK_DIE', 5); +/**#@-*/ + +/** + * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in + * the singleton method. + */ +define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); + +/** + * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} + * that has no __toString() method + */ +define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); +/** + * Error Stack Implementation + * + * Usage: + * + * // global error stack + * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); + * // local error stack + * $local_stack = new PEAR_ErrorStack('MyPackage'); + * + * @copyright 2004 Gregory Beaver + * @package PEAR_ErrorStack + * @license http://www.php.net/license/3_0.txt PHP License + */ +class PEAR_ErrorStack { + /** + * Errors are stored in the order that they are pushed on the stack. + * @since 0.4alpha Errors are no longer organized by error level. + * This renders pop() nearly unusable, and levels could be more easily + * handled in a callback anyway + * @var array + * @access private + */ + var $_errors = array(); + + /** + * Storage of errors by level. + * + * Allows easy retrieval and deletion of only errors from a particular level + * @since PEAR 1.4.0dev + * @var array + * @access private + */ + var $_errorsByLevel = array(); + + /** + * Package name this error stack represents + * @var string + * @access protected + */ + var $_package; + + /** + * Determines whether a PEAR_Error is thrown upon every error addition + * @var boolean + * @access private + */ + var $_compat = false; + + /** + * If set to a valid callback, this will be used to generate the error + * message from the error code, otherwise the message passed in will be + * used + * @var false|string|array + * @access private + */ + var $_msgCallback = false; + + /** + * If set to a valid callback, this will be used to generate the error + * context for an error. For PHP-related errors, this will be a file + * and line number as retrieved from debug_backtrace(), but can be + * customized for other purposes. The error might actually be in a separate + * configuration file, or in a database query. + * @var false|string|array + * @access protected + */ + var $_contextCallback = false; + + /** + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one an PEAR_ERRORSTACK_* constant + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @var false|string|array + * @access protected + */ + var $_errorCallback = array(); + + /** + * PEAR::Log object for logging errors + * @var false|Log + * @access protected + */ + var $_logger = false; + + /** + * Error messages - designed to be overridden + * @var array + * @abstract + */ + var $_errorMsgs = array(); + + /** + * Set up a new error stack + * + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + */ + function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false) + { + $this->_package = $package; + $this->setMessageCallback($msgCallback); + $this->setContextCallback($contextCallback); + $this->_compat = $throwPEAR_Error; + } + + /** + * Return a single error stack for this package. + * + * Note that all parameters are ignored if the stack for package $package + * has already been instantiated + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + * @param string $stackClass class to instantiate + * @static + * @return PEAR_ErrorStack + */ + function &singleton($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') + { + if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + if (!class_exists($stackClass)) { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); + } + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, + 'exception', array('stackclass' => $stackClass), + 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', + false, $trace); + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = + &new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); + } + + /** + * Internal error handler for PEAR_ErrorStack class + * + * Dies if the error is an exception (and would have died anyway) + * @access private + */ + function _handleError($err) + { + if ($err['level'] == 'exception') { + $message = $err['message']; + if (isset($_SERVER['REQUEST_URI'])) { + echo '
'; + } else { + echo "\n"; + } + var_dump($err['context']); + die($message); + } + } + + /** + * Set up a PEAR::Log object for all error stacks that don't have one + * @param Log $log + * @static + */ + function setDefaultLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } elseif (is_callable($log)) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } + } + + /** + * Set up a PEAR::Log object for this error stack + * @param Log $log + */ + function setLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $this->_logger = &$log; + } elseif (is_callable($log)) { + $this->_logger = &$log; + } + } + + /** + * Set an error code => error message mapping callback + * + * This method sets the callback that can be used to generate error + * messages for any instance + * @param array|string Callback function/method + */ + function setMessageCallback($msgCallback) + { + if (!$msgCallback) { + $this->_msgCallback = array(&$this, 'getErrorMessage'); + } else { + if (is_callable($msgCallback)) { + $this->_msgCallback = $msgCallback; + } + } + } + + /** + * Get an error code => error message mapping callback + * + * This method returns the current callback that can be used to generate error + * messages + * @return array|string|false Callback function/method or false if none + */ + function getMessageCallback() + { + return $this->_msgCallback; + } + + /** + * Sets a default callback to be used by all error stacks + * + * This method sets the callback that can be used to generate error + * messages for a singleton + * @param array|string Callback function/method + * @param string Package name, or false for all packages + * @static + */ + function setDefaultCallback($callback = false, $package = false) + { + if (!is_callable($callback)) { + $callback = false; + } + $package = $package ? $package : '*'; + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; + } + + /** + * Set a callback that generates context information (location of error) for an error stack + * + * This method sets the callback that can be used to generate context + * information for an error. Passing in NULL will disable context generation + * and remove the expensive call to debug_backtrace() + * @param array|string|null Callback function/method + */ + function setContextCallback($contextCallback) + { + if ($contextCallback === null) { + return $this->_contextCallback = false; + } + if (!$contextCallback) { + $this->_contextCallback = array(&$this, 'getFileLine'); + } else { + if (is_callable($contextCallback)) { + $this->_contextCallback = $contextCallback; + } + } + } + + /** + * Set an error Callback + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one of the ERRORSTACK_* constants. + * + * This functionality can be used to emulate PEAR's pushErrorHandling, and + * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of + * the error stack or logging + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see popCallback() + * @param string|array $cb + */ + function pushCallback($cb) + { + array_push($this->_errorCallback, $cb); + } + + /** + * Remove a callback from the error callback stack + * @see pushCallback() + * @return array|string|false + */ + function popCallback() + { + if (!count($this->_errorCallback)) { + return false; + } + return array_pop($this->_errorCallback); + } + + /** + * Set a temporary overriding error callback for every package error stack + * + * Use this to temporarily disable all existing callbacks (can be used + * to emulate the @ operator, for instance) + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see staticPopCallback(), pushCallback() + * @param string|array $cb + * @static + */ + function staticPushCallback($cb) + { + array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); + } + + /** + * Remove a temporary overriding error callback + * @see staticPushCallback() + * @return array|string|false + * @static + */ + function staticPopCallback() + { + $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); + if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { + $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + } + return $ret; + } + + /** + * Add an error to the stack + * + * If the message generator exists, it is called with 2 parameters. + * - the current Error Stack object + * - an array that is in the same format as an error. Available indices + * are 'code', 'package', 'time', 'params', 'level', and 'context' + * + * Next, if the error should contain context information, this is + * handled by the context grabbing method. + * Finally, the error is pushed onto the proper error stack + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array|Exception + * if compatibility mode is on, a PEAR_Error is also + * thrown. If the class Exception exists, then one + * is returned to allow code like: + * + * throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob'))); + * + * + * The errorData property of the exception class will be set to the array + * that would normally be returned. If a PEAR_Error is returned, the userinfo + * property is set to the array + * + * Otherwise, an array is returned in this format: + * + * array( + * 'code' => $code, + * 'params' => $params, + * 'package' => $this->_package, + * 'level' => $level, + * 'time' => time(), + * 'context' => $context, + * 'message' => $msg, + * //['repackage' => $err] repackaged error array/Exception class + * ); + * + */ + function push($code, $level = 'error', $params = array(), $msg = false, + $repackage = false, $backtrace = false) + { + $context = false; + // grab error context + if ($this->_contextCallback) { + if (!$backtrace) { + $backtrace = debug_backtrace(); + } + $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); + } + + // save error + $time = explode(' ', microtime()); + $time = $time[1] + $time[0]; + $err = array( + 'code' => $code, + 'params' => $params, + 'package' => $this->_package, + 'level' => $level, + 'time' => $time, + 'context' => $context, + 'message' => $msg, + ); + + // set up the error message, if necessary + if ($this->_msgCallback) { + $msg = call_user_func_array($this->_msgCallback, + array(&$this, $err)); + $err['message'] = $msg; + } + + if ($repackage) { + $err['repackage'] = $repackage; + } + $push = $log = true; + $die = false; + // try the overriding callback first + $callback = $this->staticPopCallback(); + if ($callback) { + $this->staticPushCallback($callback); + } + if (!is_callable($callback)) { + // try the local callback next + $callback = $this->popCallback(); + if (is_callable($callback)) { + $this->pushCallback($callback); + } else { + // try the default callback + $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; + } + } + if (is_callable($callback)) { + switch(call_user_func($callback, $err)){ + case PEAR_ERRORSTACK_IGNORE: + return $err; + break; + case PEAR_ERRORSTACK_PUSH: + $log = false; + break; + case PEAR_ERRORSTACK_LOG: + $push = false; + break; + case PEAR_ERRORSTACK_DIE: + $die = true; + break; + // anything else returned has the same effect as pushandlog + } + } + if ($push) { + array_unshift($this->_errors, $err); + $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; + } + if ($log) { + if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { + $this->_log($err); + } + } + if ($die) { + die(); + } + if ($this->_compat && $push) { + return $this->raiseError($msg, $code, null, null, $err); + } + return $err; + } + + /** + * Static version of {@link push()} + * + * @param string $package Package name this error belongs to + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|null|Exception + * if compatibility mode is on, a PEAR_Error is also + * thrown. If the class Exception exists, then one + * is returned to allow code like: + * + * throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob'))); + * + * @static + */ + function staticPush($package, $code, $level = 'error', $params = array(), + $msg = false, $repackage = false, $backtrace = false) + { + $s = &PEAR_ErrorStack::singleton($package); + if ($s->_contextCallback) { + if (!$backtrace) { + if (function_exists('debug_backtrace')) { + $backtrace = debug_backtrace(); + } + } + } + return $s->push($code, $level, $params, $msg, $repackage, $backtrace); + } + + /** + * Log an error using PEAR::Log + * @param array $err Error array + * @param array $levels Error level => Log constant map + * @access protected + */ + function _log($err) + { + if ($this->_logger) { + $logger = &$this->_logger; + } else { + $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; + } + if (is_a($logger, 'Log')) { + $levels = array( + 'exception' => PEAR_LOG_CRIT, + 'alert' => PEAR_LOG_ALERT, + 'critical' => PEAR_LOG_CRIT, + 'error' => PEAR_LOG_ERR, + 'warning' => PEAR_LOG_WARNING, + 'notice' => PEAR_LOG_NOTICE, + 'info' => PEAR_LOG_INFO, + 'debug' => PEAR_LOG_DEBUG); + if (isset($levels[$err['level']])) { + $level = $levels[$err['level']]; + } else { + $level = PEAR_LOG_INFO; + } + $logger->log($err['message'], $level, $err); + } else { // support non-standard logs + call_user_func($logger, $err); + } + } + + + /** + * Pop an error off of the error stack + * + * @return false|array + * @since 0.4alpha it is no longer possible to specify a specific error + * level to return - the last error pushed will be returned, instead + */ + function pop() + { + return @array_shift($this->_errors); + } + + /** + * Determine whether there are any errors on the stack + * @param string|array Level name. Use to determine if any errors + * of level (string), or levels (array) have been pushed + * @return boolean + */ + function hasErrors($level = false) + { + if ($level) { + return isset($this->_errorsByLevel[$level]); + } + return count($this->_errors); + } + + /** + * Retrieve all errors since last purge + * + * @param boolean set in order to empty the error stack + * @param string level name, to return only errors of a particular severity + * @return array + */ + function getErrors($purge = false, $level = false) + { + if (!$purge) { + if ($level) { + if (!isset($this->_errorsByLevel[$level])) { + return array(); + } else { + return $this->_errorsByLevel[$level]; + } + } else { + return $this->_errors; + } + } + if ($level) { + $ret = $this->_errorsByLevel[$level]; + foreach ($this->_errorsByLevel[$level] as $i => $unused) { + // entries are references to the $_errors array + $this->_errorsByLevel[$level][$i] = false; + } + // array_filter removes all entries === false + $this->_errors = array_filter($this->_errors); + unset($this->_errorsByLevel[$level]); + return $ret; + } + $ret = $this->_errors; + $this->_errors = array(); + $this->_errorsByLevel = array(); + return $ret; + } + + /** + * Determine whether there are any errors on a single error stack, or on any error stack + * + * The optional parameter can be used to test the existence of any errors without the need of + * singleton instantiation + * @param string|false Package name to check for errors + * @param string Level name to check for a particular severity + * @return boolean + * @static + */ + function staticHasErrors($package = false, $level = false) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + if ($obj->hasErrors($level)) { + return true; + } + } + return false; + } + + /** + * Get a list of all errors since last purge, organized by package + * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be + * @param boolean $purge Set to purge the error stack of existing errors + * @param string $level Set to a level name in order to retrieve only errors of a particular level + * @param boolean $merge Set to return a flat array, not organized by package + * @param array $sortfunc Function used to sort a merged array - default + * sorts by time, and should be good for most cases + * @static + * @return array + */ + function staticGetErrors($purge = false, $level = false, $merge = false, + $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) + { + $ret = array(); + if (!is_callable($sortfunc)) { + $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); + if ($test) { + if ($merge) { + $ret = array_merge($ret, $test); + } else { + $ret[$package] = $test; + } + } + } + if ($merge) { + usort($ret, $sortfunc); + } + return $ret; + } + + /** + * Error sorting function, sorts by time + * @access private + */ + function _sortErrors($a, $b) + { + if ($a['time'] == $b['time']) { + return 0; + } + if ($a['time'] < $b['time']) { + return 1; + } + return -1; + } + + /** + * Standard file/line number/function/class context callback + * + * This function uses a backtrace generated from {@link debug_backtrace()} + * and so will not work at all in PHP < 4.3.0. The frame should + * reference the frame that contains the source of the error. + * @return array|false either array('file' => file, 'line' => line, + * 'function' => function name, 'class' => class name) or + * if this doesn't work, then false + * @param unused + * @param integer backtrace frame. + * @param array Results of debug_backtrace() + * @static + */ + function getFileLine($code, $params, $backtrace = null) + { + if ($backtrace === null) { + return false; + } + $frame = 0; + $functionframe = 1; + if (!isset($backtrace[1])) { + $functionframe = 0; + } else { + while (isset($backtrace[$functionframe]['function']) && + $backtrace[$functionframe]['function'] == 'eval' && + isset($backtrace[$functionframe + 1])) { + $functionframe++; + } + } + if (isset($backtrace[$frame])) { + if (!isset($backtrace[$frame]['file'])) { + $frame++; + } + $funcbacktrace = $backtrace[$functionframe]; + $filebacktrace = $backtrace[$frame]; + $ret = array('file' => $filebacktrace['file'], + 'line' => $filebacktrace['line']); + // rearrange for eval'd code or create function errors + if (strpos($filebacktrace['file'], '(') && + preg_match(';^(.*?)\((\d+)\) : (.*?)$;', $filebacktrace['file'], + $matches)) { + $ret['file'] = $matches[1]; + $ret['line'] = $matches[2] + 0; + } + if (isset($funcbacktrace['function']) && isset($backtrace[1])) { + if ($funcbacktrace['function'] != 'eval') { + if ($funcbacktrace['function'] == '__lambda_func') { + $ret['function'] = 'create_function() code'; + } else { + $ret['function'] = $funcbacktrace['function']; + } + } + } + if (isset($funcbacktrace['class']) && isset($backtrace[1])) { + $ret['class'] = $funcbacktrace['class']; + } + return $ret; + } + return false; + } + + /** + * Standard error message generation callback + * + * This method may also be called by a custom error message generator + * to fill in template values from the params array, simply + * set the third parameter to the error message template string to use + * + * The special variable %__msg% is reserved: use it only to specify + * where a message passed in by the user should be placed in the template, + * like so: + * + * Error message: %msg% - internal error + * + * If the message passed like so: + * + * + * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); + * + * + * The returned error message will be "Error message: server error 500 - + * internal error" + * @param PEAR_ErrorStack + * @param array + * @param string|false Pre-generated error message template + * @static + * @return string + */ + function getErrorMessage(&$stack, $err, $template = false) + { + if ($template) { + $mainmsg = $template; + } else { + $mainmsg = $stack->getErrorMessageTemplate($err['code']); + } + $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); + if (count($err['params'])) { + foreach ($err['params'] as $name => $val) { + if (is_array($val)) { + // @ is needed in case $val is a multi-dimensional array + $val = @implode(', ', $val); + } + if (is_object($val)) { + if (method_exists($val, '__toString')) { + $val = $val->__toString(); + } else { + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, + 'warning', array('obj' => get_class($val)), + 'object %obj% passed into getErrorMessage, but has no __toString() method'); + $val = 'Object'; + } + } + $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); + } + } + return $mainmsg; + } + + /** + * Standard Error Message Template generator from code + * @return string + */ + function getErrorMessageTemplate($code) + { + if (!isset($this->_errorMsgs[$code])) { + return '%__msg%'; + } + return $this->_errorMsgs[$code]; + } + + /** + * Set the Error Message Template array + * + * The array format must be: + *
+     * array(error code => 'message template',...)
+     * 
+ * + * Error message parameters passed into {@link push()} will be used as input + * for the error message. If the template is 'message %foo% was %bar%', and the + * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will + * be 'message one was six' + * @return string + */ + function setErrorMessageTemplate($template) + { + $this->_errorMsgs = $template; + } + + + /** + * emulate PEAR::raiseError() + * + * @return PEAR_Error + */ + function raiseError() + { + require_once 'PEAR.php'; + $args = func_get_args(); + return call_user_func_array(array('PEAR', 'raiseError'), $args); + } +} +$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); +$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); +?> \ No newline at end of file diff --git a/src/www/lib/pear/PEAR/Exception.php b/src/www/lib/pear/PEAR/Exception.php new file mode 100644 index 00000000..4c1918ed --- /dev/null +++ b/src/www/lib/pear/PEAR/Exception.php @@ -0,0 +1,359 @@ + | +// | Hans Lellelid | +// | Bertrand Mansion | +// | Greg Beaver | +// +----------------------------------------------------------------------+ +// +// $Id: Exception.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + + +/** + * Base PEAR_Exception Class + * + * WARNING: This code should be considered stable, but the API is + * subject to immediate and drastic change, so API stability is + * at best alpha + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * + * + * @since PHP 5 + * @package PEAR + * @version $Revision: 1.1 $ + * @author Tomas V.V.Cox + * @author Hans Lellelid + * @author Bertrand Mansion + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * PEAR_Exception(string $message); + * PEAR_Exception(string $message, int $code); + * PEAR_Exception(string $message, Exception $cause); + * PEAR_Exception(string $message, Exception $cause, int $code); + * PEAR_Exception(string $message, array $causes); + * PEAR_Exception(string $message, array $causes, int $code); + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif ($p2 instanceof Exception || is_array($p2)) { + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); + } + + /** + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + *
+     * array('name' => $name, 'context' => array(...))
+     * 
+ * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } + if (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '\n"; + } + $html .= '' . "\n" + . '' + . '' + . '' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '' + . '' + . '' . "\n"; + } + $html .= '' + . '' + . '' . "\n" + . '
' + . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' + . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' + . 'on line ' . $cause['line'] . '' + . "
Exception trace
#FunctionLocation
' . $k . ''; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '' . $v['file'] . ':' . $v['line'] . '
' . ($k+1) . '{main} 
'; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} + +?> \ No newline at end of file diff --git a/src/www/lib/pear/PEAR/Frontend/CLI.php b/src/www/lib/pear/PEAR/Frontend/CLI.php new file mode 100644 index 00000000..38f97ef5 --- /dev/null +++ b/src/www/lib/pear/PEAR/Frontend/CLI.php @@ -0,0 +1,509 @@ + | + +----------------------------------------------------------------------+ + + $Id: CLI.php,v 1.1 2005/05/28 01:55:58 henrique Exp $ +*/ + +require_once "PEAR.php"; + +class PEAR_Frontend_CLI extends PEAR +{ + // {{{ properties + + /** + * What type of user interface this frontend is for. + * @var string + * @access public + */ + var $type = 'CLI'; + var $lp = ''; // line prefix + + var $params = array(); + var $term = array( + 'bold' => '', + 'normal' => '', + ); + + // }}} + + // {{{ constructor + + function PEAR_Frontend_CLI() + { + parent::PEAR(); + $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 + if (function_exists('posix_isatty') && !posix_isatty(1)) { + // output is being redirected to a file or through a pipe + } elseif ($term) { + // XXX can use ncurses extension here, if available + if (preg_match('/^(xterm|vt220|linux)/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); + $this->term['normal']=sprintf("%c%c%c", 27, 91, 109); + } elseif (preg_match('/^vt100/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); + $this->term['normal']=sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); + } + } elseif (OS_WINDOWS) { + // XXX add ANSI codes here + } + } + + // }}} + + // {{{ displayLine(text) + + function displayLine($text) + { + trigger_error("PEAR_Frontend_CLI::displayLine deprecated", E_USER_ERROR); + } + + function _displayLine($text) + { + print "$this->lp$text\n"; + } + + // }}} + // {{{ display(text) + + function display($text) + { + trigger_error("PEAR_Frontend_CLI::display deprecated", E_USER_ERROR); + } + + function _display($text) + { + print $text; + } + + // }}} + // {{{ displayError(eobj) + + /** + * @param object PEAR_Error object + */ + function displayError($eobj) + { + return $this->_displayLine($eobj->getMessage()); + } + + // }}} + // {{{ displayFatalError(eobj) + + /** + * @param object PEAR_Error object + */ + function displayFatalError($eobj) + { + $this->displayError($eobj); + exit(1); + } + + // }}} + // {{{ displayHeading(title) + + function displayHeading($title) + { + trigger_error("PEAR_Frontend_CLI::displayHeading deprecated", E_USER_ERROR); + } + + function _displayHeading($title) + { + print $this->lp.$this->bold($title)."\n"; + print $this->lp.str_repeat("=", strlen($title))."\n"; + } + + // }}} + // {{{ userDialog(prompt, [type], [default]) + + function userDialog($command, $prompts, $types = array(), $defaults = array()) + { + $result = array(); + if (is_array($prompts)) { + $fp = fopen("php://stdin", "r"); + foreach ($prompts as $key => $prompt) { + $type = $types[$key]; + $default = @$defaults[$key]; + if ($type == 'password') { + system('stty -echo'); + } + print "$this->lp$prompt "; + if ($default) { + print "[$default] "; + } + print ": "; + $line = fgets($fp, 2048); + if ($type == 'password') { + system('stty echo'); + print "\n"; + } + if ($default && trim($line) == "") { + $result[$key] = $default; + } else { + $result[$key] = $line; + } + } + fclose($fp); + } + return $result; + } + + // }}} + // {{{ userConfirm(prompt, [default]) + + function userConfirm($prompt, $default = 'yes') + { + trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); + static $positives = array('y', 'yes', 'on', '1'); + static $negatives = array('n', 'no', 'off', '0'); + print "$this->lp$prompt [$default] : "; + $fp = fopen("php://stdin", "r"); + $line = fgets($fp, 2048); + fclose($fp); + $answer = strtolower(trim($line)); + if (empty($answer)) { + $answer = $default; + } + if (in_array($answer, $positives)) { + return true; + } + if (in_array($answer, $negatives)) { + return false; + } + if (in_array($default, $positives)) { + return true; + } + return false; + } + + // }}} + // {{{ startTable([params]) + + function startTable($params = array()) + { + trigger_error("PEAR_Frontend_CLI::startTable deprecated", E_USER_ERROR); + } + + function _startTable($params = array()) + { + $params['table_data'] = array(); + $params['widest'] = array(); // indexed by column + $params['highest'] = array(); // indexed by row + $params['ncols'] = 0; + $this->params = $params; + } + + // }}} + // {{{ tableRow(columns, [rowparams], [colparams]) + + function tableRow($columns, $rowparams = array(), $colparams = array()) + { + trigger_error("PEAR_Frontend_CLI::tableRow deprecated", E_USER_ERROR); + } + + function _tableRow($columns, $rowparams = array(), $colparams = array()) + { + $highest = 1; + for ($i = 0; $i < sizeof($columns); $i++) { + $col = &$columns[$i]; + if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { + $col = wordwrap($col, $colparams[$i]['wrap'], "\n", 0); + } + if (strpos($col, "\n") !== false) { + $multiline = explode("\n", $col); + $w = 0; + foreach ($multiline as $n => $line) { + if (strlen($line) > $w) { + $w = strlen($line); + } + } + $lines = sizeof($multiline); + } else { + $w = strlen($col); + } + if ($w > @$this->params['widest'][$i]) { + $this->params['widest'][$i] = $w; + } + $tmp = count_chars($columns[$i], 1); + // handle unix, mac and windows formats + $lines = (isset($tmp[10]) ? $tmp[10] : @$tmp[13]) + 1; + if ($lines > $highest) { + $highest = $lines; + } + } + if (sizeof($columns) > $this->params['ncols']) { + $this->params['ncols'] = sizeof($columns); + } + $new_row = array( + 'data' => $columns, + 'height' => $highest, + 'rowparams' => $rowparams, + 'colparams' => $colparams, + ); + $this->params['table_data'][] = $new_row; + } + + // }}} + // {{{ endTable() + + function endTable() + { + trigger_error("PEAR_Frontend_CLI::endTable deprecated", E_USER_ERROR); + } + + function _endTable() + { + extract($this->params); + if (!empty($caption)) { + $this->_displayHeading($caption); + } + if (count($table_data) == 0) { + return; + } + if (!isset($width)) { + $width = $widest; + } else { + for ($i = 0; $i < $ncols; $i++) { + if (!isset($width[$i])) { + $width[$i] = $widest[$i]; + } + } + } + $border = false; + if (empty($border)) { + $cellstart = ''; + $cellend = ' '; + $rowend = ''; + $padrowend = false; + $borderline = ''; + } else { + $cellstart = '| '; + $cellend = ' '; + $rowend = '|'; + $padrowend = true; + $borderline = '+'; + foreach ($width as $w) { + $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); + $borderline .= '+'; + } + } + if ($borderline) { + $this->_displayLine($borderline); + } + for ($i = 0; $i < sizeof($table_data); $i++) { + extract($table_data[$i]); + if (!is_array($rowparams)) { + $rowparams = array(); + } + if (!is_array($colparams)) { + $colparams = array(); + } + $rowlines = array(); + if ($height > 1) { + for ($c = 0; $c < sizeof($data); $c++) { + $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); + if (sizeof($rowlines[$c]) < $height) { + $rowlines[$c] = array_pad($rowlines[$c], $height, ''); + } + } + } else { + for ($c = 0; $c < sizeof($data); $c++) { + $rowlines[$c] = array($data[$c]); + } + } + for ($r = 0; $r < $height; $r++) { + $rowtext = ''; + for ($c = 0; $c < sizeof($data); $c++) { + if (isset($colparams[$c])) { + $attribs = array_merge($rowparams, $colparams); + } else { + $attribs = $rowparams; + } + $w = isset($width[$c]) ? $width[$c] : 0; + //$cell = $data[$c]; + $cell = $rowlines[$c][$r]; + $l = strlen($cell); + if ($l > $w) { + $cell = substr($cell, 0, $w); + } + if (isset($attribs['bold'])) { + $cell = $this->bold($cell); + } + if ($l < $w) { + // not using str_pad here because we may + // add bold escape characters to $cell + $cell .= str_repeat(' ', $w - $l); + } + + $rowtext .= $cellstart . $cell . $cellend; + } + if (!$border) { + $rowtext = rtrim($rowtext); + } + $rowtext .= $rowend; + $this->_displayLine($rowtext); + } + } + if ($borderline) { + $this->_displayLine($borderline); + } + } + + // }}} + // {{{ outputData() + + function outputData($data, $command = '_default') + { + switch ($command) { + case 'install': + case 'upgrade': + case 'upgrade-all': + if (isset($data['release_warnings'])) { + $this->_displayLine(''); + $this->_startTable(array( + 'border' => false, + 'caption' => 'Release Warnings' + )); + $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); + $this->_endTable(); + $this->_displayLine(''); + } + $this->_displayLine($data['data']); + break; + case 'search': + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } + + foreach($data['data'] as $category) { + foreach($category as $pkg) { + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } + }; + $this->_endTable(); + break; + case 'list-all': + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } + + foreach($data['data'] as $category) { + foreach($category as $pkg) { + unset($pkg[3]); + unset($pkg[4]); + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } + }; + $this->_endTable(); + break; + case 'config-show': + $data['border'] = false; + $opts = array(0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35)); + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], + array('bold' => true), + $opts); + } + foreach($data['data'] as $group) { + foreach($group as $value) { + if ($value[2] == '') { + $value[2] = ""; + } + $this->_tableRow($value, null, $opts); + } + } + $this->_endTable(); + break; + case 'remote-info': + $data = array( + 'caption' => 'Package details:', + 'border' => false, + 'data' => array( + array("Latest", $data['stable']), + array("Installed", $data['installed']), + array("Package", $data['name']), + array("License", $data['license']), + array("Category", $data['category']), + array("Summary", $data['summary']), + array("Description", $data['description']), + ), + ); + default: { + if (is_array($data)) { + $this->_startTable($data); + $count = count($data['data'][0]); + if ($count == 2) { + $opts = array(0 => array('wrap' => 25), + 1 => array('wrap' => 48) + ); + } elseif ($count == 3) { + $opts = array(0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35) + ); + } else { + $opts = null; + } + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], + array('bold' => true), + $opts); + } + foreach($data['data'] as $row) { + $this->_tableRow($row, null, $opts); + } + $this->_endTable(); + } else { + $this->_displayLine($data); + } + } + } + } + + // }}} + // {{{ log(text) + + + function log($text, $append_crlf = true) + { + if ($append_crlf) { + return $this->_displayLine($text); + } + return $this->_display($text); + } + + + // }}} + // {{{ bold($text) + + function bold($text) + { + if (empty($this->term['bold'])) { + return strtoupper($text); + } + return $this->term['bold'] . $text . $this->term['normal']; + } + + // }}} +} + +?> diff --git a/src/www/lib/pear/PEAR/Installer.php b/src/www/lib/pear/PEAR/Installer.php new file mode 100644 index 00000000..0d0ffb7f --- /dev/null +++ b/src/www/lib/pear/PEAR/Installer.php @@ -0,0 +1,1068 @@ + | +// | Tomas V.V.Cox | +// | Martin Jansen | +// +----------------------------------------------------------------------+ +// +// $Id: Installer.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + +require_once 'PEAR/Downloader.php'; + +/** + * Administration class used to install PEAR packages and maintain the + * installed package database. + * + * TODO: + * - Check dependencies break on package uninstall (when no force given) + * - add a guessInstallDest() method with the code from _installFile() and + * use that method in Registry::_rebuildFileMap() & Command_Registry::doList(), + * others.. + * + * @since PHP 4.0.2 + * @author Stig Bakken + * @author Martin Jansen + * @author Greg Beaver + */ +class PEAR_Installer extends PEAR_Downloader +{ + // {{{ properties + + /** name of the package directory, for example Foo-1.0 + * @var string + */ + var $pkgdir; + + /** directory where PHP code files go + * @var string + */ + var $phpdir; + + /** directory where PHP extension files go + * @var string + */ + var $extdir; + + /** directory where documentation goes + * @var string + */ + var $docdir; + + /** installation root directory (ala PHP's INSTALL_ROOT or + * automake's DESTDIR + * @var string + */ + var $installroot = ''; + + /** debug level + * @var int + */ + var $debug = 1; + + /** temporary directory + * @var string + */ + var $tmpdir; + + /** PEAR_Registry object used by the installer + * @var object + */ + var $registry; + + /** List of file transactions queued for an install/upgrade/uninstall. + * + * Format: + * array( + * 0 => array("rename => array("from-file", "to-file")), + * 1 => array("delete" => array("file-to-delete")), + * ... + * ) + * + * @var array + */ + var $file_operations = array(); + + // }}} + + // {{{ constructor + + /** + * PEAR_Installer constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Installer(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + $this->debug = $this->config->get('verbose'); + //$this->registry = &new PEAR_Registry($this->config->get('php_dir')); + } + + // }}} + + // {{{ _deletePackageFiles() + + /** + * Delete a package's installed files, does not remove empty directories. + * + * @param string $package package name + * + * @return bool TRUE on success, or a PEAR error on failure + * + * @access private + */ + function _deletePackageFiles($package) + { + if (!strlen($package)) { + return $this->raiseError("No package to uninstall given"); + } + $filelist = $this->registry->packageInfo($package, 'filelist'); + if ($filelist == null) { + return $this->raiseError("$package not installed"); + } + foreach ($filelist as $file => $props) { + if (empty($props['installed_as'])) { + continue; + } + $path = $this->_prependPath($props['installed_as'], $this->installroot); + $this->addFileOperation('delete', array($path)); + } + return true; + } + + // }}} + // {{{ _installFile() + + /** + * @param string filename + * @param array attributes from tag in package.xml + * @param string path to install the file in + * @param array options from command-line + * @access private + */ + function _installFile($file, $atts, $tmp_path, $options) + { + // {{{ return if this file is meant for another platform + static $os; + if (isset($atts['platform'])) { + if (empty($os)) { + include_once "OS/Guess.php"; + $os = new OS_Guess(); + } + if (strlen($atts['platform']) && $atts['platform']{0} == '!') { + $negate = true; + $platform = substr($atts['platform'], 1); + } else { + $negate = false; + $platform = $atts['platform']; + } + if ((bool) $os->matchSignature($platform) === $negate) { + $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); + return PEAR_INSTALLER_SKIPPED; + } + } + // }}} + + // {{{ assemble the destination paths + switch ($atts['role']) { + case 'doc': + case 'data': + case 'test': + $dest_dir = $this->config->get($atts['role'] . '_dir') . + DIRECTORY_SEPARATOR . $this->pkginfo['package']; + unset($atts['baseinstalldir']); + break; + case 'ext': + case 'php': + $dest_dir = $this->config->get($atts['role'] . '_dir'); + break; + case 'script': + $dest_dir = $this->config->get('bin_dir'); + break; + case 'src': + case 'extsrc': + $this->source_files++; + return; + default: + return $this->raiseError("Invalid role `$atts[role]' for file $file"); + } + $save_destdir = $dest_dir; + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + if (dirname($file) != '.' && empty($atts['install-as'])) { + $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); + } + if (empty($atts['install-as'])) { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); + } else { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + } + $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; + + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + DIRECTORY_SEPARATOR, + array($dest_file, $orig_file)); + $installed_as = $dest_file; + $final_dest_file = $this->_prependPath($dest_file, $this->installroot); + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + // }}} + + if (!@is_dir($dest_dir)) { + if (!$this->mkDirHier($dest_dir)) { + return $this->raiseError("failed to mkdir $dest_dir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $dest_dir"); + } + if (empty($atts['replacements'])) { + if (!file_exists($orig_file)) { + return $this->raiseError("file does not exist", + PEAR_INSTALLER_FAILED); + } + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ cp $orig_file $dest_file"); + if (isset($atts['md5sum'])) { + $md5sum = md5_file($dest_file); + } + } else { + // {{{ file with replacements + if (!file_exists($orig_file)) { + return $this->raiseError("file does not exist", + PEAR_INSTALLER_FAILED); + } + $fp = fopen($orig_file, "r"); + $contents = fread($fp, filesize($orig_file)); + fclose($fp); + if (isset($atts['md5sum'])) { + $md5sum = md5($contents); + } + $subst_from = $subst_to = array(); + foreach ($atts['replacements'] as $a) { + $to = ''; + if ($a['type'] == 'php-const') { + if (preg_match('/^[a-z0-9_]+$/i', $a['to'])) { + eval("\$to = $a[to];"); + } else { + $this->log(0, "invalid php-const replacement: $a[to]"); + continue; + } + } elseif ($a['type'] == 'pear-config') { + $to = $this->config->get($a['to']); + if (is_null($to)) { + $this->log(0, "invalid pear-config replacement: $a[to]"); + continue; + } + } elseif ($a['type'] == 'package-info') { + if (isset($this->pkginfo[$a['to']]) && is_string($this->pkginfo[$a['to']])) { + $to = $this->pkginfo[$a['to']]; + } else { + $this->log(0, "invalid package-info replacement: $a[to]"); + continue; + } + } + if (!is_null($to)) { + $subst_from[] = $a['from']; + $subst_to[] = $to; + } + } + $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); + if (sizeof($subst_from)) { + $contents = str_replace($subst_from, $subst_to, $contents); + } + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + if (!fwrite($wp, $contents)) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + fclose($wp); + // }}} + } + // {{{ check the md5 + if (isset($md5sum)) { + if (strtolower($md5sum) == strtolower($atts['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); + } else { + if (empty($options['force'])) { + // delete the file + @unlink($dest_file); + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } else { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } + // }}} + // {{{ set file permissions + if (!OS_WINDOWS) { + if ($atts['role'] == 'script') { + $mode = 0777 & ~(int)octdec($this->config->get('umask')); + $this->log(3, "+ chmod +x $dest_file"); + } else { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + } + $this->addFileOperation("chmod", array($mode, $dest_file)); + if (!@chmod($dest_file, $mode)) { + $this->log(0, "failed to change mode of $dest_file"); + } + } + // }}} + $this->addFileOperation("rename", array($dest_file, $final_dest_file)); + // Store the full path where the file was installed for easy unistall + $this->addFileOperation("installed_as", array($file, $installed_as, + $save_destdir, dirname(substr($dest_file, strlen($save_destdir))))); + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; + } + + // }}} + // {{{ addFileOperation() + + /** + * Add a file operation to the current file transaction. + * + * @see startFileTransaction() + * @var string $type This can be one of: + * - rename: rename a file ($data has 2 values) + * - chmod: change permissions on a file ($data has 2 values) + * - delete: delete a file ($data has 1 value) + * - rmdir: delete a directory if empty ($data has 1 value) + * - installed_as: mark a file as installed ($data has 4 values). + * @var array $data For all file operations, this array must contain the + * full path to the file or directory that is being operated on. For + * the rename command, the first parameter must be the file to rename, + * the second its new name. + * + * The installed_as operation contains 4 elements in this order: + * 1. Filename as listed in the filelist element from package.xml + * 2. Full path to the installed file + * 3. Full path from the php_dir configuration variable used in this + * installation + * 4. Relative path from the php_dir that this file is installed in + */ + function addFileOperation($type, $data) + { + if (!is_array($data)) { + return $this->raiseError('Internal Error: $data in addFileOperation' + . ' must be an array, was ' . gettype($data)); + } + if ($type == 'chmod') { + $octmode = decoct($data[0]); + $this->log(3, "adding to transaction: $type $octmode $data[1]"); + } else { + $this->log(3, "adding to transaction: $type " . implode(" ", $data)); + } + $this->file_operations[] = array($type, $data); + } + + // }}} + // {{{ startFileTransaction() + + function startFileTransaction($rollback_in_case = false) + { + if (count($this->file_operations) && $rollback_in_case) { + $this->rollbackFileTransaction(); + } + $this->file_operations = array(); + } + + // }}} + // {{{ commitFileTransaction() + + function commitFileTransaction() + { + $n = count($this->file_operations); + $this->log(2, "about to commit $n file operations"); + // {{{ first, check permissions and such manually + $errors = array(); + foreach ($this->file_operations as $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'rename': + if (!file_exists($data[0])) { + $errors[] = "cannot rename file $data[0], doesn't exist"; + } + // check that dest dir. is writable + if (!is_writable(dirname($data[1]))) { + $errors[] = "permission denied ($type): $data[1]"; + } + break; + case 'chmod': + // check that file is writable + if (!is_writable($data[1])) { + $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); + } + break; + case 'delete': + if (!file_exists($data[0])) { + $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); + } + // check that directory is writable + if (file_exists($data[0]) && !is_writable(dirname($data[0]))) { + $errors[] = "permission denied ($type): $data[0]"; + } + break; + } + + } + // }}} + $m = sizeof($errors); + if ($m > 0) { + foreach ($errors as $error) { + $this->log(1, $error); + } + return false; + } + // {{{ really commit the transaction + foreach ($this->file_operations as $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'rename': + @unlink($data[1]); + @rename($data[0], $data[1]); + $this->log(3, "+ mv $data[0] $data[1]"); + break; + case 'chmod': + @chmod($data[1], $data[0]); + $octmode = decoct($data[0]); + $this->log(3, "+ chmod $octmode $data[1]"); + break; + case 'delete': + @unlink($data[0]); + $this->log(3, "+ rm $data[0]"); + break; + case 'rmdir': + @rmdir($data[0]); + $this->log(3, "+ rmdir $data[0]"); + break; + case 'installed_as': + $this->pkginfo['filelist'][$data[0]]['installed_as'] = $data[1]; + if (!isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) { + $this->pkginfo['filelist']['dirtree'][dirname($data[1])] = true; + while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\' + && $data[3] != '.') { + $this->pkginfo['filelist']['dirtree'] + [$this->_prependPath($data[3], $data[2])] = true; + $data[3] = dirname($data[3]); + } + } + break; + } + } + // }}} + $this->log(2, "successfully committed $n file operations"); + $this->file_operations = array(); + return true; + } + + // }}} + // {{{ rollbackFileTransaction() + + function rollbackFileTransaction() + { + $n = count($this->file_operations); + $this->log(2, "rolling back $n file operations"); + foreach ($this->file_operations as $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'rename': + @unlink($data[0]); + $this->log(3, "+ rm $data[0]"); + break; + case 'mkdir': + @rmdir($data[0]); + $this->log(3, "+ rmdir $data[0]"); + break; + case 'chmod': + break; + case 'delete': + break; + case 'installed_as': + if (isset($this->pkginfo['filelist'])) { + unset($this->pkginfo['filelist'][$data[0]]['installed_as']); + } + if (isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) { + unset($this->pkginfo['filelist']['dirtree'][dirname($data[1])]); + while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\' + && $data[3] != '.') { + unset($this->pkginfo['filelist']['dirtree'] + [$this->_prependPath($data[3], $data[2])]); + $data[3] = dirname($data[3]); + } + } + if (isset($this->pkginfo['filelist']['dirtree']) + && !count($this->pkginfo['filelist']['dirtree'])) { + unset($this->pkginfo['filelist']['dirtree']); + } + break; + } + } + $this->file_operations = array(); + } + + // }}} + // {{{ mkDirHier($dir) + + function mkDirHier($dir) + { + $this->addFileOperation('mkdir', array($dir)); + return parent::mkDirHier($dir); + } + + // }}} + // {{{ download() + + /** + * Download any files and their dependencies, if necessary + * + * @param array a mixed list of package names, local files, or package.xml + * @param PEAR_Config + * @param array options from the command line + * @param array this is the array that will be populated with packages to + * install. Format of each entry: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @param array this will be populated with any error messages + * @param false private recursion variable + * @param false private recursion variable + * @param false private recursion variable + * @deprecated in favor of PEAR_Downloader + */ + function download($packages, $options, &$config, &$installpackages, + &$errors, $installed = false, $willinstall = false, $state = false) + { + // trickiness: initialize here + parent::PEAR_Downloader($this->ui, $options, $config); + $ret = parent::download($packages); + $errors = $this->getErrorMsgs(); + $installpackages = $this->getDownloadedPackages(); + trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . + "in favor of PEAR_Downloader class", E_USER_WARNING); + return $ret; + } + + // }}} + // {{{ install() + + /** + * Installs the files within the package file specified. + * + * @param string $pkgfile path to the package file + * @param array $options + * recognized options: + * - installroot : optional prefix directory for installation + * - force : force installation + * - register-only : update registry but don't install files + * - upgrade : upgrade existing install + * - soft : fail silently + * - nodeps : ignore dependency conflicts/missing dependencies + * - alldeps : install all dependencies + * - onlyreqdeps : install only required dependencies + * + * @return array|PEAR_Error package info if successful + */ + + function install($pkgfile, $options = array()) + { + $php_dir = $this->config->get('php_dir'); + if (isset($options['installroot'])) { + if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) { + $options['installroot'] = substr($options['installroot'], 0, -1); + } + $php_dir = $this->_prependPath($php_dir, $options['installroot']); + $this->installroot = $options['installroot']; + } else { + $this->installroot = ''; + } + $this->registry = &new PEAR_Registry($php_dir); + // ==> XXX should be removed later on + $flag_old_format = false; + + if (substr($pkgfile, -4) == '.xml') { + $descfile = $pkgfile; + } else { + // {{{ Decompress pack in tmp dir ------------------------------------- + + // To allow relative package file names + $pkgfile = realpath($pkgfile); + + if (PEAR::isError($tmpdir = System::mktemp('-d'))) { + return $tmpdir; + } + $this->log(3, '+ tmp dir created at ' . $tmpdir); + + $tar = new Archive_Tar($pkgfile); + if (!@$tar->extract($tmpdir)) { + return $this->raiseError("unable to unpack $pkgfile"); + } + + // {{{ Look for existing package file + $descfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml'; + + if (!is_file($descfile)) { + // ----- Look for old package archive format + // In this format the package.xml file was inside the + // Package-n.n directory + $dp = opendir($tmpdir); + do { + $pkgdir = readdir($dp); + } while ($pkgdir{0} == '.'); + + $descfile = $tmpdir . DIRECTORY_SEPARATOR . $pkgdir . DIRECTORY_SEPARATOR . 'package.xml'; + $flag_old_format = true; + $this->log(0, "warning : you are using an archive with an old format"); + } + // }}} + // <== XXX This part should be removed later on + // }}} + } + + if (!is_file($descfile)) { + return $this->raiseError("no package.xml file after extracting the archive"); + } + + // Parse xml file ----------------------------------------------- + $pkginfo = $this->infoFromDescriptionFile($descfile); + if (PEAR::isError($pkginfo)) { + return $pkginfo; + } + $this->validatePackageInfo($pkginfo, $errors, $warnings); + // XXX We allow warnings, do we have to do it? + if (count($errors)) { + if (empty($options['force'])) { + return $this->raiseError("The following errors where found (use force option to install anyway):\n". + implode("\n", $errors)); + } else { + $this->log(0, "warning : the following errors were found:\n". + implode("\n", $errors)); + } + } + + $pkgname = $pkginfo['package']; + + // {{{ Check dependencies ------------------------------------------- + if (isset($pkginfo['release_deps']) && empty($options['nodeps'])) { + $dep_errors = ''; + $error = $this->checkDeps($pkginfo, $dep_errors); + if ($error == true) { + if (empty($options['soft'])) { + $this->log(0, substr($dep_errors, 1)); + } + return $this->raiseError("$pkgname: Dependencies failed"); + } else if (!empty($dep_errors)) { + // Print optional dependencies + if (empty($options['soft'])) { + $this->log(0, $dep_errors); + } + } + } + // }}} + + // {{{ checks to do when not in "force" mode + if (empty($options['force'])) { + $test = $this->registry->checkFileMap($pkginfo); + if (sizeof($test)) { + $tmp = $test; + foreach ($tmp as $file => $pkg) { + if ($pkg == $pkgname) { + unset($test[$file]); + } + } + if (sizeof($test)) { + $msg = "$pkgname: conflicting files found:\n"; + $longest = max(array_map("strlen", array_keys($test))); + $fmt = "%${longest}s (%s)\n"; + foreach ($test as $file => $pkg) { + $msg .= sprintf($fmt, $file, $pkg); + } + return $this->raiseError($msg); + } + } + } + // }}} + + $this->startFileTransaction(); + + if (empty($options['upgrade'])) { + // checks to do only when installing new packages + if (empty($options['force']) && $this->registry->packageExists($pkgname)) { + return $this->raiseError("$pkgname already installed"); + } + } else { + if ($this->registry->packageExists($pkgname)) { + $v1 = $this->registry->packageInfo($pkgname, 'version'); + $v2 = $pkginfo['version']; + $cmp = version_compare("$v1", "$v2", 'gt'); + if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { + return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); + } + if (empty($options['register-only'])) { + // when upgrading, remove old release's files first: + if (PEAR::isError($err = $this->_deletePackageFiles($pkgname))) { + return $this->raiseError($err); + } + } + } + } + + // {{{ Copy files to dest dir --------------------------------------- + + // info from the package it self we want to access from _installFile + $this->pkginfo = &$pkginfo; + // used to determine whether we should build any C code + $this->source_files = 0; + + if (empty($options['register-only'])) { + if (!is_dir($php_dir)) { + return $this->raiseError("no script destination directory\n", + null, PEAR_ERROR_DIE); + } + + $tmp_path = dirname($descfile); + if (substr($pkgfile, -4) != '.xml') { + $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkginfo['version']; + } + + // ==> XXX This part should be removed later on + if ($flag_old_format) { + $tmp_path = dirname($descfile); + } + // <== XXX This part should be removed later on + + // {{{ install files + foreach ($pkginfo['filelist'] as $file => $atts) { + $this->expectError(PEAR_INSTALLER_FAILED); + $res = $this->_installFile($file, $atts, $tmp_path, $options); + $this->popExpect(); + if (PEAR::isError($res)) { + if (empty($options['ignore-errors'])) { + $this->rollbackFileTransaction(); + if ($res->getMessage() == "file does not exist") { + $this->raiseError("file $file in package.xml does not exist"); + } + return $this->raiseError($res); + } else { + $this->log(0, "Warning: " . $res->getMessage()); + } + } + if ($res != PEAR_INSTALLER_OK) { + // Do not register files that were not installed + unset($pkginfo['filelist'][$file]); + } + } + // }}} + + // {{{ compile and install source files + if ($this->source_files > 0 && empty($options['nobuild'])) { + $this->log(1, "$this->source_files source files, building"); + $bob = &new PEAR_Builder($this->ui); + $bob->debug = $this->debug; + $built = $bob->build($descfile, array(&$this, '_buildCallback')); + if (PEAR::isError($built)) { + $this->rollbackFileTransaction(); + return $built; + } + $this->log(1, "\nBuild process completed successfully"); + foreach ($built as $ext) { + $bn = basename($ext['file']); + list($_ext_name, $_ext_suff) = explode('.', $bn); + if ($_ext_suff == '.so' || $_ext_suff == '.dll') { + if (extension_loaded($_ext_name)) { + $this->raiseError("Extension '$_ext_name' already loaded. " . + 'Please unload it in your php.ini file ' . + 'prior to install or upgrade'); + } + $role = 'ext'; + } else { + $role = 'src'; + } + $dest = $ext['dest']; + $this->log(1, "Installing '$ext[file]'"); + $copyto = $this->_prependPath($dest, $this->installroot); + $copydir = dirname($copyto); + if (!@is_dir($copydir)) { + if (!$this->mkDirHier($copydir)) { + return $this->raiseError("failed to mkdir $copydir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $copydir"); + } + if (!@copy($ext['file'], $copyto)) { + return $this->raiseError("failed to write $copyto", PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ cp $ext[file] $copyto"); + if (!OS_WINDOWS) { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + $this->addFileOperation('chmod', array($mode, $copyto)); + if (!@chmod($copyto, $mode)) { + $this->log(0, "failed to change mode of $copyto"); + } + } + $this->addFileOperation('rename', array($ext['file'], $copyto)); + + $pkginfo['filelist'][$bn] = array( + 'role' => $role, + 'installed_as' => $dest, + 'php_api' => $ext['php_api'], + 'zend_mod_api' => $ext['zend_mod_api'], + 'zend_ext_api' => $ext['zend_ext_api'], + ); + } + } + // }}} + } + + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); + } + // }}} + + $ret = false; + // {{{ Register that the package is installed ----------------------- + if (empty($options['upgrade'])) { + // if 'force' is used, replace the info in registry + if (!empty($options['force']) && $this->registry->packageExists($pkgname)) { + $this->registry->deletePackage($pkgname); + } + $ret = $this->registry->addPackage($pkgname, $pkginfo); + } else { + // new: upgrade installs a package if it isn't installed + if (!$this->registry->packageExists($pkgname)) { + $ret = $this->registry->addPackage($pkgname, $pkginfo); + } else { + $ret = $this->registry->updatePackage($pkgname, $pkginfo, false); + } + } + if (!$ret) { + return $this->raiseError("Adding package $pkgname to registry failed"); + } + // }}} + return $pkginfo; + } + + // }}} + // {{{ uninstall() + + /** + * Uninstall a package + * + * This method removes all files installed by the application, and then + * removes any empty directories. + * @param string package name + * @param array Command-line options. Possibilities include: + * + * - installroot: base installation dir, if not the default + * - nodeps: do not process dependencies of other packages to ensure + * uninstallation does not break things + */ + function uninstall($package, $options = array()) + { + $php_dir = $this->config->get('php_dir'); + if (isset($options['installroot'])) { + if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) { + $options['installroot'] = substr($options['installroot'], 0, -1); + } + $this->installroot = $options['installroot']; + $php_dir = $this->_prependPath($php_dir, $this->installroot); + } else { + $this->installroot = ''; + } + $this->registry = &new PEAR_Registry($php_dir); + $filelist = $this->registry->packageInfo($package, 'filelist'); + if ($filelist == null) { + return $this->raiseError("$package not installed"); + } + if (empty($options['nodeps'])) { + $depchecker = &new PEAR_Dependency($this->registry); + $error = $depchecker->checkPackageUninstall($errors, $warning, $package); + if ($error) { + return $this->raiseError($errors . 'uninstall failed'); + } + if ($warning) { + $this->log(0, $warning); + } + } + // {{{ Delete the files + $this->startFileTransaction(); + if (PEAR::isError($err = $this->_deletePackageFiles($package))) { + $this->rollbackFileTransaction(); + return $this->raiseError($err); + } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + return $this->raiseError("uninstall failed"); + } else { + $this->startFileTransaction(); + if (!isset($filelist['dirtree']) || !count($filelist['dirtree'])) { + return $this->registry->deletePackage($package); + } + // attempt to delete empty directories + uksort($filelist['dirtree'], array($this, '_sortDirs')); + foreach($filelist['dirtree'] as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + } + } + // }}} + + // Register that the package is no longer installed + return $this->registry->deletePackage($package); + } + + // }}} + // {{{ _sortDirs() + function _sortDirs($a, $b) + { + if (strnatcmp($a, $b) == -1) return 1; + if (strnatcmp($a, $b) == 1) return -1; + return 0; + } + + // }}} + // {{{ checkDeps() + + /** + * Check if the package meets all dependencies + * + * @param array Package information (passed by reference) + * @param string Error message (passed by reference) + * @return boolean False when no error occured, otherwise true + */ + function checkDeps(&$pkginfo, &$errors) + { + if (empty($this->registry)) { + $this->registry = &new PEAR_Registry($this->config->get('php_dir')); + } + $depchecker = &new PEAR_Dependency($this->registry); + $error = $errors = ''; + $failed_deps = $optional_deps = array(); + if (is_array($pkginfo['release_deps'])) { + foreach($pkginfo['release_deps'] as $dep) { + $code = $depchecker->callCheckMethod($error, $dep); + if ($code) { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + $optional_deps[] = array($dep, $code, $error); + } else { + $failed_deps[] = array($dep, $code, $error); + } + } + } + // {{{ failed dependencies + $n = count($failed_deps); + if ($n > 0) { + for ($i = 0; $i < $n; $i++) { + if (isset($failed_deps[$i]['type'])) { + $type = $failed_deps[$i]['type']; + } else { + $type = 'pkg'; + } + switch ($failed_deps[$i][1]) { + case PEAR_DEPENDENCY_MISSING: + if ($type == 'pkg') { + // install + } + $errors .= "\n" . $failed_deps[$i][2]; + break; + case PEAR_DEPENDENCY_UPGRADE_MINOR: + if ($type == 'pkg') { + // upgrade + } + $errors .= "\n" . $failed_deps[$i][2]; + break; + default: + $errors .= "\n" . $failed_deps[$i][2]; + break; + } + } + return true; + } + // }}} + + // {{{ optional dependencies + $count_optional = count($optional_deps); + if ($count_optional > 0) { + $errors = "Optional dependencies:"; + + for ($i = 0; $i < $count_optional; $i++) { + if (isset($optional_deps[$i]['type'])) { + $type = $optional_deps[$i]['type']; + } else { + $type = 'pkg'; + } + switch ($optional_deps[$i][1]) { + case PEAR_DEPENDENCY_MISSING: + case PEAR_DEPENDENCY_UPGRADE_MINOR: + default: + $errors .= "\n" . $optional_deps[$i][2]; + break; + } + } + return false; + } + // }}} + } + return false; + } + + // }}} + // {{{ _buildCallback() + + function _buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } + + // }}} +} + +// {{{ md5_file() utility function +if (!function_exists("md5_file")) { + function md5_file($filename) { + $fp = fopen($filename, "r"); + if (!$fp) return null; + $contents = fread($fp, filesize($filename)); + fclose($fp); + return md5($contents); + } +} +// }}} + +?> diff --git a/src/www/lib/pear/PEAR/Packager.php b/src/www/lib/pear/PEAR/Packager.php new file mode 100644 index 00000000..5fb2c89f --- /dev/null +++ b/src/www/lib/pear/PEAR/Packager.php @@ -0,0 +1,165 @@ + | +// | Tomas V.V.Cox | +// +----------------------------------------------------------------------+ +// +// $Id: Packager.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + +require_once 'PEAR/Common.php'; +require_once 'System.php'; + +/** + * Administration class used to make a PEAR release tarball. + * + * TODO: + * - add an extra param the dir where to place the created package + * + * @since PHP 4.0.2 + * @author Stig Bakken + */ +class PEAR_Packager extends PEAR_Common +{ + // {{{ constructor + + function PEAR_Packager() + { + parent::PEAR_Common(); + } + + // }}} + // {{{ destructor + + function _PEAR_Packager() + { + parent::_PEAR_Common(); + } + + // }}} + + // {{{ package() + + function package($pkgfile = null, $compress = true) + { + // {{{ validate supplied package.xml file + if (empty($pkgfile)) { + $pkgfile = 'package.xml'; + } + // $this->pkginfo gets populated inside + $pkginfo = $this->infoFromDescriptionFile($pkgfile); + if (PEAR::isError($pkginfo)) { + return $this->raiseError($pkginfo); + } + + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); + + $errors = $warnings = array(); + $this->validatePackageInfo($pkginfo, $errors, $warnings, $pkgdir); + foreach ($warnings as $w) { + $this->log(1, "Warning: $w"); + } + foreach ($errors as $e) { + $this->log(0, "Error: $e"); + } + if (sizeof($errors) > 0) { + return $this->raiseError('Errors in package'); + } + // }}} + + $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; + + // {{{ Create the package file list + $filelist = array(); + $i = 0; + + foreach ($pkginfo['filelist'] as $fname => $atts) { + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return $this->raiseError("File does not exist: $fname"); + } else { + $filelist[$i++] = $file; + if (empty($pkginfo['filelist'][$fname]['md5sum'])) { + $md5sum = md5_file($file); + $pkginfo['filelist'][$fname]['md5sum'] = $md5sum; + } + $this->log(2, "Adding file $fname"); + } + } + // }}} + + // {{{ regenerate package.xml + $new_xml = $this->xmlFromInfo($pkginfo); + if (PEAR::isError($new_xml)) { + return $this->raiseError($new_xml); + } + if (!($tmpdir = System::mktemp(array('-d')))) { + return $this->raiseError("PEAR_Packager: mktemp failed"); + } + $newpkgfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml'; + $np = @fopen($newpkgfile, 'wb'); + if (!$np) { + return $this->raiseError("PEAR_Packager: unable to rewrite $pkgfile as $newpkgfile"); + } + fwrite($np, $new_xml); + fclose($np); + // }}} + + // {{{ TAR the Package ------------------------------------------- + $ext = $compress ? '.tgz' : '.tar'; + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + $tar =& new Archive_Tar($dest_package, $compress); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors + // ----- Creates with the package.xml file + $ok = $tar->createModify(array($newpkgfile), '', $tmpdir); + if (PEAR::isError($ok)) { + return $this->raiseError($ok); + } elseif (!$ok) { + return $this->raiseError('PEAR_Packager: tarball creation failed'); + } + // ----- Add the content of the package + if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { + return $this->raiseError('PEAR_Packager: tarball creation failed'); + } + $this->log(1, "Package $dest_package done"); + if (file_exists("$pkgdir/CVS/Root")) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pkginfo['version']); + $cvstag = "RELEASE_$cvsversion"; + $this->log(1, "Tag the released code with `pear cvstag $pkgfile'"); + $this->log(1, "(or set the CVS tag $cvstag by hand)"); + } + // }}} + + return $dest_package; + } + + // }}} +} + +// {{{ md5_file() utility function +if (!function_exists('md5_file')) { + function md5_file($file) { + if (!$fd = @fopen($file, 'r')) { + return false; + } + $md5 = md5(fread($fd, filesize($file))); + fclose($fd); + return $md5; + } +} +// }}} + +?> diff --git a/src/www/lib/pear/PEAR/Registry.php b/src/www/lib/pear/PEAR/Registry.php new file mode 100644 index 00000000..ba24e3fd --- /dev/null +++ b/src/www/lib/pear/PEAR/Registry.php @@ -0,0 +1,538 @@ + | +// | Tomas V.V.Cox | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: Registry.php,v 1.1 2005/05/28 01:55:13 henrique Exp $ + +/* +TODO: + - Transform into singleton() + - Add application level lock (avoid change the registry from the cmdline + while using the GTK interface, for ex.) +*/ +require_once "System.php"; +require_once "PEAR.php"; + +define('PEAR_REGISTRY_ERROR_LOCK', -2); +define('PEAR_REGISTRY_ERROR_FORMAT', -3); +define('PEAR_REGISTRY_ERROR_FILE', -4); + +/** + * Administration class used to maintain the installed package database. + */ +class PEAR_Registry extends PEAR +{ + // {{{ properties + + /** Directory where registry files are stored. + * @var string + */ + var $statedir = ''; + + /** File where the file map is stored + * @var string + */ + var $filemap = ''; + + /** Name of file used for locking the registry + * @var string + */ + var $lockfile = ''; + + /** File descriptor used during locking + * @var resource + */ + var $lock_fp = null; + + /** Mode used during locking + * @var int + */ + var $lock_mode = 0; // XXX UNUSED + + /** Cache of package information. Structure: + * array( + * 'package' => array('id' => ... ), + * ... ) + * @var array + */ + var $pkginfo_cache = array(); + + /** Cache of file map. Structure: + * array( '/path/to/file' => 'package', ... ) + * @var array + */ + var $filemap_cache = array(); + + // }}} + + // {{{ constructor + + /** + * PEAR_Registry constructor. + * + * @param string (optional) PEAR install directory (for .php files) + * + * @access public + */ + function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR) + { + parent::PEAR(); + $ds = DIRECTORY_SEPARATOR; + $this->install_dir = $pear_install_dir; + $this->statedir = $pear_install_dir.$ds.'.registry'; + $this->filemap = $pear_install_dir.$ds.'.filemap'; + $this->lockfile = $pear_install_dir.$ds.'.lock'; + + // XXX Compatibility code should be removed in the future + // rename all registry files if any to lowercase + if (!OS_WINDOWS && $handle = @opendir($this->statedir)) { + $dest = $this->statedir . DIRECTORY_SEPARATOR; + while (false !== ($file = readdir($handle))) { + if (preg_match('/^.*[A-Z].*\.reg$/', $file)) { + rename($dest . $file, $dest . strtolower($file)); + } + } + closedir($handle); + } + if (!file_exists($this->filemap)) { + $this->rebuildFileMap(); + } + } + + // }}} + // {{{ destructor + + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); + } + } + + // }}} + + // {{{ _assertStateDir() + + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertStateDir() + { + if (!@is_dir($this->statedir)) { + if (!System::mkdir(array('-p', $this->statedir))) { + return $this->raiseError("could not create directory '{$this->statedir}'"); + } + } + return true; + } + + // }}} + // {{{ _packageFileName() + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _packageFileName($package) + { + return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; + } + + // }}} + // {{{ _openPackageFile() + + function _openPackageFile($package, $mode) + { + $this->_assertStateDir(); + $file = $this->_packageFileName($package); + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + return $fp; + } + + // }}} + // {{{ _closePackageFile() + + function _closePackageFile($fp) + { + fclose($fp); + } + + // }}} + // {{{ rebuildFileMap() + + function rebuildFileMap() + { + $packages = $this->listPackages(); + $files = array(); + foreach ($packages as $package) { + $version = $this->packageInfo($package, 'version'); + $filelist = $this->packageInfo($package, 'filelist'); + if (!is_array($filelist)) { + continue; + } + foreach ($filelist as $name => $attrs) { + if (isset($attrs['role']) && $attrs['role'] != 'php') { + continue; + } + if (isset($attrs['baseinstalldir'])) { + $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; + } else { + $file = $name; + } + $file = preg_replace(',^/+,', '', $file); + $files[$file] = $package; + } + } + $this->_assertStateDir(); + $fp = @fopen($this->filemap, 'wb'); + if (!$fp) { + return false; + } + $this->filemap_cache = $files; + fwrite($fp, serialize($files)); + fclose($fp); + return true; + } + + // }}} + // {{{ readFileMap() + + function readFileMap() + { + $fp = @fopen($this->filemap, 'r'); + if (!$fp) { + return $this->raiseError('PEAR_Registry: could not open filemap', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); + } + $fsize = filesize($this->filemap); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $data = fread($fp, $fsize); + set_magic_quotes_runtime($rt); + fclose($fp); + $tmp = unserialize($data); + if (!$tmp && $fsize > 7) { + return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); + } + $this->filemap_cache = $tmp; + return true; + } + + // }}} + // {{{ _lock() + + /** + * Lock the registry. + * + * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. + * See flock manual for more information. + * + * @return bool TRUE on success, FALSE if locking failed, or a + * PEAR error if some other error occurs (such as the + * lock file not being writable). + * + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (!eregi('Windows 9', php_uname())) { + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + if (PEAR::isError($err = $this->_assertStateDir())) { + return $err; + } + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH || $mode === LOCK_UN) { + if (@!is_file($this->lockfile)) { + touch($this->lockfile); + } + $open_mode = 'r'; + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = @fopen($this->lockfile, $open_mode); + } + + if (!is_resource($this->lock_fp)) { + return $this->raiseError("could not create lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } + if (!(int)flock($this->lock_fp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } + return $this->raiseError("could not acquire $str lock ($this->lockfile)", + PEAR_REGISTRY_ERROR_LOCK); + } + } + return true; + } + + // }}} + // {{{ _unlock() + + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->lock_fp)) { + fclose($this->lock_fp); + } + $this->lock_fp = null; + return $ret; + } + + // }}} + // {{{ _packageExists() + + function _packageExists($package) + { + return file_exists($this->_packageFileName($package)); + } + + // }}} + // {{{ _packageInfo() + + function _packageInfo($package = null, $key = null) + { + if ($package === null) { + return array_map(array($this, '_packageInfo'), + $this->_listPackages()); + } + $fp = $this->_openPackageFile($package, 'r'); + if ($fp === null) { + return null; + } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $data = fread($fp, filesize($this->_packageFileName($package))); + set_magic_quotes_runtime($rt); + $this->_closePackageFile($fp); + $data = unserialize($data); + if ($key === null) { + return $data; + } + if (isset($data[$key])) { + return $data[$key]; + } + return null; + } + + // }}} + // {{{ _listPackages() + + function _listPackages() + { + $pkglist = array(); + $dp = @opendir($this->statedir); + if (!$dp) { + return $pkglist; + } + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + $pkglist[] = substr($ent, 0, -4); + } + return $pkglist; + } + + // }}} + + // {{{ packageExists() + + function packageExists($package) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageExists($package); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ packageInfo() + + function packageInfo($package = null, $key = null) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageInfo($package, $key); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listPackages() + + function listPackages() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listPackages(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ addPackage() + + function addPackage($package, $info) + { + if ($this->packageExists($package)) { + return false; + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $fp = $this->_openPackageFile($package, 'wb'); + if ($fp === null) { + $this->_unlock(); + return false; + } + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_unlock(); + return true; + } + + // }}} + // {{{ deletePackage() + + function deletePackage($package) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $file = $this->_packageFileName($package); + $ret = @unlink($file); + $this->rebuildFileMap(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ updatePackage() + + function updatePackage($package, $info, $merge = true) + { + $oldinfo = $this->packageInfo($package); + if (empty($oldinfo)) { + return false; + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $fp = $this->_openPackageFile($package, 'w'); + if ($fp === null) { + $this->_unlock(); + return false; + } + $info['_lastmodified'] = time(); + if ($merge) { + fwrite($fp, serialize(array_merge($oldinfo, $info))); + } else { + fwrite($fp, serialize($info)); + } + $this->_closePackageFile($fp); + if (isset($info['filelist'])) { + $this->rebuildFileMap(); + } + $this->_unlock(); + return true; + } + + // }}} + // {{{ checkFileMap() + + /** + * Test whether a file belongs to a package. + * + * @param string $path file path, absolute or relative to the pear + * install dir + * + * @return string which package the file belongs to, or an empty + * string if the file does not belong to an installed package + * + * @access public + */ + function checkFileMap($path) + { + if (is_array($path)) { + static $notempty; + if (empty($notempty)) { + $notempty = create_function('$a','return !empty($a);'); + } + $pkgs = array(); + foreach ($path as $name => $attrs) { + if (is_array($attrs) && isset($attrs['baseinstalldir'])) { + $name = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; + } + $pkgs[$name] = $this->checkFileMap($name); + } + return array_filter($pkgs, $notempty); + } + if (empty($this->filemap_cache) && PEAR::isError($this->readFileMap())) { + return $err; + } + if (isset($this->filemap_cache[$path])) { + return $this->filemap_cache[$path]; + } + $l = strlen($this->install_dir); + if (substr($path, 0, $l) == $this->install_dir) { + $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); + } + if (isset($this->filemap_cache[$path])) { + return $this->filemap_cache[$path]; + } + return ''; + } + + // }}} + +} + +?> diff --git a/src/www/lib/pear/PEAR/Remote.php b/src/www/lib/pear/PEAR/Remote.php new file mode 100644 index 00000000..c15b42b1 --- /dev/null +++ b/src/www/lib/pear/PEAR/Remote.php @@ -0,0 +1,394 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Remote.php,v 1.1 2005/05/28 01:55:14 henrique Exp $ + +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +/** + * This is a class for doing remote operations against the central + * PEAR database. + * + * @nodep XML_RPC_Value + * @nodep XML_RPC_Message + * @nodep XML_RPC_Client + */ +class PEAR_Remote extends PEAR +{ + // {{{ properties + + var $config = null; + var $cache = null; + + // }}} + + // {{{ PEAR_Remote(config_object) + + function PEAR_Remote(&$config) + { + $this->PEAR(); + $this->config = &$config; + } + + // }}} + + // {{{ getCache() + + + function getCache($args) + { + $id = md5(serialize($args)); + $cachedir = $this->config->get('cache_dir'); + $filename = $cachedir . DIRECTORY_SEPARATOR . 'xmlrpc_cache_' . $id; + if (!file_exists($filename)) { + return null; + }; + + $fp = fopen($filename, 'rb'); + if (!$fp) { + return null; + } + $content = fread($fp, filesize($filename)); + fclose($fp); + $result = array( + 'age' => time() - filemtime($filename), + 'lastChange' => filemtime($filename), + 'content' => unserialize($content), + ); + return $result; + } + + // }}} + + // {{{ saveCache() + + function saveCache($args, $data) + { + $id = md5(serialize($args)); + $cachedir = $this->config->get('cache_dir'); + if (!file_exists($cachedir)) { + System::mkdir(array('-p', $cachedir)); + } + $filename = $cachedir.'/xmlrpc_cache_'.$id; + + $fp = @fopen($filename, "wb"); + if ($fp) { + fwrite($fp, serialize($data)); + fclose($fp); + }; + } + + // }}} + + // {{{ call(method, [args...]) + + function call($method) + { + $_args = $args = func_get_args(); + + $this->cache = $this->getCache($args); + $cachettl = $this->config->get('cache_ttl'); + // If cache is newer than $cachettl seconds, we use the cache! + if ($this->cache !== null && $this->cache['age'] < $cachettl) { + return $this->cache['content']; + }; + + if (extension_loaded("xmlrpc")) { + $result = call_user_func_array(array(&$this, 'call_epi'), $args); + if (!PEAR::isError($result)) { + $this->saveCache($_args, $result); + }; + return $result; + } + if (!@include_once("XML/RPC.php")) { + return $this->raiseError("For this remote PEAR operation you need to install the XML_RPC package"); + } + array_shift($args); + $server_host = $this->config->get('master_server'); + $username = $this->config->get('username'); + $password = $this->config->get('password'); + $eargs = array(); + foreach($args as $arg) $eargs[] = $this->_encode($arg); + $f = new XML_RPC_Message($method, $eargs); + if ($this->cache !== null) { + $maxAge = '?maxAge='.$this->cache['lastChange']; + } else { + $maxAge = ''; + }; + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($proxy = parse_url($this->config->get('http_proxy'))) { + $proxy_host = @$proxy['host']; + $proxy_port = @$proxy['port']; + $proxy_user = @urldecode(@$proxy['user']); + $proxy_pass = @urldecode(@$proxy['pass']); + } + $c = new XML_RPC_Client('/xmlrpc.php'.$maxAge, $server_host, 80, $proxy_host, $proxy_port, $proxy_user, $proxy_pass); + if ($username && $password) { + $c->setCredentials($username, $password); + } + if ($this->config->get('verbose') >= 3) { + $c->setDebug(1); + } + $r = $c->send($f); + if (!$r) { + return $this->raiseError("XML_RPC send failed"); + } + $v = $r->value(); + if ($e = $r->faultCode()) { + if ($e == $GLOBALS['XML_RPC_err']['http_error'] && strstr($r->faultString(), '304 Not Modified') !== false) { + return $this->cache['content']; + } + return $this->raiseError($r->faultString(), $e); + } + + $result = XML_RPC_decode($v); + $this->saveCache($_args, $result); + return $result; + } + + // }}} + + // {{{ call_epi(method, [args...]) + + function call_epi($method) + { + do { + if (extension_loaded("xmlrpc")) { + break; + } + if (OS_WINDOWS) { + $ext = 'dll'; + } elseif (PHP_OS == 'HP-UX') { + $ext = 'sl'; + } elseif (PHP_OS == 'AIX') { + $ext = 'a'; + } else { + $ext = 'so'; + } + $ext = OS_WINDOWS ? 'dll' : 'so'; + @dl("xmlrpc-epi.$ext"); + if (extension_loaded("xmlrpc")) { + break; + } + @dl("xmlrpc.$ext"); + if (extension_loaded("xmlrpc")) { + break; + } + return $this->raiseError("unable to load xmlrpc extension"); + } while (false); + $params = func_get_args(); + array_shift($params); + $method = str_replace("_", ".", $method); + $request = xmlrpc_encode_request($method, $params); + $server_host = $this->config->get("master_server"); + if (empty($server_host)) { + return $this->raiseError("PEAR_Remote::call: no master_server configured"); + } + $server_port = 80; + if ($http_proxy = $this->config->get('http_proxy')) { + $proxy = parse_url($http_proxy); + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + $proxy_host = @$proxy['host']; + $proxy_port = @$proxy['port']; + $proxy_user = @urldecode(@$proxy['user']); + $proxy_pass = @urldecode(@$proxy['pass']); + $fp = @fsockopen($proxy_host, $proxy_port); + $use_proxy = true; + } else { + $use_proxy = false; + $fp = @fsockopen($server_host, $server_port); + } + if (!$fp && $http_proxy) { + return $this->raiseError("PEAR_Remote::call: fsockopen(`$proxy_host', $proxy_port) failed"); + } elseif (!$fp) { + return $this->raiseError("PEAR_Remote::call: fsockopen(`$server_host', $server_port) failed"); + } + $len = strlen($request); + $req_headers = "Host: $server_host:$server_port\r\n" . + "Content-type: text/xml\r\n" . + "Content-length: $len\r\n"; + $username = $this->config->get('username'); + $password = $this->config->get('password'); + if ($username && $password) { + $req_headers .= "Cookie: PEAR_USER=$username; PEAR_PW=$password\r\n"; + $tmp = base64_encode("$username:$password"); + $req_headers .= "Authorization: Basic $tmp\r\n"; + } + if ($this->cache !== null) { + $maxAge = '?maxAge='.$this->cache['lastChange']; + } else { + $maxAge = ''; + }; + + if ($use_proxy && $proxy_host != '' && $proxy_user != '') { + $req_headers .= 'Proxy-Authorization: Basic ' + .base64_encode($proxy_user.':'.$proxy_pass) + ."\r\n"; + } + + if ($this->config->get('verbose') > 3) { + print "XMLRPC REQUEST HEADERS:\n"; + var_dump($req_headers); + print "XMLRPC REQUEST BODY:\n"; + var_dump($request); + } + + if ($use_proxy && $proxy_host != '') { + $post_string = "POST http://".$server_host; + if ($proxy_port > '') { + $post_string .= ':'.$server_port; + } + } else { + $post_string = "POST "; + } + + fwrite($fp, ($post_string."/xmlrpc.php$maxAge HTTP/1.0\r\n$req_headers\r\n$request")); + $response = ''; + $line1 = fgets($fp, 2048); + if (!preg_match('!^HTTP/[0-9\.]+ (\d+) (.*)!', $line1, $matches)) { + return $this->raiseError("PEAR_Remote: invalid HTTP response from XML-RPC server"); + } + switch ($matches[1]) { + case "200": // OK + break; + case "304": // Not Modified + return $this->cache['content']; + case "401": // Unauthorized + if ($username && $password) { + return $this->raiseError("PEAR_Remote: authorization failed", 401); + } else { + return $this->raiseError("PEAR_Remote: authorization required, please log in first", 401); + } + default: + return $this->raiseError("PEAR_Remote: unexpected HTTP response", (int)$matches[1], null, null, "$matches[1] $matches[2]"); + } + while (trim(fgets($fp, 2048)) != ''); // skip rest of headers + while ($chunk = fread($fp, 10240)) { + $response .= $chunk; + } + fclose($fp); + if ($this->config->get('verbose') > 3) { + print "XMLRPC RESPONSE:\n"; + var_dump($response); + } + $ret = xmlrpc_decode($response); + if (is_array($ret) && isset($ret['__PEAR_TYPE__'])) { + if ($ret['__PEAR_TYPE__'] == 'error') { + if (isset($ret['__PEAR_CLASS__'])) { + $class = $ret['__PEAR_CLASS__']; + } else { + $class = "PEAR_Error"; + } + if ($ret['code'] === '') $ret['code'] = null; + if ($ret['message'] === '') $ret['message'] = null; + if ($ret['userinfo'] === '') $ret['userinfo'] = null; + if (strtolower($class) == 'db_error') { + $ret = $this->raiseError(PEAR::errorMessage($ret['code']), + $ret['code'], null, null, + $ret['userinfo']); + } else { + $ret = $this->raiseError($ret['message'], $ret['code'], + null, null, $ret['userinfo']); + } + } + } elseif (is_array($ret) && sizeof($ret) == 1 && isset($ret[0]) + && is_array($ret[0]) && + !empty($ret[0]['faultString']) && + !empty($ret[0]['faultCode'])) { + extract($ret[0]); + $faultString = "XML-RPC Server Fault: " . + str_replace("\n", " ", $faultString); + return $this->raiseError($faultString, $faultCode); + } + return $ret; + } + + // }}} + + // {{{ _encode + + // a slightly extended version of XML_RPC_encode + function _encode($php_val) + { + global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double; + global $XML_RPC_String, $XML_RPC_Array, $XML_RPC_Struct; + + $type = gettype($php_val); + $xmlrpcval = new XML_RPC_Value; + + switch($type) { + case "array": + reset($php_val); + $firstkey = key($php_val); + end($php_val); + $lastkey = key($php_val); + if ($firstkey === 0 && is_int($lastkey) && + ($lastkey + 1) == count($php_val)) { + $is_continuous = true; + reset($php_val); + $size = count($php_val); + for ($expect = 0; $expect < $size; $expect++, next($php_val)) { + if (key($php_val) !== $expect) { + $is_continuous = false; + break; + } + } + if ($is_continuous) { + reset($php_val); + $arr = array(); + while (list($k, $v) = each($php_val)) { + $arr[$k] = $this->_encode($v); + } + $xmlrpcval->addArray($arr); + break; + } + } + // fall though if not numerical and continuous + case "object": + $arr = array(); + while (list($k, $v) = each($php_val)) { + $arr[$k] = $this->_encode($v); + } + $xmlrpcval->addStruct($arr); + break; + case "integer": + $xmlrpcval->addScalar($php_val, $XML_RPC_Int); + break; + case "double": + $xmlrpcval->addScalar($php_val, $XML_RPC_Double); + break; + case "string": + case "NULL": + $xmlrpcval->addScalar($php_val, $XML_RPC_String); + break; + case "boolean": + $xmlrpcval->addScalar($php_val, $XML_RPC_Boolean); + break; + case "unknown type": + default: + return null; + } + return $xmlrpcval; + } + + // }}} + +} + +?> diff --git a/src/www/lib/pear/PEAR/RunTest.php b/src/www/lib/pear/PEAR/RunTest.php new file mode 100644 index 00000000..a0f154d1 --- /dev/null +++ b/src/www/lib/pear/PEAR/RunTest.php @@ -0,0 +1,363 @@ + | +// | Greg Beaver | +// | | +// +----------------------------------------------------------------------+ +// +// $Id: RunTest.php,v 1.1 2005/05/28 01:55:14 henrique Exp $ +// + +/** + * Simplified version of PHP's test suite + * -- EXPERIMENTAL -- + + Try it with: + + $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);' + + +TODO: + +Actually finish the development and testing + + */ + +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +define('DETAILED', 1); +putenv("PHP_PEAR_RUNTESTS=1"); + +class PEAR_RunTest +{ + var $_logger; + + /** + * An object that supports the PEAR_Common->log() signature, or null + * @param PEAR_Common|null + */ + function PEAR_RunTest($logger = null) + { + $this->_logger = $logger; + } + + // + // Run an individual test case. + // + + function run($file, $ini_settings = '') + { + $cwd = getcwd(); + $conf = &PEAR_Config::singleton(); + $php = $conf->get('php_bin'); + //var_dump($php);exit; + global $log_format, $info_params, $ini_overwrites; + + $info_params = ''; + $log_format = 'LEOD'; + + // Load the sections of the test file. + $section_text = array( + 'TEST' => '(unnamed test)', + 'SKIPIF' => '', + 'GET' => '', + 'ARGS' => '', + ); + + if (!is_file($file) || !$fp = fopen($file, "r")) { + return PEAR::raiseError("Cannot open test file: $file"); + } + + $section = ''; + while (!feof($fp)) { + $line = fgets($fp); + + // Match the beginning of a section. + if (ereg('^--([A-Z]+)--',$line,$r)) { + $section = $r[1]; + $section_text[$section] = ''; + continue; + } + + // Add to the section text. + $section_text[$section] .= $line; + } + fclose($fp); + + $shortname = str_replace($cwd.'/', '', $file); + $tested = trim($section_text['TEST'])." [$shortname]"; + + $tmp = realpath(dirname($file)); + $tmp_skipif = $tmp . uniqid('/phpt.'); + $tmp_file = ereg_replace('\.phpt$','.php',$file); + $tmp_post = $tmp . uniqid('/phpt.'); + + @unlink($tmp_skipif); + @unlink($tmp_file); + @unlink($tmp_post); + + // unlink old test results + @unlink(ereg_replace('\.phpt$','.diff',$file)); + @unlink(ereg_replace('\.phpt$','.log',$file)); + @unlink(ereg_replace('\.phpt$','.exp',$file)); + @unlink(ereg_replace('\.phpt$','.out',$file)); + + // Check if test should be skipped. + $info = ''; + $warn = false; + if (array_key_exists('SKIPIF', $section_text)) { + if (trim($section_text['SKIPIF'])) { + $this->save_text($tmp_skipif, $section_text['SKIPIF']); + //$extra = substr(PHP_OS, 0, 3) !== "WIN" ? + // "unset REQUEST_METHOD;": ""; + + //$output = `$extra $php $info_params -f $tmp_skipif`; + $output = `$php $info_params -f $tmp_skipif`; + unlink($tmp_skipif); + if (eregi("^skip", trim($output))) { + $skipreason = "SKIP $tested"; + $reason = (eregi("^skip[[:space:]]*(.+)\$", trim($output))) ? eregi_replace("^skip[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE; + if ($reason) { + $skipreason .= " (reason: $reason)"; + } + $this->_logger->log(0, $skipreason); + if (isset($old_php)) { + $php = $old_php; + } + return 'SKIPPED'; + } + if (eregi("^info", trim($output))) { + $reason = (ereg("^info[[:space:]]*(.+)\$", trim($output))) ? ereg_replace("^info[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE; + if ($reason) { + $info = " (info: $reason)"; + } + } + if (eregi("^warn", trim($output))) { + $reason = (ereg("^warn[[:space:]]*(.+)\$", trim($output))) ? ereg_replace("^warn[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE; + if ($reason) { + $warn = true; /* only if there is a reason */ + $info = " (warn: $reason)"; + } + } + } + } + + // We've satisfied the preconditions - run the test! + $this->save_text($tmp_file,$section_text['FILE']); + + $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; + + $cmd = "$php$ini_settings -f $tmp_file$args 2>&1"; + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + $savedir = getcwd(); // in case the test moves us around + if (isset($section_text['RETURNS'])) { + ob_start(); + system($cmd, $return_value); + $out = ob_get_contents(); + ob_end_clean(); + @unlink($tmp_post); + $section_text['RETURNS'] = (int) trim($section_text['RETURNS']); + $returnfail = ($return_value != $section_text['RETURNS']); + } else { + $out = `$cmd`; + $returnfail = false; + } + chdir($savedir); + // Does the output match what is expected? + $output = trim($out); + $output = preg_replace('/\r\n/', "\n", $output); + + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + if (isset($section_text['EXPECTF'])) { + $wanted = trim($section_text['EXPECTF']); + } else { + $wanted = trim($section_text['EXPECTREGEX']); + } + $wanted_re = preg_replace('/\r\n/',"\n",$wanted); + if (isset($section_text['EXPECTF'])) { + $wanted_re = preg_quote($wanted_re, '/'); + // Stick to basics + $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy + $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re); + $wanted_re = str_replace("%d", "[0-9]+", $wanted_re); + $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re); + $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re); + $wanted_re = str_replace("%c", ".", $wanted_re); + // %f allows two points "-.0.0" but that is the best *simple* expression + } + /* DEBUG YOUR REGEX HERE + var_dump($wanted_re); + print(str_repeat('=', 80) . "\n"); + var_dump($output); + */ + if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) { + @unlink($tmp_file); + $this->_logger->log(0, "PASS $tested$info"); + if (isset($old_php)) { + $php = $old_php; + } + return 'PASSED'; + } + + } else { + $wanted = trim($section_text['EXPECT']); + $wanted = preg_replace('/\r\n/',"\n",$wanted); + // compare and leave on success + $ok = (0 == strcmp($output,$wanted)); + if (!$returnfail && $ok) { + @unlink($tmp_file); + $this->_logger->log(0, "PASS $tested$info"); + if (isset($old_php)) { + $php = $old_php; + } + return 'PASSED'; + } + } + + // Test failed so we need to report details. + if ($warn) { + $this->_logger->log(0, "WARN $tested$info"); + } else { + $this->_logger->log(0, "FAIL $tested$info"); + } + + if (isset($section_text['RETURNS'])) { + $GLOBALS['__PHP_FAILED_TESTS__'][] = array( + 'name' => $file, + 'test_name' => $tested, + 'output' => ereg_replace('\.phpt$','.log', $file), + 'diff' => ereg_replace('\.phpt$','.diff', $file), + 'info' => $info, + 'return' => $return_value + ); + } else { + $GLOBALS['__PHP_FAILED_TESTS__'][] = array( + 'name' => $file, + 'test_name' => $tested, + 'output' => ereg_replace('\.phpt$','.log', $file), + 'diff' => ereg_replace('\.phpt$','.diff', $file), + 'info' => $info, + ); + } + + // write .exp + if (strpos($log_format,'E') !== FALSE) { + $logname = ereg_replace('\.phpt$','.exp',$file); + if (!$log = fopen($logname,'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log,$wanted); + fclose($log); + } + + // write .out + if (strpos($log_format,'O') !== FALSE) { + $logname = ereg_replace('\.phpt$','.out',$file); + if (!$log = fopen($logname,'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log,$output); + fclose($log); + } + + // write .diff + if (strpos($log_format,'D') !== FALSE) { + $logname = ereg_replace('\.phpt$','.diff',$file); + if (!$log = fopen($logname,'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log, $this->generate_diff($wanted, $output, + isset($section_text['RETURNS']) ? array(trim($section_text['RETURNS']), + $return_value) : null)); + fclose($log); + } + + // write .log + if (strpos($log_format,'L') !== FALSE) { + $logname = ereg_replace('\.phpt$','.log',$file); + if (!$log = fopen($logname,'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log," +---- EXPECTED OUTPUT +$wanted +---- ACTUAL OUTPUT +$output +---- FAILED +"); + if ($returnfail) { + fwrite($log," +---- EXPECTED RETURN +$section_text[RETURNS] +---- ACTUAL RETURN +$return_value +"); + } + fclose($log); + //error_report($file,$logname,$tested); + } + + if (isset($old_php)) { + $php = $old_php; + } + + return $warn ? 'WARNED' : 'FAILED'; + } + + function generate_diff($wanted, $output, $return_value) + { + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $w1 = array_diff_assoc($w,$o); + $o1 = array_diff_assoc($o,$w); + $w2 = array(); + $o2 = array(); + foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1).$val; + foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1).$val; + $diff = array_merge($w2, $o2); + ksort($diff); + if ($return_value) { + $extra = "##EXPECTED: $return_value[0]\r\n##RETURNED: $return_value[1]"; + } else { + $extra = ''; + } + return implode("\r\n", $diff) . $extra; + } + + // + // Write the given text to a temporary file, and return the filename. + // + + function save_text($filename, $text) + { + if (!$fp = fopen($filename, 'w')) { + return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)"); + } + fwrite($fp,$text); + fclose($fp); + if (1 < DETAILED) echo " +FILE $filename {{{ +$text +}}} +"; + } + +} +?> \ No newline at end of file diff --git a/src/www/lib/pear/System.php b/src/www/lib/pear/System.php new file mode 100644 index 00000000..0ef51f37 --- /dev/null +++ b/src/www/lib/pear/System.php @@ -0,0 +1,540 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: System.php,v 1.1 2005/05/28 01:55:10 henrique Exp $ +// + +require_once 'PEAR.php'; +require_once 'Console/Getopt.php'; + +$GLOBALS['_System_temp_files'] = array(); + +/** +* System offers cross plattform compatible system functions +* +* Static functions for different operations. Should work under +* Unix and Windows. The names and usage has been taken from its respectively +* GNU commands. The functions will return (bool) false on error and will +* trigger the error with the PHP trigger_error() function (you can silence +* the error by prefixing a '@' sign after the function call). +* +* Documentation on this class you can find in: +* http://pear.php.net/manual/ +* +* Example usage: +* if (!@System::rm('-r file1 dir1')) { +* print "could not delete file1 or dir1"; +* } +* +* In case you need to to pass file names with spaces, +* pass the params as an array: +* +* System::rm(array('-r', $file1, $dir1)); +* +* @package System +* @author Tomas V.V.Cox +* @version $Revision: 1.1 $ +* @access public +* @see http://pear.php.net/manual/ +*/ +class System +{ + /** + * returns the commandline arguments of a function + * + * @param string $argv the commandline + * @param string $short_options the allowed option short-tags + * @param string $long_options the allowed option long-tags + * @return array the given options and there values + * @access private + */ + function _parseArgs($argv, $short_options, $long_options = null) + { + if (!is_array($argv) && $argv !== null) { + $argv = preg_split('/\s+/', $argv); + } + return Console_Getopt::getopt2($argv, $short_options); + } + + /** + * Output errors with PHP trigger_error(). You can silence the errors + * with prefixing a "@" sign to the function call: @System::mkdir(..); + * + * @param mixed $error a PEAR error or a string with the error message + * @return bool false + * @access private + */ + function raiseError($error) + { + if (PEAR::isError($error)) { + $error = $error->getMessage(); + } + trigger_error($error, E_USER_WARNING); + return false; + } + + /** + * Creates a nested array representing the structure of a directory + * + * System::_dirToStruct('dir1', 0) => + * Array + * ( + * [dirs] => Array + * ( + * [0] => dir1 + * ) + * + * [files] => Array + * ( + * [0] => dir1/file2 + * [1] => dir1/file3 + * ) + * ) + * @param string $sPath Name of the directory + * @param integer $maxinst max. deep of the lookup + * @param integer $aktinst starting deep of the lookup + * @return array the structure of the dir + * @access private + */ + + function _dirToStruct($sPath, $maxinst, $aktinst = 0) + { + $struct = array('dirs' => array(), 'files' => array()); + if (($dir = @opendir($sPath)) === false) { + System::raiseError("Could not open dir $sPath"); + return $struct; // XXX could not open error + } + $struct['dirs'][] = $sPath; // XXX don't add if '.' or '..' ? + $list = array(); + while ($file = readdir($dir)) { + if ($file != '.' && $file != '..') { + $list[] = $file; + } + } + closedir($dir); + sort($list); + if ($aktinst < $maxinst || $maxinst == 0) { + foreach($list as $val) { + $path = $sPath . DIRECTORY_SEPARATOR . $val; + if (is_dir($path)) { + $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1); + $struct = array_merge_recursive($tmp, $struct); + } else { + $struct['files'][] = $path; + } + } + } + return $struct; + } + + /** + * Creates a nested array representing the structure of a directory and files + * + * @param array $files Array listing files and dirs + * @return array + * @see System::_dirToStruct() + */ + function _multipleToStruct($files) + { + $struct = array('dirs' => array(), 'files' => array()); + settype($files, 'array'); + foreach ($files as $file) { + if (is_dir($file)) { + $tmp = System::_dirToStruct($file, 0); + $struct = array_merge_recursive($tmp, $struct); + } else { + $struct['files'][] = $file; + } + } + return $struct; + } + + /** + * The rm command for removing files. + * Supports multiple files and dirs and also recursive deletes + * + * @param string $args the arguments for rm + * @return mixed PEAR_Error or true for success + * @access public + */ + function rm($args) + { + $opts = System::_parseArgs($args, 'rf'); // "f" do nothing but like it :-) + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + foreach($opts[0] as $opt) { + if ($opt[0] == 'r') { + $do_recursive = true; + } + } + $ret = true; + if (isset($do_recursive)) { + $struct = System::_multipleToStruct($opts[1]); + foreach($struct['files'] as $file) { + if (!@unlink($file)) { + $ret = false; + } + } + foreach($struct['dirs'] as $dir) { + if (!@rmdir($dir)) { + $ret = false; + } + } + } else { + foreach ($opts[1] as $file) { + $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; + if (!@$delete($file)) { + $ret = false; + } + } + } + return $ret; + } + + /** + * Make directories. Note that we use call_user_func('mkdir') to avoid + * a problem with ZE2 calling System::mkDir instead of the native PHP func. + * + * @param string $args the name of the director(y|ies) to create + * @return bool True for success + * @access public + */ + function mkDir($args) + { + $opts = System::_parseArgs($args, 'pm:'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + $mode = 0777; // default mode + foreach($opts[0] as $opt) { + if ($opt[0] == 'p') { + $create_parents = true; + } elseif($opt[0] == 'm') { + // if the mode is clearly an octal number (starts with 0) + // convert it to decimal + if (strlen($opt[1]) && $opt[1]{0} == '0') { + $opt[1] = octdec($opt[1]); + } else { + // convert to int + $opt[1] += 0; + } + $mode = $opt[1]; + } + } + $ret = true; + if (isset($create_parents)) { + foreach($opts[1] as $dir) { + $dirstack = array(); + while (!@is_dir($dir) && $dir != DIRECTORY_SEPARATOR) { + array_unshift($dirstack, $dir); + $dir = dirname($dir); + } + while ($newdir = array_shift($dirstack)) { + if (!call_user_func('mkdir', $newdir, $mode)) { + $ret = false; + } + } + } + } else { + foreach($opts[1] as $dir) { + if (!@is_dir($dir) && !call_user_func('mkdir', $dir, $mode)) { + $ret = false; + } + } + } + return $ret; + } + + /** + * Concatenate files + * + * Usage: + * 1) $var = System::cat('sample.txt test.txt'); + * 2) System::cat('sample.txt test.txt > final.txt'); + * 3) System::cat('sample.txt test.txt >> final.txt'); + * + * Note: as the class use fopen, urls should work also (test that) + * + * @param string $args the arguments + * @return boolean true on success + * @access public + */ + function &cat($args) + { + $ret = null; + $files = array(); + if (!is_array($args)) { + $args = preg_split('/\s+/', $args); + } + for($i=0; $i < count($args); $i++) { + if ($args[$i] == '>') { + $mode = 'wb'; + $outputfile = $args[$i+1]; + break; + } elseif ($args[$i] == '>>') { + $mode = 'ab+'; + $outputfile = $args[$i+1]; + break; + } else { + $files[] = $args[$i]; + } + } + if (isset($mode)) { + if (!$outputfd = fopen($outputfile, $mode)) { + $err = System::raiseError("Could not open $outputfile"); + return $err; + } + $ret = true; + } + foreach ($files as $file) { + if (!$fd = fopen($file, 'r')) { + System::raiseError("Could not open $file"); + continue; + } + while ($cont = fread($fd, 2048)) { + if (isset($outputfd)) { + fwrite($outputfd, $cont); + } else { + $ret .= $cont; + } + } + fclose($fd); + } + if (@is_resource($outputfd)) { + fclose($outputfd); + } + return $ret; + } + + /** + * Creates temporary files or directories. This function will remove + * the created files when the scripts finish its execution. + * + * Usage: + * 1) $tempfile = System::mktemp("prefix"); + * 2) $tempdir = System::mktemp("-d prefix"); + * 3) $tempfile = System::mktemp(); + * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); + * + * prefix -> The string that will be prepended to the temp name + * (defaults to "tmp"). + * -d -> A temporary dir will be created instead of a file. + * -t -> The target dir where the temporary (file|dir) will be created. If + * this param is missing by default the env vars TMP on Windows or + * TMPDIR in Unix will be used. If these vars are also missing + * c:\windows\temp or /tmp will be used. + * + * @param string $args The arguments + * @return mixed the full path of the created (file|dir) or false + * @see System::tmpdir() + * @access public + */ + function mktemp($args = null) + { + static $first_time = true; + $opts = System::_parseArgs($args, 't:d'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + foreach($opts[0] as $opt) { + if($opt[0] == 'd') { + $tmp_is_dir = true; + } elseif($opt[0] == 't') { + $tmpdir = $opt[1]; + } + } + $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; + if (!isset($tmpdir)) { + $tmpdir = System::tmpdir(); + } + if (!System::mkDir("-p $tmpdir")) { + return false; + } + $tmp = tempnam($tmpdir, $prefix); + if (isset($tmp_is_dir)) { + unlink($tmp); // be careful possible race condition here + if (!call_user_func('mkdir', $tmp, 0700)) { + return System::raiseError("Unable to create temporary directory $tmpdir"); + } + } + $GLOBALS['_System_temp_files'][] = $tmp; + if ($first_time) { + PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); + $first_time = false; + } + return $tmp; + } + + /** + * Remove temporary files created my mkTemp. This function is executed + * at script shutdown time + * + * @access private + */ + function _removeTmpFiles() + { + if (count($GLOBALS['_System_temp_files'])) { + $delete = $GLOBALS['_System_temp_files']; + array_unshift($delete, '-r'); + System::rm($delete); + } + } + + /** + * Get the path of the temporal directory set in the system + * by looking in its environments variables. + * Note: php.ini-recommended removes the "E" from the variables_order setting, + * making unavaible the $_ENV array, that s why we do tests with _ENV + * + * @return string The temporal directory on the system + */ + function tmpdir() + { + if (OS_WINDOWS) { + if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { + return $var; + } + if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { + return $var; + } + if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { + return $var; + } + return getenv('SystemRoot') . '\temp'; + } + if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { + return $var; + } + return '/tmp'; + } + + /** + * The "which" command (show the full path of a command) + * + * @param string $program The command to search for + * @return mixed A string with the full path or false if not found + * @author Stig Bakken + */ + function which($program, $fallback = false) + { + // is_executable() is not available on windows + if (OS_WINDOWS) { + $pear_is_executable = 'is_file'; + } else { + $pear_is_executable = 'is_executable'; + } + + // full path given + if (basename($program) != $program) { + return (@$pear_is_executable($program)) ? $program : $fallback; + } + + // XXX FIXME honor safe mode + $path_delim = OS_WINDOWS ? ';' : ':'; + $exe_suffixes = OS_WINDOWS ? array('.exe','.bat','.cmd','.com') : array(''); + $path_elements = explode($path_delim, getenv('PATH')); + foreach ($exe_suffixes as $suff) { + foreach ($path_elements as $dir) { + $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; + if (@is_file($file) && @$pear_is_executable($file)) { + return $file; + } + } + } + return $fallback; + } + + /** + * The "find" command + * + * Usage: + * + * System::find($dir); + * System::find("$dir -type d"); + * System::find("$dir -type f"); + * System::find("$dir -name *.php"); + * System::find("$dir -name *.php -name *.htm*"); + * System::find("$dir -maxdepth 1"); + * + * Params implmented: + * $dir -> Start the search at this directory + * -type d -> return only directories + * -type f -> return only files + * -maxdepth -> max depth of recursion + * -name -> search pattern (bash style). Multiple -name param allowed + * + * @param mixed Either array or string with the command line + * @return array Array of found files + * + */ + function find($args) + { + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + $dir = array_shift($args); + $patterns = array(); + $depth = 0; + $do_files = $do_dirs = true; + for ($i = 0; $i < count($args); $i++) { + switch ($args[$i]) { + case '-type': + if (in_array($args[$i+1], array('d', 'f'))) { + if ($args[$i+1] == 'd') { + $do_files = false; + } else { + $do_dirs = false; + } + } + $i++; + break; + case '-name': + $patterns[] = "(" . preg_replace(array('/\./', '/\*/'), + array('\.', '.*'), + $args[$i+1]) + . ")"; + $i++; + break; + case '-maxdepth': + $depth = $args[$i+1]; + break; + } + } + $path = System::_dirToStruct($dir, $depth); + if ($do_files && $do_dirs) { + $files = array_merge($path['files'], $path['dirs']); + } elseif ($do_dirs) { + $files = $path['dirs']; + } else { + $files = $path['files']; + } + if (count($patterns)) { + $patterns = implode('|', $patterns); + $ret = array(); + for ($i = 0; $i < count($files); $i++) { + if (preg_match("#^$patterns\$#", $files[$i])) { + $ret[] = $files[$i]; + } + } + return $ret; + } + return $files; + } +} +?> diff --git a/src/www/lib/root.php b/src/www/lib/root.php new file mode 100644 index 00000000..368a7682 --- /dev/null +++ b/src/www/lib/root.php @@ -0,0 +1,27 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + \ No newline at end of file diff --git a/src/www/lib/spmtable.py b/src/www/lib/spmtable.py new file mode 100644 index 00000000..d28dc362 --- /dev/null +++ b/src/www/lib/spmtable.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +import sys +from socket import * + +class Spm: + + def __init__(self, server = 'localhost', port = 1750): + self.server = server + self.port = port + + self.proto = {'PM_SERVER' : '\x00\x01', 'PM_CLIENT' : '\x00\x02', 'PM_CLOSE' : '\x00\x03', + 'PM_RESEND' : '\x00\x04', 'PM_QUIT' : '\x00\x05', 'PM_SORRY' : '\x00\x06', + 'PM_OK' : '\x00\x07', 'PM_ACCEPT' : '\x00\x08', 'PM_TABLE' : '\x00\x09', + 'PM_RMSERVER': '\x00\x10', 'PM_FWINIT' : '\x00\x11', 'PM_SHARE' : '\x00\x12', + 'PM_OKSHARE' : '\x00\x13', 'PM_BIGBUF' : 1024, 'PM_MAXTRY' : 20 } + + def getPort(self, server = None): + """ + Retorna a porta de um dado servidor. + @param server servidor do qual deseja saber a porta + """ + + pass + + def getTable(self): + """ + Retorna um dictionary com os servidores e respectivas portas + ativos no momento. + """ + + dic = {} + + sk = socket(AF_INET, SOCK_STREAM) + + try: + sk.connect((self.server, self.port)) + sk.send(self.proto['PM_TABLE']) + + if sk.recv(2) == self.proto['PM_OK']: + num = sk.recv(2) + data = sk.recv(self.proto['PM_BIGBUF']) + sk.close() + + data = data.split('\x00') + del data[-1] + + for i in data: + item = i.split(':') + dic[item[0].strip()] = int(item[1]) + + return dic + + elif sk.recv(2) == self.proto['PM_RESEND']: + sk.close() + return dic + + except error, msg: + print "Erro:",msg[1] + sys.exit(-1) + + def dumpTable(self, table=None): + if table == None: + table = self.getTable() + + if(table): + for i,v in table.items(): + print "%s %d" % (i, v) + + +if __name__ == '__main__': + + if(len(sys.argv) < 2): + spm = Spm() + else: + spm = Spm(sys.argv[1]) + + spm.dumpTable() diff --git a/src/www/lib/utils.php b/src/www/lib/utils.php new file mode 100644 index 00000000..163b2b82 --- /dev/null +++ b/src/www/lib/utils.php @@ -0,0 +1,328 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> +"; echo var_dump($spmout); echo ""; + + if(count($spmout) < 2) { + return FALSE; + } + + for($i = 2; $i < count($spmout) -1; $i++) { + $tmp = split(":", $spmout[$i]); + $servers[trim($tmp[1])] = trim($tmp[2]); + } + + return $servers; +} + + +// validaçoes +// ra (hh:mm:ss) +// dec (+/-gg:mm:ss) +// gg 00-90 +// hh 00-12 +// mm 00-59 +// ss 00-59 + +function validate_dec($dec) { + + return ereg("[0-9]{2}:[0-5][0-9]:[0-5][0-9]", $dec); + +} + +function dumpSession() { + + echo "
"; + echo "
";
+  print_r($_SESSION);
+  echo "
"; + echo "
"; + +} + +function updateFilename($dir = "", $name = "", $index = "") { + + if($dir) + $_SESSION['bf_dir'] = $dir; + + if($name) + $_SESSION['bf_name'] = $name; + + if($index) + $_SESSION['bf_index'] = $index; + + $_SESSION['bf_fullpath'] = $_SESSION['bf_dir'] . "/" . $_SESSION['user'] . "/" . $_SESSION['inicio']; + + $_SESSION['bf_fullname'] = $_SESSION['bf_fullpath'] . "/" . $_SESSION['bf_name'] . "-" . (count($_SESSION['log'])+1) . "-" . strftime($_SESSION['bf_index'], time()); + +} + +function formatSize($size) { + + # format a file size adding kb, Mb, Gb + + $res = $size / 1024.0; + + if ($res >= 1024.0) { + + $res = $res / 1024.0; + + return floor($res) . " Mb"; + + } else { + + return floor($res) . " kb"; + + } + +} + +function byte_format($input, $dec=0) +{ + $prefix_arr = array("", "K", "M", "G", "T"); + $value = round($input, $dec); + while ($value>1024) + { + $value /= 1024; + $i++; + } + $return_str = round($value, $dec).$prefix_arr[$i]; + return $return_str; +} + +// Mainly based on code by: matt_DOTbevan_ATmarginsoftware_DOTcom +function mkdir_p($target) { + // If the path already exists && is a directory, all is well. + // If the path is not a directory, we've a problem. + if (file_exists($target)) { + if (!is_dir($target)) return false; + else return true; + } + + // Attempting to create the directory may clutter up our display. + if (@mkdir($target, 0777)) + return @chmod($target, 0777); + +} + +function doLogin($nome, $user, $user_id, $root, $db) { + + if(!$root) { + $sql = "INSERT INTO logged VALUES('$user_id')"; + $res =& $db->query($sql); + } + + if(PEAR::isError($res)) { + Header("Location: " . getError("index.php", "Não foi possível efetuar o login. Tente novamente.")); + exit(0); + } + + session_start(); + + $_SESSION['nome'] = $nome; + $_SESSION['user'] = $user; + $_SESSION['user_id'] = $user_id; + $_SESSION['inicio'] = strftime("%Y%m%d-%H%M%Z", time()); + $_SESSION['root'] = $root; + + $_SESSION['log'] = array(); + $_SESSION['obj'] = array(); + $_SESSION['ra'] = array(); + $_SESSION['dec'] = array(); + $_SESSION['num_exp'] = array(); + $_SESSION['exp_time'] = array(); + $_SESSION['filter'] = array(); + $_SESSION['start_time'] = array(); + + updateFilename(getcwd() . "/data", "imagem", "%Y%m%d%H%M%S"); + + $userAreaCreated = 0; + + // create user image space + if(!file_exists($_SESSION['bf_dir'] . "/" . $_SESSION['user'])) + mkdir_p($_SESSION['bf_dir'] . "/" . $_SESSION['user'], 0777); + + if(mkdir_p($_SESSION['bf_dir'] ."/". $_SESSION['user'] ."/". $_SESSION['inicio'], 0777)) { + mkdir_p($_SESSION['bf_dir'] ."/". $_SESSION['user'] ."/". $_SESSION['inicio'] . "/thumbs", 0777); + $userAreaCreated = 1; + } + + Header("Location: home.php?userspace=" . $userAreaCreated); + +} + +function userAllowed($id, $db) { + + $agora = time(); + + $sql = "SELECT * FROM user_sched WHERE (user_id = $id) AND ((inicio <= $agora) AND (fim >= $agora))"; + $res =& $db->query($sql); + + if(PEAR::isError($res)) { + return 0; + } + + if($res->numRows()) { + return 1; + } else { + return 0; + } + +} + +function userUniq($id, $db) { + + $sql = "SELECT * FROM logged WHERE id = $id"; + $res =& $db->query($sql); + + if(PEAR::isError($res)) { + return 0; + } + + if($res->numRows()) { + return 0; + } else { + return 1; + } + +} + +// from MediaWiki install scripts + +function replacevars( $ins, $vars ) { + $varnames = array( + 'uts_mysql_db', 'uts_mysql_server', 'uts_mysql_user', 'uts_mysql_user_pass' + ); + + foreach ( $varnames as $var ) { + $ins = str_replace( '{$' . $var . '}', $vars[$var], $ins ); + $ins = str_replace( '/*$' . $var . '*/`', '`' . $vars[$var], $ins ); + $ins = str_replace( '/*$' . $var . '*/', $vars[$var], $ins ); + } + return $ins; +} + +# +# Read and execute SQL commands from a file +# +function dbsource($fname, $vars, $database = false) { + + + $fp = fopen( $fname, 'r' ); + if ( false === $fp ) { + print "Could not open \"{$fname}\".\n"; + exit(); + } + + $cmd = ""; + $done = false; + + while ( ! feof( $fp ) ) { + $line = trim( fgets( $fp, 1024 ) ); + $sl = strlen( $line ) - 1; + + if ( $sl < 0 ) { continue; } + if ( '-' == $line{0} && '-' == $line{1} ) { continue; } + + if ( ';' == $line{$sl} ) { + $done = true; + $line = substr( $line, 0, $sl ); + } + + if ( '' != $cmd ) { $cmd .= ' '; } + $cmd .= $line; + + if ( $done ) { + $cmd = replacevars( $cmd , $vars); + if( $database ) + $res = $database->query( $cmd ); + else + $res = mysql_query( $cmd ); + + if ( false === $res ) { + $err = mysql_error(); + print "Query \"{$cmd}\" failed with error code \"$err\".\n"; + exit(); + } + + $cmd = ''; + $done = false; + } + } + fclose( $fp ); +} +?> diff --git a/src/www/lib/utils.php.orig b/src/www/lib/utils.php.orig new file mode 100644 index 00000000..2aaf1668 --- /dev/null +++ b/src/www/lib/utils.php.orig @@ -0,0 +1,304 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> +"; echo var_dump($spmout); echo ""; + + if(count($spmout) < 2) { + return FALSE; + } + + for($i = 2; $i < count($spmout) -1; $i++) { + $tmp = split(":", $spmout[$i]); + $servers[trim($tmp[1])] = trim($tmp[2]); + } + + return $servers; +} + + +// validaçoes +// ra (hh:mm:ss) +// dec (+/-gg:mm:ss) +// gg 00-90 +// hh 00-12 +// mm 00-59 +// ss 00-59 + +function validate_dec($dec) { + + return ereg("[0-9]{2}:[0-5][0-9]:[0-5][0-9]", $dec); + +} + +function dumpSession() { + + echo "
"; + echo "
";
+  print_r($_SESSION);
+  echo "
"; + echo "
"; + +} + +function updateFilename($dir = "", $name = "", $index = "") { + + if($dir) + $_SESSION['bf_dir'] = $dir; + + if($name) + $_SESSION['bf_name'] = $name; + + if($index) + $_SESSION['bf_index'] = $index; + + $_SESSION['bf_fullpath'] = $_SESSION['bf_dir'] . "/" . $_SESSION['user'] . "/" . $_SESSION['inicio']; + + $_SESSION['bf_fullname'] = $_SESSION['bf_fullpath'] . "/" . $_SESSION['bf_name'] . "-" . strftime($_SESSION['bf_index'], time()); + +} + +function formatSize($size) { + + # format a file size adding kb, Mb, Gb + + $res = $size / 1024.0; + + if ($res >= 1024.0) { + + $res = $res / 1024.0; + + return floor($res) . " Mb"; + + } else { + + return floor($res) . " kb"; + + } + +} + +function byte_format($input, $dec=0) +{ + $prefix_arr = array("", "K", "M", "G", "T"); + $value = round($input, $dec); + while ($value>1024) + { + $value /= 1024; + $i++; + } + $return_str = round($value, $dec).$prefix_arr[$i]; + return $return_str; +} + +// Mainly based on code by: matt_DOTbevan_ATmarginsoftware_DOTcom +function mkdir_p($target) { + // If the path already exists && is a directory, all is well. + // If the path is not a directory, we've a problem. + if (file_exists($target)) { + if (!is_dir($target)) return false; + else return true; + } + + // Attempting to create the directory may clutter up our display. + if (@mkdir($target, 0777)) + return @chmod($target, 0777); + +} + +function doLogin($nome, $user, $user_id, $root, $db) { + + if(!$root) { + $sql = "INSERT INTO logged VALUES('$user_id')"; + $res =& $db->query($sql); + } + + if(PEAR::isError($res)) { + Header("Location: " . getError("index.php", "Nao foi possivel efetuar o login. Contate o administrador.")); + exit(0); + } + + session_start(); + + $_SESSION['nome'] = $nome; + $_SESSION['user'] = $user; + $_SESSION['user_id'] = $user_id; + $_SESSION['inicio'] = strftime("%Y%m%d-%H%M%Z", time()); + $_SESSION['root'] = $root; + + $_SESSION['log'] = array(); + $_SESSION['obj'] = array(); + $_SESSION['ra'] = array(); + $_SESSION['dec'] = array(); + $_SESSION['num_exp'] = array(); + $_SESSION['exp_time'] = array(); + $_SESSION['filter'] = array(); + $_SESSION['start_time'] = array(); + + updateFilename(getcwd() . "/data", "imagem", "%Y%m%d%H%M%S"); + + $userAreaCreated = 0; + + // create user image space + if(!file_exists($_SESSION['bf_dir'] . "/" . $_SESSION['user'])) + mkdir_p($_SESSION['bf_dir'] . "/" . $_SESSION['user'], 0777); + + if(mkdir_p($_SESSION['bf_dir'] ."/". $_SESSION['user'] ."/". $_SESSION['inicio'], 0777)) { + mkdir_p($_SESSION['bf_dir'] ."/". $_SESSION['user'] ."/". $_SESSION['inicio'] . "/thumbs", 0777); + $userAreaCreated = 1; + } + + Header("Location: home.php?userspace=" . $userAreaCreated); + +} + +function userAllowed($id, $db) { + + $agora = time(); + + $sql = "SELECT * FROM user_sched WHERE (user_id = $id) AND ((inicio <= $agora) AND (fim >= $agora))"; + $res =& $db->query($sql); + + if(PEAR::isError($res)) { + return 0; + } + + if($res->numRows()) { + return 1; + } else { + return 0; + } + +} + +function userUniq($id, $db) { + + $sql = "SELECT * FROM logged WHERE id = $id"; + $res =& $db->query($sql); + + if(PEAR::isError($res)) { + return 0; + } + + if($res->numRows()) { + return 0; + } else { + return 1; + } + +} + +// from MediaWiki install scripts + +function replacevars( $ins, $vars ) { + $varnames = array( + 'uts_mysql_db', 'uts_mysql_server', 'uts_mysql_user', 'uts_mysql_user_pass' + ); + + foreach ( $varnames as $var ) { + $ins = str_replace( '{$' . $var . '}', $vars[$var], $ins ); + $ins = str_replace( '/*$' . $var . '*/`', '`' . $vars[$var], $ins ); + $ins = str_replace( '/*$' . $var . '*/', $vars[$var], $ins ); + } + return $ins; +} + +# +# Read and execute SQL commands from a file +# +function dbsource($fname, $vars, $database = false) { + + + $fp = fopen( $fname, 'r' ); + if ( false === $fp ) { + print "Could not open \"{$fname}\".\n"; + exit(); + } + + $cmd = ""; + $done = false; + + while ( ! feof( $fp ) ) { + $line = trim( fgets( $fp, 1024 ) ); + $sl = strlen( $line ) - 1; + + if ( $sl < 0 ) { continue; } + if ( '-' == $line{0} && '-' == $line{1} ) { continue; } + + if ( ';' == $line{$sl} ) { + $done = true; + $line = substr( $line, 0, $sl ); + } + + if ( '' != $cmd ) { $cmd .= ' '; } + $cmd .= $line; + + if ( $done ) { + $cmd = replacevars( $cmd , $vars); + if( $database ) + $res = $database->query( $cmd ); + else + $res = mysql_query( $cmd ); + + if ( false === $res ) { + $err = mysql_error(); + print "Query \"{$cmd}\" failed with error code \"$err\".\n"; + exit(); + } + + $cmd = ''; + $done = false; + } + } + fclose( $fp ); +} +?> diff --git a/src/www/login.php b/src/www/login.php new file mode 100644 index 00000000..3fc1e80e --- /dev/null +++ b/src/www/login.php @@ -0,0 +1,77 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + +if(PEAR::isError($res)) { // DB error + Header("Location: " . getError("index.php", "Não foi possível contatar o observatório. Consulte o responsável.")); + exit(2); +} + +if(!$res->numRows()) { // usuário não encontrado + Header("Location: " . getError("index.php", "Senha ou usuário inválidos")); + exit(1); +} + +// OK.. usuario encontrado, checar senha +$res->fetchInto($data, DB_FETCHMODE_ASSOC); + +if($data['passwd'] == md5(trim($_POST['pass']))) { // OK, senha confere + + // checa se é administrador, se for, deixa passar, mesmo sem checar tempo e unicidade da sessao + if($data['root'] == 1) { + doLogin($data['nome'], $data['username'], $data['id'], 1, $db); + exit(0); + } + + if(userAllowed($data['id'], $db)) { // eu sei! poderia usar && (AND), mas para poder especificar o erro corretamente uso dois if's + + if(userUniq($data['id'], $db)) { + doLogin($data['nome'], $data['username'], $data['id'], 0, $db); + exit(0); + } else { + Header("Location: " . getError("index.php", "Já há uma sessão em andamento para este usuário.")); + exit(3); + } + + } else { + + Header("Location: " . getError("index.php", "Você não possuí tempo alocado para este momento. Consulte o responsável.")); + exit(3); + + } + +} else { /// OOps, senha errada. + Header("Location: " . getError("index.php", "Senha ou usuário inválidos.")); + exit(1); +} + +?> \ No newline at end of file diff --git a/src/www/logout.php b/src/www/logout.php new file mode 100644 index 00000000..7f09b47e --- /dev/null +++ b/src/www/logout.php @@ -0,0 +1,66 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>query($sql); + + if(PEAR::isError($res) || !$db->affectedRows()) { + Header("Location " . getError("home.php", "Não foi possível efetuar o logout, aguarde mais alguns instantes e tente novamente.")); + } else { + session_destroy(); + Header("Location: index.php"); + } + +} else { + + session_destroy(); + Header("Location: index.php"); + +} + +?> + + + + + + + + + diff --git a/src/www/opcoes.php b/src/www/opcoes.php new file mode 100644 index 00000000..f81900c2 --- /dev/null +++ b/src/www/opcoes.php @@ -0,0 +1,48 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + + + + + + diff --git a/src/www/root.php b/src/www/root.php new file mode 100644 index 00000000..8fa6c796 --- /dev/null +++ b/src/www/root.php @@ -0,0 +1,26 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> diff --git a/src/www/sky.php b/src/www/sky.php new file mode 100644 index 00000000..619b75dd --- /dev/null +++ b/src/www/sky.php @@ -0,0 +1,61 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?> + + + + +Telescópios na Escola - Céu + + + + + + +:: voltar ::

+&Lng=&Time=&BW=1&size=600&SL=1&SN=1"> +
+Developed and maintained by Chris Peat, Heavens-Above GmbH
+
+ + diff --git a/src/www/status.php b/src/www/status.php new file mode 100644 index 00000000..67691ed5 --- /dev/null +++ b/src/www/status.php @@ -0,0 +1,222 @@ + +// +// This file is part of UTS-www. +// UTS-www 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. +// +// UTS-www 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 +// + +?>setInteractive(0); +$ccd->connect(); + +$tel = new Tel('status'); +$tel->setInteractive(0); +$tel->connect(); + +$sync = new Sync('status'); +$sync->setInteractive(0); +$sync->connect(); + +// primeira vez? +if(!count($_SESSION['log'])) { + $primeiraVez = 1; +} else { + $primeiraVez = 0; +} + + +// estima o tempo da observacao +// tempo = apontamento + num_exp(tempo_leitura + tempo_exposicao) +// so perde tempo com isso, se houver observacao em andamento +$stat0 = $tel->isBusy(); +$stat1 = $ccd->isBusy(); + +if($stat0 || $stat1) { + + $nexp = intval($sync->getStatus("NEXP")); + $exp_time = intval($sync->getStatus("EXPTIME")); + + $cte_ap = UTS_POINTING_TIME; + $tempo_leitura = UTS_CCD_READ_TIME; + + $tempo = $cte_ap + (($tempo_leitura * $nexp) + ($nexp * $exp_time)); + + $ocupado = 1; + +} else { + + $tempo = 0; + $ocupado = 0; + +} + +$format = "parseInt('%Y'),parseInt('%m'),parseInt('%d'),parseInt('%H'),parseInt('%M'),parseInt('%S')"; +$agora = time(); +$curr = count($_SESSION['log']) - 1; +$countdown = strftime($format, ($agora + $tempo) - ($agora - $_SESSION['start_time'][$curr])); + + +$sync->disconnect(); +$tel->disconnect(); +$ccd->disconnect() + +?> + + + + +Telescópios na Escola ::: Estado da +observação + + + + + + + + +
Telescópios na Escola
+
+
+ +
+

Não há observações em andamento.

+
+ +
A T E N Ç Ã +O +

Aguarde, a observação está sendo +efetuada.

+
+

+

+
+

A seguinte observação +está sendo efetuada:

+

+ + + + + + + + + + + + + + + + + + + + + + + + +
Pedido # +
RA +
DEC +
Número de exposições +
Tempo de exposição +
Filtro +
+
+ +

::: voltar :::

+ + +