1
0
Fork 0

wmweather+: Remove from repository.

This dockapp is still maintained by its original upstream author, Brad
Jorsch, and a newer version (2.15) is available at [1].  Therefore, it is
not appropriate for the Window Maker dockapps repository.

[1] https://sourceforge.net/projects/wmweatherplus/
This commit is contained in:
Doug Torrance 2015-05-15 23:19:54 -05:00 committed by Carlos R. Mafra
parent 89c9512c8d
commit fdb596cd42
77 changed files with 0 additions and 9897 deletions

View file

@ -434,15 +434,6 @@ url = https://web.archive.org/web/20091027110712/http://geocities.com/jl1n/wmtz/
dockapps = 24
category = Date/Time
[wmweather+]
image = "wmweather+.png,wmweather+2.png,wmweather+4.png"
description = "wmweather+ will download the National Weather Serivce METAR bulletins, ANV and MRF forecasts, and any weather map for display in a WindowMaker dockapp. Think wmweather with a smaller font, forecasts, a weather map, and a sky condition display.
Please see the sourceforge page for the latest version."
url = https://sourceforge.net/projects/wmweatherplus/
dockapps = 112
category = General/Others
[wmWeather]
image = wmWeather.gif
description = "Shows local weather conditions."

View file

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -1,247 +0,0 @@
wmweather+ (2.12) unstable; urgency=low
* Remove curl handle from the multihandle before closing the file
descriptor and before doing the callbacks. Otherwise we might get another
completion message, which will cause double-free errors and such.
-- Brad Jorsch <anomie@users.sourceforge.net> Tue, 17 Aug 2010 15:27:37 -0400
wmweather+ (2.11) unstable; urgency=low
* Apply 01_wmweather+_patch_displaydelay.dpatch from Debian
* Fix Debian bug #419644 in a different way: First, change snprintf and
vsnprintf handling to be more like AC_FUNC_MALLOC handles malloc. Second,
just always call FUNC_VSNPRINTF_LIBOBJ instead of being conditional on
snprintf.
-- Brad Jorsch <anomie@users.sourceforge.net> Fri, 18 Jan 2008 10:30:05 -0500
wmweather+ (2.10) unstable; urgency=low
* Remove libwww, add libcurl.
-- Brad Jorsch <anomie@users.sourceforge.net> Sun, 06 Jan 2008 22:42:07 -0500
wmweather+ (2.9) unstable; urgency=low
* Add support for the new FW/SC distinction in some of the forecast data.
Also do it for METAR, even though the two are supposedly the same there.
* Fix some nasty double-free bugs in download.c if terminate_handler were to
be called before HTLoadAbsolute/HTPostAbsolute returned.
-- Brad Jorsch <anomie@users.sourceforge.net> Mon, 17 May 2004 23:55:48 -0400
wmweather+ (2.8) unstable; urgency=low
* The downloader now tracks active downloads, and refuses to start a second
download when one is already active for a particular target file. Also,
downloads now time out after 10 minutes.
-- Brad Jorsch <anomie@users.sourceforge.net> Mon, 29 Mar 2004 22:22:31 -0500
wmweather+ (2.7) unstable; urgency=low
* Oops, forgot to fix the manpage when the URIs changed in v2.5.
-- Brad Jorsch <anomie@users.sourceforge.net> Fri, 21 Nov 2003 20:55:07 -0500
wmweather+ (2.6) unstable; urgency=low
* Use atexit() to clean up downloaded files.
* Alter forecast parsers to be less picky. 'AVN' and 'MRF' are changing to
'GFS' and 'GFSX' on Dec 16, and looking for just "MOS GUIDANCE" instead of
"xxx MOS GUIDANCE" should work about as well.
-- Brad Jorsch <anomie@users.sourceforge.net> Fri, 21 Nov 2003 20:55:07 -0500
wmweather+ (2.5) unstable; urgency=low
* Added the "-display-mode" option. This fixes part of Debian bug #200110.
* Tack the PID on to downloaded files, so multiple instances of wmweather+
won't stomp on each other. This fixes the rest of Debian bug #200110
* Rewrote the longitude-guessing code, now it just depends on time_t being
an arithmetic type (which mkgmtime() did already).
* Replace the old b0rken/mktime.c with the one from GNU tar. The old one has
a SysVism that wasn't working too well for BSD people, who need the
replacement because mktime() on BSD fails for 'impossible' times (i.e. the
hour skipped when DST begins).
* Change forecast URIs, because NOAA changed them.
* Add a 'forget-warning-zones' option, which IMO adequately covers Debian
bug #214482. And it allows you to override zones on the command line too.
-- Brad Jorsch <anomie@users.sourceforge.net> Tue, 28 Oct 2003 13:35:24 -0500
wmweather+ (2.4) unstable; urgency=low
* Remove a bunch of unused variables.
* Initialize a few things the compiler can't tell will always be initialized
before they're used.
- dock.c update_dock(): i will be initialized if either j&1 or j&2, and
only used if j&3. j is not volatile, so this will always initialize i.
- forecast.c locate_current(): current is set to NULL at the beginning of
the function. curdiff is set whenever current is, and is only used when
current!=NULL.
* Added .nf commands to the manpage, so man won't complain about long
pseudo-URLs (Fixes Debian bug #184306).
* Fixed various assumptions about char signedness (i.e. I made them
explicitly signed char) (Fixes Debian bug #181245).
* Added multiple warning zones, so for example you can look at both kyz036
and kyc209 for warnings (Partially fixes Debian bug #185651).
- The summary isn't so much a warning summary, as a summary of the weather
over the past day or so.
- Unless those "warnings not in the expected place" were due to the kyc209
versus kyz036 issue, I can't determine where the files might actually
have been. Sorry.
* Updated some of the docs.
* autoconf changed the name of the malloc cache variable...
* Added a replacement mktime. Hopefully it works right.
-- Brad Jorsch <anomie@users.sourceforge.net> Sat, 22 Mar 2003 12:45:10 -0500
wmweather+ (2.3) unstable; urgency=low
* Fix a compiler warning, thanks to Martin Godisch
* Remove the debian directory at the request of the Debian maintainer; if
you want those files, they are available at debian.org
* Removed documentation of useless -geometry option
* Fixed crash on right-click when no warning zone was given
-- Brad Jorsch <anomie@users.sourceforge.net> Tue, 28 Jan 2003 12:47:07 -0500
wmweather+ (2.2) unstable; urgency=low
* It seems I forgot to create a b0rken/malloc.c
-- Brad Jorsch <anomie@users.sourceforge.net> Tue, 1 Oct 2002 16:36:12 -0400
wmweather+ (2.1) unstable; urgency=low
* Make the 'malformed location' error message more clear.
* Fix stupid crash in forecast.c (didn't wrap properly when iterating over
an array)
* Fix is_forecast_current, mktime wants 0-based month.
-- Brad Jorsch <anomie@users.sourceforge.net> Mon, 30 Sep 2002 15:02:29 -0400
wmweather+ (2.0) unstable; urgency=low
* In no particular order:
* Animations can now display a label indicating the percent being shown. The
forecast window uses this extensively.
* All URIs can now be changed via command line/config file options.
* Added ./configure checks for b0rken snprintf/vsnprintf.
* Added ETA forecasts. These are mixed in with the AVN forecasts in the
rotation, sorted by time.
* Added display of the forecast type, which shows up at the bottom of the
forecast window where wind chill, heat index, and so on appear.
* When not animating, the percent chance cutoff can be adjusted using the
mouse wheel (as mapped to buttons 4 and 5).
* Made all forecast and warning options optional. Thus, if you don't specify
e.g. avn-station, no AVN forecasts will be downloaded.
* Regularized options: -radar is now -radar-uri, and -zone is now
-warning-zone.
* Support for POST for the radar image.
* Support for system-wide configs.
* -email is now optional too.
* Lots of code cleanups.
-- Brad Jorsch <anomie@users.sourceforge.net> Sun, 22 Sep 2002 14:25:58 -0400
wmweather+ (1.11) unstable; urgency=low
* Fix a few URIs.
* Fix rounding errors in the pressure conversion functions (returned floats
don't need to be rounded, damnit!)
* Fix a bug in the warning code (displaying the wrong warnings)
-- Brad Jorsch <anomie@users.sourceforge.net> Sun, 15 Sep 2002 18:35:18 -0400
wmweather+ (1.10) unstable; urgency=low
* Handle libwww fds going bad, so the select will still function.
-- Brad Jorsch <anomie@users.sourceforge.net> Sun, 8 Sep 2002 11:22:05 -0400
wmweather+ (1.9) unstable; urgency=low
* Remove dependancy on libftp, we use libwww's FTP module now.
* Rewrote the file downloader to take advantage of libwww's callbacks
(instead of waiting for the file to appear).
* Adjusted the m4 files to be more informative, and to check for libwraster
in /usr/X11R6 (stupid place for it, but oh well).
* Add some international METAR support. Mainly things reported in different
units.
* Make dock.c signals safe!
-- Brad Jorsch <anomie@users.sourceforge.net> Thu, 5 Sep 2002 22:01:42 -0400
wmweather+ (1.8) unstable; urgency=low
* Added failure conditions to configure.ac.
* Actually use LIBOBJS. Change to automake-1.6 since 1.4 is b0rken.
-- Brad Jorsch <anomie@users.sourceforge.net> Sun, 1 Sep 2002 20:31:55 -0400
wmweather+ (1.7) unstable; urgency=low
* Initial Debianization
* Autoconfiscated
* Updated wmgeneral from wmpasman
* Fixed a bug in createXBMfromXPM
* Use createXBMfromXPM to get the mask. It's easier.
-- Brad Jorsch <anomie@users.sourceforge.net> Thu, 15 Aug 2002 15:31:46 -0400
version 1.6
* Apparently, AVN uses JUNE instead of JUN. Let's guess it uses JULY too
while we're at it.
-- Tue, 18 Jun 2002 08:52:27 -0500
version 1.5
* Fixed heat index so it'll display when the temp is below 100 ;)
-- Tue, 16 Apr 2002 21:22:07 -0500
version 1.4
* Changed the METAR display around a little bit. Local time is now primary.
* Changed the warning output to indicate the file the warning is from.
* minor code cleanups
-- Sat, 8 Sep 2001 17:14:32 -0500
version 1.3
* Display a moon instead of a sun when it's supposed to be night. We even
calculate a rough moon phase and calculate the solar zenith to determine
whether the sun is up or not.
* Adjusted some of the graphics again. master is even smaller now!
* Make the forecast bottom line change priority every few seconds (in other
words, if more than one line could be displayed it will alternate between
them).
-- Thu, 6 Sep 2001 22:55:10 -0500
version 1.2
* Fixed SEPT bug
-- Sat, 1 Sep 2001 21:10:22 -0500
version 1.1
* Made the master xpm smaller.
* Changed the font handling so only 1 copy of the characters is needed.
* Changed some of the wmgeneral stuff more.
-- Tue, 28 Aug 2001 12:46:54 -0500
version 1.0
* Wrote the thing over the past few weeks. I probably should have been
adding changelog entries all along, oh well.
-- Tue, 21 Aug 2001 18:36:32 -0500

View file

@ -1,74 +0,0 @@
Hints for wmweather+
(blatantly copied from the Hints for WMPPP ;)
Generic
--------------------------------------------------------------
wmweather+ supports various commandline options, 'wmweather+ -h' prints
help about them. Actually, any unrecognized option will print the same help.
WindowMaker
--------------------------------------------------------------
WindowMaker users simply drag and drop the wmweather+ dock.app on
the WindowMaker Dock (preferred) or the Clip.
Now press the rightmouse button on wmweather+'s outer edges and
select "Settings..." from the popup menu that appears.
Enable the 'Start when WindowMaker is started' option, then
click on the 'OK' button in the Docked Applications Panel.
Afterstep
--------------------------------------------------------------
Afterstep users put something like this in their .steprc
"Wharf wmweather+ - MaxSwallow "wmweather+" wmweather+ &"
Other WindowManagers
--------------------------------------------------------------
For other windowmanagers, wmweather+ runs nicely as a 64x64
pixel shaped icon on your desktop.
BTW, FVWM can swallow it too, so we've heard ;-)
Dragging wmweather+
--------------------------------------------------------------
Be sure to drag wmweather+ on it's outer edges, wmweather+ is a bit
picky due to the large gfx pixmap it keeps ;-)
Network Usage
--------------------------------------------------------------
wmweather+ is really rather useless without network access, since it
has to download everything it wants to display...
Command Line
--------------------------------------------------------------
Remember to quote your arguments properly. For example, this command:
wmweather+ -s KORD -location 48N 78W
Will be interpreted as passing the value "48N" to the "-location" option.
wmweather+ will then complain that the location is badly formed. Instead, try
quoting any options containing spaces like this:
wmweather+ -s KORD -location "48N 78W"
Config File
--------------------------------------------------------------
You may have noticed wmweather+ has an insane number of command line
options. You may also have noticed the comment in the manpage along the
lines of "The configuration file is simply one option (with value if
necessary) per line, leading dashes optional. Empty lines and lines
beginning with the '#' character are ignored." This means just what it says:
your configuration file should contain your command line options, with one
option per line.
See the file example.conf for a sample configuration file.
Font Size
--------------------------------------------------------------
If you think the fonts are too small, you are welcome to redesign the
display and the font. Please keep in mind the following constraints:
* The window size is limited to 64x64. Taking off the border, that means
you get about 54x54 pixels to work with.
* I require the app to display at least the station ID, the effective
date and time of the observarion/forecast, the weather graphic, the
temperature (and high and low for forecasts), the relative humidity, and
the wind speed+direction. At least one extra line is needed for
pressure/heat index/wind chill/precip amount as appropriate.

View file

@ -1,21 +0,0 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = b0rken m4 wmgeneral
bin_PROGRAMS = wmweather+
wmweather__SOURCES = animation.c animation.h avn.c avn.h convert.c convert.h \
die.c die.h diff.c diff.h dock.c dock.h download.c download.h \
eta.c eta.h font.c font.h forecast.c forecast.h getLine.c getLine.h \
metar.c metar.h moon.c moon.h mrf.c mrf.h radar.c radar.h subst.c \
subst.h sunzenith.c sunzenith.h warnings.c warnings.h wmweather+.c \
wmweather+.h characters.xpm wmweather_master.xpm
wmweather__LDADD = wmgeneral/libwmgeneral.a wmgeneral/libwmgeneral-x11.a b0rken/libb0rken.a @XLIBS@
man_MANS = wmweather+.1
EXTRA_DIST = HINTS bootstrap example.conf $(man_MANS)
reallyclean: distclean
-rm -rf autom4te.cache
-rm Makefile.in */Makefile.in aclocal.m4 config.h.in* config.guess config.sub configure install-sh ltmain.sh missing mkinstalldirs stamp-h.in

View file

@ -1,43 +0,0 @@
COMPILATION
===========
You will need the following libraries (with proper headers) installed
in order to compile this app. If you're using Debian, try packages like
the ones indicated.
libwraster libwraster2, libwraster2-dev
libpcre libpcre3, libpcre3-dev
libm libc6, libc6-dev
libXpm xlibs, xlibs-dev
libX11 xlibs, xlibs-dev
libcurl libcurl4, libcurl4-dev
For the most part, you should just have to do "./configure && make install"
and the thing will build everything and install it.
The only really interesting compile-time parameters would be the P and X
variables in animation.c, if you don't like the 10-second cycle or
something.
If you get errors about a missing libwraster, check the following:
1) Do you have both the library AND the header installed? If the command
"locate wraster.h" doesn't come back with a header file in one of the
normal places, you'll have trouble.
2) Check for a line like the following in your ./configure output:
checking if libwraster is wanted... yes: libraries /usr/lib includes /usr/include
In this case, we will look for the files /usr/lib/libwraster.so and
/usr/include/wraster.h. If for some reason you have these files in a
place other than ./configure looks for them, use the --with-libwraster
option to specify the proper prefix. If you have something really dumb
like /usr/include/wraster.h and /usr/X11R6/lib/libwraster.so, try adding
specific -I and -L options to your CFLAGS variable.
If you get errors about a missing pcre.h, and you have your header in
/usr/include/pcre/pcre.h instead of /usr/include/pcre.h, you will have to
add "-I/usr/include/pcre" to your CFLAGS variable when running ./configure.
If you get an error about anything missing in the b0rken subdirectory, the
problem is most likely that some library function or another is broken on
your system, configure detected this fact, a replacement was requested, and
no replacement is available. You are welcome to submit a patch.
For run-time hints, please see the HINTS file.

View file

@ -1,138 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "wmgeneral/wmgeneral-x11.h"
#include "wmgeneral/xpm_trans.h"
#include "wmweather+.h"
#include "animation.h"
#include "moon.h"
#include "font.h"
#define P 4 /* Percent to increment by */
#define X 4 /* Frames to wait before incrementing */
#define M (((100/P)+1)*X)
static int heights[5]={ 11, 12, 14, 14, 19 };
void SetAnimation(struct animation *a, int x, int y, int sky, int obs, int vis,
int frz, int snow, int rain, int tstorm, int svtstorm,
double moon){
int i;
a->changed=1;
a->active=1;
a->x=x;
a->y=y;
if(sky>=0 && sky<6) a->sky=sky*27;
else a->sky=-1;
if(vis<7 && obs>0 && vis>0 && obs<4){
a->obs=obs*27-27;
a->vis=256-236*(vis-1)/6;
} else a->vis=0;
a->items[0]=frz;
a->items[1]=snow;
a->items[2]=rain;
a->items[3]=tstorm;
a->items[4]=svtstorm;
for(i=0; i<5; i++){
if(a->items[i]==0) continue;
if(a->items[i]%P) a->items[i]=a->items[i]/P+1;
else a->items[i]=a->items[i]/P;
a->items[i]*=X;
if(a->items[i]!=0) a->changed=1;
}
a->ac=0;
a->moon=moon;
}
void DoAnimation(struct animation *a){
int i;
int top, h;
/* Turned off? */
if(!a->active) return;
/* Any parameters changed? If yes, draw */
if(a->changed) goto doit;
/* Nothing changed, quit if not animating */
if(!a->do_animate) return;
/* We are animating. If it's the first frame of a cycle, draw it */
a->ac++; if(a->ac>=M){ a->ac=0; goto doit; }
/* Not the first frame, see if anything changed. If so, draw it */
for(i=0; i<5; i++){
if(a->ac>=a->items[i] && a->ac<=a->items[i]+X) goto doit;
}
/* Just draw the counter... */
if(a->show_counter) goto do_counter;
/* Nothing to draw, quit */
return;
doit:
if(a->min_pct!=a->old_pct){
if(a->min_pct%P) a->pct=(a->min_pct/P+1)*X;
else a->pct=(a->min_pct/P)*X;
a->old_pct=a->min_pct;
}
a->changed=0;
if(!a->do_animate) a->ac=a->pct;
copyPixmapArea(124, 18, 26, 31, a->x, a->y);
if(a->sky!=-1){
copySunMoon(a->x, a->y, a->moon);
combineWithTrans(a->sky, 64, 26, 25, a->x, a->y);
}
if(a->vis>0) combineWithOpacity(a->obs, 89, 26, 25, a->x, a->y, a->vis);
for(i=0; i<5; i++){
if(a->items[i]==0 || a->ac>=a->items[i]+X) continue;
h=heights[i];
top=h;
if(a->ac<X){
h=h*a->ac/X;
} else if(a->ac>=a->items[i] && a->ac<a->items[i]+X){
h-=h*(a->ac%X)/X;
top=h;
}
combineWithTrans(i*27, 129-top, 26, h, a->x, a->y+31-top);
}
if(a->show_counter){{
char foo[5];
do_counter:
if(!a->do_animate){
snprintf(foo, 5, "%d%%", a->min_pct);
} else {
for(i=0; i<100 && a->ac>((i+P-1)/P)*X; i++);
snprintf(foo, 5, "%d%%", i);
}
i=GetStringWidth(foo);
copyPixmapArea(124, 18, i+2, 7, a->x+(26-i-2)/2, a->y+12);
DrawString(a->x+(26-i)/2, a->y+13, foo, 2);
}}
}

View file

@ -1,23 +0,0 @@
struct animation {
int do_animate:1; /* animate, or use min_pct? */
int show_counter:1; /* display the percentage counter? */
unsigned int min_pct:7; /* when not animating, show any occurence with more
than this percent chance */
int changed:1; /* Set this if you change any of the above */
int active:1;
int x, y;
int sky;
int obs;
int vis;
int items[5];
int ac;
double moon;
unsigned int old_pct:7;
int pct;
};
void SetAnimation(struct animation *a, int x, int y, int sky, int obs, int vis,
int frz, int snow, int rain, int tstorm, int svtstorm,
double moon);
void DoAnimation(struct animation *a);

View file

@ -1,373 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include "wmweather+.h"
#include "forecast.h"
#include "getLine.h"
#include "convert.h"
#include "download.h"
#include "diff.h"
#include "die.h"
#include "sunzenith.h"
#include "moon.h"
#include "subst.h"
/* Important variables */
#define AVN_MAX 21
static time_t avn_time=0;
static char *avn_file=NULL;
static char *avn_newfile=NULL;
static char *avn_req[2]={ NULL, NULL };
static struct forecast forecasts[AVN_MAX];
/********* init functions ************/
static int parse_avn(char *file);
static void reset_avn(void){
int i;
for(i=0; i<AVN_MAX; i++) reset_forecast(&forecasts[i]);
}
void init_avn(void){
char *e;
int i;
struct subst_val subs[]={
{ 's', STRING, &avn_station },
{ 0, 0, 0 }
};
strncpy(bigbuf, avn_station, BIGBUF_LEN-14);
bigbuf[BIGBUF_LEN-14]='\0';
for(e=bigbuf; *e!='\0'; e++);
strcpy(e, ".avn.txt");
avn_file=get_pid_filename(bigbuf);
strcpy(e, ".new-avn.txt");
avn_newfile=get_pid_filename(bigbuf);
if((avn_req[0]=subst(avn_uri, subs))==NULL) die("init_avn");
if(avn_post!=NULL && (avn_req[1]=subst(avn_post, subs))==NULL) die("init_avn");
avn_time=0;
/* Remove stale file */
unlink(avn_file);
unlink(avn_newfile);
reset_avn();
for(i=0; i<AVN_MAX; i++) add_forecast(&forecasts[i], "AVN", avn_station);
}
/********* download functions ************/
static void avn_callback(char *filename, void *v){
struct stat statbuf;
if(stat(avn_newfile, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& diff(avn_newfile, avn_file) && parse_avn(avn_newfile)){
avn_time=find_next_time(avn_newfile, "MOS GUIDANCE", 720);
rename(avn_newfile, avn_file);
} else {
unlink(avn_newfile);
if(!parse_avn(avn_file)) reset_avn();
}
}
}
void avn_cleanup(void){
if(avn_file==NULL) return;
unlink(avn_newfile);
unlink(avn_file);
}
void update_avn(int force){
time_t t;
if(avn_file==NULL) return;
t=time(NULL)/60;
if(!force && avn_time>t) return;
avn_time=find_next_time(avn_file, "MOS GUIDANCE", 15);
download_file(avn_newfile, avn_req[0], avn_req[1], force?DOWNLOAD_KILL_OTHER_REQUESTS:0, avn_callback, NULL);
}
/********* parse functions ************/
#define NEXT(s) free(s); \
len=getLine(&s, fp); \
if(strstr(s, "</PRE>")!=NULL) len=0;
#define DIE() return (free(s), fclose(fp), 0)
#define SPLIT(s) { \
ID[0]=s[0]; \
ID[1]=s[1]; \
ID[2]=s[2]; \
ID[3]='\0'; \
for(n=0, c=s+4; c<s+len && n<AVN_MAX; n++, c+=3){ \
split[n][0]=c[0]; \
split[n][1]=c[1]; \
split[n][2]=c[2]; \
split[n][3]='\0'; \
} \
}
#define ASSIGN(field) \
for(n=0; n<AVN_MAX; n++) forecasts[n].field=atoi(split[n]);
#define ASSIGN2(field, inval) \
for(n=0; n<AVN_MAX; n++){ \
i=atoi(split[n]); \
if(i!=inval) forecasts[n].field=i; \
}
static int parse_avn(char *file){
FILE *fp;
char *s, *c;
int len;
int mon, day;
int h, i=0, j, k, m, n, x, y, z;
char ID[4];
char split[AVN_MAX][4];
reset_avn();
if((fp=fopen(file, "r"))==NULL) return 0;
/* Look for something like an AVN coded forecast */
c=NULL;
while(!feof(fp)){
len=getLine(&s, fp);
if((c=strstr(s, "MOS GUIDANCE"))!=NULL) break;
free(s);
}
if(c==NULL) return (fclose(fp), 0);
c=strchr(c, '/');
if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
m=atoi(c-2);
c=strchr(c+1, '/');
if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
y=atoi(c+1)-1900;
NEXT(s);
if(len<10) DIE();
if(strncmp(s, "DT ", 3)) DIE();
mon=13;
c=s;
i=4;
while(mon>12){
c=strchr(c+1, '/');
if(c==NULL) DIE();
for(mon=1; mon<=12; mon++){
if(!strncmp(c+1, monthnames[mon], 3) && isspace(*(c+4))) break;
if(!strncmp(c+1, monthnames2[mon], 4) && isspace(*(c+5))){
i=5;
break;
}
}
}
day=atoi(c+i);
if(day<1) DIE();
if(c>s+4) day--;
if(mon<m) y++;
NEXT(s);
if(len<10) DIE();
if(strncmp(s, "HR ", 3)) DIE();
x=day;
m=mon;
SPLIT(s);
for(n=0; n<AVN_MAX; n++){
i=atoi(split[n]);
if(i==0){
x++;
fix_date(&mon, &x, &y, NULL);
}
m=mon;
j=x;
z=y;
h=utc2local(i*100, &m, &j, &z, &k)/100;
forecasts[n].month=m;
forecasts[n].day=j;
forecasts[n].year=z;
forecasts[n].hour=h;
forecasts[n].wday=k;
if(latitude!=999 && calcSolarZenith(latitude, longitude, y, mon, x, i*60)>90)
forecasts[n].moon=calc_moon(m, j, z, h*100);
}
while(1){
NEXT(s);
if(len<=10) break;
SPLIT(s);
if(!strcmp(ID, "X/N")) j=1;
else if(!strcmp(ID, "N/X")) j=2;
else j=0;
if(j!=0){
for(n=0; n<AVN_MAX; n++){
if(!isdigit(split[n][2])) continue;
i=atoi(split[n]);
k=day+(j>>1);
for(m=0; m<AVN_MAX; m++){
if((j&1)==1 &&
((forecasts[m].day==k-1 && forecasts[m].hour>=19)
|| (forecasts[m].day==k && forecasts[m].hour<19)))
forecasts[m].high=i;
if((j&1)==0 &&
((forecasts[m].day==k-1 && forecasts[m].hour>=8)
|| (forecasts[m].day==k && forecasts[m].hour<8)))
forecasts[m].low=i;
}
j++;
}
continue;
}
if(!strcmp(ID, "TMP")){
ASSIGN(temp);
continue;
}
if(!strcmp(ID, "DPT")){
ASSIGN(dewpt);
continue;
}
if(!strcmp(ID, "WDR")){
for(n=0; n<AVN_MAX; n++){
i=atoi(split[n]);
if(i==99) forecasts[n].winddir=0;
else forecasts[n].winddir=((int)((i+1.125)/2.25))%16+1;
}
continue;
}
if(!strcmp(ID, "WSP")){
ASSIGN2(windspeed, 99);
continue;
}
if(!strcmp(ID, "P06")){
for(m=0; m<AVN_MAX; m++){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]);
if(i!=999){
forecasts[m].pcp_total=i;
/* AVN_MAX-2 because the last 2
* are already 6-hour intervals */
if(m>0 && m<AVN_MAX-2) forecasts[m-1].pcp_total=i;
}
}
continue;
}
if(!strcmp(ID, "T06")){
for(m=1; m<AVN_MAX; m+=2){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]); if(i==999) i=0;
j=atoi(split[m+1]+1); if(j==99) j=0;
j=i*j/100;
forecasts[m].tstorm=forecasts[m+1].tstorm=i;
forecasts[m].svtstorm=forecasts[m+1].svtstorm=j;
}
continue;
}
if(!strcmp(ID, "Q06")){
for(m=0; m<AVN_MAX; m++){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]);
if(i!=999){
forecasts[m].precipamt=i;
/* AVN_MAX-2 because the last 2
* are already 6-hour intervals */
if(m>0 && m<AVN_MAX-2) forecasts[m-1].precipamt=i;
}
}
continue;
}
if(!strcmp(ID, "SNW")){
for(m=0; m<AVN_MAX; m++){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]);
if(i!=9){
j=forecasts[m].hour;
k=forecasts[m].day;
for(n=m; n>=0; n--){
if(forecasts[n].day<k && forecasts[n].hour<j) break;
forecasts[n].snowamt=i;
}
}
}
continue;
}
if(!strcmp(ID, "CLD")){
for(m=0; m<AVN_MAX; m++){
if(split[m][1]=='C') forecasts[m].sky=0;
if(split[m][1]=='F') forecasts[m].sky=1;
if(split[m][1]=='S') forecasts[m].sky=2;
if(split[m][1]=='B') forecasts[m].sky=3;
if(split[m][1]=='O') forecasts[m].sky=4;
}
continue;
}
if(!strcmp(ID, "VIS")){
ASSIGN2(vis, 9);
continue;
}
if(!strcmp(ID, "OBV")){
for(m=0; m<AVN_MAX; m++){
if(split[m][2]=='N') forecasts[m].obs=0;
if(split[m][2]=='R' || split[m][2]=='G') forecasts[m].obs=1;
if(split[m][2]=='Z') forecasts[m].obs=2;
if(split[m][2]=='L') forecasts[m].obs=3;
}
continue;
}
if(!strcmp(ID, "POZ")){
ASSIGN2(frz, 999);
continue;
}
if(!strcmp(ID, "POS")){
ASSIGN2(snow, 999);
continue;
}
}
free(s);
fclose(fp);
for(m=0; m<AVN_MAX; m++){
forecasts[m].rh=rh_F(forecasts[m].temp, forecasts[m].dewpt);
forecasts[m].heatindex=heatindex_F(forecasts[m].temp, forecasts[m].rh);
forecasts[m].windchill=windchill_F(forecasts[m].temp, forecasts[m].windspeed);
forecasts[m].rain=93-forecasts[m].frz-forecasts[m].snow;
forecasts[m].rain=forecasts[m].rain*forecasts[m].pcp_total/93;
forecasts[m].snow=forecasts[m].snow*forecasts[m].pcp_total/93;
forecasts[m].frz=forecasts[m].frz*forecasts[m].pcp_total/93;
}
return 1;
}
#undef NEXT
#undef DIE
#undef SPLIT
#undef ASSIGN
#undef ASSIGN2

View file

@ -1,8 +0,0 @@
#ifndef AVN_H
#define AVN_H
void init_avn(void);
void update_avn(int force);
void avn_cleanup(void);
#endif

View file

@ -1,3 +0,0 @@
noinst_LIBRARIES = libb0rken.a
libb0rken_a_SOURCES =
libb0rken_a_LIBADD = @LIBOBJS@

View file

@ -1 +0,0 @@
/* We never really use lstat, so... */

View file

@ -1,15 +0,0 @@
/* Version of malloc that avoids the malloc(0) bug */
#if HAVE_CONFIG_H
# include "config.h"
#endif
#undef malloc
#include <sys/types.h>
void *malloc();
void *rpl_malloc(size_t size){
if(size==0) size=1;
return malloc(size);
}

View file

@ -1,13 +0,0 @@
/* Cheapo version of memcmp */
#include <stdlib.h>
int memcmp(const void *s1, const void *s2, size_t n){
int i, j;
for(i=0; i<n; i++){
j=((unsigned char *)s1)[i]-((unsigned char *)s2)[i];
if(j) return j;
}
return 0;
}

View file

@ -1,527 +0,0 @@
/* Convert a `struct tm' to a time_t value.
Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Paul Eggert (eggert@twinsun.com).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
/* Define this to have a standalone program to test this implementation of
mktime. */
/* #define DEBUG 1 */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef _LIBC
# define HAVE_LIMITS_H 1
# define STDC_HEADERS 1
#endif
/* Assume that leap seconds are possible, unless told otherwise.
If the host has a `zic' command with a `-L leapsecondfilename' option,
then it supports leap seconds; otherwise it probably doesn't. */
#ifndef LEAP_SECONDS_POSSIBLE
# define LEAP_SECONDS_POSSIBLE 1
#endif
#include <sys/types.h> /* Some systems define `time_t' here. */
#include <time.h>
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#if DEBUG
# include <stdio.h>
# if STDC_HEADERS
# include <stdlib.h>
# endif
/* Make it work even if the system's libc has its own mktime routine. */
# define mktime my_mktime
#endif /* DEBUG */
#ifndef __P
# if defined __GNUC__ || (defined __STDC__ && __STDC__)
# define __P(args) args
# else
# define __P(args) ()
# endif /* GCC. */
#endif /* Not __P. */
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* The extra casts work around common compiler bugs. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
It is necessary at least when t == time_t. */
#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
#ifndef INT_MIN
# define INT_MIN TYPE_MINIMUM (int)
#endif
#ifndef INT_MAX
# define INT_MAX TYPE_MAXIMUM (int)
#endif
#ifndef TIME_T_MIN
# define TIME_T_MIN TYPE_MINIMUM (time_t)
#endif
#ifndef TIME_T_MAX
# define TIME_T_MAX TYPE_MAXIMUM (time_t)
#endif
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#ifndef __isleap
/* Nonzero if YEAR is a leap year (every 4 years,
except every 100th isn't, and every 400th is). */
# define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#endif
/* How many days come before each month (0-12). */
const unsigned short int __mon_yday[2][13] =
{
/* Normal years. */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/* Leap years. */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
#ifdef _LIBC
# define my_mktime_localtime_r __localtime_r
#else
/* If we're a mktime substitute in a GNU program, then prefer
localtime to localtime_r, since many localtime_r implementations
are buggy. */
static struct tm *
my_mktime_localtime_r (const time_t *t, struct tm *tp)
{
struct tm *l = localtime (t);
if (! l)
return 0;
*tp = *l;
return tp;
}
#endif /* ! _LIBC */
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
measured in seconds, ignoring leap seconds.
YEAR uses the same numbering as TM->tm_year.
All values are in range, except possibly YEAR.
If TP is null, return a nonzero value.
If overflow occurs, yield the low order bits of the correct answer. */
static time_t
ydhms_tm_diff (int year, int yday, int hour, int min, int sec,
const struct tm *tp)
{
if (!tp)
return 1;
else
{
/* Compute intervening leap days correctly even if year is negative.
Take care to avoid int overflow. time_t overflow is OK, since
only the low order bits of the correct time_t answer are needed.
Don't convert to time_t until after all divisions are done, since
time_t might be unsigned. */
int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
int a100 = a4 / 25 - (a4 % 25 < 0);
int b100 = b4 / 25 - (b4 % 25 < 0);
int a400 = a100 >> 2;
int b400 = b100 >> 2;
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
time_t years = year - (time_t) tp->tm_year;
time_t days = (365 * years + intervening_leap_days
+ (yday - tp->tm_yday));
return (60 * (60 * (24 * days + (hour - tp->tm_hour))
+ (min - tp->tm_min))
+ (sec - tp->tm_sec));
}
}
/* Use CONVERT to convert *T to a broken down time in *TP.
If *T is out of range for conversion, adjust it so that
it is the nearest in-range value and then convert that. */
static struct tm *
ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
time_t *t, struct tm *tp)
{
struct tm *r;
if (! (r = (*convert) (t, tp)) && *t)
{
time_t bad = *t;
time_t ok = 0;
struct tm tm;
/* BAD is a known unconvertible time_t, and OK is a known good one.
Use binary search to narrow the range between BAD and OK until
they differ by 1. */
while (bad != ok + (bad < 0 ? -1 : 1))
{
time_t mid = *t = (bad < 0
? bad + ((ok - bad) >> 1)
: ok + ((bad - ok) >> 1));
if ((r = (*convert) (t, tp)))
{
tm = *r;
ok = mid;
}
else
bad = mid;
}
if (!r && ok)
{
/* The last conversion attempt failed;
revert to the most recent successful attempt. */
*t = ok;
*tp = tm;
r = tp;
}
}
return r;
}
/* Convert *TP to a time_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
compared to what the result would be for UTC without leap seconds.
If *OFFSET's guess is correct, only one CONVERT call is needed. */
time_t
__mktime_internal (struct tm *tp,
struct tm *(*convert) (const time_t *, struct tm *),
time_t *offset)
{
time_t t, dt, t0, t1, t2;
struct tm tm;
/* The maximum number of probes (calls to CONVERT) should be enough
to handle any combinations of time zone rule changes, solar time,
leap seconds, and oscillations around a spring-forward gap.
POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
int remaining_probes = 6;
/* Time requested. Copy it in case CONVERT modifies *TP; this can
occur if TP is localtime's returned value and CONVERT is localtime. */
int sec = tp->tm_sec;
int min = tp->tm_min;
int hour = tp->tm_hour;
int mday = tp->tm_mday;
int mon = tp->tm_mon;
int year_requested = tp->tm_year;
int isdst = tp->tm_isdst;
/* Ensure that mon is in range, and set year accordingly. */
int mon_remainder = mon % 12;
int negative_mon_remainder = mon_remainder < 0;
int mon_years = mon / 12 - negative_mon_remainder;
int year = year_requested + mon_years;
/* The other values need not be in range:
the remaining code handles minor overflows correctly,
assuming int and time_t arithmetic wraps around.
Major overflows are caught at the end. */
/* Calculate day of year from year, month, and day of month.
The result need not be in range. */
int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
[mon_remainder + 12 * negative_mon_remainder])
+ mday - 1);
int sec_requested = sec;
#if LEAP_SECONDS_POSSIBLE
/* Handle out-of-range seconds specially,
since ydhms_tm_diff assumes every minute has 60 seconds. */
if (sec < 0)
sec = 0;
if (59 < sec)
sec = 59;
#endif
/* Invert CONVERT by probing. First assume the same offset as last time.
Then repeatedly use the error to improve the guess. */
tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
for (t = t1 = t2 = t0 + *offset;
(dt = ydhms_tm_diff (year, yday, hour, min, sec,
ranged_convert (convert, &t, &tm)));
t1 = t2, t2 = t, t += dt)
if (t == t1 && t != t2
&& (isdst < 0 || tm.tm_isdst < 0
|| (isdst != 0) != (tm.tm_isdst != 0)))
/* We can't possibly find a match, as we are oscillating
between two values. The requested time probably falls
within a spring-forward gap of size DT. Follow the common
practice in this case, which is to return a time that is DT
away from the requested time, preferring a time whose
tm_isdst differs from the requested value. In practice,
this is more useful than returning -1. */
break;
else if (--remaining_probes == 0)
return -1;
/* If we have a match, check whether tm.tm_isdst has the requested
value, if any. */
if (dt == 0 && isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
{
/* tm.tm_isdst has the wrong value. Look for a neighboring
time with the right value, and use its UTC offset.
Heuristic: probe the previous three calendar quarters (approximately),
looking for the desired isdst. This isn't perfect,
but it's good enough in practice. */
int quarter = 7889238; /* seconds per average 1/4 Gregorian year */
int i;
/* If we're too close to the time_t limit, look in future quarters. */
if (t < TIME_T_MIN + 3 * quarter)
quarter = -quarter;
for (i = 1; i <= 3; i++)
{
time_t ot = t - i * quarter;
struct tm otm;
ranged_convert (convert, &ot, &otm);
if (otm.tm_isdst == isdst)
{
/* We found the desired tm_isdst.
Extrapolate back to the desired time. */
t = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm);
ranged_convert (convert, &t, &tm);
break;
}
}
}
*offset = t - t0;
#if LEAP_SECONDS_POSSIBLE
if (sec_requested != tm.tm_sec)
{
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
if (! (*convert) (&t, &tm))
return -1;
}
#endif
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
{
/* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
so check for major overflows. A gross check suffices,
since if t has overflowed, it is off by a multiple of
TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
the difference that is bounded by a small value. */
double dyear = (double) year_requested + mon_years - tm.tm_year;
double dday = 366 * dyear + mday;
double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
/* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
correct results, ie., it erroneously gives a positive value
of 715827882. Setting a variable first then doing math on it
seems to work. (ghazi@caip.rutgers.edu) */
const time_t time_t_max = TIME_T_MAX;
const time_t time_t_min = TIME_T_MIN;
if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
return -1;
}
*tp = tm;
return t;
}
static time_t localtime_offset;
/* Convert *TP to a time_t value. */
time_t
mktime (tp)
struct tm *tp;
{
#ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
#endif
return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
}
#ifdef weak_alias
weak_alias (mktime, timelocal)
#endif
#if DEBUG
static int
not_equal_tm (a, b)
struct tm *a;
struct tm *b;
{
return ((a->tm_sec ^ b->tm_sec)
| (a->tm_min ^ b->tm_min)
| (a->tm_hour ^ b->tm_hour)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_mon ^ b->tm_mon)
| (a->tm_year ^ b->tm_year)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_yday ^ b->tm_yday)
| (a->tm_isdst ^ b->tm_isdst));
}
static void
print_tm (tp)
struct tm *tp;
{
if (tp)
printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec,
tp->tm_yday, tp->tm_wday, tp->tm_isdst);
else
printf ("0");
}
static int
check_result (tk, tmk, tl, lt)
time_t tk;
struct tm tmk;
time_t tl;
struct tm *lt;
{
if (tk != tl || !lt || not_equal_tm (&tmk, lt))
{
printf ("mktime (");
print_tm (&tmk);
printf (")\nyields (");
print_tm (lt);
printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
return 1;
}
return 0;
}
int
main (argc, argv)
int argc;
char **argv;
{
int status = 0;
struct tm tm, tmk, tml;
struct tm *lt;
time_t tk, tl;
char trailer;
if ((argc == 3 || argc == 4)
&& (sscanf (argv[1], "%d-%d-%d%c",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
== 3)
&& (sscanf (argv[2], "%d:%d:%d%c",
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
== 3))
{
tm.tm_year -= TM_YEAR_BASE;
tm.tm_mon--;
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
tmk = tm;
tl = mktime (&tmk);
lt = localtime (&tl);
if (lt)
{
tml = *lt;
lt = &tml;
}
printf ("mktime returns %ld == ", (long) tl);
print_tm (&tmk);
printf ("\n");
status = check_result (tl, tmk, tl, lt);
}
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
{
time_t from = atol (argv[1]);
time_t by = atol (argv[2]);
time_t to = atol (argv[3]);
if (argc == 4)
for (tl = from; tl <= to; tl += by)
{
lt = localtime (&tl);
if (lt)
{
tmk = tml = *lt;
tk = mktime (&tmk);
status |= check_result (tk, tmk, tl, tml);
}
else
{
printf ("localtime (%ld) yields 0\n", (long) tl);
status = 1;
}
}
else
for (tl = from; tl <= to; tl += by)
{
/* Null benchmark. */
lt = localtime (&tl);
if (lt)
{
tmk = tml = *lt;
tk = tl;
status |= check_result (tk, tmk, tl, tml);
}
else
{
printf ("localtime (%ld) yields 0\n", (long) tl);
status = 1;
}
}
}
else
printf ("Usage:\
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
argv[0], argv[0], argv[0]);
return status;
}
#endif /* DEBUG */
/*
Local Variables:
compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
End:
*/

View file

@ -1,43 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(HAVE_WORKING_SNPRINTF)
/* snprintf works, nothing to do */
#else
/* snprintf is b0rken, use vsnprintf */
#include <stdio.h>
#include <stdarg.h>
int rpl_snprintf(char *str, size_t size, const char *format, ...){
va_list ap;
int r;
fprintf(stderr, "Using snprintf replacement\n");
va_start(ap, format);
r=vsnprintf(str, size, format, ap);
va_end(ap);
return r;
}
#endif

View file

@ -1 +0,0 @@
#error Please supply a version of stat.

View file

@ -1 +0,0 @@
#error Please supply a version of strtod.

View file

@ -1,95 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef vsnprintf
# undef vsnprintf
#endif
#include <stdio.h>
#include <stdarg.h>
#if defined(HAVE_WORKING_VSNPRINTF)
/* vsnprintf works, nothing to do */
#elif !defined(VSNPRINTF_BOGUS_RETVAL)
/* vsnprintf is b0rken, but the return value is ok (thus, the only problem is
* NULL) */
int rpl_vsnprintf(char *str, size_t size, const char *format, va_list ap){
if(str==NULL || size==0){{
char foo[3];
return vsnprintf(foo, 3, format, ap);
}} else {
return vsnprintf(str, size, format, ap);
}
}
#elif !defined(VSNPRINTF_IS_VSPRINTF) && defined(HAVE_VPRINTF)
/* vsnprintf's retval is bogus, so we compensate. */
static FILE *devnull;
#ifndef va_copy
# ifdef __va_copy
# define va_copy(dest, src) __va_copy(dest, src)
# else
# include <string.h>
# define va_copy(dest, src) memcpy(&dest, &src, sizeof(va_list))
# endif
#endif
int rpl_vsnprintf(char *str, size_t size, const char *format, va_list ap){
va_list ap2;
int r;
va_copy(ap2, ap);
#ifdef VSNPRINTF_NULL_OK
vsnprintf(str, size, format, ap);
#else
if(str==NULL || size==0){{
char foo[3];
vsnprintf(foo, 3, format, ap);
}} else {
vsnprintf(str, size, format, ap);
}
#endif
if(devnull==NULL){
if((devnull=fopen("/dev/null", "w"))==NULL){
perror("Couldn't open /dev/null for writing");
exit(72);
}
}
r=vfprintf(devnull, format, ap2);
va_end(ap2);
return r;
}
#else
/* OK, we're screwed */
# error "vsnprintf is so broken we can't compensate. Sorry."
#endif

View file

@ -1,6 +0,0 @@
#! /bin/sh
aclocal-1.10 -I m4 \
&& autoheader \
&& automake-1.10 --gnu --add-missing \
&& autoconf

View file

@ -1,15 +0,0 @@
/* XPM */
static char * characters_xpm[] = {
"179 7 5 1",
" c None",
". c #000000 s Background",
"+ c #0C4E66 s Low",
"@ c #1EC3FF s High",
"# c #127599 s Mid",
"...................................................................................................................................................................................",
".+@+.@@+..@@.@@..@@@.@@@..@@.@.@.@@@...@.@.@.@.....@.@...#@#.@@+.+@+.@@+.+@@.@@@.@.@.@.@.@.#.@.@.@.@.@@@.+@+..@..@@+.@@+.@.@.@@@..@..@@@.+@+.#@#...@.@..@.@..@.@..@.+.......@.@..@.",
".@.@.@.@.@...@.@.@...@...@...@.@..@....@.@.@.@....@...@..@.@.@.@.@.@.@.@.@....@..@.@.@.@...@.@.@.@.@.+#@.@.@..@....@...@.@.@.@...@.....@.@.@.@.@...@.@@@@.@@.@.@..@.@......@...@.@.",
".@@@.@@+.@...@.@.@@..@@..@.@.@@@..@....@.@@..@...@.....@.@.@.@@+.@.@.@@+.+@+..@..@.@.@.@..@...@...@..+@..@.@..@...@+.#@+.@@@.@@+.@@#..@..#@#.#@@..@..@##@.@.@@.@##@.....@@.@...@...",
".@.@.@.@.@...@.@.@...@...@.@.@.@..@..@.@.@.@.@....@...@..@.@.@...@@@.@.@...@..@..@.@.@.@.@...@.@..@..@...@.@..@..@.....@...@...@.@.@..@..@.@...@.@...@..@.@..@.@@@@.@.+....@...@...",
".@.@.@@+..@@.@@..@@@.@....@@.@.@.@@@.+@+.@.@.@@@...@.@...#@#.@...+@@.@.@.@@+..@..@@@..@..#.@.@.@..@..@@@.+@+..@..@@@.@@+...@.@@+.#@#..@..+@+..@..@...@..@.@..@.@..@.+.@.....@.@....",
"..................................................................................................................................................................................."};

View file

@ -1,84 +0,0 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(wmweather+.c)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(wmweather+, 2.12)
# We need GNU sources for certain features
AH_VERBATIM([_GNU_SOURCE],
[/* Enable GNU extensions on systems that have them */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif])
DATE=`date '+%B %e, %Y'`
AC_SUBST(DATE)
AC_SUBST(VERSION)
# for wmgeneral
WMGENERAL_GUI="libwmgeneral-x11.a"
AC_SUBST(WMGENERAL_GUI)
# Checks for programs.
AC_PROG_AWK
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_RANLIB
# Checks for libraries.
AC_CHECK_LIB([m],[cos])
CHECK_LIBPCRE(, AC_MSG_ERROR(libpcre is required))
LIBCURL_CHECK_CONFIG(yes,,,AC_MSG_ERROR(libcurl is required))
# Checks for header files.
AC_PATH_XTRA
AC_FIND_XPM
if test "$LINK_XPM" = ""; then
AC_MSG_ERROR(cannot find libxpm)
fi
CHECK_LIBWRASTER(, AC_MSG_ERROR(libwraster is required))
AC_HEADER_STDC
if test "$ac_cv_header_stdc" != "yes"; then AC_MSG_WARN(standard C headers not found); fi
AC_HEADER_SYS_WAIT
if test "$ac_cv_header_sys_wait_h" != "yes"; then AC_MSG_WARN(sys/wait.h not found); fi
AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/time.h],, AC_MSG_WARN($ac_header not found))
AC_HEADER_TIME
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_CHECK_TYPES([ssize_t])
AH_BOTTOM(
[#if !HAVE_SSIZE_T
typedef signed ssize_t;
#endif])
AC_STRUCT_TM
# Checks for library functions.
AC_FUNC_FORK
if test "$ac_cv_func_fork_works" != "yes"; then AC_MSG_WARN(fork() doesn't seem to work); fi
AC_FUNC_MALLOC
if test "$ac_cv_func_malloc_0_nonnull" != "yes"; then AC_MSG_WARN(malloc() doesn't seem to work); fi
AC_FUNC_MEMCMP
AC_FUNC_MKTIME
AC_TYPE_SIGNAL
AC_FUNC_STAT
AC_FUNC_STRTOD
AC_FUNC_VPRINTF
if test "$ac_cv_func_vprintf" != "yes"; then AC_MSG_WARN(vprintf() doesn't seem to exist); fi
AC_CHECK_FUNCS([atexit dup2 mkdir pow select strchr strcspn strdup strerror strrchr strspn strstr strtol],, AC_MSG_WARN($ac_func doesn't seem to be available))
FUNC_SNPRINTF_LIBOBJ
FUNC_VSNPRINTF_LIBOBJ
CFLAGS="$CFLAGS \$(X_CFLAGS) \$(LIBCURL_CPPFLAGS)"
LIBS="$LIBS \$(LIBCURL)"
XLIBS="\$(X_PRE_LIBS) \$(X_LIBS) \$(LINK_XPM) -lX11 -lXext \$(X_EXTRA_LIBS)"
AC_SUBST(XLIBS)
AC_CONFIG_FILES([Makefile wmweather+.1])
AC_CONFIG_FILES([b0rken/Makefile])
AC_CONFIG_FILES([m4/Makefile])
AC_CONFIG_FILES([wmgeneral/Makefile])
AC_OUTPUT

View file

@ -1,443 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <math.h>
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "convert.h"
/*
* To indicate unavailable data
* 999 is used for temperature
* x<0 is used for rh, pressure, and windspeed
*/
/* Calculations */
int rh_C(int temp_C, int dewpt_C){
float f;
if(temp_C==999 || dewpt_C==999) return 999;
f=1782.75*(dewpt_C-temp_C)/((237.7+dewpt_C)*(237.7+temp_C));
return round(pow(10, f+2));
}
int rh_F(int temp_F, int dewpt_F){
float f;
if(temp_F==999 || dewpt_F==999) return 999;
f=3208.95*(dewpt_F-temp_F)/((395.86+dewpt_F)*(395.86+temp_F));
return round(pow(10, f+2));
}
int heatindex_C(int temp_C, int rh){
#if 1
if(temp_C==999 || temp_C<21 || rh<0) return 999;
return heatindex_F(temp_C2F(temp_C), rh);
#else
int temp2, rh2;
if(temp_C==999 || temp_C<38 || rh<0) return 999;
temp2=temp_C*temp_C;
rh2=rh*rh;
return round(16.18754948 + 2.900509394*temp_C - 0.0221545692*temp2 + 4.20938791*rh - 0.26300889*temp_C*rh + 0.0039811176*temp2*rh - 0.02956469*rh2 + 0.001305828*temp_C*rh2 - 6.4476e-06*temp2*rh2);
#endif
}
int heatindex_F(int temp_F, int rh){
int temp2, temp3, rh2, rh3;
if(temp_F==999 || temp_F<70 || rh<0) return 999;
temp2=temp_F*temp_F;
temp3=temp2*temp_F;
rh2=rh*rh;
rh3=rh2*rh;
return round(16.923 + .185212*temp_F + 5.37941*rh - .100254*temp_F*rh + (9.41695e-3)*temp2 + (7.28898e-3)*rh2 + (3.45372e-4)*temp2*rh - (8.14971e-4)*temp_F*rh2 + (1.02102e-5)*temp2*rh2 - (3.8646e-5)*temp3 + (2.91583e-5)*rh3 + (1.42721e-6)*temp3*rh + (1.97483e-7)*temp_F*rh3 - (2.18429e-8)*temp3*rh2 + (8.43296e-10)*temp2*rh3 - (4.81975e-11)*temp3*rh3);
#if 0
return round(-42.379 + 2.04901523*temp_F + 10.14333127*rh - 0.22475541*temp_F*rh - .00683783*temp2 - .05481717*rh2 + .00122874*temp2*rh + .00085282*temp_F*rh2 - .00000199*temp2*rh2);
#endif
}
int windchill_C(int temp_C, int windspeed){
if(temp_C==999 || windspeed<0) return 999;
return windchill_F(temp_C2F(temp_C), windspeed);
}
int windchill_F(int temp_F, int windspeed){
double ret;
if(temp_F==999 || windspeed<0) return 999;
ret=35.74 + 0.6215*temp_F + (-35.75 + 0.4275*temp_F)*pow(windspeed*50292/57875.0, 0.16);
if(ret>temp_F) return temp_F;
return round(ret);
}
/* Length Conversions */
int in2cm(int in){
if(in<0) return in;
return round(in*2.54);
}
float m2mi(int meters){
if(meters<0) return meters;
return meters*125/201168;
}
/* Windspeed Conversions */
int knots2mph(int knots){
if(knots<0) return knots;
return round(knots*57875/50292.0);
}
int knots2kph(int knots){
if(knots<0) return knots;
return round(knots*463/250.0);
}
int kph2knots(int kph){
if(kph<0) return kph;
return round(kph*250/463.0);
}
int knots2mps(int knots){
if(knots<0) return knots;
return round(knots*463/900.0);
}
int mps2knots(int mps){
if(mps<0) return mps;
return round(mps*900/463.0);
}
int knots2beaufort(int knots){
if(knots<0) return knots;
if(knots<1) return 0;
if(knots<=3) return 1;
if(knots<=6) return 2;
if(knots<=10) return 3;
if(knots<=16) return 4;
if(knots<=21) return 5;
if(knots<=27) return 6;
if(knots<=33) return 7;
if(knots<=40) return 8;
if(knots<=47) return 9;
if(knots<=55) return 10;
if(knots<=63) return 11;
return 12;
}
/* Temperature Conversions */
int temp_C2F(int temp_C){
if(temp_C==999) return 999;
return round(temp_C*9/5.0+32);
}
int temp_F2C(int temp_F){
if(temp_F==999) return 999;
return round((temp_F-32)*5/9.0);
}
/* Pressure Conversions */
float inHg2mmHg(float inHg){
if(inHg<0) return inHg;
return inHg*25.4;
}
float inHg2hPa(float inHg){
if(inHg<0) return inHg;
return inHg*33.8639;
}
float inHg2atm(float inHg){
if(inHg<0) return inHg;
return inHg*.033421052632;
}
float hPa2inHg(float hPa){
if(hPa<0) return hPa;
return hPa/33.8639;
}
/* Time Conversions */
/* NOTE: y%400==100 because y=year-1900 */
#define is_leap(y) (y%4==0 && (y%100!=0 || y%400==100))
/* mktime for UTC, more or less.
* Differences:
* - no range checking
* - never recalculates tm_wday or tm_yday
*/
time_t mkgmtime(struct tm *tm){
static long msec[]={0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600};
time_t t;
int i;
t=0;
if(tm->tm_year>70){
for(i=70; i<tm->tm_year; i++){
t+=31536000;
if(is_leap(i)) t+=86400;
}
} else if(tm->tm_year<70){
for(i=69; i>=tm->tm_year; i--){
t-=31536000;
if(is_leap(i)) t-=86400;
}
}
t+=msec[tm->tm_mon];
if(tm->tm_mon>1 && is_leap(tm->tm_year)) t+=86400;
t+=(((tm->tm_mday-1)*24+tm->tm_hour)*60+tm->tm_min)*60+tm->tm_sec;
return t;
}
int utc2local(int hm, int *month, int *day, int *year, int *wday){
time_t t=time(NULL);
struct tm *tm;
tm=gmtime(&t);
tm->tm_hour=hm/100;
tm->tm_min=hm%100;
if(month!=NULL && *month!=-1) tm->tm_mon=*month-1;
if(day!=NULL && *day!=-1) tm->tm_mday=*day;
if(year!=NULL && *year!=-1) tm->tm_year=*year;
t=mkgmtime(tm);
tm=localtime(&t);
if(month!=NULL) *month=tm->tm_mon+1;
if(day!=NULL) *day=tm->tm_mday;
if(year!=NULL) *year=tm->tm_year;
if(wday!=NULL) *wday=tm->tm_wday;
return tm->tm_hour*100+tm->tm_min;
}
int local2utc(int hm, int *month, int *day, int *year, int *wday){
time_t t=time(NULL);
struct tm *tm;
tm=localtime(&t);
tm->tm_hour=hm/100;
tm->tm_min=hm%100;
if(month!=NULL && *month!=-1) tm->tm_mon=*month-1;
if(day!=NULL && *day!=-1) tm->tm_mday=*day;
if(year!=NULL && *year!=-1) tm->tm_year=*year;
t=mktime(tm);
tm=gmtime(&t);
if(month!=NULL) *month=tm->tm_mon+1;
if(day!=NULL) *day=tm->tm_mday;
if(year!=NULL) *year=tm->tm_year;
if(wday!=NULL) *wday=tm->tm_wday;
return tm->tm_hour*100+tm->tm_min;
}
void fix_date(int *month, int *day, int *year, int *wday){
time_t t=time(NULL);
struct tm *tm;
tm=gmtime(&t);
if(month!=NULL && *month!=-1) tm->tm_mon=*month-1;
if(day!=NULL && *day!=-1) tm->tm_mday=*day;
if(year!=NULL && *year!=-1) tm->tm_year=*year;
t=mkgmtime(tm);
tm=gmtime(&t);
if(month!=NULL) *month=tm->tm_mon+1;
if(day!=NULL) *day=tm->tm_mday;
if(year!=NULL) *year=tm->tm_year;
if(wday!=NULL) *wday=tm->tm_wday;
}
int hm2min(int hm){
return hm/100*60+hm%100;
}
/* Letter Case (destructive!) */
char *str_upper(char *str){
char *c;
for(c=str; *c!='\0'; c++){
*c=toupper(*c);
}
return str;
}
char *str_lower(char *str){
char *c;
for(c=str; *c!='\0'; c++){
*c=tolower(*c);
}
return str;
}
/* Angle conversions */
/* Convert radian angle to degrees */
double rad2deg(double angle) {
return 180.0*angle/PI;
}
/* Convert degree angle to radians */
double deg2rad(double angle) {
return PI*angle/180.0;
}
/* Date conversions */
/* Numerical day-of-year from month, day and year */
int mdy2doy(int mn, int dy, int y) {
return 275*mn/9 - ((y%4==0 && (y%100!=0 || y%400==100))?1:2)*(mn + 9)/12 + dy-30;
}
/* Julian day from month/day/year */
double mdy2jd(int year, int month, int day) {
int A, B;
year+=1900;
if (month <= 2) {
year -= 1;
month += 12;
}
A=year/100;
B=2 - A + A/4;
return (int)(365.25*(year + 4716)) + (int)(30.6001*(month+1)) + day + B - 1524.5;
}
/* convert Julian Day to centuries since J2000.0. */
double jd2jcent(double jd) {
return (jd - 2451545.0)/36525.0;
}
/* convert centuries since J2000.0 to Julian Day. */
double jcent2jd(double t) {
return t * 36525.0 + 2451545.0;
}
/* Lat/Long conversions */
static double parse_dd_or_dms(char *s, char **e){
double deg;
*e=s;
if(strchr(s, 'x') || strchr(s, 'X')) return NAN;
if(!strchr(s, '\'')){
if(!isdigit(*s) && *s!='.') return NAN;
return strtod(s, e);
}
if(!isdigit(*s)) return NAN;
deg=strtol(s, e, 10);
if(*e==s || *e==NULL || **e!='\'') return deg;
s=++(*e);
if(!isdigit(*s)) return deg;
deg+=strtol(s, e, 10)/60.0;
if(*e==s || *e==NULL || **e!='\'') return deg;
s=++(*e);
if(!isdigit(*s) && *s!='.') return NAN;
deg+=strtod(s, e)/3600.0;
if(*e!=s && *e!=NULL && **e=='\'') (*e)++;
return deg;
}
int str2dd(char *s, double *lat, double *lon){
char *e;
int dir=0;
char c;
c=toupper(*s);
if(c=='+' || c=='N'){
s++; dir=1;
}
if(c=='-' || c=='S'){
s++; dir=-1;
}
*lat=parse_dd_or_dms(s, &e);
if(isnan(*lat) || e==NULL || e==s || *e=='\0') return 0;
if(!dir){
c=toupper(*e);
if(c=='N') dir=1;
if(c=='S') dir=-1;
if(dir) e++;
}
if(dir<0) *lat=-*lat;
while(isspace(*e)) e++;
if(*e=='\0') return 0;
s=e; dir=0;
c=toupper(*s);
if(c=='+' || c=='W'){
s++; dir=1;
}
if(c=='-' || c=='E'){
s++; dir=-1;
}
*lon=parse_dd_or_dms(s, &e);
if(isnan(*lon) || e==s) return 0;
if(e==NULL || *e=='\0') return 1;
if(dir==0){
c=toupper(*e);
if(c=='W') dir=1;
if(c=='E') dir=-1;
if(dir!=0) e++;
}
if(dir<0) *lon=-*lon;
return (*e=='\0');
}

View file

@ -1,67 +0,0 @@
#ifndef PI
# define PI 3.1415926535897932384626433832795029L
#endif
/*
* Note that all floating point calculations are rounded with .5 going up.
* Since C automatically truncates, adding .5 to every calculation does
* rounding for us nicely.
*
* To indicate unavailable data
* 999 is used for temperature
* x<0 is used for rh, pressure, and windspeed
*/
/* Calculations */
int rh_C(int temp_C, int dewpt_C);
int rh_F(int temp_F, int dewpt_F);
int heatindex_C(int temp_C, int rh);
int heatindex_F(int temp_F, int rh);
int windchill_C(int temp_C, int windspeed); /* knots */
int windchill_F(int temp_F, int windspeed); /* knots */
/* Length Conversions */
int in2cm(int in);
float m2mi(int meters);
/* Windspeed Conversions */
int knots2mph(int knots);
int knots2kph(int knots);
int knots2mps(int knots);
int knots2beaufort(int knots);
int kph2knots(int kph);
int mps2knots(int mps);
/* Temperature Conversions */
int temp_C2F(int temp_C);
int temp_F2C(int temp_F);
/* Pressure Conversions */
float inHg2mmHg(float inHg);
float inHg2hPa(float inHg);
float inHg2atm(float inHg);
float hPa2inHg(float hPa);
/* Time Conversions */
time_t mkgmtime(struct tm *tm);
int utc2local(int hm, int *mon, int *day, int *year, int *wday);
int local2utc(int hm, int *mon, int *day, int *year, int *wday);
void fix_date(int *month, int *day, int *year, int *wday);
int hm2min(int hm);
/* Letter Case (destructive!) */
char *str_upper(char *str);
char *str_lower(char *str);
/* Angle conversions */
double rad2deg(double angle);
double deg2rad(double angle);
/* Date conversions */
int mdy2doy(int mn, int dy, int y);
double mdy2jd(int year, int month, int day);
double jd2jcent(double jd);
double jcent2jd(double t);
/* Lat/Long conversions */
int str2dd(char *s, double *lat, double *lon);

View file

@ -1,57 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "wmweather+.h"
#include "die.h"
void vwarn(char *fmt, va_list ap){
fprintf(stderr, "%s: ", ProgName);
vfprintf(stderr, fmt, ap);
if (errno) fprintf(stderr, ": %s", strerror(errno));
fprintf(stderr, "\n");
}
void warn(char *fmt, ...){
va_list argv;
va_start(argv, fmt);
vwarn(fmt, argv);
va_end(argv);
}
void vdie(char *fmt, va_list ap){
vwarn(fmt, ap);
exit(1);
}
void die(char *fmt, ...){
va_list argv;
va_start(argv, fmt);
vwarn(fmt, argv);
va_end(argv);
exit(1);
}

View file

@ -1,7 +0,0 @@
#include <stdarg.h>
void warn(char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
void die(char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2), __noreturn__));
void vwarn(char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 1, 0)));
void vdie(char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 1, 0), __noreturn__));

View file

@ -1,62 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "wmweather+.h"
int diff(char *file1, char *file2){
FILE *fp1, *fp2;
size_t len1, len2;
struct stat statbuf;
int ret;
int len=BIGBUF_LEN/2;
char *s1=(char *)bigbuf, *s2=(char *)(bigbuf+len);
if((fp1=fopen(file1, "r"))==NULL) return -1;
if((fp2=fopen(file2, "r"))==NULL){ fclose(fp1); return -1; }
if(fstat(fileno(fp1), &statbuf)<0 || !S_ISREG(statbuf.st_mode)){
fclose(fp1);
fclose(fp2);
return -1;
}
len1=statbuf.st_size;
if(fstat(fileno(fp2), &statbuf)<0 || !S_ISREG(statbuf.st_mode)){
fclose(fp1);
fclose(fp2);
return -1;
}
len2=statbuf.st_size;
if(len1!=len2){ fclose(fp1); fclose(fp2); return 1; }
if(len1==0){ fclose(fp1); fclose(fp2); return 0; }
while(!feof(fp1) && !feof(fp2)){
len1=fread(s1, sizeof(char), len, fp1);
len2=fread(s2, sizeof(char), len, fp2);
if(len1!=len2 || memcmp(s1, s2, len1)){
fclose(fp1); fclose(fp2); return 1;
}
}
ret=(!feof(fp1) || !feof(fp2));
fclose(fp1);
fclose(fp2);
return ret;
}

View file

@ -1,5 +0,0 @@
/* Returns 0 if the files are identical
* 1 if they differ
* -1 if fopen or fstat fails, or if files are not both regular files
*/
int diff(char *file1, char *file2);

View file

@ -1,773 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "wmgeneral/wmgeneral-x11.h"
#include "wmgeneral/mouse_regions.h"
#include "wmgeneral/xpm_trans.h"
#include "wmweather_master.xpm"
static int wmweather_mask_width;
static int wmweather_mask_height;
static char *wmweather_mask_bits;
#include "wmweather+.h"
#include "convert.h"
#include "metar.h"
#include "avn.h"
#include "eta.h"
#include "mrf.h"
#include "warnings.h"
#include "forecast.h"
#include "radar.h"
#include "animation.h"
#include "die.h"
#include "font.h"
/* Globals */
int current_mode;
struct forecast *cur_forecast;
int window_X, window_Y;
#define X 4
#define P 4
#define M (((100/P)+1)*X)
static struct forecast *last_fcst;
static int last_font=-1;
static time_t last_time=0;
static int but_stat=-1;
static int dclick=0;
static int dclick_counter=-1;
static time_t update_time;
static int forecast_priority, last_priority;
static struct animation anim;
static int counter_timer=0;
static int show_counter;
static int min_pct;
static int sigs=0;
/* Prototypes */
void DrawDisplay(int force);
/* Functions */
void sigusr2(int i){
sigs |= 2;
if(signal(SIGUSR2, sigusr2)==SIG_ERR)
warn("Error setting SIGUSR2 signal handler!");
}
void sigusr1(int i){
sigs |= 1;
if(signal(SIGUSR1, sigusr1)==SIG_ERR)
warn("Error setting SIGUSR1 signal handler!");
}
void sigfunc(int i){
sigs |= i<<8;
if(signal(i, sigfunc)==SIG_ERR)
warn("Error setting %d signal handler!", i);
}
void do_cleanup(void){
metar_cleanup();
warnings_cleanup();
avn_cleanup();
eta_cleanup();
mrf_cleanup();
radar_cleanup();
}
void init_dock(int argc, char **argv){
sscanf(wmweather_master_xpm[0], "%d %d %*s", &wmweather_mask_width, &wmweather_mask_height);
wmweather_mask_bits=malloc((wmweather_mask_width+7)/8*wmweather_mask_height);
if(!wmweather_mask_bits) die("malloc failed");
createXBMfromXPM(wmweather_mask_bits, wmweather_master_xpm, wmweather_mask_width, wmweather_mask_height);
openDockWindow(argc, argv, wmweather_master_xpm, wmweather_mask_bits, wmweather_mask_width, wmweather_mask_height);
AddMouseRegion(0, 5, 5, 23, 14); /* Cur button */
AddMouseRegion(1, 23, 5, 41, 14); /* Fcst burron */
AddMouseRegion(2, 41, 5, 59, 14); /* Map button */
AddMouseRegion(3, 5, 17, 59, 59); /* Large window */
AddMouseRegion(4, 5, 17, 11, 24); /* left forecast arrow */
AddMouseRegion(5, 53, 17, 59, 24); /* right forecast arrow */
AddMouseRegion(6, 14, 17, 50, 24); /* forecast little window */
AddMouseRegion(7, 5, 27, 59, 59); /* forecast big window */
init_metar();
if(warning_zones) init_warnings();
if(avn_station) init_avn();
if(eta_station) init_eta();
if(mrf_station) init_mrf();
init_radar();
errno=0;
if(atexit(do_cleanup)) warn("atexit() failed, files will not be cleaned up\n");
current_mode=starting_mode;
window_X=0; window_Y=0;
cur_forecast=NULL;
last_fcst=NULL;
last_font=-1;
last_time=0;
anim.do_animate=start_do_animation;
anim.show_counter=0;
anim.changed=1;
anim.min_pct=1;
anim.old_pct=0;
min_pct=20;
show_counter=0;
but_stat=-1;
dclick=0;
dclick_counter=-1;
update_time=0;
forecast_priority=4;
last_priority=-1;
if(signal(SIGUSR1, sigusr1)==SIG_ERR)
warn("Error setting SIGUSR1 signal handler!");
if(signal(SIGUSR2, sigusr2)==SIG_ERR)
warn("Error setting SIGUSR2 signal handler!");
if(signal(SIGHUP, sigfunc)==SIG_ERR)
warn("Error setting SIGHUP signal handler!");
if(signal(SIGINT, sigfunc)==SIG_ERR)
warn("Error setting SIGINT signal handler!");
if(signal(SIGPIPE, sigfunc)==SIG_ERR)
warn("Error setting SIGPIPE signal handler!");
if(signal(SIGTERM, sigfunc)==SIG_ERR)
warn("Error setting SIGTERM signal handler!");
DrawDisplay(1);
}
void update_dock(){
XEvent Event;
int i=0, j;
int exposeflag=0;
j=sigs;
sigs=0;
if(j){
if(j&~3) exit(j);
if(j&1) i=current_mode;
if(j&2) i=-1;
if(j&3){
switch(i){
case 0:
update_metar(1);
break;
case 1:
update_avn(1);
update_eta(1);
update_mrf(1);
break;
case 2:
update_radar(1);
break;
default:
update_metar(1);
update_avn(1);
update_eta(1);
update_mrf(1);
update_radar(1);
break;
}
}
}
if(update_time<time(NULL)){
update_time=time(NULL)+2;
update_metar(0);
update_avn(0);
update_eta(0);
update_mrf(0);
update_radar(0);
forecast_priority=(forecast_priority+1)%5;
DrawDisplay(0);
}
if(counter_timer>0) if(!--counter_timer){
anim.changed=1;
show_counter=anim.show_counter=0;
}
if(dclick_counter>-1) dclick_counter--;
while(XPending(display)){
XNextEvent(display, &Event);
switch (Event.type){
case GraphicsExpose:
case NoExpose:
case Expose:
exposeflag=1;
break;
case DestroyNotify:
XCloseDisplay(display);
exit(0);
break;
case ButtonPress:
but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
if((dclick!=but_stat+1 && dclick!=-but_stat-1) || dclick_counter<0){
dclick=-but_stat-1;
dclick_counter=4;
} else if(dclick==-but_stat-1) dclick=but_stat+1;
switch(but_stat){
case 0:
case 1:
case 2:
if(current_mode!=but_stat){
current_mode=but_stat;
if(!anim.do_animate && !show_counter){
show_counter=1;
counter_timer=10;
}
DrawDisplay(1);
}
break;
case 3:
case 7:
switch(Event.xbutton.button){
case 2:
if(current_mode==2){
if(radar_cross!=NULL){
do_radar_cross=1;
DrawDisplay(1);
}
} else {
anim.changed=1;
anim.show_counter=0;
anim.do_animate=!anim.do_animate;
anim.min_pct=1;
if(!anim.do_animate && current_mode==1){
anim.min_pct=min_pct;
show_counter=anim.show_counter=1;
counter_timer=20;
}
}
break;
case 4:
if(current_mode==1 && !anim.do_animate && min_pct<100){
if(Event.xbutton.state&ShiftMask){
min_pct+=10;
if(min_pct>100) min_pct=100;
} else min_pct++;
anim.min_pct=min_pct;
show_counter=anim.show_counter=1;
counter_timer=20;
anim.changed=1;
}
break;
case 5:
if(current_mode==1 && !anim.do_animate && min_pct>0){
if(Event.xbutton.state&ShiftMask){
min_pct-=10;
if(min_pct<0) min_pct=0;
} else min_pct--;
anim.min_pct=min_pct;
anim.show_counter=1;
counter_timer=20;
anim.changed=1;
}
break;
case 6:
if(current_mode==1){
show_counter=anim.show_counter=1;
anim.changed=1;
counter_timer=0;
}
break;
}
break;
case 4:
copyPixmapArea(123, 96, 6, 7, 65, 17);
break;
case 5:
copyPixmapArea(129, 96, 6, 7, 113, 17);
break;
}
break;
case ButtonRelease:
i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
if(dclick_counter<0) dclick=0;
if(but_stat==4){
copyPixmapArea(123, 89, 6, 7, 65, 17);
}
if(but_stat==5){
copyPixmapArea(129, 89, 6, 7, 113, 17);
}
if(current_mode==2 && (but_stat==3 || but_stat==7)
&& Event.xbutton.button==2){
do_radar_cross=0;
DrawDisplay(1);
}
if(but_stat == i && but_stat >= 0){
switch(but_stat){
case 3:
case 7:
if(Event.xbutton.button==1){
if(dclick==but_stat+1) kill(getpid(), SIGUSR1);
else if(warning_zones) output_warnings(0);
}
if(Event.xbutton.button==2){
if(dclick==but_stat+1 && current_mode==1){
show_counter=anim.show_counter=!anim.show_counter;
anim.changed=1;
counter_timer=0;
}
}
if(Event.xbutton.button==3 && warning_zones) output_warnings(1);
if(Event.xbutton.button==6){
show_counter=anim.show_counter=0;
anim.changed=1;
}
break;
case 4:
current_forecast_next(-1);
forecast_priority=4;
last_priority=0;
DrawDisplay(0);
break;
case 5:
current_forecast_next(1);
forecast_priority=4;
last_priority=0;
DrawDisplay(0);
break;
case 6:
if(Event.xbutton.button==3) current_forecast_next(-1);
if(Event.xbutton.button==2){{
struct forecast *f=current_forecast_get();
struct forecast *g;
current_forecast_next(1);
while((g=current_forecast_get())!=f){
if((f->hour<0 && g->hour>=0) ||
(f->hour>=0 && g->hour<0)) break;
current_forecast_next(1);
}
}}
if(Event.xbutton.button==1) current_forecast_next(1);
forecast_priority=4;
last_priority=0;
DrawDisplay(0);
break;
}
but_stat=-1;
}
break;
}
}
if(exposeflag){
setMaskXY(-window_X, -window_Y);
RedrawWindowXY(window_X, window_Y);
}
DoAnimation(&anim);
}
void DrawDisplay(int force){
int font=0;
int x, y, z;
struct forecast *f;
time_t t;
struct tm *tm;
if(current_warnings) font=1;
if(force || last_font!=font) last_time=-1;
last_font=font;
switch(current_mode){
case 0:
if(last_time==current.last_update) break;
last_time=current.last_update;
EnableMouseRegion(3);
DisableMouseRegion(4);
DisableMouseRegion(5);
DisableMouseRegion(6);
DisableMouseRegion(7);
window_X=0; window_Y=0;
copyPixmapArea(124, 0, 54, 9, 5, 5);
copyPixmapArea(124, 9, 18, 9, 5, 5);
copyPixmapArea(124, 18, 54, 42, 5, 17);
DrawString(7, 17, metar_station, font+1);
if(current.month>0 && current.month<13 && current.date!=-1){
snprintf(bigbuf, BIGBUF_LEN, "%s %d", monthnames[(int)current.month], current.date);
DrawString(32, 17, bigbuf, font+1);
}
if(current.time!=-1){
snprintf(bigbuf, BIGBUF_LEN, "%04dL (%04dZ)", current.time, local2utc(current.time, NULL, NULL, NULL, NULL));
DrawString(7, 23, bigbuf, font+1);
}
if(current.temp!=999){
x=(temp_mode==0)?temp_C2F(current.temp):current.temp;
if(x<-99) x=-99;
if(x>199) x=199;
snprintf(bigbuf, BIGBUF_LEN, "%d", x);
DrawString(32, 29, bigbuf, font);
}
if(current.rh!=-1){
DrawChar(55, 29, '%', font);
DrawNumber(54, 29, current.rh, font);
}
if(current.windspeed==0){
x=GetStringWidth("CALM");
DrawString(32+(26-x)/2, 35, "CALM", font);
} else {
if(current.winddir>=0 && current.winddir<=16){
x=GetStringWidth(directions[current.winddir]);
DrawString(45-x, 35, directions[current.winddir], font);
}
switch(windspeed_mode){
case 0:
x=knots2mph(current.windspeed);
break;
case 1:
x=knots2kph(current.windspeed);
break;
case 3:
x=knots2mps(current.windspeed);
break;
case 4:
x=knots2beaufort(current.windspeed);
break;
}
if(x>=0 && x<1000)
DrawNumber(58, 35, x, font);
}
if(current.pressure>0){
switch(pressure_mode){
case 1:
snprintf(bigbuf, BIGBUF_LEN, "P:%4.0f", inHg2hPa(current.pressure));
break;
case 2:
snprintf(bigbuf, BIGBUF_LEN, "P:%5.1f", inHg2mmHg(current.pressure));
break;
case 3:
snprintf(bigbuf, BIGBUF_LEN, "P:%5.3f", inHg2atm(current.pressure));
break;
default:
snprintf(bigbuf, BIGBUF_LEN, "P:%5.2f", current.pressure);
break;
}
DrawString(32, 41, bigbuf, font);
}
if(current.heatindex!=999){
x=(temp_mode==0)?current.heatindex:temp_F2C(current.heatindex);
if(x<-99) x=-99;
if(x>199) x=199;
snprintf(bigbuf, BIGBUF_LEN, "HI: %d", x);
DrawString(32, 47, bigbuf, font);
}
if(current.windchill!=999){
x=(temp_mode==0)?current.windchill:temp_F2C(current.windchill);
if(x<-99) x=-99;
if(x>199) x=199;
snprintf(bigbuf, BIGBUF_LEN, "WC: %d", x);
DrawString(32, 53, bigbuf, font);
}
anim.show_counter=0;
anim.min_pct=1;
SetAnimation(&anim, 5, 28, current.sky, current.obs, current.vis,
current.frz, current.snow, current.rain, current.tstorm, 0,
current.moon);
break;
case 1:
f=current_forecast_get();
if(last_fcst!=f) last_time=-1;
last_fcst=f;
if(f!=NULL){
if(last_time==f->last_update)
goto case_1_end; /* still check bottom line priority */
else last_time=f->last_update;
}
DisableMouseRegion(3);
EnableMouseRegion(4);
EnableMouseRegion(5);
EnableMouseRegion(6);
EnableMouseRegion(7);
window_X=60; window_Y=0;
last_priority=-1;
copyPixmapArea(124, 0, 54, 9, 65, 5);
copyPixmapArea(142, 9, 18, 9, 83, 5);
copyPixmapArea(123, 89, 6, 7, 65, 17);
copyPixmapArea(129, 89, 6, 7, 113, 17);
copyPixmapArea(124, 18, 36, 7, 74, 17);
copyPixmapArea(124, 18, 54, 32, 65, 27);
if(f==NULL) break;
t=time(NULL);
tm=localtime(&t);
bigbuf[0]='\0';
if(tm->tm_mon+1==f->month && tm->tm_mday==f->day){
if(f->hour<0) snprintf(bigbuf, BIGBUF_LEN, "TODAY");
else snprintf(bigbuf, BIGBUF_LEN, "TODAY %dL", f->hour);
} else {
x=tm->tm_mon+1;
y=tm->tm_mday+1;
fix_date(&x, &y, NULL, NULL);
if(x==f->month && y==f->day){
if(f->hour<0) snprintf(bigbuf, BIGBUF_LEN, "TOMORROW");
else snprintf(bigbuf, BIGBUF_LEN, "TMRW %dL", f->hour);
} else {
z=0;
if(f->wday!=-1){
for(z=0; z<5; z++){
y++;
fix_date(&x, &y, NULL, NULL);
if(x==f->month && y==f->day){
if(f->hour<0) snprintf(bigbuf, BIGBUF_LEN, "%s",
wdaynames[(int)f->wday]);
else snprintf(bigbuf, BIGBUF_LEN, "%.3s %dL",
wdaynames[(int)f->wday], f->hour);
z=99;
}
}
}
if(z<99 && f->month>0 && f->day>0){
if(f->hour<0)
snprintf(bigbuf, BIGBUF_LEN, "%.3s %d",
monthnames[(int)f->month], f->day);
else snprintf(bigbuf, BIGBUF_LEN, "%.3s %d %dL",
monthnames[(int)f->month], f->day,
f->hour);
}
}
}
x=GetStringWidth(bigbuf);
DrawString(60+(64-x)/2, 18, bigbuf, font);
x=GetStringWidth(f->station);
DrawString(118-x, 28, f->station, font+1);
if(f->high!=999 || f->low!=999){
DrawChar(104, 35, '/', font);
if(f->high!=999){
x=(temp_mode==0)?f->high:temp_F2C(f->high);
if(x<-99) x=-99;
if(x>199) x=199;
DrawNumber(103, 35, x, font);
}
if(f->low!=999){
x=(temp_mode==0)?f->low:temp_F2C(f->low);
if(x<-99) x=-99;
if(x>199) x=199;
DrawNumber(118, 35, x, font);
}
}
if(f->temp!=999){
x=(temp_mode==0)?f->temp:temp_F2C(f->temp);
if(x<-99) x=-99;
if(x>199) x=199;
snprintf(bigbuf, BIGBUF_LEN, "%d", x);
DrawString(92, 41, bigbuf, font);
}
if(f->rh!=-1){
DrawChar(115, 41, '%', font);
DrawNumber(114, 41, f->rh, font);
}
if(f->windspeed==0){
x=GetStringWidth("CALM");
DrawString(92+(26-x)/2, 47, "CALM", font);
} else {
if(f->winddir>=0 && f->winddir<=16){
x=GetStringWidth(directions[f->winddir]);
DrawString(105-x, 47, directions[f->winddir], font);
}
switch(windspeed_mode){
case 0:
x=knots2mph(f->windspeed);
break;
case 1:
x=knots2kph(f->windspeed);
break;
case 3:
x=knots2mps(f->windspeed);
break;
case 4:
x=knots2beaufort(f->windspeed);
break;
}
if(x>=0 && x<1000)
DrawNumber(118, 47, x, font);
}
anim.show_counter=show_counter;
anim.min_pct=min_pct;
SetAnimation(&anim, 65, 28, f->sky, f->obs, f->vis,
f->frz, f->snow, f->rain, f->tstorm, f->svtstorm,
f->moon);
case_1_end:
if(f==NULL || forecast_priority==last_priority) break;
/* This is a little tricky. We use the switch as a calculated goto
* (ick) to determine which order to try things in. Fall-through is
* intended. */
switch(forecast_priority){
default:
/* WTF? Oh well, just start at the beginning */
case 0:
if(f->heatindex>=80 && f->heatindex!=999){
copyPixmapArea(124, 18, 26, 5, 92, 53);
x=(temp_mode==0)?f->heatindex:temp_F2C(f->heatindex);
snprintf(bigbuf, BIGBUF_LEN, "HI: %d", x);
DrawString(92, 53, bigbuf, font);
forecast_priority=0;
break;
}
case 1:
if(f->windchill<=40 && f->windchill!=999){
copyPixmapArea(124, 18, 26, 5, 92, 53);
x=(temp_mode==0)?f->windchill:temp_F2C(f->windchill);
snprintf(bigbuf, BIGBUF_LEN, "WC: %d", x);
DrawString(92, 53, bigbuf, font);
forecast_priority=1;
break;
}
case 2:
if(f->snowamt>0){
copyPixmapArea(124, 18, 26, 5, 92, 53);
if(f->snowamt==1){ x=1; y=2; }
else if(f->snowamt==8){ x=8; y=-1; }
else { x=f->snowamt; y=x+2; }
if(length_mode==1){
x=in2cm(x); y=in2cm(y);
}
if(x>9 && y>9) x=9;
if(y==-1) snprintf(bigbuf, BIGBUF_LEN, "SN:>%d", x);
else snprintf(bigbuf, BIGBUF_LEN, "SN:%d-%d", x, y);
DrawString(92, 53, bigbuf, font);
forecast_priority=2;
break;
}
case 3:
if(f->precipamt>0){
copyPixmapArea(124, 18, 26, 5, 92, 53);
switch(f->precipamt){
case 1:
if(length_mode==0) DrawString(92, 53, "P:.01-.1", font);
if(length_mode==1) DrawString(92, 53, "P: 0-.25", font);
break;
case 2:
if(length_mode==0) DrawString(92, 53, "P:.1-.25", font);
if(length_mode==1) DrawString(92, 53, "P:.25-.6", font);
break;
case 3:
if(length_mode==0) DrawString(92, 53, "P:.25-.5", font);
if(length_mode==1) DrawString(92, 53, "P:.6-1.3", font);
break;
case 4:
if(length_mode==0) DrawString(92, 53, "P: .5-1", font);
if(length_mode==1) DrawString(92, 53, "P: 1-2.5", font);
break;
case 5:
if(length_mode==0) DrawString(92, 53, "P: 1-2", font);
if(length_mode==1) DrawString(92, 53, "P: 2.5-5", font);
break;
case 6:
if(length_mode==0) DrawString(92, 53, "P: >2", font);
if(length_mode==1) DrawString(92, 53, "P: >5", font);
break;
case 7:
if(length_mode==0) DrawString(92, 53, "P: >3", font);
if(length_mode==1) DrawString(92, 53, "P: >7.6", font);
break;
}
forecast_priority=3;
break;
}
case 4:
copyPixmapArea(124, 18, 26, 5, 92, 53);
x=GetStringWidth("<")+1;
y=GetStringWidth(f->ID)+1;
z=GetStringWidth(">");
DrawChar(118-x-y-z, 53, '<', font+1);
DrawString(118-y-z, 53, f->ID, font+1);
DrawChar(118-z, 53, '>', font+1);
forecast_priority=4;
break;
}
last_priority=forecast_priority;
break;
case 2:
if(last_time==radar_update_time) break;
last_time=radar_update_time;
EnableMouseRegion(3);
DisableMouseRegion(4);
DisableMouseRegion(5);
DisableMouseRegion(6);
DisableMouseRegion(7);
window_X=0; window_Y=0;
copyPixmapArea(124, 0, 54, 9, 5, 5);
copyPixmapArea(160, 9, 18, 9, 41, 5);
put_radar(6, 18, font);
anim.active=0;
break;
}
DoAnimation(&anim);
}

View file

@ -1,2 +0,0 @@
void init_dock(int argc, char **argv);
void update_dock();

View file

@ -1,267 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <curl/curl.h>
#include "die.h"
#include "download.h"
static CURLM *multi_handle=NULL;
static int still_running=0;
struct download_info {
CURL *handle;
FILE *fp;
void (*callback)(char *filename, void *data);
char *filename;
void *data;
int flags;
struct download_info *next;
struct download_info *prev;
};
static struct download_info *active_list=NULL;
static void add_active(struct download_info *d){
d->next=active_list;
d->prev=NULL;
if(active_list!=NULL) active_list->prev=d;
active_list=d;
}
static void remove_active(struct download_info *d){
if(active_list==d) active_list=d->next;
if(d->prev!=NULL) d->prev->next=d->next;
if(d->next!=NULL) d->next->prev=d->prev;
d->next=NULL;
d->prev=NULL;
}
static struct download_info *find_active_file(char *f){
struct download_info *d;
for(d=active_list; d!=NULL; d=d->next){
if(!strcmp(d->filename,f)) return d;
}
return NULL;
}
static void handle_done(CURLMsg *msg){
struct download_info *info;
long status;
if(curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &info)!=CURLE_OK || info==NULL){
warn("Could not retrieve info handle from CURL handle. WTF?");
for(info=active_list; info && info->handle!=msg->easy_handle; info=info->next);
if(info==NULL){
warn("Could not find it in the active list either. WTF?");
curl_multi_remove_handle(multi_handle, msg->easy_handle);
curl_easy_cleanup(msg->easy_handle);
return;
}
}
remove_active(info);
curl_multi_remove_handle(multi_handle, info->handle);
fclose(info->fp);
if(msg->data.result!=CURLE_OK){
if(msg->data.result==CURLE_HTTP_RETURNED_ERROR){
if(curl_easy_getinfo(info->handle, CURLINFO_RESPONSE_CODE, &status)!=CURLE_OK) status=600;
if(status!=404 || !(info->flags&DOWNLOAD_NO_404))
warn("HTTP download of %s returned %d", info->filename, status);
} else {
warn("Download of %s failed: %s", info->filename, curl_easy_strerror(msg->data.result));
}
unlink(info->filename);
} else {
(*info->callback)(info->filename, info->data);
}
curl_easy_cleanup(info->handle);
free(info->filename);
free(info);
}
void download_init(char *email){
if(multi_handle==NULL){
if(curl_global_init(CURL_GLOBAL_ALL))
die("Could not initialize CURL");
multi_handle=curl_multi_init();
if(multi_handle==NULL) die("Could not create a CURL multihandle");
}
}
void download_process(unsigned long sleeptime){
fd_set rd, wr, er;
struct timeval tv;
int maxfd, n, x;
CURLMsg *msg;
if(sleeptime>0){
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_ZERO(&er);
curl_multi_fdset(multi_handle, &rd, &wr, &er, &maxfd);
tv.tv_sec=0;
tv.tv_usec=sleeptime;
if(sleeptime>=1000000){
tv.tv_sec=sleeptime/1000000;
tv.tv_usec=sleeptime%1000000;
}
n=select(maxfd+1, &rd, &wr, &er, &tv);
if(n==0) return;
if(n<0){
switch(errno){
case EINTR:
case ENOMEM:
/* transient errors, hope it's good next time */
break;
default:
warn("WTF? select errno=%d", errno);
break;
}
usleep(sleeptime);
return;
}
}
while(curl_multi_perform(multi_handle, &x)==CURLM_CALL_MULTI_PERFORM);
while((msg=curl_multi_info_read(multi_handle, &x))){
switch(msg->msg){
case CURLMSG_DONE:
handle_done(msg);
break;
default:
warn("Unknown CURL message type %d", msg->msg);
break;
}
}
}
int download_kill(char *filename){
struct download_info *info;
info=find_active_file(filename);
if(info==NULL) return ENOENT;
remove_active(info);
curl_multi_remove_handle(multi_handle, info->handle);
warn("Download of %s interrupted", info->filename);
unlink(info->filename);
curl_easy_cleanup(info->handle);
free(info->filename);
fclose(info->fp);
free(info);
return 0;
}
int download_file(char *filename, char *from_addr, char *postdata, int flags, void (*callback)(char *filename, void *data), void *data){
struct download_info *info=NULL;
FILE *fp;
if(callback==NULL || filename==NULL || from_addr==NULL) return 1;
if(flags&DOWNLOAD_KILL_OTHER_REQUESTS){
download_kill(filename);
} else {
info=find_active_file(filename);
if(info!=NULL){
errno=0;
warn("Cannot download %s: download already in progress", filename);
return 1;
}
}
if((info=malloc(sizeof(*info)))==NULL){
warn("Malloc error in download_file");
goto fail;
}
info->handle=NULL;
info->fp=NULL;
info->callback=callback;
info->filename=NULL;
info->data=data;
info->flags=flags;
info->next=NULL;
info->prev=NULL;
if((info->filename=strdup(filename))==NULL) goto fail;
if((info->fp=fopen(info->filename, "wb"))==NULL){
warn("Error opening %s for output", info->filename);
goto fail;
}
info->handle=curl_easy_init();
if(info->handle==NULL){
warn("Error creating a CURL handle");
goto fail;
}
if(curl_easy_setopt(info->handle, CURLOPT_URL, from_addr)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_NOPROGRESS, 1)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_NOSIGNAL, 1)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_WRITEDATA, info->fp)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_FAILONERROR, 1)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_AUTOREFERER, 1)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_FOLLOWLOCATION, 1)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_TIMEOUT, 10*60)!=CURLE_OK ||
curl_easy_setopt(info->handle, CURLOPT_PRIVATE, info)!=CURLE_OK
){
warn("Error setting CURL options");
goto fail;
}
if(postdata!=NULL){
if(curl_easy_setopt(info->handle, CURLOPT_COPYPOSTFIELDS, postdata)!=CURLE_OK
){
warn("Error setting CURL post options");
goto fail;
}
}
if(curl_multi_add_handle(multi_handle, info->handle)!=CURLM_OK){
warn("Could not add handle for %s to multihandle", info->filename);
goto fail;
}
add_active(info);
/* Call download_process with 0 to force at least one call to
* curl_multi_process, because curl won't actually create a socket until
* that function is called and download_process won't otherwise call
* curl_multi_process until the socket is created...
*/
download_process(0);
return 0;
fail:
if(info){
if(info->handle) curl_easy_cleanup(info->handle);
info->handle=NULL;
if(info->fp) fclose(info->fp);
info->fp=NULL;
if(info->filename){
unlink(info->filename);
free(info->filename);
}
info->filename=NULL;
free(info);
}
return 1;
}

View file

@ -1,13 +0,0 @@
#ifndef DOWNLOAD_H
#define DOWNLOAD_H
/* flags for download_file */
#define DOWNLOAD_NO_404 1
#define DOWNLOAD_KILL_OTHER_REQUESTS 2
void download_init(char *email);
void download_process(unsigned long sleep_time);
int download_kill(char *filename);
int download_file(char *filename, char *from_addr, char *postdata, int flags, void (*callback)(char *filename, void *data), void *data);
#endif

View file

@ -1,365 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include "wmweather+.h"
#include "forecast.h"
#include "getLine.h"
#include "convert.h"
#include "download.h"
#include "diff.h"
#include "die.h"
#include "sunzenith.h"
#include "moon.h"
#include "subst.h"
/* Important variables */
#define ETA_MAX 21
static time_t eta_time=0;
static char *eta_file=NULL;
static char *eta_newfile=NULL;
static char *eta_req[2]={ NULL, NULL };
static struct forecast forecasts[ETA_MAX];
/********* init functions ************/
static int parse_eta(char *file);
static void reset_eta(void){
int i;
for(i=0; i<ETA_MAX; i++) reset_forecast(&forecasts[i]);
}
void init_eta(void){
char *e;
int i;
struct subst_val subs[]={
{ 's', STRING, &eta_station },
{ 0, 0, 0 }
};
strncpy(bigbuf, eta_station, BIGBUF_LEN-14);
bigbuf[BIGBUF_LEN-14]='\0';
for(e=bigbuf; *e!='\0'; e++);
strcpy(e, ".eta.txt");
eta_file=get_pid_filename(bigbuf);
strcpy(e, ".new-eta.txt");
eta_newfile=get_pid_filename(bigbuf);
if((eta_req[0]=subst(eta_uri, subs))==NULL) die("init_eta");
if(eta_post!=NULL && (eta_req[1]=subst(eta_post, subs))==NULL) die("init_eta");
eta_time=0;
/* Remove stale file */
unlink(eta_file);
unlink(eta_newfile);
reset_eta();
for(i=0; i<ETA_MAX; i++) add_forecast(&forecasts[i], "ETA", eta_station);
}
/********* download functions ************/
static void eta_callback(char *filename, void *v){
struct stat statbuf;
if(stat(eta_newfile, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& diff(eta_newfile, eta_file) && parse_eta(eta_newfile)){
eta_time=find_next_time(eta_newfile, "MOS GUIDANCE", 720);
rename(eta_newfile, eta_file);
} else {
unlink(eta_newfile);
if(!parse_eta(eta_file)) reset_eta();
}
}
}
void eta_cleanup(void){
if(eta_file==NULL) return;
unlink(eta_newfile);
unlink(eta_file);
}
void update_eta(int force){
time_t t;
if(eta_file==NULL) return;
t=time(NULL)/60;
if(!force && eta_time>t) return;
eta_time=find_next_time(eta_file, "MOS GUIDANCE", 15);
download_file(eta_newfile, eta_req[0], eta_req[1], force?DOWNLOAD_KILL_OTHER_REQUESTS:0, eta_callback, NULL);
}
/********* parse functions ************/
#define NEXT(s) free(s); \
len=getLine(&s, fp); \
if(strstr(s, "</PRE>")!=NULL) len=0;
#define DIE() return (free(s), fclose(fp), 0)
#define SPLIT(s) { \
ID[0]=s[0]; \
ID[1]=s[1]; \
ID[2]=s[2]; \
ID[3]='\0'; \
memset(split,'\0',sizeof(split)); \
for(n=0, c=s+4; c<s+len && n<ETA_MAX; n++, c+=3){ \
split[n][0]=c[0]; \
split[n][1]=c[1]; \
split[n][2]=c[2]; \
split[n][3]='\0'; \
} \
}
#define ASSIGN(field) \
for(n=0; n<ETA_MSG_MAX; n++) forecasts[n].field=atoi(split[n]);
#define ASSIGN2(field, inval) \
for(n=0; n<ETA_MSG_MAX; n++){ \
i=atoi(split[n]); \
if(i!=inval) forecasts[n].field=i; \
}
static int parse_eta(char *file){
int ETA_MSG_MAX = ETA_MAX;
FILE *fp;
char *s, *c;
int len;
int mon, day;
int h, i=0, j, k, m, n, x, y, z;
char ID[4];
char split[ETA_MAX][4];
reset_eta();
if((fp=fopen(file, "r"))==NULL) return 0;
/* Look for something like an ETA coded forecast */
c=NULL;
while(!feof(fp)){
len=getLine(&s, fp);
if((c=strstr(s, "MOS GUIDANCE"))!=NULL) break;
free(s);
}
if(c==NULL) return (fclose(fp), 0);
c=strchr(c, '/');
if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
m=atoi(c-2);
c=strchr(c+1, '/');
if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
y=atoi(c+1)-1900;
/* get first date */
NEXT(s);
if(len<10) DIE();
if(strncmp(s, "DT ", 3)) DIE();
mon=13;
c=s;
i=4;
while(mon>12){
c=strchr(c+1, '/');
if(c==NULL) DIE();
for(mon=1; mon<=12; mon++){
if(!strncmp(c+1, monthnames[mon], 3) && isspace(*(c+4))) break;
if(!strncmp(c+1, monthnames2[mon], 4) && isspace(*(c+5))){
i=5;
break;
}
}
}
day=atoi(c+i);
if(day<1) DIE();
if(c>s+4) day--;
if(mon<m) y++;
NEXT(s);
if(len<10) DIE();
if(strncmp(s, "HR ", 3)) DIE();
x=day;
m=mon;
SPLIT(s);
for(n=0; n<ETA_MAX; n++){
if(split[n][0]=='\0'){
ETA_MSG_MAX = n;
break;
}
i=atoi(split[n]);
if(i==0){
x++;
fix_date(&mon, &x, &y, NULL);
}
m=mon;
j=x;
z=y;
h=utc2local(i*100, &m, &j, &z, &k)/100;
forecasts[n].month=m;
forecasts[n].day=j;
forecasts[n].year=z;
forecasts[n].hour=h;
forecasts[n].wday=k;
if(latitude!=999 && calcSolarZenith(latitude, longitude, y, mon, x, i*60)>90)
forecasts[n].moon=calc_moon(m, j, z, h*100);
}
while(1){
NEXT(s);
if(len<=10) break;
SPLIT(s);
if(!strcmp(ID, "X/N")) j=1;
else if(!strcmp(ID, "N/X")) j=2;
else j=0;
if(j!=0){
for(n=0; n<ETA_MSG_MAX; n++){
if(!isdigit(split[n][2])) continue;
i=atoi(split[n]);
k=day+(j>>1);
for(m=0; m<ETA_MSG_MAX; m++){
if((j&1)==1 &&
((forecasts[m].day==k-1 && forecasts[m].hour>=19)
|| (forecasts[m].day==k && forecasts[m].hour<19)))
forecasts[m].high=i;
if((j&1)==0 &&
((forecasts[m].day==k-1 && forecasts[m].hour>=8)
|| (forecasts[m].day==k && forecasts[m].hour<8)))
forecasts[m].low=i;
}
j++;
}
continue;
}
if(!strcmp(ID, "TMP")){
ASSIGN(temp);
continue;
}
if(!strcmp(ID, "DPT")){
ASSIGN(dewpt);
continue;
}
if(!strcmp(ID, "WDR")){
for(n=0; n<ETA_MSG_MAX; n++){
i=atoi(split[n]);
if(i==99) forecasts[n].winddir=0;
else forecasts[n].winddir=((int)((i+1.125)/2.25))%16+1;
}
continue;
}
if(!strcmp(ID, "WSP")){
ASSIGN2(windspeed, 99);
continue;
}
if(!strcmp(ID, "P06")){
for(m=0; m<ETA_MSG_MAX; m++){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]);
if(i!=999){
forecasts[m].pcp_total=i;
/* ETA_MSG_MAX-2 because the last 2
* are already 6-hour intervals */
if(m>0 && m<ETA_MSG_MAX-2) forecasts[m-1].pcp_total=i;
}
}
continue;
}
if(!strcmp(ID, "T06")){
for(m=1; m<ETA_MSG_MAX; m+=2){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]); if(i==999) i=0;
j=atoi(split[m+1]+1); if(j==99) j=0;
j=i*j/100;
forecasts[m].tstorm=forecasts[m+1].tstorm=i;
forecasts[m].svtstorm=forecasts[m+1].svtstorm=j;
}
continue;
}
if(!strcmp(ID, "Q06")){
for(m=0; m<ETA_MSG_MAX; m++){
if(!isdigit(split[m][2])) continue;
i=atoi(split[m]);
if(i!=999){
forecasts[m].precipamt=i;
/* ETA_MSG_MAX-2 because the last 2
* are already 6-hour intervals */
if(m>0 && m<ETA_MSG_MAX-2) forecasts[m-1].precipamt=i;
}
}
continue;
}
if(!strcmp(ID, "CLD")){
for(m=0; m<ETA_MSG_MAX; m++){
if(split[m][1]=='C') forecasts[m].sky=0;
if(split[m][1]=='F') forecasts[m].sky=1;
if(split[m][1]=='S') forecasts[m].sky=2;
if(split[m][1]=='B') forecasts[m].sky=3;
if(split[m][1]=='O') forecasts[m].sky=4;
}
continue;
}
if(!strcmp(ID, "VIS")){
ASSIGN2(vis, 9);
continue;
}
if(!strcmp(ID, "OBV")){
for(m=0; m<ETA_MSG_MAX; m++){
if(split[m][2]=='N') forecasts[m].obs=0;
if(split[m][2]=='R' || split[m][2]=='G') forecasts[m].obs=1;
if(split[m][2]=='Z') forecasts[m].obs=2;
if(split[m][2]=='L') forecasts[m].obs=3;
}
continue;
}
if(!strcmp(ID, "POZ")){
ASSIGN2(frz, 999);
continue;
}
if(!strcmp(ID, "POS")){
ASSIGN2(snow, 999);
continue;
}
}
free(s);
fclose(fp);
for(m=0; m<ETA_MSG_MAX; m++){
forecasts[m].rh=rh_F(forecasts[m].temp, forecasts[m].dewpt);
forecasts[m].heatindex=heatindex_F(forecasts[m].temp, forecasts[m].rh);
forecasts[m].windchill=windchill_F(forecasts[m].temp, forecasts[m].windspeed);
forecasts[m].rain=93-forecasts[m].frz-forecasts[m].snow;
forecasts[m].rain=forecasts[m].rain*forecasts[m].pcp_total/93;
forecasts[m].snow=forecasts[m].snow*forecasts[m].pcp_total/93;
forecasts[m].frz=forecasts[m].frz*forecasts[m].pcp_total/93;
}
return 1;
}
#undef NEXT
#undef DIE
#undef SPLIT
#undef ASSIGN
#undef ASSIGN2

View file

@ -1,8 +0,0 @@
#ifndef ETA_H
#define ETA_H
void init_eta(void);
void update_eta(int force);
void eta_cleanup(void);
#endif

View file

@ -1,9 +0,0 @@
# Sample configuration file for the Chicago, IL area
# Note that there are several other possible stations to choose from
email you@example.com
station KORD
warning-zone ilz014
radar-uri http://image.weather.com/web/radar/us_ord_closeradar_small_usen.jpg
radar-crop 81x55+104+80
radar-cross 42x25

View file

@ -1,147 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <ctype.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "font.h"
#include "wmgeneral/wmgeneral-x11.h"
extern XpmIcon wmgen;
extern GC NormalGC;
extern Window Root;
#include "characters.xpm"
static Pixmap fonts[3]={ None, None, None };
static char *colors[3][4]={
{ "#000000", "#0C4E66", "#127599", "#1EC3FF" },
{ "#000000", "#664D0B", "#997411", "#FFC21D" },
{ "#000000", "#662B31", "#99414A", "#FF6D7B" }
};
void init_font(int i){
XpmIcon x;
XpmColorSymbol cols[4]={
{"Background", NULL, 0},
{"Low", NULL, 0},
{"Mid", NULL, 0},
{"High", NULL, 0}
};
int j;
if(fonts[i]!=None) return;
for(j=0; j<4; j++){
cols[j].pixel=GetColor(colors[i][j]);
}
x.attributes.numsymbols=5;
x.attributes.colorsymbols=cols;
x.attributes.exactColors=False;
x.attributes.closeness=40000;
x.attributes.valuemask=(XpmColorSymbols | XpmExactColors | XpmCloseness);
GetXPM(&x, characters_xpm);
fonts[i]=x.pixmap;
XFreePixmap(display, x.mask);
}
int DrawString(int x, int y, char *str, int font){
int w;
char *c;
w=0;
for(c=str; *c!='\0'; c++){
w+=DrawChar(x+w, y, *c, font);
w++;
}
return w-1;
}
int GetStringWidth(char *str){
int w;
char *c;
w=0;
for(c=str; *c!='\0'; c++){
w+=DrawChar(-1, -1, *c, -1);
w++;
}
return w-1;
}
int DrawNumber(int x, int y, int n, int font){
int w;
int flag=0;
char c;
if(n<0){
flag=1;
n=-n;
}
w=0;
do {
w+=3;
c='0'+(n%10);
DrawChar(x-w, y, c, font);
n/=10;
w++;
} while(n>0);
if(flag){
w+=2;
DrawChar(x-w, y, '-', font);
w++;
}
return w-1;
}
int DrawChar(int x, int y, char c, int font){
int sx, w;
c=toupper(c);
w=3;
if(c>='A' && c<='Z'){
sx=(c-'A')*4+1;
if(c=='M'){ w=4; sx=149; }
if(c=='N'){ w=4; sx=154; }
if(c=='W'){ w=4; sx=159; }
} else if(c>='0' && c<='9') sx=(c-'0')*4+105;
else if(c==':'){ w=1; sx=164; }
else if(c=='('){ w=2; sx=171; }
else if(c==')'){ w=2; sx=174; }
else if(c=='%') sx=89;
else if(c=='-'){ w=2; sx=168; }
else if(c=='.'){ w=1; sx=166; }
else if(c=='<') sx=49;
else if(c=='>') sx=53;
else if(c=='/') sx=145;
else if(c=='\''){ w=1; sx=177; }
else return 0;
if(x>=0 && y>=0 && x+w<192 && y<174 && font>=0 && font<3){
init_font(font);
XCopyArea(display, fonts[font], wmgen.pixmap, NormalGC, sx, 1, w, 5, x, y);
}
return w;
}

View file

@ -1,7 +0,0 @@
int DrawString(int x, int y, char *str, int font);
int GetStringWidth(char *str);
int DrawNumber(int x, int y, int n, int font);
int DrawChar(int x, int y, char c, int font);
/* This is called automatically if necessary */
void init_font(int i);

View file

@ -1,311 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <string.h>
#include <limits.h>
#include <math.h>
#include <pcre.h>
#include "forecast.h"
#include "convert.h"
#include "getLine.h"
#include "die.h"
/* Important variables */
static struct forecast **forecasts=NULL;
static int num_forecasts=0;
static pcre *date=NULL;
static int ovecsize=1;
static int changed=0;
/* functions */
time_t find_next_time(char *file, char *pat, int minutes){
FILE *fp;
char *s;
time_t t, mintime;
mintime=time(NULL)/60+15;
if((fp=fopen(file, "r"))==NULL) return mintime;
s=NULL;
while(!feof(fp)){
getLine(&s, fp);
if(strstr(s, pat)!=NULL) break;
free(s);
s=NULL;
}
fclose(fp);
if(s==NULL) return mintime;
t=parse_time_string(s)/60+minutes;
free(s);
return (t>mintime)?t:mintime;
}
time_t parse_time_string(char *s){
struct tm tm;
int ovector[ovecsize];
int ovalue;
char *e;
int i;
if(date==NULL){
date=pcre_compile("\\b(\\d+)/(\\d+)/(\\d+)\\s+(\\d\\d)(\\d\\d)\\s*UTC\\b", 0, (const char **)&e, &i, NULL);
if(date==NULL){
warn("find_next PCRE error: %s at %i", e, i);
return -1;
}
pcre_fullinfo(date, NULL, PCRE_INFO_CAPTURECOUNT, &ovecsize);
ovecsize=(ovecsize+1)*3;
return parse_time_string(s);
}
ovalue=pcre_exec(date, NULL, s, strlen(s), 0, 0, ovector, ovecsize);
if(ovalue<=0) return -1;
if(pcre_get_substring(s, ovector, ovalue, 1, (const char **)&e)<0) return 0;
tm.tm_mon=atoi(e)-1;
pcre_free_substring(e);
if(pcre_get_substring(s, ovector, ovalue, 2, (const char **)&e)<0) return 0;
tm.tm_mday=atoi(e);
pcre_free_substring(e);
if(pcre_get_substring(s, ovector, ovalue, 3, (const char **)&e)<0) return 0;
tm.tm_year=atoi(e)-1900;
pcre_free_substring(e);
if(pcre_get_substring(s, ovector, ovalue, 4, (const char **)&e)<0) return 0;
tm.tm_hour=atoi(e);
pcre_free_substring(e);
if(pcre_get_substring(s, ovector, ovalue, 5, (const char **)&e)<0) return 0;
tm.tm_min=atoi(e);
pcre_free_substring(e);
tm.tm_sec=0;
return mkgmtime(&tm);
}
void add_forecast(struct forecast *f, char *ID, char *station){
if((forecasts=realloc(forecasts, ++num_forecasts*sizeof(*forecasts)))==NULL)
die("realloc in add_forecast");
if(ID==NULL){
memset(f->ID, '\0', 4);
} else {
strncpy(f->ID, ID, 3);
f->ID[3]='\0';
}
f->station=station;
forecasts[num_forecasts-1]=f;
changed=1;
}
void reset_forecast(struct forecast *f){
f->last_update=time(NULL);
f->month=0;
f->day=-1;
f->year=SHRT_MIN;
f->wday=-1;
f->hour=-1;
f->low=999;
f->high=999;
f->temp=999;
f->dewpt=999;
f->rh=-1;
f->winddir=-1;
f->windspeed=-1;
f->heatindex=999;
f->windchill=999;
f->precipamt=-1;
f->snowamt=-1;
f->sky=-1;
f->vis=7;
f->obs=0;
f->pcp_total=0;
f->frz=0;
f->snow=0;
f->rain=0;
f->tstorm=0;
f->svtstorm=0;
f->moon=NAN;
f->time=-1;
changed=1;
}
static int is_forecast_valid(const struct forecast *a){
return (a->ID[0]!='\0' &&
a->month>0 && a->month<=12 &&
a->day>0 && a->day<=31 &&
a->year!=SHRT_MIN);
}
static int is_forecast_current(struct forecast *f, time_t now){
time_t t;
t=forecast_time(f);
t+=(f->hour<0)?86399:3599;
return t>now;
}
static int compar(const void *aa, const void *bb){
struct forecast *a=*(struct forecast **)aa;
struct forecast *b=*(struct forecast **)bb;
int i, j;
/* First, any undefined forecast is greater than any defined forecast */
i=is_forecast_valid(a);
j=is_forecast_valid(b);
if(!i && !j) return 0; /* all undef forecasts are equal */
if(!i) return 1;
if(!j) return -1;
/* Any whole-day forecast is greater than any partial forecast */
if(a->hour<0 && b->hour>=0) return 1;
if(a->hour>=0 && b->hour<0) return -1;
/* Ok, compare dates now */
if(a->year>b->year) return 1;
if(a->year<b->year) return -1;
if(a->month>b->month) return 1;
if(a->month<b->month) return -1;
if(a->day>b->day) return 1;
if(a->day<b->day) return -1;
if(a->hour>b->hour) return 1;
if(a->hour<b->hour) return -1;
/* Last resort, sort in alphabetical order by ID */
return strcasecmp(a->ID, b->ID);
}
static void sort_forecasts(void){
if(forecasts==NULL) return;
qsort(forecasts, num_forecasts, sizeof(struct forecast *), compar);
changed=0;
}
time_t forecast_time(struct forecast *f){
struct tm tm;
if(f->time!=-1) return f->time;
tm.tm_year=f->year;
tm.tm_mon=f->month-1;
tm.tm_mday=f->day;
tm.tm_hour=(f->hour<0)?0:f->hour;
tm.tm_min=tm.tm_sec=0;
return (f->time=mktime(&tm));
}
static char current_ID[4]={ '\0', '\0', '\0', '\0' };
static int current_index=-1;
static struct forecast *current=NULL;
static time_t current_time=0;
static int current_hour=0;
static void set_current(int i){
current_index=i;
if(i<0 || i>num_forecasts){
current=NULL;
memset(current_ID, 0, 4);
current_time=0;
current_hour=0;
} else {
current=forecasts[i];
memcpy(current_ID, current->ID, 4);
current_time=forecast_time(current);
current_hour=current->hour;
}
}
static void locate_current(void){
int i;
time_t now, target;
int target_hour;
long curdiff=0;
long tmpdiff;
char target_ID[4];
now=time(NULL);
if(!changed && current!=NULL && is_forecast_current(current, now)) return;
sort_forecasts();
target=current_time;
target_hour=current_hour;
memcpy(target_ID, current_ID, 4);
set_current(-1);
for(i=0; i<num_forecasts; i++){
if(!is_forecast_valid(forecasts[i])) continue;
if(!is_forecast_current(forecasts[i], now)) continue;
tmpdiff=abs(forecast_time(forecasts[i])-target);
if((target_hour<0 && forecasts[i]->hour>=0) ||
(target_hour>=0 && forecasts[i]->hour<0))
tmpdiff+=31556926;
if(memcmp(forecasts[i]->ID, target_ID, 4)) tmpdiff++;
if(current==NULL || tmpdiff<curdiff){
set_current(i);
curdiff=tmpdiff;
}
}
}
struct forecast *current_forecast_get(void){
locate_current();
return current;
}
static inline int mod(int i, int n){
i=i%n; if(i<0) i+=n;
return i;
}
void current_forecast_next(int dir){
int i;
time_t now;
if(num_forecasts==0) return;
locate_current();
now=time(NULL);
if(current_index<0 || current_index>num_forecasts) current_index=0;
for(i=mod(current_index+dir, num_forecasts); ; i=mod(i+dir, num_forecasts)){
if(is_forecast_valid(forecasts[i]) && is_forecast_current(forecasts[i], now)){
set_current(i);
return;
}
if(i==current_index){
set_current(-1);
return;
}
}
}

View file

@ -1,47 +0,0 @@
#ifndef FORECAST_H
#define FORECAST_H
/* functions to manage the 'current forecast' */
struct forecast *current_forecast_get(void);
void current_forecast_next(int dir);
struct forecast {
char ID[4]; /* Forecast type ("AVN", "MRF", etc) */
char *station; /* station name */
time_t last_update; /* last updated time */
signed char month; /* 0, 1 - 12 */
signed char day; /* -1, 1 - 31 */
short year; /* -1, number */
signed char wday; /* -1, 0-6 */
signed char hour; /* -1, 0 - 23 (local) */
short low; /* 999, -210 - 390 (degrees F) */
short high; /* 999, -210 - 390 (degrees F) */
short temp; /* 999, -210 - 390 (degrees F) */
short dewpt; /* 999, -210 - 390 (degrees F) */
signed char rh; /* -1, 0 - 100 (%) */
short winddir; /* -1, 0 - 16 (direction) */
short windspeed; /* -1, 0 - MAX */
short heatindex; /* 999, -99 - 199 (degrees F) */
short windchill; /* 999, -99 - 199 (degrees F) */
short precipamt; /* -1, 0 - 7 (amount code) */
short snowamt; /* -1, 0 - 8 (amount code) */
signed char sky; /* -1, 0-4 (condition) */
signed char vis; /* 7, 1-7 (status code) */
signed char obs; /* 0, 0-3 (type) */
signed char pcp_total; /* 0, 0-100 (percent chance) */
signed char frz; /* 0, 0-100 (percent chance) */
signed char snow; /* 0, 0-100 (percent chance) */
signed char rain; /* 0, 0-100 (percent chance) */
signed char tstorm; /* 0, 0-100 (percent chance) */
signed char svtstorm; /* 0, 0-100 (percent chance) */
double moon; /* NAN, -1 - 1 (percent and wax/wane) */
time_t time; /* -1, time_t value */
};
void add_forecast(struct forecast *f, char *ID, char *station);
time_t forecast_time(struct forecast *f);
time_t parse_time_string(char *s);
time_t find_next_time(char *file, char *pat, int minutes);
void reset_forecast(struct forecast *f);
#endif

View file

@ -1,67 +0,0 @@
#include "config.h"
/* Copyright (C) 2000 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/* inspired by read_line from Eric S. Raymond's fetchmail program, by
* way of Aaron Sethman's odsclient. */
int getLine(char **s, FILE *fd){
int len=8196;
int toread=len;
int l=0;
char *ptr, *p, *q;
*s=NULL;
if(feof(fd)) return -1;
q=ptr=malloc(len);
if(ptr==NULL) return -1;
*q=0;
p=q=ptr;
while(fgets(p, toread, fd)!=NULL){
l=strlen(ptr);
q=strchr(p, '\n');
if(q!=NULL){ l=q-ptr+1; break; }
len*=2;
toread=len-l;
p=realloc(ptr, len);
if(p==NULL){
free(ptr);
return -1;
}
ptr=p;
q=p=ptr+l;
}
while(q>ptr && (*q=='\0' || isspace(*q))){
*q='\0';
l--;
q--;
}
for(p=ptr; isspace(*p); p++, l--);
if((*s=malloc(l+1))==NULL){
free(ptr);
return -1;
}
memcpy(*s, p, l+1);
free(ptr);
return l;
}

View file

@ -1,4 +0,0 @@
#include <stdio.h>
/* Gets a single line of input, stripping leading and trailing whitespace */
int getLine(char **s, FILE *fd);

View file

@ -1,2 +0,0 @@
SUBDIRS =
EXTRA_DIST = libpcre.m4 libwraster.m4 snprintf.m4 vsnprintf.m4 xpm.m4

View file

@ -1,57 +0,0 @@
dnl @synopsis CHECK_LIBPCRE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl
dnl This macro searches for an installed libpcre library. If nothing
dnl was specified when calling configure, it searches first in /usr/local
dnl and then in /usr. If the --with-libpcre=DIR is specified, it will try
dnl to find it in DIR/include/pcre.h and DIR/lib/libpcre.a. If --without-libpcre
dnl is specified, the library is not searched at all.
dnl
dnl It defines the symbol HAVE_LIBPCRE if the library is found. You should
dnl use autoheader to include a definition for this symbol in a config.h
dnl file.
dnl
dnl Sources files should then use something like
dnl
dnl #ifdef HAVE_LIBPCRE
dnl #include <pcre.h>
dnl #endif /* HAVE_LIBPCRE */
dnl
dnl @version 1.0
dnl based on CHECK_ZLIB by Loic Dachary <loic@senga.org>
dnl
AC_DEFUN([CHECK_LIBPCRE],
#
# Handle user hints
#
[AC_MSG_CHECKING(if libpcre is wanted)
AC_ARG_WITH(libpcre,
[ --with-libpcre=DIR root directory path of libpcre installation [defaults to
/usr/local or /usr if not found in /usr/local]
--without-libpcre to disable libpcre usage completely],
[if test "$withval" != no ; then
LIBPCRE_HOME="$withval"
AC_MSG_RESULT([yes: libraries ${LIBPCRE_HOME}/lib includes ${LIBPCRE_HOME}/include])
else
AC_MSG_RESULT(no)
fi],
[LIBPCRE_HOME=/usr/local
if test ! -f "${LIBPCRE_HOME}/include/pcre.h"
then
LIBPCRE_HOME=/usr
fi
AC_MSG_RESULT([yes: libraries ${LIBPCRE_HOME}/lib includes ${LIBPCRE_HOME}/include])
])
#
# Locate libpcre, if wanted
#
if test -n "${LIBPCRE_HOME}"
then
LDFLAGS="$LDFLAGS -L${LIBPCRE_HOME}/lib"
CPPFLAGS="$CPPFLAGS -I${LIBPCRE_HOME}/include"
AC_CHECK_LIB(pcre, pcre_compile, $1, $2)
else
$2
fi
])

View file

@ -1,61 +0,0 @@
dnl @synopsis CHECK_LIBWRASTER([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl
dnl This macro searches for an installed libwraster library. If nothing
dnl was specified when calling configure, it searches first in /usr/local
dnl and then in /usr. If the --with-libwraster=DIR is specified, it will try
dnl to find it in DIR/include/wraster.h and DIR/lib/libwraster.a. If --without-libwraster
dnl is specified, the library is not searched at all.
dnl
dnl It defines the symbol HAVE_LIBWRASTER if the library is found. You should
dnl use autoheader to include a definition for this symbol in a config.h
dnl file.
dnl
dnl Sources files should then use something like
dnl
dnl #ifdef HAVE_LIBWRASTER
dnl #include <wraster.h>
dnl #endif /* HAVE_LIBWRASTER */
dnl
dnl @version 1.0
dnl based on CHECK_ZLIB by Loic Dachary <loic@senga.org>
dnl
AC_DEFUN([CHECK_LIBWRASTER],
#
# Handle user hints
#
[AC_MSG_CHECKING(if libwraster is wanted)
AC_ARG_WITH(libwraster,
[ --with-libwraster=DIR root directory path of libwraster installation [defaults to
/usr/local or /usr if not found in /usr/local]
--without-libwraster to disable libwraster usage completely],
[if test "$withval" != no ; then
LIBWRASTER_HOME="$withval"
AC_MSG_RESULT([yes: libraries ${LIBWRASTER_HOME}/lib includes ${LIBWRASTER_HOME}/include])
else
AC_MSG_RESULT(no)
fi],
[LIBWRASTER_HOME=/usr/local
if test ! -f "${LIBWRASTER_HOME}/include/wraster.h"
then
LIBWRASTER_HOME=/usr
if test ! -f "${LIBWRASTER_HOME}/include/wraster.h"
then
LIBWRASTER_HOME=/usr/X11R6
fi
fi
AC_MSG_RESULT([yes: libraries ${LIBWRASTER_HOME}/lib includes ${LIBWRASTER_HOME}/include])
])
#
# Locate libwraster, if wanted
#
if test -n "${LIBWRASTER_HOME}"
then
LDFLAGS="$LDFLAGS -L${LIBWRASTER_HOME}/lib"
CPPFLAGS="$CPPFLAGS -I${LIBWRASTER_HOME}/include"
AC_CHECK_LIB(wraster, RCreateContext, $1, $2)
else
$2
fi
])

View file

@ -1,120 +0,0 @@
# FUNC_SNPRINTF_EXISTS
# --------------------
# Checks if snprintf exists. x_cv_func_snprintf_exists is set.
AC_DEFUN([FUNC_SNPRINTF_EXISTS],
[AC_CHECK_FUNC(snprintf, [x_cv_func_snprintf_exists=yes], [x_cv_func_snprintf_exists=no])])# FUNC_SNPRINTF_EXISTS
# FUNC_SNPRINTF_SIZE
# ------------------
# Checks if snprintf honors its size argument. SNPRINTF_IS_SPRINTF is defined
# if not. x_cv_func_snprintf_size is set to yes or no.
#
# Note that this depends on FUNC_SNPRINTF_EXISTS, so if that fails this will
# also fail (and define SNPRINTF_IS_SPRINTF).
AC_DEFUN([FUNC_SNPRINTF_SIZE],
[AC_REQUIRE([FUNC_SNPRINTF_EXISTS])
if test $x_cv_func_snprintf_exists != yes; then x_cv_func_snprintf_size=no; else
AC_CACHE_CHECK([if snprintf honors the size argument], x_cv_func_snprintf_size,
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#if STDC_HEADERS || HAVE_STDIO_H
# include <stdio.h>
#else
int snprintf(char *str, size_t size, const char *format, ...);
#endif
]],
[[char foo[]="ABC"; snprintf(foo, 2, "%d", 12);
exit((foo[0]=='1' && foo[1]=='\0' && foo[2]=='C')?0:1);]])],
[x_cv_func_snprintf_size=yes],
[x_cv_func_snprintf_size=no],
[x_cv_func_snprintf_size=no])])
fi
test $x_cv_func_snprintf_size != yes && AC_DEFINE(SNPRINTF_IS_SPRINTF, 1, [Define if snprintf ignores the size argument])
])# FUNC_SNPRINTF_SIZE
# FUNC_SNPRINTF_RETVAL
# ------------------
# Checks if snprintf returns the number of bytes that would have been written,
# as specified by C99. SNPRINTF_BOGUS_RETVAL is defined if not.
# x_cv_func_snprintf_retval is set to yes or no.
#
# Note that this depends on FUNC_SNPRINTF_SIZE, so if that fails this will fail
# too and SNPRINTF_BOGUS_RETVAL will be set.
AC_DEFUN([FUNC_SNPRINTF_RETVAL],
[AC_REQUIRE([FUNC_SNPRINTF_SIZE])
if test $x_cv_func_snprintf_size != yes; then x_cv_func_snprintf_retval=no; else
AC_CACHE_CHECK([if snprintf return value is sane], x_cv_func_snprintf_retval,
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#if STDC_HEADERS || HAVE_STDIO_H
# include <stdio.h>
#else
int snprintf(char *str, size_t size, const char *format, ...);
#endif
]],
[[char foo[10]; exit((snprintf(foo, 1, "%d", 9876)==4)?0:1);]])],
[x_cv_func_snprintf_retval=yes],
[x_cv_func_snprintf_retval=no],
[x_cv_func_snprintf_retval=no])])
fi
test $x_cv_func_snprintf_retval != yes && AC_DEFINE(SNPRINTF_BOGUS_RETVAL, 1, [Define if snprintf's return value isn't as specified by C99])
])# FUNC_SNPRINTF_RETVAL
# FUNC_SNPRINTF_NULL_OK
# ---------------------
# Checks whether snprintf acceps a NULL string if size is zero. Sets
# x_cv_func_snprintf_null_ok. If so, define SNPRINTF_NULL_OK.
#
# Note that this depends on FUNC_SNPRINTF_SIZE, so if that fails this will fail
# too and SNPRINTF_BOGUS_RETVAL will be set.
AC_DEFUN([FUNC_SNPRINTF_NULL_OK],
[AC_REQUIRE([FUNC_SNPRINTF_SIZE])
if test $x_cv_func_snprintf_size != yes; then x_cv_func_snprintf_null_ok=no; else
AC_CACHE_CHECK([if snprintf(NULL, 0, ...) works], x_cv_func_snprintf_null_ok,
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#if STDC_HEADERS || HAVE_STDIO_H
# include <stdio.h>
#else
int snprintf(char *str, size_t size, const char *format, ...);
#endif
]],
[int r=snprintf(NULL, 0, "%d", 100); exit((r==3 || r==-1)?0:1);])],
[x_cv_func_snprintf_null_ok=yes],
[x_cv_func_snprintf_null_ok=no],
[x_cv_func_snprintf_null_ok=no])])
fi
test $x_cv_func_snprintf_null_ok = yes && AC_DEFINE(SNPRINTF_NULL_OK, 1, [Define if snprintf(NULL, 0, ...) works properly])
])# FUNC_SNPRINTF_NULL_OK
# FUNC_SNPRINTF([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------
# Checks various aspects of snprintf. In particular:
# * Does it exist?
# * Is the size honored?
# * Is the return value correct?
# * Is NULL with length 0 ok?
# If all the above pass, HAVE_WORKING_SNPRINTF is defined and
# x_cv_func_snprintf_working is set to yes. Otherwise, it's set to no.
AC_DEFUN([FUNC_SNPRINTF],
[AC_REQUIRE([FUNC_SNPRINTF_RETVAL])
AC_REQUIRE([FUNC_SNPRINTF_NULL_OK])
if test $x_cv_func_snprintf_retval = yes -a $x_cv_func_snprintf_null_ok = yes; then
AC_DEFINE(HAVE_WORKING_SNPRINTF, 1, [Define if snprintf works properly])
x_cv_func_snprintf_working=yes
$1
else
x_cv_func_snprintf_working=no
$2
fi
])# FUNC_SNPRINTF
# FUNC_SNPRINTF_LIBOBJ
# --------------------
# If FUNC_SNPRINTF fails, does AC_LIBOBJ
AC_DEFUN([FUNC_SNPRINTF_LIBOBJ],
[FUNC_SNPRINTF(, [AC_LIBOBJ([snprintf])
AC_DEFINE([snprintf], [rpl_snprintf], [Define to rpl_snprintf if the replacement function should be used.])])])
])#FUNC_SNPRINTF_LIBOBJ

View file

@ -1,149 +0,0 @@
# FUNC_VSNPRINTF_EXISTS
# --------------------
# Checks if vsnprintf exists. x_cv_func_vsnprintf_exists is set.
AC_DEFUN([FUNC_VSNPRINTF_EXISTS],
[AC_REQUIRE([AC_FUNC_VPRINTF])
if test $ac_cv_func_vprintf != yes; then x_cv_func_vsnprintf_exists=no; else
AC_CHECK_FUNC(vsnprintf, [x_cv_func_vsnprintf_exists=yes], [x_cv_func_vsnprintf_exists=no])
fi
])# FUNC_VSNPRINTF_EXISTS
# FUNC_VSNPRINTF_SIZE
# ------------------
# Checks if vsnprintf honors its size argument. VSNPRINTF_IS_VSPRINTF is defined
# if not. x_cv_func_vsnprintf_size is set to yes or no.
#
# Note that this depends on FUNC_VSNPRINTF_EXISTS, so if that fails this will
# also fail (and define VSNPRINTF_IS_VSPRINTF).
AC_DEFUN([FUNC_VSNPRINTF_SIZE],
[AC_REQUIRE([FUNC_VSNPRINTF_EXISTS])
if test $x_cv_func_vsnprintf_exists != yes; then x_cv_func_vsnprintf_size=no; else
AC_CACHE_CHECK([if vsnprintf honors the size argument], x_cv_func_vsnprintf_size,
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#include <stdarg.h>
#if STDC_HEADERS || HAVE_STDIO_H
# include <stdio.h>
#else
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
#endif
int doit(char *str, size_t size, const char *format, ...){
va_list ap;
int r;
va_start(ap, format);
r=vsnprintf(str, size, format, ap);
va_end(ap);
return r;
}
]],
[[char foo[]="ABC"; doit(foo, 2, "%d", 12);
exit((foo[0]=='1' && foo[1]=='\0' && foo[2]=='C')?0:1);]])],
[x_cv_func_vsnprintf_size=yes],
[x_cv_func_vsnprintf_size=no],
[x_cv_func_vsnprintf_size=no])])
fi
test $x_cv_func_vsnprintf_size != yes && AC_DEFINE(VSNPRINTF_IS_VSPRINTF, 1, [Define if vsnprintf ignores the size argument])
])# FUNC_VSNPRINTF_SIZE
# FUNC_VSNPRINTF_RETVAL
# ------------------
# Checks if vsnprintf returns the number of bytes that would have been written,
# as specified by C99. VSNPRINTF_BOGUS_RETVAL is defined if not.
# x_cv_func_vsnprintf_retval is set to yes or no.
#
# Note that this depends on FUNC_VSNPRINTF_SIZE, so if that fails this will fail
# too and VSNPRINTF_BOGUS_RETVAL will be set.
AC_DEFUN([FUNC_VSNPRINTF_RETVAL],
[AC_REQUIRE([FUNC_VSNPRINTF_SIZE])
if test $x_cv_func_vsnprintf_size != yes; then x_cv_func_vsnprintf_retval=no; else
AC_CACHE_CHECK([if vsnprintf return value is sane], x_cv_func_vsnprintf_retval,
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#include <stdarg.h>
#if STDC_HEADERS || HAVE_STDIO_H
# include <stdio.h>
#else
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
#endif
int doit(char *str, size_t size, const char *format, ...){
va_list ap;
int r;
va_start(ap, format);
r=vsnprintf(str, size, format, ap);
va_end(ap);
return r;
}
]],
[[char foo[10]; exit((doit(foo, 1, "%d", 9876)==4)?0:1);]])],
[x_cv_func_vsnprintf_retval=yes],
[x_cv_func_vsnprintf_retval=no],
[x_cv_func_vsnprintf_retval=no])])
fi
test $x_cv_func_vsnprintf_retval != yes && AC_DEFINE(VSNPRINTF_BOGUS_RETVAL, 1, [Define if vsnprintf's return value isn't as specified by C99])
])# FUNC_VSNPRINTF_RETVAL
# FUNC_VSNPRINTF_NULL_OK
# ---------------------
# Checks whether vsnprintf acceps a NULL string if size is zero. Sets
# x_cv_func_vsnprintf_null_ok. If so, define VSNPRINTF_NULL_OK.
#
# Note that this depends on FUNC_VSNPRINTF_SIZE, so if that fails this will
# fail too and VSNPRINTF_NULL_OK will not be set.
AC_DEFUN([FUNC_VSNPRINTF_NULL_OK],
[AC_REQUIRE([FUNC_VSNPRINTF_SIZE])
if test $x_cv_func_vsnprintf_size != yes; then x_cv_func_vsnprintf_null_ok=no; else
AC_CACHE_CHECK([if vsnprintf(NULL, 0, ...) works], x_cv_func_vsnprintf_null_ok,
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#include <stdarg.h>
#if STDC_HEADERS || HAVE_STDIO_H
# include <stdio.h>
#else
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
#endif
int doit(char *str, size_t size, const char *format, ...){
va_list ap;
int r;
va_start(ap, format);
r=vsnprintf(str, size, format, ap);
va_end(ap);
return r;
}
]],
[int r=doit(NULL, 0, "%d", 100); exit((r==3 || r==-1)?0:1);])],
[x_cv_func_vsnprintf_null_ok=yes],
[x_cv_func_vsnprintf_null_ok=no],
[x_cv_func_vsnprintf_null_ok=no])])
fi
test $x_cv_func_vsnprintf_null_ok = yes && AC_DEFINE(VSNPRINTF_NULL_OK, 1, [Define if vsnprintf(NULL, 0, ...) works properly])
])# FUNC_VSNPRINTF_NULL_OK
# FUNC_VSNPRINTF([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------
# Checks various aspects of vsnprintf. In particular:
# * Does it exist?
# * Is the size honored?
# * Is the return value correct?
# * Is NULL with length 0 ok?
# If all the above pass, HAVE_WORKING_VSNPRINTF is defined and
# x_cv_func_vsnprintf_working is set to yes. Otherwise, it's set to no.
AC_DEFUN([FUNC_VSNPRINTF],
[AC_REQUIRE([FUNC_VSNPRINTF_RETVAL])
AC_REQUIRE([FUNC_VSNPRINTF_NULL_OK])
if test $x_cv_func_vsnprintf_retval = yes -a $x_cv_func_vsnprintf_null_ok = yes; then
AC_DEFINE(HAVE_WORKING_VSNPRINTF, 1, [Define if vsnprintf works properly])
x_cv_func_snprintf_working=yes
$1
else
x_cv_func_snprintf_working=no
$2
fi
])# FUNC_VSNPRINTF
# FUNC_VSNPRINTF_LIBOBJ
# --------------------
# If FUNC_VSNPRINTF fails, does AC_LIBOBJ.
AC_DEFUN([FUNC_VSNPRINTF_LIBOBJ],
[FUNC_VSNPRINTF(, [AC_LIBOBJ([vsnprintf])
AC_DEFINE([vsnprintf], [rpl_vsnprintf], [Define to rpl_vsnprintf if the replacement function should be used.])])])
])#FUNC_VSNPRINTF_LIBOBJ

View file

@ -1,190 +0,0 @@
dnl AC_FIND_XPM
dnl ---------------
dnl
dnl Find Xpm libraries and headers.
dnl Put Xpm include directory in xpm_includes,
dnl put Xpm library directory in xpm_libraries,
dnl and add appropriate flags to X_CFLAGS and X_LIBS.
dnl
dnl
AC_DEFUN([AC_FIND_XPM],
[
AC_REQUIRE([AC_PATH_XTRA])
xpm_includes=
xpm_libraries=
AC_ARG_WITH(xpm,
[ --without-xpm do not use the Xpm library])
dnl Treat --without-xpm like
dnl --without-xpm-includes --without-xpm-libraries.
if test "$with_xpm" = "no"
then
xpm_includes=no
xpm_libraries=no
fi
AC_ARG_WITH(xpm-includes,
[ --with-xpm-includes=DIR Xpm include files are in DIR],
xpm_includes="$withval")
AC_ARG_WITH(xpm-libraries,
[ --with-xpm-libraries=DIR
Xpm libraries are in DIR],
xpm_libraries="$withval")
AC_MSG_CHECKING(for Xpm)
#
#
# Search the include files. Note that XPM can come in <X11/xpm.h> (as
# in X11R6) or in <xpm.h> if installed locally.
#
if test "$xpm_includes" = ""; then
AC_CACHE_VAL(ice_cv_xpm_includes,
[
ice_xpm_save_LIBS="$LIBS"
ice_xpm_save_CFLAGS="$CFLAGS"
ice_xpm_save_CPPFLAGS="$CPPFLAGS"
ice_xpm_save_LDFLAGS="$LDFLAGS"
#
LIBS="$X_PRE_LIBS -lXpm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
CFLAGS="$X_CFLAGS $CFLAGS"
CPPFLAGS="$X_CFLAGS $CPPFLAGS"
LDFLAGS="$X_LIBS $LDFLAGS"
#
AC_TRY_COMPILE([
#include <X11/xpm.h>
],[int a;],
[
# X11/xpm.h is in the standard search path.
ice_cv_xpm_includes=
],
[
# X11/xpm.h is not in the standard search path.
# Locate it and put its directory in `xpm_includes'
#
# /usr/include/Motif* are used on HP-UX (Motif).
# /usr/include/X11* are used on HP-UX (X and Xaw).
# /usr/dt is used on Solaris (Motif).
# /usr/openwin is used on Solaris (X and Xaw).
# Other directories are just guesses.
for dir in "$x_includes" "${prefix}/include" /usr/include /usr/local/include \
/usr/include/Motif2.0 /usr/include/Motif1.2 /usr/include/Motif1.1 \
/usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 \
/usr/dt/include /usr/openwin/include \
/usr/dt/*/include /opt/*/include /usr/include/Motif* \
/usr/*/include/X11R6 /usr/*/include/X11R5 /usr/*/include/X11R4 \
"${prefix}"/*/include /usr/*/include /usr/local/*/include \
"${prefix}"/include/* /usr/include/* /usr/local/include/*; do
if test -f "$dir/X11/xpm.h" || test -f "$dir/xpm.h"; then
ice_cv_xpm_includes="$dir"
break
fi
done
if test "$ice_cv_xpm_includes" = "/usr/include"; then
ice_cv_xpm_includes=
fi
])
#
LIBS="$ice_xpm_save_LIBS"
CFLAGS="$ice_xpm_save_CFLAGS"
CPPFLAGS="$ice_xpm_save_CPPFLAGS"
LDFLAGS="$ice_xpm_save_LDFLAGS"
])
xpm_includes="$ice_cv_xpm_includes"
fi
#
#
# Now for the libraries.
#
if test "$xpm_libraries" = ""; then
AC_CACHE_VAL(ice_cv_xpm_libraries,
[
ice_xpm_save_LIBS="$LIBS"
ice_xpm_save_CFLAGS="$CFLAGS"
ice_xpm_save_CPPFLAGS="$CPPFLAGS"
ice_xpm_save_LDFLAGS="$LDFLAGS"
#
LIBS="$X_PRE_LIBS -lXpm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
CFLAGS="$X_CFLAGS $CFLAGS"
CPPFLAGS="$X_CFLAGS $CPPFLAGS"
LDFLAGS="$X_LIBS $LDFLAGS"
#
#
# We use XtToolkitInitialize() here since it takes no arguments
# and thus also works with a C++ compiler.
AC_TRY_LINK([
#include <X11/Intrinsic.h>
#include <X11/xpm.h>
],[XtToolkitInitialize();],
[
# libxpm.a is in the standard search path.
ice_cv_xpm_libraries=
],
[
# libXpm.a is not in the standard search path.
# Locate it and put its directory in `xpm_libraries'
#
#
# /usr/lib/Motif* are used on HP-UX (Motif).
# /usr/lib/X11* are used on HP-UX (X and Xpm).
# /usr/dt is used on Solaris (Motif).
# /usr/openwin is used on Solaris (X and Xpm).
# Other directories are just guesses.
for dir in "$x_libraries" "${prefix}/lib" /usr/lib /usr/local/lib \
/usr/lib/Motif2.0 /usr/lib/Motif1.2 /usr/lib/Motif1.1 \
/usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4 /usr/lib/X11 \
/usr/dt/lib /usr/openwin/lib \
/usr/dt/*/lib /opt/*/lib /usr/lib/Motif* \
/usr/*/lib/X11R6 /usr/*/lib/X11R5 /usr/*/lib/X11R4 /usr/*/lib/X11 \
"${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \
"${prefix}"/lib/* /usr/lib/* /usr/local/lib/*; do
if test -d "$dir" && test "`ls $dir/libXpm.* 2> /dev/null`" != ""; then
ice_cv_xpm_libraries="$dir"
break
fi
done
])
#
LIBS="$ice_xpm_save_LIBS"
CFLAGS="$ice_xpm_save_CFLAGS"
CPPFLAGS="$ice_xpm_save_CPPFLAGS"
LDFLAGS="$ice_xpm_save_LDFLAGS"
])
#
xpm_libraries="$ice_cv_xpm_libraries"
fi
#
# Add Xpm definitions to X flags
#
if test "$xpm_includes" != "" && test "$xpm_includes" != "$x_includes" && test "$xpm_includes" != "no"
then
X_CFLAGS="-I$xpm_includes $X_CFLAGS"
fi
if test "$xpm_libraries" != "" && test "$xpm_libraries" != "$x_libraries" && test "$xpm_libraries" != "no"
then
case "$X_LIBS" in
*-R\ *) X_LIBS="-L$xpm_libraries -R $xpm_libraries $X_LIBS";;
*-R*) X_LIBS="-L$xpm_libraries -R$xpm_libraries $X_LIBS";;
*) X_LIBS="-L$xpm_libraries $X_LIBS";;
esac
fi
#
#
xpm_libraries_result="$xpm_libraries"
xpm_includes_result="$xpm_includes"
if test "$xpm_libraries_result" != "no" && test "$xpm_includes_result" != "no"
then AC_DEFINE(HAVE_XPM, 1, "Define if you have libxpm")
LINK_XPM="-lXpm"
else LINK_XPM=""
fi
AC_SUBST(LINK_XPM)
test "$xpm_libraries_result" = "" &&
xpm_libraries_result="in default path"
test "$xpm_includes_result" = "" &&
xpm_includes_result="in default path"
test "$xpm_libraries_result" = "no" &&
xpm_libraries_result="(none)"
test "$xpm_includes_result" = "no" &&
xpm_includes_result="(none)"
AC_MSG_RESULT(
[libraries $xpm_libraries_result, headers $xpm_includes_result])
])dnl

View file

@ -1,436 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <unistd.h>
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pcre.h>
#include "wmweather+.h"
#include "metar.h"
#include "warnings.h"
#include "download.h"
#include "convert.h"
#include "die.h"
#include "sunzenith.h"
#include "moon.h"
#include "subst.h"
/* Important variables */
static time_t metar_time=0;
static char *metar_newfile=NULL;
static char *metar_file=NULL;
static char *metar_req[2]={ NULL, NULL };
struct current_weather current;
/* Regular Expressions */
static pcre *station_time;
static pcre *wind;
static pcre *weather;
static pcre *vis[4];
static pcre *temp;
static pcre *pressure;
static int ovecsize;
/* prototypes */
static int parse_metar(char *file);
/* functions */
static void reset_current(struct current_weather *c){
c->last_update=time(NULL);
c->month=0;
c->date=-1;
c->time=-1;
c->temp=999;
c->rh=-1;
c->winddir=-1;
c->windspeed=-1;
c->pressure=-1;
c->heatindex=999;
c->windchill=999;
c->sky=-1;
c->vis=7;
c->obs=0;
c->frz=0;
c->snow=0;
c->rain=0;
c->tstorm=0;
c->moon=NAN;
}
#define compile(var, re) \
var=pcre_compile(re, 0, (const char **)&e, &i, NULL); \
if(var==NULL) die("init_metar PCRE error: %s at %i", e, i); \
pcre_fullinfo(var, NULL, PCRE_INFO_CAPTURECOUNT, &i); \
if(i>ovecsize) ovecsize=i;
void init_metar(void){
int i;
char *e;
struct subst_val subs[]={
{ 's', STRING, &metar_station },
{ 0, 0, 0 }
};
snprintf(bigbuf, BIGBUF_LEN, "%s.metar.txt", metar_station);
metar_file=get_pid_filename(bigbuf);
snprintf(bigbuf, BIGBUF_LEN, "%s.new-metar.txt", metar_station);
metar_newfile=get_pid_filename(bigbuf);
if((metar_req[0]=subst(metar_uri, subs))==NULL) die("init_metar");
if(metar_post!=NULL && (metar_req[1]=subst(metar_post, subs))==NULL) die("init_metar");
metar_time=0;
ovecsize=0;
strncpy(bigbuf, metar_station, BIGBUF_LEN-25);
bigbuf[BIGBUF_LEN-25]='\0';
strcat(bigbuf, " ((?:\\d\\d)?)(\\d\\d\\d\\d)Z( .* )");
compile(station_time, bigbuf);
compile(wind, " (VRB|\\d\\d\\d)(\\d\\d\\d?)(?:G\\d\\d\\d?)?(KT|MPS|KMH)((?: \\d\\d\\dV\\d\\d\\d)?) ");
compile(weather, " ((?:-|\\+|VC)?)((?:MI|PR|BC|DR|BL|SH|TS|FZ)?)((?:DZ|RA|SN|SG|IC|PE|PL|GR|GS|UP){0,3})((?:BR|FG|FU|VA|DU|SA|HZ|PY)?)((?:PO|SQ|FC|SS|DS)?)\\b");
compile(vis[0], " (\\d+)SM ");
compile(vis[1], " (\\d+)/(\\d+)SM ");
compile(vis[2], " (\\d+) (\\d+)/(\\d+)SM ");
compile(vis[3], " (\\d{4})[NS]?[EW]? ");
compile(temp, " (M?\\d\\d\\d?)/((?:M?\\d\\d\\d?)?) ");
compile(pressure, " ([AQ])(\\d\\d\\d\\d) ");
ovecsize=(ovecsize+1)*3;
/* Remove stale file */
unlink(metar_file);
unlink(metar_newfile);
reset_current(&current);
current.last_update = 0; // This was not a real "update", just an init
}
#undef compile
static void metar_callback(char *filename, void *v){
struct stat statbuf;
if(stat(metar_newfile, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& parse_metar(metar_newfile)){
rename(metar_newfile, metar_file);
} else {
unlink(metar_newfile);
if(!parse_metar(metar_file)) reset_current(&current);
}
}
update_warnings(v!=NULL);
}
void metar_cleanup(void){
unlink(metar_newfile);
unlink(metar_file);
}
void update_metar(int force){
time_t t;
t=time(NULL)/60;
if(!force && metar_time>t) return;
metar_time=t+15;
download_file(metar_newfile, metar_req[0], metar_req[1], force?DOWNLOAD_KILL_OTHER_REQUESTS:0, metar_callback, force?"":NULL);
}
#define get_substr(n, c) \
if(pcre_get_substring(s, ovector, ovalue, n, (const char **)&c)<0){ pcre_free_substring(s); return 0; }
static int parse_metar(char *file){
FILE *fp;
char *s, *c;
int ovector[ovecsize];
int ovalue;
int len;
float f;
int i, j;
reset_current(&current);
if((fp=fopen(file, "r"))==NULL) return 0;
len=fread(bigbuf, sizeof(char), BIGBUF_LEN-2, fp);
fclose(fp);
if(len<1) return 0;
for(i=0; i<len; i++){
if(isspace(bigbuf[i])) bigbuf[i]=' ';
}
c=strstr(bigbuf, " RMK");
if(c!=NULL) *(c+1)='\0';
c=strstr(bigbuf, " TEMPO");
s=strstr(bigbuf, " BECMG");
if(c!=NULL) *(c+1)='\0';
if(s!=NULL) *(s+1)='\0';
/* XXX: parse trend forecast data? */
len=strlen(bigbuf);
if(bigbuf[len-1]!=' '){
bigbuf[len++]=' ';
bigbuf[len]='\0';
}
/* Look for something like a METAR coded report */
ovalue=pcre_exec(station_time, NULL, bigbuf, len, 0, 0, ovector, ovecsize);
if(ovalue<=0) return 0;
if(pcre_get_substring(bigbuf, ovector, ovalue, 1, (const char **)&c)<0) return 0;
if(c[0]!='\0') current.date=atoi(c);
pcre_free_substring(c);
if(pcre_get_substring(bigbuf, ovector, ovalue, 2, (const char **)&c)<0) return 0;
current.time=atoi(c);
pcre_free_substring(c);
/* Chop off extraneous stuff */
if(pcre_get_substring(bigbuf, ovector, ovalue, 3, (const char **)&s)<0) return 0;
/* windspeed, winddir */
ovalue=pcre_exec(wind, NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(4, c);
if(c[0]!='\0'){
current.winddir=0;
} else {
pcre_free_substring(c);
get_substr(1, c);
if(c[0]=='V') current.winddir=0;
else current.winddir=((int)((atoi(c)+11.25)/22.5))%16+1;
}
pcre_free_substring(c);
get_substr(2, c);
current.windspeed=atoi(c);
pcre_free_substring(c);
get_substr(3, c);
if(c[0]=='M'){ /* MPS */
current.windspeed=mps2knots(current.windspeed);
} else if(c[0]=='K' && c[1]=='M'){ /* KMH */
current.windspeed=kph2knots(current.windspeed);
}
}
/* vis */
f=99;
c=strstr(s, " M1/4SM ");
if(c!=NULL){
f=0;
goto wind_done;
}
ovalue=pcre_exec(vis[2], NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(2, c);
i=atoi(c);
pcre_free_substring(c);
get_substr(3, c);
j=atoi(c);
pcre_free_substring(c);
get_substr(1, c);
f=atoi(c)+(float)i/j;
pcre_free_substring(c);
goto wind_done;
}
ovalue=pcre_exec(vis[1], NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(2, c);
i=atoi(c);
pcre_free_substring(c);
get_substr(1, c);
f=(float)atoi(c)/i;
pcre_free_substring(c);
goto wind_done;
}
ovalue=pcre_exec(vis[0], NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(1, c);
f=atoi(c);
pcre_free_substring(c);
goto wind_done;
}
c=strstr(s, " CAVOK ");
if(c!=NULL){
f=99;
current.sky=0;
goto wind_done;
}
ovalue=pcre_exec(vis[3], NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(1, c);
f=m2mi(atoi(c));
pcre_free_substring(c);
goto wind_done;
}
wind_done:
if(f<=6) current.vis=6;
if(f<=5) current.vis=5;
if(f<3) current.vis=4;
if(f<1) current.vis=3;
if(f<=.5) current.vis=2;
if(f<=.25) current.vis=1;
/* temp, rh */
ovalue=pcre_exec(temp, NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(1, c);
if(c[0]=='M') c[0]='-';
current.temp=atoi(c);
pcre_free_substring(c);
get_substr(2, c);
if(c[0]!='\0'){
if(c[0]=='M') c[0]='-';
current.rh=rh_C(current.temp, atoi(c));
}
pcre_free_substring(c);
}
/* pressure */
ovalue=pcre_exec(pressure, NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0){
get_substr(2, c);
i=atoi(c);
pcre_free_substring(c);
get_substr(1, c);
if(c[0]=='Q'){
current.pressure=hPa2inHg(i);
} else {
current.pressure=i/100.0;
}
pcre_free_substring(c);
}
/* sky */
if(strstr(s, " SKC")!=NULL || strstr(s, " CLR")!=NULL) current.sky=0;
if(strstr(s, " FEW")!=NULL) current.sky=1;
if(strstr(s, " SCT")!=NULL) current.sky=2;
if(strstr(s, " BKN")!=NULL) current.sky=3;
if(strstr(s, " OVC")!=NULL || strstr(s, " VV")!=NULL) current.sky=4;
/* obs, frz, snow, rain, tstorm */
/* There can be multiple weather chunks, so we while loop */
j=0;
while((ovalue=pcre_exec(weather, NULL, s, len, j, 0, ovector, ovecsize))>0){{
char *in, *de, *pp, *ob, *ot;
j=ovector[0]+1;
get_substr(0, c);
i=(c[1]=='\0');
pcre_free_substring(c);
if(i) continue;
get_substr(1, in);
get_substr(2, de);
get_substr(3, pp);
get_substr(4, ob);
get_substr(5, ot);
#define IN(haystack, needle) ((needle[0]=='\0')?0:strstr(haystack, needle))
if(current.obs<1 && strcmp(de, "FZ") && IN("BR|FG", ob))
current.obs=1;
if(current.obs<2 && IN("FU|VA|DU|SA|HZ|PY", ob))
current.obs=2;
if(current.obs<3 && IN("PO|SS|DS", ot))
current.obs=3;
if(current.obs<3 && IN("DR|BL", de)
&& (strstr(pp, "SN") || IN("DU|SA|PY", ob)))
current.obs=3;
if(!strcmp(ot, "FC")){
current.sky=5;
current.obs=99;
current.vis=7;
}
#undef IN
i=66;
if(in[0]=='-' || in[0]=='V') i=33;
if(in[0]=='+') i=99;
if(!strcmp(de, "SH")) i=33;
if(current.frz<i
&& ((!strcmp(de, "FZ") && (strstr(pp, "DZ") || strstr(pp, "RA")))
|| strstr(pp, "IC") || strstr(pp, "PE") || strstr(pp, "PL")
|| strstr(pp, "GR") || strstr(pp, "GS")))
current.frz=i;
if(current.snow<i && strcmp(de, "BL")
&& (strstr(pp, "SN") || strstr(pp, "SG")))
current.snow=i;
if(current.rain<i && (strstr(pp, "UP")
|| (strcmp(de, "FZ")
&& (strstr(pp, "DZ") || strstr(pp, "RA")))))
current.rain=i;
if(current.tstorm<i && !strcmp(de, "TS"))
current.tstorm=i;
pcre_free_substring(in);
pcre_free_substring(de);
pcre_free_substring(pp);
pcre_free_substring(ob);
pcre_free_substring(ot);
}}
if(current.obs==99) current.obs=0;
pcre_free_substring(s); /* Done parsing! Just a few final calculations... */
current.heatindex=heatindex_C(current.temp, current.rh);
current.windchill=windchill_C(current.temp, current.windspeed);
/* Figure out the proper month... */
{
int mon, day, year, time2; /* holds UTC */
int y; /* with current.*, holds local time */
time_t t=time(NULL);
struct tm *tm=gmtime(&t);
current.month=tm->tm_mon+1;
if(tm->tm_mday<current.date) current.month--;
if(current.month<1){ current.month+=12; tm->tm_year--; }
y=year=tm->tm_year;
mon=current.month;
day=current.date;
time2=current.time;
current.time=utc2local((int)current.time, &current.month, &current.date, &y, NULL);
if(latitude!=999 && calcSolarZenith(latitude, longitude, year, mon, day, hm2min(time2))>90)
current.moon=calc_moon(current.month, current.date, y, current.time);
}
return 1;
}
#undef get_substr

View file

@ -1,27 +0,0 @@
struct current_weather {
time_t last_update;
int month; /* 0, 1 - 12 */
int date; /* -1, 1 - 31 (GMT) */
short time; /* -1, 0000 - 2359 */
short temp; /* 999, -210 - 390 (degrees C) */
signed char rh; /* -1, 0 - 100 (%) */
short winddir; /* -1, 0 - 16 (direction) */
short windspeed; /* -1, 0 - MAX (knots) */
float pressure; /* -1, 0 - MAX (inHg) */
short heatindex; /* 999, -99 - 199 (degrees F) */
short windchill; /* 999, -99 - 199 (degrees F) */
signed char sky; /* -1, 0-4 (condition) */
signed char vis; /* 7, 1-7 (status code) */
signed char obs; /* 0, 0-3 (type) */
signed char frz; /* 0, 0, 33, 66, 99 (intensity) */
signed char snow; /* 0, 0, 33, 66, 99 (intensity) */
signed char rain; /* 0, 0, 33, 66, 99 (intensity) */
signed char tstorm; /* 0, 0, 33, 66, 99 (intensity) */
double moon; /* NAN, -1 - 1 (percent and wax/wane) */
};
extern struct current_weather current;
void init_metar(void);
void update_metar(int force);
void metar_cleanup(void);

View file

@ -1,179 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* One-line algorithm from http://www.moonstick.com/moon_phase_emergency.htm
* It's a bit rough, but it works well enough */
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <math.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "convert.h"
#include "wmgeneral/wmgeneral-x11.h"
static double fpart(double t){
return t-trunc(t);
}
double calc_moon(int month, int day, int year, int hm){
time_t t=time(NULL);
struct tm *tm;
double p;
tm=gmtime(&t);
tm->tm_hour=hm/100;
tm->tm_min=hm%100;
tm->tm_sec=0;
tm->tm_mon=month-1;
tm->tm_mday=day;
tm->tm_year=year;
t=mkgmtime(tm);
/* This next line is the algorithm. */
p=fpart(((t/86400.0-11323.0)*850.0+5130.5769)/25101.0);
if(p>.5) return -.5+cos(2*PI*p)/2;
return .5-cos(2*PI*p)/2;
}
#define darkside 0.19921875
#define lightside (1-0.19921875)
#define maxwidth 17
static int widths[]={ 7, 11, 13, 15, 15, 17, 17, 17, 17, 17, 17, 17, 15, 15, 13, 11, 7, -1 };
extern int screen;
extern XpmIcon wmgen;
extern GC NormalGC;
/* Duplicates quite a bit of code from combineWithOpacity for speed */
void copySunMoon(int x, int y, double percent){
XImage *pix;
unsigned int w, h, bar;
int foo;
Window baz;
int rmask, gmask, bmask;
unsigned long spixel;
int xx, terminator, oflag;
int flag;
double frac;
if(isnan(percent)){
copyPixmapArea(164, 64, 26, 25, x, y);
return;
}
XGetGeometry(display, wmgen.pixmap, &baz, &foo, &foo, &w, &h, &bar, &bar);
pix=XGetImage(display, wmgen.pixmap, 0, 0, w, h, AllPlanes, ZPixmap);
if (pix->depth == DefaultDepth(display, screen)) {{
Visual *visual=DefaultVisual(display, screen);
rmask = visual->red_mask;
gmask = visual->green_mask;
bmask = visual->blue_mask;
}} else {
rmask = pix->red_mask;
gmask = pix->green_mask;
bmask = pix->blue_mask;
}
x+=4; y+=4;
flag=(percent<0);
if(flag) percent=-percent;
for(h=0; widths[h]>0; h++){
xx=(maxwidth-widths[h])>>1;
if(flag){
oflag=1;
terminator=widths[h]*percent;
} else {
oflag=0;
terminator=widths[h]-widths[h]*percent;
}
frac=lightside*fpart(widths[h]*percent)+darkside;
for(w=0; w<widths[h]; w++){
spixel=XGetPixel(pix, 168+xx+w, 93+h);
if(w==terminator){
oflag=!oflag;
XPutPixel(pix, x+xx+w, y+h,
(((unsigned long)((spixel&rmask)*frac))&rmask) |
(((unsigned long)((spixel&gmask)*frac))&gmask) |
(((unsigned long)((spixel&bmask)*frac))&bmask));
} else if(oflag){
XPutPixel(pix, x+xx+w, y+h, spixel);
} else {
XPutPixel(pix, x+xx+w, y+h,
(((unsigned long)((spixel&rmask)*darkside))&rmask) |
(((unsigned long)((spixel&gmask)*darkside))&gmask) |
(((unsigned long)((spixel&bmask)*darkside))&bmask));
}
}
}
XPutImage(display, wmgen.pixmap, NormalGC, pix, 0, 0, 0, 0, pix->width, pix->height);
XDestroyImage(pix);
}
#if 0
void copySunMoon(int x, int y, double percent){
int w, h;
int xx;
int frac;
int flag;
if(isnan(percent)){
copyPixmapArea(164, 64, 26, 25, x, y);
return;
}
combineWithOpacity(164, 89, 26, 25, x, y, 51);
x+=4; y+=4;
flag=(percent<0);
if(flag) percent=-percent;
for(h=0; h<=8; h++){
w=widths[h]*percent;
frac=(widths[h]*percent-w)*100;
if(flag) xx=(17-widths[h])/2;
else xx=(17+widths[h])/2-w;
copyPixmapArea(141+xx, 93+h, w, 1, x+xx, y+h);
copyPixmapArea(141+xx, 109-h, w, 1, x+xx, y+16-h);
if(flag){
combineWithOpacity(141+xx+w, 93+h, 1, 1, x+xx+w, y+h, frac);
combineWithOpacity(141+xx+w, 109-h, 1, 1, x+xx+w, y+16-h, frac);
} else {
combineWithOpacity(141+xx-1, 93+h, 1, 1, x+xx-1, y+h, frac);
combineWithOpacity(141+xx-1, 109-h, 1, 1, x+xx-1, y+16-h, frac);
}
}
}
#endif

View file

@ -1,2 +0,0 @@
double calc_moon(int month, int day, int year, int hm);
void copySunMoon(int x, int y, double percent);

View file

@ -1,318 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/stat.h>
#include "wmweather+.h"
#include "forecast.h"
#include "getLine.h"
#include "convert.h"
#include "download.h"
#include "diff.h"
#include "die.h"
#include "subst.h"
/* Important variables */
#define MRF_MAX 7
static time_t mrf_time=0;
static char *mrf_file=NULL;
static char *mrf_newfile=NULL;
static char *mrf_req[2]={ NULL, NULL };
static struct forecast forecasts[MRF_MAX];
/********* init functions ************/
static int parse_mrf(char *file);
static void reset_mrf(void){
int i;
for(i=0; i<MRF_MAX; i++) reset_forecast(&forecasts[i]);
}
void init_mrf(void){
int i;
char *e;
struct subst_val subs[]={
{ 's', STRING, &mrf_station },
{ 0, 0, 0 }
};
strncpy(bigbuf, mrf_station, BIGBUF_LEN-14);
bigbuf[BIGBUF_LEN-14]='\0';
for(e=bigbuf; *e!='\0'; e++);
strcpy(e, ".mrf.txt");
mrf_file=get_pid_filename(bigbuf);
strcpy(e, ".new-mrf.txt");
mrf_newfile=get_pid_filename(bigbuf);
if((mrf_req[0]=subst(mrf_uri, subs))==NULL) die("init_mrf");
if(mrf_post!=NULL && (mrf_req[1]=subst(mrf_post, subs))==NULL) die("init_mrf");
mrf_time=0;
/* Remove stale file */
unlink(mrf_file);
unlink(mrf_newfile);
reset_mrf();
for(i=0; i<MRF_MAX; i++) add_forecast(&forecasts[i], "MRF", mrf_station);
}
static void mrf_callback(char *filename, void *v){
struct stat statbuf;
if(stat(mrf_newfile, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& diff(mrf_newfile, mrf_file) && parse_mrf(mrf_newfile)){
mrf_time=find_next_time(mrf_newfile, "MOS GUIDANCE", 1440);
rename(mrf_newfile, mrf_file);
} else {
unlink(mrf_newfile);
if(!parse_mrf(mrf_file)) reset_mrf();
}
}
}
void mrf_cleanup(void){
if(mrf_file==NULL) return;
unlink(mrf_newfile);
unlink(mrf_file);
}
void update_mrf(int force){
time_t t;
if(mrf_file==NULL) return;
t=time(NULL)/60;
if(!force && mrf_time>t) return;
mrf_time=find_next_time(mrf_file, "MOS GUIDANCE", 15);
download_file(mrf_newfile, mrf_req[0], mrf_req[1], 0, mrf_callback, NULL);
}
#define NEXT(s) free(s); \
len=getLine(&s, fp); \
if(strstr(s, "</PRE>")!=NULL) len=0;
#define DIE() return (free(s), fclose(fp), 0)
#define INT(c) (tmp[0]=*c, tmp[1]=*(c+1), tmp[2]=*(c+2), tmp[3]=0, atoi(tmp))
static int parse_mrf(char *file){
FILE *fp;
char *s, *c;
int len;
int mon, day;
int i, j, m, x, y;
int flag;
char tmp[4]={0, 0, 0, 0};
flag=0;
reset_mrf();
if((fp=fopen(file, "r"))==NULL) return 0;
/* Look for something like an MRF coded forecast */
c=NULL;
while(!feof(fp)){
len=getLine(&s, fp);
if((c=strstr(s, "MOS GUIDANCE"))!=NULL) break;
free(s);
}
if(c==NULL) return (fclose(fp), 0);
c=strchr(c, '/');
if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
mon=atoi(c-2);
x=atoi(c+1);
if(mon<1 || mon>12 || x<1 || x>31) DIE();
c=strchr(c+1, '/');
if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
y=atoi(c+1)-1900;
NEXT(s);
if(len<10) DIE();
if(strncmp(s, "FHR", 3)) DIE();
NEXT(s);
if(len<10) DIE();
for(i=0; i<7; i++){
if(!strncmp(s, wdaynames[i], 3)) break;
}
if(i>=7) DIE();
day=atoi(s+4);
if(x>25 && day<5) mon++;
if(x<5 && day>25) mon--;
for(m=0; m<MRF_MAX; m++){
day++;
i++; i%=7;
fix_date(&mon, &day, &y, &j);
if(j!=i){
warn("Something wicked happened with the mrf_parse dates...");
DIE();
}
forecasts[m].month=mon;
forecasts[m].day=day;
forecasts[m].year=y;
forecasts[m].wday=i;
forecasts[m].hour=-1;
}
while(1){
NEXT(s);
if(len<=10) break;
if(!strncmp(s, "X/N", 3)){
for(c=s+12, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
forecasts[m].high=INT(c);
if(c+4<s+len) forecasts[m].low=INT((c+4));
}
continue;
}
if(!strncmp(s, "TMP", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=INT(c); j=INT((c+4));
if(i!=999 && j!=999) forecasts[m].temp=(i+j)/2;
else if(i!=999) forecasts[m].temp=i;
else if(j!=999) forecasts[m].temp=j;
}
continue;
}
if(!strncmp(s, "DPT", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=INT(c); j=INT((c+4));
if(i!=999 && j!=999) forecasts[m].dewpt=(i+j)/2;
else if(i!=999) forecasts[m].dewpt=i;
else if(j!=999) forecasts[m].dewpt=j;
}
continue;
}
if(!strncmp(s, "WND", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=INT(c); j=INT((c+4));
if(i!=999 && j!=999) forecasts[m].windspeed=(i+j)/2;
else if(i!=999) forecasts[m].windspeed=i;
else if(j!=999) forecasts[m].windspeed=j;
}
continue;
}
if(!strncmp(s, "T24", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=atoi(c);
if(i!=999) forecasts[m].tstorm=i;
}
continue;
}
if(!strncmp(s, "Q24", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=atoi(c);
if(i!=9) forecasts[m].precipamt=i;
}
continue;
}
if(!strncmp(s, "SNW", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=atoi(c);
if(i!=9) forecasts[m].snowamt=i;
}
continue;
}
if(!strncmp(s, "CLD", 3)){
for(c=s+13, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
if(*c=='C') forecasts[m].sky=0;
if(*c=='P'){
if(*(c-4)=='C') forecasts[m].sky=2;
else if(*(c-4)=='O') forecasts[m].sky=3;
else if(c+4<s+len && *(c+4)=='C') forecasts[m].sky=2;
else if(c+4<s+len && *(c+4)=='O') forecasts[m].sky=3;
else forecasts[m].sky=3;
}
if(*c=='O') forecasts[m].sky=4;
}
continue;
}
if(!strncmp(s, "PZP", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=INT(c); j=INT((c+4));
if(i!=999 && j!=999) forecasts[m].frz=(i+j)/2;
else if(i!=999) forecasts[m].frz=i;
else if(j!=999) forecasts[m].frz=j;
}
continue;
}
if(!strncmp(s, "PSN", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=INT(c); j=INT((c+4));
if(i!=999 && j!=999) forecasts[m].snow=(i+j)/2;
else if(i!=999) forecasts[m].snow=i;
else if(j!=999) forecasts[m].snow=j;
}
continue;
}
if(!strncmp(s, "PRS", 3)){
/* stick "rain & snow" prob into rain for later */
flag=1;
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=INT(c); j=INT((c+4));
if(i!=999 && j!=999) forecasts[m].rain=(i+j)/2;
else if(i!=999) forecasts[m].rain=i;
else if(j!=999) forecasts[m].rain=j;
}
continue;
}
if(!strncmp(s, "P24", 3)){
for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
i=atoi(c);
if(i!=999) forecasts[m].pcp_total=i;
}
continue;
}
}
free(s);
fclose(fp);
for(m=0; m<MRF_MAX; m++){
forecasts[m].rh=rh_F(forecasts[m].temp, forecasts[m].dewpt);
forecasts[m].heatindex=heatindex_F(forecasts[m].temp, forecasts[m].rh);
forecasts[m].windchill=windchill_F(forecasts[m].temp, forecasts[m].windspeed);
/* real rain = 100 - frz - snow
* real snow = snow + "rain & snow"
*/
i=100-forecasts[m].frz-forecasts[m].snow;
forecasts[m].snow+=forecasts[m].rain;
forecasts[m].rain=i;
forecasts[m].rain=forecasts[m].rain*forecasts[m].pcp_total/100;
forecasts[m].snow=forecasts[m].snow*forecasts[m].pcp_total/100;
forecasts[m].frz=forecasts[m].frz*forecasts[m].pcp_total/100;
/* These aren't really useful here... */
forecasts[m].temp=999;
forecasts[m].dewpt=999;
}
return 1;
}
#undef NEXT
#undef DIE
#undef INT

View file

@ -1,8 +0,0 @@
#ifndef MRF_H
#define MRF_H
void init_mrf(void);
void update_mrf(int force);
void mrf_cleanup(void);
#endif

View file

@ -1,266 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <wraster.h>
#include <X11/xpm.h>
#include "wmweather+.h"
#include "wmgeneral/wmgeneral-x11.h"
#include "wmgeneral/xpm_trans.h"
#include "download.h"
#include "radar.h"
#include "die.h"
/* Important variables */
static time_t radar_time=0;
static char *radar_file=NULL;
static char *radar_newfile=NULL;
static int cropx, cropy, cropw, croph;
static int crossx, crossy;
time_t radar_update_time;
Pixmap radar;
int do_radar_cross;
extern XpmIcon wmgen;
extern GC NormalGC;
extern int screen;
extern int d_depth;
/* prototypes */
static int parse_radar(char *file);
/* functions */
static void reset_radar(Pixmap *r){
XCopyArea(display, wmgen.pixmap, *r, NormalGC, 124, 18, 52, 40, 0, 0);
XCopyArea(display, wmgen.pixmap, *r, NormalGC, 108, 89, 15, 14, 18, 13);
}
static void parse_cross(void){
char *p1, *p2;
if(radar_cross==NULL) return;
crossx=strtol(radar_cross, &p1, 10);
if(crossx<0 || crossx>=52 || p1==NULL || p1==radar_cross || *p1!='x'){
radar_cross=NULL;
return;
}
crossy=strtol(++p1, &p2, 10);
if(crossy<0 || crossy>=40 || (p2!=NULL && *p2!='\0')){
radar_cross=NULL;
return;
}
}
static void parse_crop(void){
char *p1, *p2;
if(radar_crop==NULL) return;
cropx=strtol(radar_crop, &p1, 10);
if(p1==NULL || p1==radar_crop || *p1!='x'){
radar_crop=NULL;
return;
}
cropy=strtol(++p1, &p2, 10);
if(p2==NULL || p2==p1 || *p2!='+'){
radar_crop=NULL;
return;
}
cropw=strtol(p2, &p1, 10);
if(cropw<1 || p1==NULL || *p1!='+'){
radar_crop=NULL;
return;
}
croph=strtol(p1, &p2, 10);
if(croph<1 || (p2!=NULL && *p2!='\0')){
radar_crop=NULL;
return;
}
}
void init_radar(void){
char *e;
radar=XCreatePixmap(display, wmgen.pixmap, 52, 40, d_depth);
reset_radar(&radar);
if(radar_uri==NULL) return;
e=strrchr(radar_uri, '/');
if(e==NULL) e=radar_uri;
else e++;
snprintf(bigbuf, BIGBUF_LEN-21, "%s.", e);
for(e=bigbuf; *e!='\0'; e++){
if(!isalnum(*e) && *e!='.' && *e!='-' && *e!='+' && *e!='%'
&& *e!='?' && *e!='=' && *e!='&') *e='_';
}
strcpy(e, "radar-image");
radar_file=get_pid_filename(bigbuf);
strcpy(e, "new-radar-image");
radar_newfile=get_pid_filename(bigbuf);
radar_update_time=radar_time==0;
parse_crop();
parse_cross();
do_radar_cross=0;
/* Delete stale files, if any */
unlink(radar_file);
unlink(radar_newfile);
}
static void radar_callback(char *filename, void *v){
struct stat statbuf;
if(stat(radar_newfile, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& parse_radar(radar_newfile)){
rename(radar_newfile, radar_file);
} else {
unlink(radar_newfile);
if(!parse_radar(radar_file)) reset_radar(&radar);
}
}
}
void radar_cleanup(void){
if(radar_file==NULL) return;
unlink(radar_newfile);
unlink(radar_file);
}
void update_radar(int force){
time_t t;
if(radar_file==NULL) return;
t=time(NULL)/60;
if(!force && radar_time>t) return;
radar_time=t+30;
download_file(radar_newfile, radar_uri, radar_post, force?DOWNLOAD_KILL_OTHER_REQUESTS:0, radar_callback, NULL);
}
static RContext *rc=NULL;
static int parse_radar(char *file){
RImage *r, *n;
float w, h;
RColor col={ 0, 0, 0, 255};
int x, y, ww, hh;
errno=0;
radar_update_time=time(NULL);
reset_radar(&radar);
if(rc==NULL){
rc=RCreateContext(display, screen, NULL);
if(rc==NULL){
warn("parse_radar context creation: %s", RMessageForError(RErrorCode));
return 0;
}
}
r=RLoadImage(rc, file, 0);
if(!r) return 0;
if(radar_crop!=NULL){
x=cropx; y=cropy;
ww=cropw; hh=croph;
if(x<0) x+=r->width;
if(y<0) y+=r->height;
if(x<0){ ww+=x; x=0; }
if(y<0){ hh+=y; y=0; }
if(x>=r->width || y>=r->width || ww<=0 || hh<=0){
RReleaseImage(r);
warn("parse_radar radar_crop exceeds image dimensions");
return 0;
}
n=RGetSubImage(r, x, y, ww, hh);
RReleaseImage(r);
r=n;
if(!r){
warn("parse_radar crop: %s", RMessageForError(RErrorCode));
return 0;
}
}
if(r->width>52 || r->height>40 || (r->width!=52 && r->height!=40)){
w=r->width/52;
h=r->height/40;
if(w>h) h=w;
else w=h;
n=RSmoothScaleImage(r, r->width/w, r->height/h);
RReleaseImage(r);
r=n;
if(!r){
warn("parse_radar scale: %s", RMessageForError(RErrorCode));
return 0;
}
}
if(r->width!=52 || r->height!=40){
n=RMakeCenteredImage(r, 52, 40, &col);
RReleaseImage(r);
r=n;
if(!r){
warn("parse_radar center: %s", RMessageForError(RErrorCode));
return 0;
}
}
if(!RConvertImage(rc, r, &radar)){
RReleaseImage(r);
warn("parse_radar convert: %s", RMessageForError(RErrorCode));
return 0;
}
RReleaseImage(r);
return 1;
}
void put_radar(int x, int y, int font){
int i;
XCopyArea(display, radar, wmgen.pixmap, NormalGC, 0, 0, 52, 40, x, y);
if(font==0) i=0;
else i=1;
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 124, 60+i, 54, 1, x-1, y-1);
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 124, 60+i, 54, 1, x-1, y+40);
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 162+i, 64, 1, 40, x-1, y);
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 162+i, 64, 1, 40, x+52, y);
if(radar_cross && do_radar_cross){
combineWithOpacity(124, 60+i, 52, 1, x, y+crossy, 128);
combineWithOpacity(162+i, 64, 1, 40, x+crossx, y, 128);
}
}

View file

@ -1,10 +0,0 @@
#include <X11/xpm.h>
extern time_t radar_update_time;
extern Pixmap radar;
extern int do_radar_cross;
void init_radar(void);
void update_radar(int force);
void put_radar(int x, int y, int font);
void radar_cleanup(void);

View file

@ -1,188 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include "die.h"
#include "subst.h"
#define GROW(var, len){{ \
void *c; \
len<<=1; \
if(len==0) len=1; \
if((var=realloc(c=var, len))==NULL){ \
out=c; \
warn("realloc error"); \
goto fail; \
} \
}}
#define COPY(c) { \
if(k>=formatlen) GROW(format, formatlen); \
format[k++]=c; \
}
char *subst(const char *s, struct subst_val *substitutes){
int i, j, k, n, m;
char *out=NULL;
size_t outlen=0;
char *format=NULL;
size_t formatlen=0;
int flags;
ssize_t str_start;
for(i=j=0; s[i]!='\0'; i++){
if(s[i]!='%'){
if(j>=outlen) GROW(out, outlen);
out[j++]=s[i];
continue;
}
if(s[i+1]=='%'){
if(j>=outlen) GROW(out, outlen);
out[j++]=s[i++];
continue;
}
n=i;
k=0;
COPY('%');
/* skip flags */
flags=0;
while(strchr("#0- +'!", s[++n])){
if(s[n]=='!'){
flags|=1;
} else {
COPY(s[n]);
}
}
/* min width? */
if(isdigit(s[n]) && s[n]!='0'){
COPY(s[n]);
while(isdigit(s[++n])){ COPY(s[n]); }
}
/* precision? */
if(s[n]=='.'){
COPY('.');
while(isdigit(s[++n])){ COPY(s[n]); }
}
str_start=0;
if(s[n]=='>'){
if(s[n+1]=='-'){
flags|=2;
n++;
}
while(isdigit(s[++n])){
str_start=str_start*10+s[n]-'0';
}
if(flags&2) str_start=-str_start;
}
for(m=0; s[n]!=substitutes[m].id && substitutes[m].id!='\0'; m++);
if(substitutes[m].id=='\0'){
warn("Unknown substitition character '%c' (at %d)\n", s[n], i);
goto fail;
}
switch(substitutes[m].type){
case HEX:
case FLOAT_E:
case FLOAT_F:
case FLOAT_G:
case FLOAT_A:
if(flags&1){
COPY(toupper(substitutes[m].type));
break;
}
/* fall through*/
default:
COPY(substitutes[m].type);
break;
}
COPY('\0');
#define PRINT(var) { while((k=j+snprintf(out+j, outlen-j, format, var))>=outlen) GROW(out, outlen); j=k; }
switch(substitutes[m].type){
case INT:
PRINT(*(signed int *)substitutes[m].val);
break;
case UINT:
case OCTAL:
case HEX:
PRINT(*(unsigned int *)substitutes[m].val);
break;
case FLOAT_E:
case FLOAT_F:
case FLOAT_G:
case FLOAT_A:
PRINT(*(double *)substitutes[m].val);
break;
case CHAR:
PRINT(*(char *)substitutes[m].val);
if(flags&1) out[j-1]=toupper(out[j-1]);
break;
case STRING:
{
char *s=*(char **)substitutes[m].val;
if(str_start<0){
str_start+=strlen(s);
if(str_start<0) str_start=0;
} else if(str_start>strlen(s)){
s="";
str_start=0;
}
s+=str_start;
i=j;
PRINT(s);
if(flags&1){
for(; i<j; i++) out[i]=toupper(out[i]);
}
}
break;
default:
warn("Unknown substitution type '%c'\n", substitutes[m].type);
goto fail;
}
i=n;
}
free(format);
if(j>=outlen) GROW(out, outlen);
out[j]='\0';
return out;
fail:
free(format);
free(out);
return NULL;
}

View file

@ -1,23 +0,0 @@
#ifndef SUBST_H
#define SUBST_H
struct subst_val {
char id; /* if id=='X', %X will be substituted */
enum {
INT ='i', /* val => signed int */
UINT ='u', /* val => unsigned int */
OCTAL ='o', /* val => unsigned int */
HEX ='x', /* val => unsigned int */
FLOAT_E ='e', /* val => double */
FLOAT_F ='f', /* val => double */
FLOAT_G ='g', /* val => double */
FLOAT_A ='a', /* val => double */
CHAR ='c', /* val => char */
STRING ='s' /* val => char * */
} type;
void *val;
};
char *subst(const char *s, struct subst_val *substitutes);
#endif

View file

@ -1,138 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Algorithms from http://www.srrb.noaa.gov/highlights/sunrise/azel.html */
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <limits.h>
#include "convert.h"
/* Purpose: calculate the Geometric Mean Longitude of the Sun (degrees) */
double calcGeomMeanLongSun(double t) {
double L0 = 280.46646 + t * (36000.76983 + 0.0003032 * t);
while(L0 > 360.0) {
L0 -= 360.0;
}
while(L0 < 0.0) {
L0 += 360.0;
}
return L0;
}
/* Purpose: calculate the Geometric Mean Anomaly of the Sun (degrees) */
double calcGeomMeanAnomalySun(double t) {
return 357.52911 + t * (35999.05029 - 0.0001537 * t);
}
/* Purpose: calculate the eccentricity of earth's orbit */
double calcEccentricityEarthOrbit(double t) {
return 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
}
/* Purpose: calculate the equation of center for the sun (degrees) */
double calcSunEqOfCenter(double t) {
double m = deg2rad(calcGeomMeanAnomalySun(t));
return sin(m) * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin(m+m) * (0.019993 - 0.000101 * t) + sin(m+m+m) * 0.000289;
}
/* Purpose: calculate the true longitude of the sun (degrees) */
double calcSunTrueLong(double t) {
return calcGeomMeanLongSun(t) + calcSunEqOfCenter(t);
}
/* Purpose: calculate the apparent longitude of the sun (degrees) */
double calcSunApparentLong(double t) {
return calcSunTrueLong(t) - 0.00569 - 0.00478 * sin(deg2rad(125.04-1934.136*t));
}
/* Purpose: calculate the mean obliquity of the ecliptic (degrees) */
double calcMeanObliquityOfEcliptic(double t) {
return 23.0 + (26.0 + ((21.448 - t*(46.8150 + t*(0.00059 - t*(0.001813))))/60.0))/60.0;
}
/* Purpose: calculate the corrected obliquity of the ecliptic (degrees) */
double calcObliquityCorrection(double t) {
return calcMeanObliquityOfEcliptic(t) + 0.00256*cos(deg2rad(125.04-1934.136*t));
}
/* Purpose: calculate the declination of the sun (degrees) */
double calcSunDeclination(double t) {
return rad2deg(asin(sin(deg2rad(calcObliquityCorrection(t))) *
sin(deg2rad(calcSunApparentLong(t)))));
}
/* Purpose: calculate the difference between true solar time and mean
* solar time (minutes)
*/
double calcEquationOfTime(double t) {
double l0 = deg2rad(calcGeomMeanLongSun(t));
double e = calcEccentricityEarthOrbit(t);
double m = deg2rad(calcGeomMeanAnomalySun(t));
double y = tan(deg2rad(calcObliquityCorrection(t))/2.0);
double sinm = sin(m);
y *= y;
return rad2deg(y*sin(2.0*l0) - 2.0*e*sinm + 4.0*e*y*sinm*cos(2.0*l0)
- 0.5*y*y*sin(4.0*l0) - 1.25*e*e*sin(2.0*m))*4.0;
}
double calcSolarZenith(double latitude, double longitude, int year, int month, int day, int timeUTC){
double T, trueSolarTime, hourAngle, solarDec, csz, zenith, exoatmElevation, te, refractionCorrection;
T=jd2jcent(mdy2jd(year, month, day) + timeUTC/1440.0);
trueSolarTime = timeUTC + calcEquationOfTime(T) - 4.0 * longitude;
hourAngle = trueSolarTime / 4.0 - 180.0;
solarDec = calcSunDeclination(T);
csz = sin(deg2rad(latitude)) * sin(deg2rad(solarDec)) +
cos(deg2rad(latitude)) * cos(deg2rad(solarDec)) *
cos(deg2rad(hourAngle));
zenith=rad2deg(acos(csz));
exoatmElevation = 90.0 - zenith;
if (exoatmElevation > 85.0) {
refractionCorrection = 0.0;
} else {
te = tan(deg2rad(exoatmElevation));
if (exoatmElevation > 5.0) {
refractionCorrection = 58.1/te - 0.07/(te*te*te) +
0.000086/(te*te*te*te*te);
} else if (exoatmElevation > -0.575) {
refractionCorrection = 1735.0 + exoatmElevation*(-518.2 + exoatmElevation*(103.4 + exoatmElevation*(-12.79 + exoatmElevation*0.711)));
} else {
refractionCorrection = -20.774 / te;
}
refractionCorrection = refractionCorrection / 3600.0;
}
return zenith - refractionCorrection;
}

View file

@ -1 +0,0 @@
double calcSolarZenith(double latitude, double longitude, int year, int month, int day, int timeUTC);

View file

@ -1,306 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pcre.h>
#include "wmweather+.h"
#include "download.h"
#include "getLine.h"
#include "diff.h"
#include "die.h"
#include "subst.h"
/* Important variables */
static char *warning_filename1=NULL;
static char *warning_endptr1=NULL;
static char *filenames[]={
"tornado", "flash_flood>warning", "flash_flood>watch",
"flash_flood>statement", "flood>warning", "flood>coastal",
"flood>statement", "severe_weather_stmt", "special_weather_stmt",
"thunderstorm", "special_marine", "urgent_weather_message", "non_precip",
"fire_weather", "lake_shore", NULL
};
static char **reqs[sizeof(filenames)/sizeof(*filenames)-1][2];
unsigned long current_warnings;
static unsigned long *zone_current_warnings;
/* Regular Expressions */
static pcre *expires;
static int ovecsize;
/* prototypes */
static int check_warning(char *file);
/* functions */
#define compile(var, re) \
var=pcre_compile(re, 0, (const char **)&e, &i, NULL); \
if(var==NULL) die("init_warnings PCRE error: %s at %i", e, i); \
pcre_fullinfo(var, NULL, PCRE_INFO_CAPTURECOUNT, &i); \
if(i>ovecsize) ovecsize=i;
void init_warnings(void){
int i, j, z=0;
char *e;
struct subst_val subs[]={
{ 'z', STRING, NULL },
{ 'f', STRING, &bigbuf },
{ 0, 0, 0 }
};
/* Count zones, and find length of longest */
for(i=0; warning_zones[i]!=NULL; i++){
j=strlen(warning_zones[i]);
if(j>z) z=j;
}
/* Allocate char ptrs for each filename for each zone */
for(j=0; filenames[j]!=NULL; j++){
reqs[j][0]=malloc(sizeof(char *)*i);
reqs[j][1]=malloc(sizeof(char *)*i);
if(reqs[j][0]==NULL || reqs[j][1]==NULL) die("init_warnings malloc");
}
zone_current_warnings=calloc(i, sizeof(*zone_current_warnings));
if(zone_current_warnings==NULL) die("init_warnings malloc");
/* Allocate filename base */
e=get_pid_filename("");
i=strlen(e);
warning_filename1=malloc(i+z+32);
if(warning_filename1==NULL)
die("init_warnings malloc");
strcpy(warning_filename1, e);
free(e);
warning_endptr1=warning_filename1+i;
/* Setup misc vars */
current_warnings=0;
ovecsize=0;
compile(expires, "Expires:(\\d+)(\\d\\d)(\\d\\d)(\\d\\d)(\\d\\d);");
ovecsize=(ovecsize+1)*3;
/* Remove stale files, and allocate URIs */
for(z=0; warning_zones[z]!=NULL; z++){
subs[0].val=warning_zones+z;
for(i=0; filenames[i]!=NULL; i++){
sprintf(warning_endptr1, "%s.%s.txt", warning_zones[z], filenames[i]);
unlink(warning_filename1);
sprintf(warning_endptr1, "%s.new-%s.txt", warning_zones[z], filenames[i]);
unlink(warning_filename1);
strncpy(bigbuf, filenames[i], BIGBUF_LEN);
bigbuf[BIGBUF_LEN-1]='\0';
for(j=0; bigbuf[j]; j++){
if(bigbuf[j]=='>') bigbuf[j]='/';
}
if((reqs[i][0][z]=subst(warning_uri, subs))==NULL) die("init_warning");
reqs[i][1][z]=NULL;
if(warning_post!=NULL && (reqs[i][1][z]=subst(warning_post, subs))==NULL) die("init_warning");
}
}
}
#undef compile
struct callback_data {
int zone;
int warning;
};
static void warning_callback(char *filename, void *v){
struct stat statbuf;
struct callback_data *d=(struct callback_data *)v;
sprintf(warning_endptr1, "%s.%s.txt", warning_zones[d->zone], filenames[d->warning]);
if(stat(filename, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& check_warning(filename)
&& diff(filename, warning_filename1)){
current_warnings|=1<<d->warning;
zone_current_warnings[d->zone]|=1<<d->warning;
rename(filename, warning_filename1);
} else {
unlink(filename);
}
}
}
void warnings_cleanup(void){
int i, z;
if(warning_filename1==NULL) return;
for(z=0; warning_zones[z]!=NULL; z++){
for(i=0; filenames[i]!=NULL; i++){
sprintf(warning_endptr1, "%s.%s.txt", warning_zones[z], filenames[i]);
unlink(warning_filename1);
sprintf(warning_endptr1, "%s.new-%s.txt", warning_zones[z], filenames[i]);
unlink(warning_filename1);
}
}
}
void update_warnings(int force){
// time_t t;
struct stat statbuf;
int i, z;
struct callback_data *d;
if(warning_filename1==NULL) return;
// t=time(NULL)/60;
// if(!force && warning_time>t) return;
// warning_time=t+15;
for(z=0; warning_zones[z]!=NULL; z++){
for(i=0; filenames[i]!=NULL; i++){
/* expire old wanrings */
sprintf(warning_endptr1, "%s.%s.txt", warning_zones[z], filenames[i]);
if(stat(warning_filename1, &statbuf)>=0){
if(!S_ISREG(statbuf.st_mode) || statbuf.st_size==0
|| !check_warning(warning_filename1)){
unlink(warning_filename1);
current_warnings&=~(1<<i);
zone_current_warnings[z]&=~(1<<i);
}
} else {
current_warnings&=~(1<<i);
zone_current_warnings[z]&=~(1<<i);
}
if((d=malloc(sizeof(*d)))==NULL) continue;
sprintf(warning_endptr1, "%s.new-%s.txt", warning_zones[z], filenames[i]);
d->zone=z;
d->warning=i;
download_file(warning_filename1, reqs[i][0][z], reqs[i][1][z], DOWNLOAD_NO_404, warning_callback, d);
}
}
}
#define get_substr(n, c) \
if(pcre_get_substring(s, ovector, ovalue, n, (const char **)&c)<0){ free(s); return 0; }
static int check_warning(char *file){
FILE *fp;
char *s, *c;
int len;
int i;
time_t t;
struct tm *tm;
int ovector[ovecsize];
int ovalue;
if((fp=fopen(file, "r"))==NULL) return 0;
ovalue=-1;
while((len=getLine(&s, fp))>0){
ovalue=pcre_exec(expires, NULL, s, len, 0, 0, ovector, ovecsize);
if(ovalue>0) break;
free(s);
}
fclose(fp);
if(ovalue<=0) return 0;
t=time(NULL);
tm=gmtime(&t);
get_substr(1, c); i=atoi(c)-1900; pcre_free_substring(c);
if(tm->tm_year<i){ free(s); return 1; }
if(tm->tm_year>i){ free(s); return 0; }
get_substr(2, c); i=atoi(c)-1; pcre_free_substring(c);
if(tm->tm_mon<i){ free(s); return 1; }
if(tm->tm_mon>i){ free(s); return 0; }
get_substr(3, c); i=atoi(c); pcre_free_substring(c);
if(tm->tm_mday<i){ free(s); return 1; }
if(tm->tm_mday>i){ free(s); return 0; }
get_substr(4, c); i=atoi(c); pcre_free_substring(c);
if(tm->tm_hour<i){ free(s); return 1; }
if(tm->tm_hour>i){ free(s); return 0; }
get_substr(5, c); i=atoi(c); pcre_free_substring(c);
if(tm->tm_min<=i){ free(s); return 1; }
free(s); return 0;
}
void output_warnings(int all){
FILE *fp;
int i, z, len;
pid_t pid;
int pipefd[2];
if(!all && current_warnings==0) return;
if(pipe(pipefd)) die("output_warnings pipe creation");
/* Fork to display the file */
pid=fork();
if(pid==-1){
warn("output_warnings fork");
return;
}
/* CHILD: Redirects stdin/stderr/stdout and execs the viewer */
if(pid==0){
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
dup2(devnull, STDOUT_FILENO);
execl("/bin/sh", "/bin/sh", "-c", viewer, NULL);
die("output_warnings exec");
}
/* PARENT writes warnings to the pipe and returns */
close(pipefd[0]);
for(z=0; warning_zones[z]!=NULL; z++){
if(!zone_current_warnings[z]) continue;
for(i=0; filenames[i]!=NULL; i++){
if(!all && !(zone_current_warnings[z]&(1<<i))) continue;
sprintf(warning_endptr1, "%s.%s.txt", warning_zones[z], filenames[i]);
if((fp=fopen(warning_filename1, "r"))==NULL) continue;
snprintf(bigbuf, BIGBUF_LEN, "======== BEGIN %s %s ========\n", warning_zones[z], filenames[i]);
write(pipefd[1], bigbuf, strlen(bigbuf));
while(!feof(fp)){
len=fread(bigbuf, sizeof(char), BIGBUF_LEN, fp);
write(pipefd[1], bigbuf, len);
}
fclose(fp);
}
if(!all) zone_current_warnings[z]=0;
}
close(pipefd[1]);
if(!all) current_warnings=0;
return;
}

View file

@ -1,6 +0,0 @@
extern unsigned long current_warnings;
void init_warnings(void);
void update_warnings(int force);
void output_warnings(int all);
void warnings_cleanup(void);

View file

@ -1,10 +0,0 @@
EXTRA_LIBRARIES = libwmgeneral-gtk.a libwmgeneral-x11.a
noinst_LIBRARIES = libwmgeneral.a @WMGENERAL_GUI@
libwmgeneral_a_SOURCES = wmgeneral.c \
mouse_regions.c mouse_regions.h rcfile.c rcfile.h
libwmgeneral_gtk_a_SOURCES = wmgeneral-gtk.c wmgeneral-gtk.h
libwmgeneral_x11_a_SOURCES = wmgeneral-x11.c wmgeneral-x11.h \
xpm_trans.c xpm_trans.h

View file

@ -1,131 +0,0 @@
#include "../config.h"
/*
Best viewed with vim5, using ts=4
wmgeneral was taken from wmppp.
It has a lot of routines which most of the wm* programs use.
------------------------------------------------------------
Author: Martijn Pieterse (pieterse@xs4all.nl)
---
CHANGES:
---
11/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Moved all the mouse region related stuff to mouse_regions.[ch]
28/08/2001 (Brad Jorsch, anomie@users.sourceforge.net)
* Added EnableMouseRegion and DisableMouseRegion
* Got annoyed with the 81-character lines. Fixed it. If you don't like
it, find a different copy of wmgeneral.c ;)
* GraphicsExpose events are enabled here.
* GetXPM is exported. It optionally takes an XpmColorSymbol array.
* GetColor is exported.
30/09/2000 (Brad Jorsch, anomie@users.sourceforge.net)
* You know, wmgen.mask sounds like a much nicer place to store the
mask... why don't we do that?
21/09/1999 (Brad Jorsch, anomie@users.sourceforge.net)
* Changed openXwindow to use only the filename, sans path,
as the name and class properties of the app.
14/09/1998 (Dave Clark, clarkd@skyia.com)
* Updated createXBMfromXPM routine
* Now supports >256 colors
11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Removed a bug from parse_rcfile. You could
not use "start" in a command if a label was
also start.
* Changed the needed geometry string.
We don't use window size, and don't support
negative positions.
03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added parse_rcfile2
02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added -geometry support (untested)
28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added createXBMfromXPM routine
* Saves a lot of work with changing xpm's.
02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon
* debugged the parse_rc file.
30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Ripped similar code from all the wm* programs,
and put them in a single file.
*/
#include "mouse_regions.h"
/*****************/
/* Mouse Regions */
/*****************/
typedef struct {
int enable;
int top;
int bottom;
int left;
int right;
} MOUSE_REGION;
MOUSE_REGION mouse_region[MAX_MOUSE_REGION];
/******************************************************************************\
|* AddMouseRegion *|
\******************************************************************************/
void AddMouseRegion(int index, int left, int top, int right, int bottom) {
if (index < MAX_MOUSE_REGION) {
mouse_region[index].enable = 1;
mouse_region[index].top = top;
mouse_region[index].left = left;
mouse_region[index].bottom = bottom;
mouse_region[index].right = right;
}
}
/******************************************************************************\
|* CheckMouseRegion *|
\******************************************************************************/
int CheckMouseRegion(int x, int y) {
int i;
int found;
found = 0;
for (i=0; i<MAX_MOUSE_REGION && !found; i++) {
if (mouse_region[i].enable==1 &&
x <= mouse_region[i].right &&
x >= mouse_region[i].left &&
y <= mouse_region[i].bottom &&
y >= mouse_region[i].top)
found = 1;
}
if (!found) return -1;
return (i-1);
}
/******************************************************************************\
|* EnableMouseRegion *|
\******************************************************************************/
void EnableMouseRegion(int i) {
if(i<MAX_MOUSE_REGION && mouse_region[i].enable==2)
mouse_region[i].enable=1;
}
/******************************************************************************\
|* DisableMouseRegion *|
\******************************************************************************/
void DisableMouseRegion(int i) {
if(i<MAX_MOUSE_REGION && mouse_region[i].enable==1)
mouse_region[i].enable=2;
}

View file

@ -1,19 +0,0 @@
#ifndef MOUSE_REGIONS_H_INCLUDED
#define MOUSE_REGIONS_H_INCLUDED
/***********/
/* Defines */
/***********/
#define MAX_MOUSE_REGION (16)
/***********************/
/* Function Prototypes */
/***********************/
void AddMouseRegion(int index, int left, int top, int right, int bottom);
int CheckMouseRegion(int x, int y);
void EnableMouseRegion(int index);
void DisableMouseRegion(int index);
#endif

View file

@ -1,134 +0,0 @@
#include "../config.h"
/*
Best viewed with vim5, using ts=4
wmgeneral was taken from wmppp.
It has a lot of routines which most of the wm* programs use.
------------------------------------------------------------
Author: Martijn Pieterse (pieterse@xs4all.nl)
---
CHANGES:
---
11/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Moved all the rc-file related stuff to rcfile.[ch]
28/08/2001 (Brad Jorsch, anomie@users.sourceforge.net)
* Added EnableMouseRegion and DisableMouseRegion
* Got annoyed with the 81-character lines. Fixed it. If you don't like
it, find a different copy of wmgeneral.c ;)
* GraphicsExpose events are enabled here.
* GetXPM is exported. It optionally takes an XpmColorSymbol array.
* GetColor is exported.
30/09/2000 (Brad Jorsch, anomie@users.sourceforge.net)
* You know, wmgen.mask sounds like a much nicer place to store the
mask... why don't we do that?
21/09/1999 (Brad Jorsch, anomie@users.sourceforge.net)
* Changed openXwindow to use only the filename, sans path,
as the name and class properties of the app.
14/09/1998 (Dave Clark, clarkd@skyia.com)
* Updated createXBMfromXPM routine
* Now supports >256 colors
11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Removed a bug from parse_rcfile. You could
not use "start" in a command if a label was
also start.
* Changed the needed geometry string.
We don't use window size, and don't support
negative positions.
03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added parse_rcfile2
02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added -geometry support (untested)
28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added createXBMfromXPM routine
* Saves a lot of work with changing xpm's.
02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon
* debugged the parse_rc file.
30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Ripped similar code from all the wm* programs,
and put them in a single file.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rcfile.h"
/******************************************************************************\
|* parse_rcfile *|
\******************************************************************************/
void parse_rcfile(const char *filename, rckeys *keys) {
char *p,*q;
char temp[128];
char *tokens = " :\t\n";
FILE *fp;
int i,key;
fp = fopen(filename, "r");
if (fp) {
while (fgets(temp, 128, fp)) {
key = 0;
q = strdup(temp);
q = strtok(q, tokens);
while (key >= 0 && keys[key].label) {
if ((!strcmp(q, keys[key].label))) {
p = strstr(temp, keys[key].label);
p += strlen(keys[key].label);
p += strspn(p, tokens);
if ((i = strcspn(p, "#\n"))) p[i] = 0;
free(*keys[key].var);
*keys[key].var = strdup(p);
key = -1;
} else key++;
}
free(q);
}
fclose(fp);
}
}
/******************************************************************************\
|* parse_rcfile2 *|
\******************************************************************************/
void parse_rcfile2(const char *filename, rckeys2 *keys) {
char *p;
char temp[128];
char *tokens = " :\t\n";
FILE *fp;
int i,key;
char *family = NULL;
fp = fopen(filename, "r");
if (fp) {
while (fgets(temp, 128, fp)) {
key = 0;
while (key >= 0 && keys[key].label) {
if ((p = strstr(temp, keys[key].label))) {
p += strlen(keys[key].label);
p += strspn(p, tokens);
if ((i = strcspn(p, "#\n"))) p[i] = 0;
free(*keys[key].var);
*keys[key].var = strdup(p);
key = -1;
} else key++;
}
}
fclose(fp);
}
free(family);
}

View file

@ -1,29 +0,0 @@
#ifndef RCFILE_H_INCLUDED
#define RCFILE_H_INCLUDED
/************/
/* Typedefs */
/************/
typedef struct _rckeys rckeys;
struct _rckeys {
const char *label;
char **var;
};
typedef struct _rckeys2 rckeys2;
struct _rckeys2 {
const char *family;
const char *label;
char **var;
};
/***********************/
/* Function Prototypes */
/***********************/
void parse_rcfile(const char *, rckeys *);
#endif

View file

@ -1,192 +0,0 @@
#include "../config.h"
/*
Best viewed with vim5, using ts=4
wmgeneral was taken from wmppp.
It has a lot of routines which most of the wm* programs use.
------------------------------------------------------------
Author: Brad Jorsch, anomie@users.sourceforge.net
---
CHANGES:
---
15/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Pulled createXBMfromXPM into its own file, because it's the same in
both -gtk and -x11.
11/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* This is based on wmgeneral-x11.c (formerly wmgeneral.c), it
implements a subset of the interface using Gtk+ 2.0
*/
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "wmgeneral-gtk.h"
/******************/
/* Gtk+ Variables */
/******************/
static GtkWidget *dockwin, *iconwin;
static GdkPixmap *pixmap, *mask;
static GdkGC *pixmap_gc, *mask_gc;
static void (*click_func)(GdkEventButton *ev);
/******************************************************************************\
|* RedrawWindow *|
\******************************************************************************/
void RedrawWindow(void) {
gdk_draw_drawable(dockwin->window, pixmap_gc, pixmap, 0, 0, 0, 0, 64, 64);
gdk_draw_drawable(iconwin->window, pixmap_gc, pixmap, 0, 0, 0, 0, 64, 64);
}
static gint redraw_dock(gpointer d){
RedrawWindow();
return 0;
}
/******************************************************************************\
|* RedrawWindowXY *|
\******************************************************************************/
void RedrawWindowXY(int x, int y) {
gdk_draw_drawable(dockwin->window, pixmap_gc, pixmap, x, y, 0, 0, 64, 64);
gdk_draw_drawable(iconwin->window, pixmap_gc, pixmap, x, y, 0, 0, 64, 64);
}
/******************************************************************************\
|* copyXPMArea *|
\******************************************************************************/
void copyPixmapArea(int sx, int sy, int w, int h, int dx, int dy){
gdk_draw_drawable(pixmap, pixmap_gc, pixmap, sx, sy, dx, dy, w, h);
}
/******************************************************************************\
|* copyXBMArea *|
\******************************************************************************/
void copyMaskArea(int sx, int sy, int w, int h, int dx, int dy){
gdk_draw_drawable(mask, mask_gc, mask, sx, sy, dx, dy, w, h);
}
/******************************************************************************\
|* setMaskXY *|
\******************************************************************************/
void setMaskXY(int x, int y) {
gtk_widget_shape_combine_mask(dockwin, mask, x, y);
gtk_widget_shape_combine_mask(iconwin, mask, x, y);
}
/******************************************************************************\
|* setClickCallback *|
\******************************************************************************/
void setClickCallback(void (*func)(GdkEventButton *ev)){
click_func=func;
}
/******************************************************************************\
|* openXwindow *|
\******************************************************************************/
static GdkWindow *get_gdk_leader(GdkWindow *win){
GdkAtom atom, type;
gint len;
guchar *data;
GdkWindow *leader=NULL;
atom=gdk_atom_intern("WM_CLIENT_LEADER", TRUE);
type=gdk_atom_intern("WINDOW", TRUE);
if(atom==GDK_NONE || type==GDK_NONE) return NULL;
if(!gdk_property_get(win, atom, type, 0, 4, FALSE, NULL, NULL, &len, &data)) return NULL; if(len==4) leader=gdk_window_foreign_new(*(GdkNativeWindow *)data);
g_free(data);
return leader;
}
static GdkFilterReturn button_filter(XEvent *x, GdkEvent *ev, gpointer data){
/* Bleh, Gdk insists on trying to translate buttons 4-7 into Scroll events.
* Which would be ok, except for the part where it just _throws_ _away_ the
* releases! Damnit... So, we cheat and change any buttons >3 into
* button+4, and change it back in the click handler. */
if((x->type==ButtonPress || x->type==ButtonRelease) && x->xbutton.button>3){
x->xbutton.button+=4;
}
return GDK_FILTER_CONTINUE;
}
static void dock_click(GtkWidget *w, GdkEventButton *ev, gpointer d){
if(ev->button>7) ev->button-=4;
if(click_func!=NULL) click_func(ev);
}
#define die(args...) { fprintf(stderr, args); exit(1); }
void openDockWindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height){
GdkColormap *cmap;
GdkColor white, black;
GdkWindow *leader;
XWMHints hints;
click_func=NULL;
if((dockwin=gtk_window_new(GTK_WINDOW_TOPLEVEL))==NULL) die("Couldn't create window");
if((iconwin=gtk_window_new(GTK_WINDOW_TOPLEVEL))==NULL) die("Couldn't create window");
gtk_widget_set_size_request(dockwin, 64, 64);
gtk_widget_set_size_request(iconwin, 64, 64);
gtk_widget_set_app_paintable(dockwin, TRUE);
gtk_widget_set_app_paintable(iconwin, TRUE);
gtk_widget_add_events(dockwin, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_SCROLL_MASK);
gtk_widget_add_events(iconwin, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_SCROLL_MASK);
g_signal_connect(G_OBJECT(dockwin), "expose-event", G_CALLBACK(redraw_dock), NULL);
g_signal_connect(G_OBJECT(iconwin), "expose-event", G_CALLBACK(redraw_dock), NULL);
g_signal_connect(G_OBJECT(dockwin), "button-press-event", G_CALLBACK(dock_click), NULL);
g_signal_connect(G_OBJECT(iconwin), "button-press-event", G_CALLBACK(dock_click), NULL);
g_signal_connect(G_OBJECT(dockwin), "button-release-event", G_CALLBACK(dock_click), NULL);
g_signal_connect(G_OBJECT(iconwin), "button-release-event", G_CALLBACK(dock_click), NULL);
g_signal_connect(G_OBJECT(dockwin), "destroy", G_CALLBACK(exit), NULL);
g_signal_connect(G_OBJECT(iconwin), "destroy", G_CALLBACK(exit), NULL);
gtk_widget_realize(dockwin);
gtk_widget_realize(iconwin);
gdk_window_add_filter(dockwin->window, (GdkFilterFunc)button_filter, NULL);
gdk_window_add_filter(iconwin->window, (GdkFilterFunc)button_filter, NULL);
if((leader=get_gdk_leader(dockwin->window))==NULL) die("Couldn't obtain Gdk leader window");
gdk_window_set_icon(leader, iconwin->window, NULL, NULL);
gdk_window_reparent(iconwin->window, leader, 0, 0);
gdk_window_unref(leader);
hints.initial_state = WithdrawnState;
hints.flags = StateHint;
XSetWMHints(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(dockwin->window), &hints);
cmap=gdk_colormap_get_system();
white.red=65535;
white.green=65535;
white.blue=65535;
black.red=0;
black.green=0;
black.blue=0;
gdk_color_alloc(cmap, &white);
gdk_color_alloc(cmap, &black);
mask=gdk_pixmap_create_from_data(NULL, pixmask_bits, pixmask_width, pixmask_height, 1, &white, &black);
pixmap=gdk_pixmap_colormap_create_from_xpm_d(NULL, cmap, NULL, NULL, pixmap_bytes);
pixmap_gc=gdk_gc_new(iconwin->window);
mask_gc=gdk_gc_new(mask);
setMaskXY(0, 0);
RedrawWindow();
gtk_widget_show(iconwin);
gtk_widget_show(dockwin);
gdk_window_withdraw(dockwin->window);
}

View file

@ -1,20 +0,0 @@
#ifndef WMGENERAL_GTK_H_INCLUDED
#define WMGENERAL_GTK_H_INCLUDED
#include <gtk/gtk.h>
/***********************/
/* Function Prototypes */
/***********************/
void openDockWindow(int argc, char *argv[], char **, char *, int, int);
void RedrawWindow(void);
void RedrawWindowXY(int x, int y);
void setClickCallback(void (*func)(GdkEventButton *ev));
void createXBMfromXPM(char *, char **, int, int);
void copyPixmapArea(int, int, int, int, int, int);
void copyMaskArea(int, int, int, int, int, int);
void setMaskXY(int, int);
#endif

View file

@ -1,343 +0,0 @@
#include "../config.h"
/*
Best viewed with vim5, using ts=4
wmgeneral was taken from wmppp.
It has a lot of routines which most of the wm* programs use.
------------------------------------------------------------
Author: Martijn Pieterse (pieterse@xs4all.nl)
---
CHANGES:
---
15/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Pulled createXBMfromXPM into its own file, because it's the same in
both -gtk and -x11.
11/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Removed the rc-file and mouse region stuff to their own files.
* Renamed this file to "wmgeneral-x11.c"
* Renamed a few of the functions
28/08/2001 (Brad Jorsch, anomie@users.sourceforge.net)
* Added EnableMouseRegion and DisableMouseRegion
* Got annoyed with the 81-character lines. Fixed it. If you don't like
it, find a different copy of wmgeneral.c ;)
* GraphicsExpose events are enabled here.
* GetXPM is exported. It optionally takes an XpmColorSymbol array.
* GetColor is exported.
30/09/2000 (Brad Jorsch, anomie@users.sourceforge.net)
* You know, wmgen.mask sounds like a much nicer place to store the
mask... why don't we do that?
21/09/1999 (Brad Jorsch, anomie@users.sourceforge.net)
* Changed openXwindow to use only the filename, sans path,
as the name and class properties of the app.
14/09/1998 (Dave Clark, clarkd@skyia.com)
* Updated createXBMfromXPM routine
* Now supports >256 colors
11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Removed a bug from parse_rcfile. You could
not use "start" in a command if a label was
also start.
* Changed the needed geometry string.
We don't use window size, and don't support
negative positions.
03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added parse_rcfile2
02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added -geometry support (untested)
28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added createXBMfromXPM routine
* Saves a lot of work with changing xpm's.
02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon
* debugged the parse_rc file.
30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Ripped similar code from all the wm* programs,
and put them in a single file.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <stdarg.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include "wmgeneral-x11.h"
/*****************/
/* X11 Variables */
/*****************/
Window Root;
int screen;
int x_fd;
int d_depth;
XSizeHints mysizehints;
XWMHints mywmhints;
Pixel back_pix, fore_pix;
char *Geometry = "";
Window iconwin, win;
GC NormalGC;
GC RedrawGC;
XpmIcon wmgen;
/***********************/
/* Function Prototypes */
/***********************/
void RedrawWindow(void);
/******************************************************************************\
|* GetXPM *|
\******************************************************************************/
void GetXPM(XpmIcon *wmgen, char *pixmap_bytes[]) {
XWindowAttributes attributes;
int err;
/* For the colormap */
XGetWindowAttributes(display, Root, &attributes);
wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
err = XpmCreatePixmapFromData(display, Root, pixmap_bytes, &(wmgen->pixmap),
&(wmgen->mask), &(wmgen->attributes));
if (err != XpmSuccess) {
fprintf(stderr, "Not enough free colorcells.\n");
exit(1);
}
}
/******************************************************************************\
|* GetColor *|
\******************************************************************************/
Pixel GetColor(char *name) {
XColor color;
XWindowAttributes attributes;
XGetWindowAttributes(display, Root, &attributes);
color.pixel = 0;
if (!XParseColor(display, attributes.colormap, name, &color)) {
fprintf(stderr, "wm.app: can't parse %s.\n", name);
} else if (!XAllocColor(display, attributes.colormap, &color)) {
fprintf(stderr, "wm.app: can't allocate %s.\n", name);
}
return color.pixel;
}
/******************************************************************************\
|* flush_expose *|
\******************************************************************************/
static int flush_expose(Window w) {
XEvent dummy;
int i=0;
while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
i++;
return i;
}
/******************************************************************************\
|* RedrawWindow *|
\******************************************************************************/
void RedrawWindow(void) {
flush_expose(iconwin);
XCopyArea(display, wmgen.pixmap, iconwin, RedrawGC,
0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
flush_expose(win);
XCopyArea(display, wmgen.pixmap, win, RedrawGC,
0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
}
/******************************************************************************\
|* RedrawWindowXY *|
\******************************************************************************/
void RedrawWindowXY(int x, int y) {
flush_expose(iconwin);
XCopyArea(display, wmgen.pixmap, iconwin, RedrawGC,
x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
flush_expose(win);
XCopyArea(display, wmgen.pixmap, win, RedrawGC,
x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
}
/******************************************************************************\
|* copyXPMArea *|
\******************************************************************************/
void copyPixmapArea(int x, int y, int sx, int sy, int dx, int dy) {
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
}
/******************************************************************************\
|* copyXBMArea *|
\******************************************************************************/
void copyMaskArea(int x, int y, int sx, int sy, int dx, int dy) {
XCopyArea(display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
}
/******************************************************************************\
|* setMaskXY *|
\******************************************************************************/
void setMaskXY(int x, int y) {
XShapeCombineMask(display, win, ShapeBounding, x, y, wmgen.mask, ShapeSet);
XShapeCombineMask(display, iconwin, ShapeBounding, x, y, wmgen.mask, ShapeSet);
}
/******************************************************************************\
|* openXwindow *|
\******************************************************************************/
void openDockWindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height) {
unsigned int borderwidth = 1;
XClassHint classHint;
char *display_name = NULL;
char *wname;
XTextProperty name;
XGCValues gcv;
unsigned long gcm;
char *geometry = NULL;
int dummy=0;
int i, wx, wy;
wname=strrchr(argv[0], '/');
if(wname==NULL) wname=argv[0];
else wname++;
for (i=1; argv[i]; i++) {
if (!strcmp(argv[i], "-display")) {
display_name = argv[i+1];
i++;
}
if (!strcmp(argv[i], "-geometry")) {
geometry = argv[i+1];
i++;
}
}
if (!(display = XOpenDisplay(display_name))) {
fprintf(stderr, "%s: can't open display %s\n",
wname, XDisplayName(display_name));
exit(1);
}
screen = DefaultScreen(display);
Root = RootWindow(display, screen);
d_depth = DefaultDepth(display, screen);
x_fd = XConnectionNumber(display);
/* Convert XPM to XImage */
GetXPM(&wmgen, pixmap_bytes);
/* Create a window to hold the stuff */
mysizehints.flags = USSize | USPosition;
mysizehints.x = 0;
mysizehints.y = 0;
back_pix = GetColor("white");
fore_pix = GetColor("black");
XWMGeometry(display, screen, Geometry, NULL, borderwidth, &mysizehints,
&mysizehints.x, &mysizehints.y,&mysizehints.width,&mysizehints.height, &dummy);
mysizehints.width = 64;
mysizehints.height = 64;
win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y,
mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
iconwin = XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y,
mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
/* Activate hints */
XSetWMNormalHints(display, win, &mysizehints);
classHint.res_name = wname;
classHint.res_class = wname;
XSetClassHint(display, win, &classHint);
XSelectInput(display, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
XSelectInput(display, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
if (XStringListToTextProperty(&wname, 1, &name) == 0) {
fprintf(stderr, "%s: can't allocate window name\n", wname);
exit(1);
}
XSetWMName(display, win, &name);
/* Create GC for drawing */
gcm = GCForeground | GCBackground | GCGraphicsExposures;
gcv.foreground = fore_pix;
gcv.background = back_pix;
gcv.graphics_exposures = True;
NormalGC = XCreateGC(display, Root, gcm, &gcv);
gcv.graphics_exposures = False;
RedrawGC = XCreateGC(display, Root, gcm, &gcv);
/* ONLYSHAPE ON */
if(pixmask_bits!=NULL){
XFreePixmap(display, wmgen.mask);
wmgen.mask = XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width, pixmask_height);
}
XShapeCombineMask(display, win, ShapeBounding, 0, 0, wmgen.mask, ShapeSet);
XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, wmgen.mask, ShapeSet);
/* ONLYSHAPE OFF */
mywmhints.initial_state = WithdrawnState;
mywmhints.icon_window = iconwin;
mywmhints.icon_x = mysizehints.x;
mywmhints.icon_y = mysizehints.y;
mywmhints.window_group = win;
mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
XSetWMHints(display, win, &mywmhints);
XSetCommand(display, win, argv, argc);
XMapWindow(display, win);
if (geometry) {
if (sscanf(geometry, "+%d+%d", &wx, &wy) != 2) {
fprintf(stderr, "Bad geometry string.\n");
exit(1);
}
XMoveWindow(display, win, wx, wy);
}
}

View file

@ -1,37 +0,0 @@
#ifndef WMGENERAL_X11_H_INCLUDED
#define WMGENERAL_X11_H_INCLUDED
#include <X11/xpm.h>
/************/
/* Typedefs */
/************/
typedef struct {
Pixmap pixmap;
Pixmap mask;
XpmAttributes attributes;
} XpmIcon;
/*******************/
/* Global variable */
/*******************/
Display *display;
/***********************/
/* Function Prototypes */
/***********************/
void openDockWindow(int argc, char *argv[], char **, char *, int, int);
void RedrawWindow(void);
void RedrawWindowXY(int x, int y);
Pixel GetColor(char *);
void GetXPM(XpmIcon *, char **);
void createXBMfromXPM(char *, char **, int, int);
void copyPixmapArea(int, int, int, int, int, int);
void copyMaskArea(int, int, int, int, int, int);
void setMaskXY(int, int);
#endif

View file

@ -1,124 +0,0 @@
#include "../config.h"
/*
Best viewed with vim5, using ts=4
wmgeneral was taken from wmppp.
It has a lot of routines which most of the wm* programs use.
------------------------------------------------------------
Author: Martijn Pieterse (pieterse@xs4all.nl)
---
CHANGES:
---
15/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Updated createXBMfromXPM to handle the case where the XBM is to be
wider than the XPM, or the XBM width is not a multiple of 8.
* Pulled createXBMfromXPM into its own file, because it's the same in
both -gtk and -x11.
11/08/2002 (Brad Jorsch, anomie@users.sourceforge.net)
* Removed the rc-file and mouse region stuff to their own files.
* Renamed this file to "wmgeneral-x11.c"
* Renamed a few of the functions
28/08/2001 (Brad Jorsch, anomie@users.sourceforge.net)
* Added EnableMouseRegion and DisableMouseRegion
* Got annoyed with the 81-character lines. Fixed it. If you don't like
it, find a different copy of wmgeneral.c ;)
* GraphicsExpose events are enabled here.
* GetXPM is exported. It optionally takes an XpmColorSymbol array.
* GetColor is exported.
30/09/2000 (Brad Jorsch, anomie@users.sourceforge.net)
* You know, wmgen.mask sounds like a much nicer place to store the
mask... why don't we do that?
21/09/1999 (Brad Jorsch, anomie@users.sourceforge.net)
* Changed openXwindow to use only the filename, sans path,
as the name and class properties of the app.
14/09/1998 (Dave Clark, clarkd@skyia.com)
* Updated createXBMfromXPM routine
* Now supports >256 colors
11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Removed a bug from parse_rcfile. You could
not use "start" in a command if a label was
also start.
* Changed the needed geometry string.
We don't use window size, and don't support
negative positions.
03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added parse_rcfile2
02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added -geometry support (untested)
28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Added createXBMfromXPM routine
* Saves a lot of work with changing xpm's.
02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon
* debugged the parse_rc file.
30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
* Ripped similar code from all the wm* programs,
and put them in a single file.
*/
#include <stdio.h>
/******************************************************************************\
|* createXBMfromXPM *|
\******************************************************************************/
void createXBMfromXPM(char *xbm, char **xpm, int sx, int sy) {
int i,j,k;
int width, height, numcol, depth;
int zero=0;
unsigned char bwrite;
int bcount;
int curpixel;
while(sx&7){ sx++; }
sscanf(*xpm, "%d %d %d %d", &width, &height, &numcol, &depth);
width*=depth;
for (k=0; k!=depth; k++)
{
zero <<=8;
zero |= xpm[1][k];
}
for (i=numcol+1; i < numcol+sy+1; i++) {
bcount = 0;
bwrite = 0;
for (j=0; j<sx*depth; j+=depth) {
bwrite >>= 1;
if(j<width){
curpixel=0;
for (k=0; k!=depth; k++)
{
curpixel <<=8;
curpixel |= xpm[i][j+k];
}
} else {
curpixel=zero;
}
if ( curpixel != zero ) {
bwrite += 128;
}
bcount++;
if (bcount == 8) {
*xbm = bwrite;
xbm++;
bcount = 0;
bwrite = 0;
}
}
}
}

View file

@ -1,122 +0,0 @@
#include "../config.h"
/*
Best viewed with vim5, using ts=4
An add-on to wmgeneral to copy XPM areas with transparency and opacity.
------------------------------------------------------------
Author: Brad Jorsch (anomie@users.sourceforge.net)
---
CHANGES:
---
16/08/2001 (Brad Jorsch, anomie@users.sourceforge.net)
* Wrote these routines.
*/
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "wmgeneral-x11.h"
extern int screen;
extern XpmIcon wmgen;
extern GC NormalGC;
static int get_shift(unsigned mask){
int i=0;
while(!mask&1){
mask>>=1;
i++;
}
return i;
}
void combineWithTrans(int sx, int sy, unsigned w, unsigned h, int dx, int dy){
XImage *pix, *mask;
unsigned int ww, hh, bar;
int foo;
Window baz;
unsigned x, y;
XGetGeometry(display, wmgen.pixmap, &baz, &foo, &foo, &ww, &hh, &bar, &bar);
pix=XGetImage(display, wmgen.pixmap, 0, 0, ww, hh, AllPlanes, ZPixmap);
XGetGeometry(display, wmgen.mask, &baz, &foo, &foo, &ww, &hh, &bar, &bar);
mask=XGetImage(display, wmgen.mask, 0, 0, ww, hh, AllPlanes, ZPixmap);
for(y=0; y<h; y++){
for(x=0; x<w; x++){
if(!XGetPixel(mask, sx+x, sy+y)) continue;
XPutPixel(pix, dx+x, dy+y, XGetPixel(pix, sx+x, sy+y));
}
}
XPutImage(display, wmgen.pixmap, NormalGC, pix, 0, 0, 0, 0, pix->width, pix->height);
XDestroyImage(pix);
XDestroyImage(mask);
}
void combineWithOpacity(int sx, int sy, unsigned w, unsigned h, int dx, int dy, int o){
XImage *pix, *mask;
unsigned int ww, hh, bar;
int foo;
Window baz;
int rmask, gmask, bmask;
int rshift, gshift, bshift;
unsigned long spixel, dpixel;
unsigned x, y;
int c_o;
if(o==0) return;
if(o==256){
combineWithTrans(sx, sy, w, h, dx, dy);
return;
}
XGetGeometry(display, wmgen.pixmap, &baz, &foo, &foo, &ww, &hh, &bar, &bar);
pix=XGetImage(display, wmgen.pixmap, 0, 0, ww, hh, AllPlanes, ZPixmap);
XGetGeometry(display, wmgen.mask, &baz, &foo, &foo, &ww, &hh, &bar, &bar);
mask=XGetImage(display, wmgen.mask, 0, 0, ww, hh, AllPlanes, ZPixmap);
if (pix->depth == DefaultDepth(display, screen)) {{
Visual *visual=DefaultVisual(display, screen);
rmask = visual->red_mask;
gmask = visual->green_mask;
bmask = visual->blue_mask;
}} else {
rmask = pix->red_mask;
gmask = pix->green_mask;
bmask = pix->blue_mask;
}
c_o=256-o;
rshift=get_shift(rmask);
gshift=get_shift(gmask);
bshift=get_shift(bmask);
/* NOTE: >>s then <<s to prevent overflow when multiplying opacity */
#define AVG(m, s) ((((((spixel&m)>>s)*o+((dpixel&m)>>s)*c_o)>>8)<<s)&m)
for(y=0; y<h; y++){
for(x=0; x<w; x++){
if(!XGetPixel(mask, sx+x, sy+y)) continue;
spixel=XGetPixel(pix, sx+x, sy+y);
if(!XGetPixel(mask, dx+x, dy+y)){
XPutPixel(pix, dx+x, dy+y, spixel);
} else {
dpixel=XGetPixel(pix, dx+x, dy+y);
XPutPixel(pix, dx+x, dy+y,
AVG(rmask, rshift) |
AVG(gmask, gshift) |
AVG(bmask, bshift));
}
}
}
#undef AVG
XPutImage(display, wmgen.pixmap, NormalGC, pix, 0, 0, 0, 0, pix->width, pix->height);
XDestroyImage(pix);
XDestroyImage(mask);
}

View file

@ -1,7 +0,0 @@
/* Like copyXPMArea, but only copies non-masked pixels */
void combineWithTrans(int sx, int sy, unsigned w, unsigned h, int dx, int dy);
/* Like combineWithTrans, except it combines pixels by this formula:
* new = (src * o + dest * (256 - o)) / 256
*/
void combineWithOpacity(int sx, int sy, unsigned w, unsigned h, int dx, int dy, int o);

View file

@ -1,418 +0,0 @@
.de Sh
.br
.if t .Sp
.ne 5
.PP
\fB\\$1\fR
.PP
..
.TH wmweather+ 1x "@DATE@"
.SH NAME
wmweather+ \- A dock app for displaying weather information
.P
.SH SYNOPSIS
.B wmweather+
.RB [\| options \|]
.SH DESCRIPTION
\fBwmweather+\fP downloads current conditions, forecast data, and optionally a
radar image. It will also watch for various warnings and display them using an
external command.
.SH OPTIONS
Note that later options override earlier ones, and command line options
override configuration file options. All multi-character options may be
specified with one or two leading dashes. The configuration file is simply one
option (with value if necessary) per line, leading dashes optional. Empty lines
and lines beginning with the '#' character are ignored.
.SS General Options
.TP
.BI "-display " <display\ name>
Name of display to use.
.TP
.BI "-c " <file>
Specify a configuration file instead of the default. This option is ignored in
the configuration file.
.TP
.BI "-display-mode " <string>
Specify the starting display mode. Valid values are "cur"/"current",
"fcst"/"forecast", and "map"/"radar".
.TP
.BI "-location " <latitude+longitude>
Specify a latitude and longitude, for example "41'59'00N 87'55'00W" or
"N41.9833333333333 W87.9166666666667". You may use either the decimal or DMS
notation, with either a prefixed sign or a prefixed or suffixed N/S/E/W. If
this option isn't given, the program will assume you live on the equator and
guess your longitude based on your system timezone offset.
.TP
.BR "-e\fR,\fP\ -email " <address>
Specify the anonymous FTP password.
.TP
.BR -v ", " -version
Display version number and exit.
.TP
.BI "-viewer " <program>
External program for viewing weather warnings. This command must take the text
to display from standard input. It will be executed as '/bin/sh -c
\fI<program>\fP' with stdout redirected to /dev/null. If not specified, it will
default to "xless".
.TP
.BR -animate ", " -noanimate
Turn animation on or off. Animation may still be toggled with the middle mouse
button as described below. The default is on.
.SS Station Options
.TP
.BI "-s\fR,\fP\ -station " <ID>
Station ID for all stations. Equivalent to
.RI "'-metar-station " <ID> " -avn-station " <ID>
.RI " -eta-station " <ID> " -mrf-station " <ID> '.
.TP
.BI "-metar-station " <ID>
Station ID for METAR observations. See \fBCurrent Conditions\fP for more
information. A value must be provided.
.TP
.BI "-avn-station " <ID>
Station ID for AVN forecasts. See \fBForecasts\fP for more information.
.TP
.BI "-eta-station " <ID>
Station ID for ETA forecasts. See \fBForecasts\fP for more information.
.TP
.BI "-mrf-station " <ID>
Station ID for MRF forecasts. See \fBForecasts\fP for more information.
.TP
.BI "-warning-zone " <zoneID>
Zone ID for weather warnings. See \fBWarnings\fP for more information. This
option may be repeated for multiple zones.
.TP
.BI "-forget-warning-zones"
Cause wmweather+ to forget all warning zones found to this point. Useful for
user configuration files to override the warning zones specified in the
system-wide configuration.
.P
.BI "-metar-uri " <URI>
.br
.BI "-avn-uri " <URI>
.br
.BI "-eta-uri " <URI>
.br
.BI "-mrf-uri " <URI>
.br
.BI "-warning-uri " <URI>
.RS
URI to download the specified data from. See \fBURIs\fP for more information.
.RE
.P
.BI "-metar-post " <DATA>
.br
.BI "-avn-post " <DATA>
.br
.BI "-eta-post " <DATA>
.br
.BI "-mrf-post " <DATA>
.br
.BI "-warning-post " <DATA>
.RS
Post data for downloading the specified data. See \fBURIs\fP for more
information. Note that the post option must follow the corresponding URI
option. Note that the post data will \fInot\fP be URL-encoded for you.
.RE
.TP
.B -noradar
Do not display a radar image. This is the default.
.P
.BI "-radar-uri " <URI>
.br
.BI "-radar-post " <DATA>
.RS
Retrieve an image from the specified URI. See \fBRadar Map\fP for more
information.
.RE
.TP
.BI "-radar-crop " <string>
How to crop the radar image.
.IR X x Y + W + H
format. See \fBRadar Map\fP for more information.
.TP
.BI "-radar-cross " <string>
Where to draw radar crosshairs.
.IR X x Y
format. See \fBRadar Map\fP for more
information.
.SS Measurement Options
.TP
.BR -m ", " -metric
Same as '-cm -hPa -kph -tempc'.
.TP
.B -in
Display precipitation amounts in inches. This is the default.
.TP
.B -cm
Display precipitation amounts in centimeters.
.TP
.B -inHg
Display pressure in inches of mercury. This is the default.
.TP
.BR -hPa ", " -mbar
Display pressure in hectopascal (millibars)
.TP
.B -mmHg
Display pressure in millimeters of mercury.
.TP
.B -atm
Display pressure in atmospheres.
.TP
.B -mph
Display windspeed in miles/hour. This is the default.
.TP
.B -kph
Display windspeed in kilometers/hour.
.TP
.B -knots
Display windspeed in knots.
.TP
.B -mps
Display windspeed in meters/second.
.TP
.B -beaufort
Display windspeed on the Beaufort scale.
.TP
.B -tempf
Display temperature in degrees Fahrenheit. This is the default.
.TP
.B -tempc
Display temperature in degrees Celcius.
.SH DISPLAY
The dockapp has three display modes: Current Conditions, Forecasts, and Radar
Map. Modes are selected by the buttons across the top of the icon. Weather
Warning status is indicated by the font color. At any point
double-(left)clicking the main display will send SIGUSR1 to the process (see
\fBSIGNALS\fP).
.Sh "Current Conditions"
This mode displays the current conditions as given in the METAR report for the
selected station, as downloaded from
.UR http://weather.noaa.gov/pub/data/observations/metar/stations/
http://weather.noaa.gov/pub/data/observations/metar/stations/
.UE
.RI .
Downloads are attempted every 15 minutes. Find your station at
.UR http://www.nws.noaa.gov/tg/siteloc.shtml
http://www.nws.noaa.gov/tg/siteloc.shtml
.UE
.RI .
.P
The station ID is displayed at the top left of the display. The observation
date (local) is to the right, and the time (local and UTC) occupies the line
below. Under that, to the right is the temperature and relative humidity, the
wind direction and speed, the atmospheric pressure (indicated by "P"), the
heat index (indicated by "HI"), and the wind chill (indicated by "WC").
.P
To the left is a graphical display of the current weather. The sky condition is
indicated as clear (sun), partly cloudy (sun with small clouds), mostly cloudy
(sun behind a large cloud), or overcast (large cloud). This image may be
covered by fog (foggy overlay), dust/sand/haze (brownish particles), or blowing
snow/dust/sand (blue wind-lines), with the level of transparency indicating the
degree of visibility. If a funnel cloud or tornado was reported, a tornado
graphic will be displayed instead of the sky condition.
.P
Beneath this graphic, icons will depict rain (raindrop), snow (snowflake),
freezing precipitation (hailstones), and thunderstorms (lightning bolt). If
animation is enabled, the icons will appear and vanish on a ten second cycle
to indicate precipitation intensity. Animation may be enabled or disabled by
middle-clicking the display.
.Sh Forecasts
This mode displays the current conditions as given in the AVN, ETA, and MRF
data for the selected stations, as downloaded from
.UR http://www.nws.noaa.gov/tdl/synop/products/bullform.mav.htm
http://www.nws.noaa.gov/tdl/synop/products/bullform.mav.htm
.UE
.RI ,
.UR http://www.nws.noaa.gov/mdl/synop/products/bullform.met.htm
http://www.nws.noaa.gov/mdl/synop/products/bullform.met.htm
.UE
and
.UR http://www.nws.noaa.gov/tdl/synop/products/bullform.mex.htm
http://www.nws.noaa.gov/tdl/synop/products/bullform.mex.htm
.UE
.RI .
AVN and ETA reports are downloaded at startup, 0000Z, and 1200Z. MRF reports
are downloaded at startup and 0000Z. In the event of failure, downloads will be
retried every 15 minutes. See the URIs given to find your stations.
.P
The display is divided into two sections. A small window at the top indicates
the date and hour (local time) for which this forecast is valid. Left-clicking
this window or clicking the small arrow-button to the right will advance to
the next forecast; right-clicking or clicking the small arrow-button to the
left will move to the previous forecast. Middle-clicking will return to the
first forecast in the list.
.P
The larger display at the bottom shows the forecast for the selected date and
time. To the right from top to bottom are the station ID, the daily high and
low temperatures, the predicted temperature and relative humidity, and the
wind direction and speed. The final line may display the heat index (HI), the
wind chill (WC), the amount of snow to fall in that period (SN), the amount of
liquid-equivalent precipitation to fall in that period (P), or the forecast
type (e.g. "AVN" or "MRF").
.P
To the left is a weather display similar to that for the Current Conditions.
The animation here indicates the percent chance of rain, snow, freezing
precipitation, thunderstorms, and severe thunderstorms (large lightning bolt).
Animation may be turned on or off with the middle button. When animation is
off, the mouse wheel may be used to adjust the cutoff chance for the display
(hold Shift to adjust faster). The cutoff will be displayed briefly when first
turning off animation, when first displaying forecasts, whenever button 6
(typically, the 'side' button) is held down in the large display. Permanent
cutoff display may be toggled by double-middle-clicking the large display.
.Sh "Radar Map"
The radar image will be downloaded every 30 minutes from the URI specified.
Then, if -radar-crop was specified in the form
.IR X x Y + W + H ,
a subimage of witdh \fIW\fP and height \fIH\fP will be taken, with the
upper-left pixel taken from
.RI ( X ", " Y ).
If \fIX\fP or \fIY\fP is negative, it will be measured from the right/bottom of
the image instead of the top/left. The image is then resized to fit within the
52x40 rectangle available. A border around the image indicates the current font
color. If -radar-cross was specified in the form
.IR X x Y ,
crosshairs will then be
drawn over the pixel
.RI ( X ", " Y )
when the middle button is held on the radar map.
.P
If -noradar was specified or no radar data is available, an image to that
effect will be displayed instead.
.P
Some nice images are available from
.UR http://weather.noaa.gov/radar/mosaic/DS.p19r0/ar.us.conus.shtml
http://weather.noaa.gov/radar/mosaic/DS.p19r0/ar.us.conus.shtml
.UE
and
.UR http://www.weather.com/common/home/maps.html
http://www.weather.com/common/home/maps.html
.UE
.RI .
Be kind, since the display is so small pick the smallest version of the image
to download.
.Sh "Weather Warnings"
Various weather warnings, watches, and statements for the specified zone are
downloaded from
.UR http://weather.noaa.gov/pub/data/watches_warnings/
http://weather.noaa.gov/pub/data/watches_warnings/
.UE
.RI .
Downloads are attempted at the same time METAR observations are retrieved. Find
your zone at
.UR http://weather.noaa.gov/
http://weather.noaa.gov/
.UE
or
.UR http://weather.gov/
http://weather.gov/
.UE
.RI .
Note that some areas issue weather warnings by multiple geopolitical units
(e.g. "zones" and "counties"). The -warning-zone option may be specified
multiple times, so all appropriate files may be inspected.
.P
If any new warnings are downloaded, all text will be displayed in an
orange/red scheme instead of the normal blue/orange. The new warnings may then
be viewed by left-clicking the large display window in any mode. At any point,
all current warnings may be displayed by right-clicking the large display.
.SH "URIs"
The URIs from which the various observations, forecasts, and images are
downloaded can be easily customized by supplying values for the various
.I -*-uri
options. The following substitution variables are available:
.TP
.B %s
The station ID for the specified data type (note that warnings have no station
ID).
.TP
.B %z
The zone ID, for warnings.
.TP
.B %f
The warning type, for warnings (e.g. "tornado", "special_weather_stmt").
.P
The substitutions can be manipulated with the standard
.BR printf (3)
modifiers for strings, in particular the
.BR # ", " 0 ", " - ", "
.BR "' '" ", " + ", and " '
flags, the
.BR "field width" ,
and the
.B precision
fields are accepted. Also, an additional flag
.B !
is recognized to use the capitalized versions of various numeric flags (e.g.
\fBX\fP versus \fBx\fP) and to capitalize character or string values, and an
additional syntax
.BI ">" "<offset>"
after the precision is recognized to start at an offset into the string value
(negative values indicate offset from the end of the string).
.P
The current defaults are:
.TP
metar-uri
.nf
http://weather.noaa.gov/pub/data/observations/metar/stations/%s.TXT
.fi
.TP
avn-uri
.nf
http://www.nws.noaa.gov/cgi-bin/mos/getmav.pl?sta=%s
.fi
.TP
eta-uri
.nf
http://www.nws.noaa.gov/cgi-bin/mos/getmet.pl?sta=%s
.fi
.TP
mrf-uri
.nf
http://www.nws.noaa.gov/cgi-bin/mos/getmex.pl?sta=%s
.fi
.TP
warning-uri
.nf
http://weather.noaa.gov/pub/data/watches_warnings/%f/%.2z/%z.txt
.fi
.SH FILES
.TP
.I $HOME/.wmweather+/
Directory used to store downloaded data files. These files may be deleted at
any time.
.TP
.I $HOME/.wmweather+/conf
User configuration.
.TP
.I /etc/wmweather+.conf
System configuration.
.TP
.I $HOME/.wmweather+/.dir-test
Created and deleted to test write access to \fI$HOME/.wmweather+/\fP
.SH SIGNALS
.TP
.I SIGUSR1
Forces downloads for the current mode to be attempted immediately.
.TP
.I SIGUSR2
Forces all downloads to be attempted immediately.
.SH BUGS
Before reporting a bug, please check the HINTS file (in particular,
proxy instructions are in that file). Also, please verify that you have
the latest version of wmweather+, and that your bug has not already been
reported. Bugs may be filed at
.UR http://sourceforge.net/tracker/?group_id=60336&atid=493854
http://sourceforge.net/tracker/?group_id=60336&atid=493854
.UE
.RI .
.SH AUTHORS
\fBwmweather+\fP was written by \fIBrad Jorsch
<anomie@users.sourceforge.net>\fP, using the wmgeneral code by \fIMartijn
Pieterse <pieterse@xs4all.nl>\fP.
.P
Email regarding wmweather+ should be sent to
\fIanomie@users.sourceforge.net\fP.
.SH INSPIRATION
wmWeather was a good idea, but it didn't give me enough information. However,
no code from wmWeather was used in writing wmweather+.

View file

@ -1,822 +0,0 @@
#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/wait.h>
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
#else
#include <time.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/xpm.h>
#include "wmweather+.h"
#include "convert.h"
#include "download.h"
#include "dock.h"
#include "die.h"
#include "animation.h"
char *ProgName;
char *bigbuf;
int devnull;
char *monthnames[]={ "", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
char *monthnames2[]={ "", "", "", "", "", "", "JUNE", "JULY", "", "SEPT", "", "", "" };
char *wdaynames[]={ "SUNDAY", "MONDAY", "TUESDAY", "WEDN'SDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
char *directions[]={"VRB", "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
char *error;
char *unknown_option="Unknown option";
#define F(a) fprintf(stderr, a "\n");
/***************************************************
* Configuration parameters
***************************************************/
char *email_address=NULL;
char *metar_station=NULL;
char *metar_uri=NULL;
char *metar_post=NULL;
char **warning_zones=NULL;
char *warning_uri=NULL;
char *warning_post=NULL;
char *avn_station=NULL;
char *avn_uri=NULL;
char *avn_post=NULL;
char *eta_station=NULL;
char *eta_uri=NULL;
char *eta_post=NULL;
char *mrf_station=NULL;
char *mrf_uri=NULL;
char *mrf_post=NULL;
char *radar_uri=NULL;
char *radar_post=NULL;
char *radar_crop=NULL;
char *radar_cross=NULL;
char *viewer=NULL;
int pressure_mode=0;
int windspeed_mode=0;
int temp_mode=0;
int length_mode=0;
double latitude=999, longitude=999;
int start_do_animation=1;
int starting_mode=0;
/**********************************
* Prototypes
**********************************/
void usage(int i) __THROW __attribute__ ((__noreturn__));
void printversion(void);
int readconf(char *file);
int parse_option(char *option, char *value);
char *get_filename(char *file);
/**********************************
* Functions
**********************************/
void sigchld(int i){
while(waitpid(-1, NULL, WNOHANG)>0);
}
int parse_option(char *option, char *value){
int i;
void *v;
errno=0;
error=unknown_option;
if(option[0]=='-') option++;
if(option[0]=='-' && option[1]!='\0' && option[2]!='\0') option++;
if(option[0]=='\0') return 0;
if(value!=NULL && value[0]=='\0') value=NULL;
switch (option[0]){
case 'a':
if(!strncmp(option, "avn-", 4)){
if(!strcmp(option+4, "station")){
if(value==NULL){
error="avn-station given with no station ID";
return 0;
}
if(avn_station!=NULL) free(avn_station);
avn_station=strdup(value);
if(avn_station==NULL) die("avn-station strdup");
return 2;
} else if(!strcmp(option+4, "uri")){
if(value==NULL){
error="avn-uri given with no URI";
return 0;
}
if(avn_uri!=NULL) free(avn_uri);
avn_uri=strdup(value);
if(avn_uri==NULL) die("avn-uri strdup");
if(avn_post!=NULL) free(avn_post);
avn_post=NULL;
return 2;
} else if(!strcmp(option+4, "post")){
if(value==NULL){
error="avn-post given with no data";
return 0;
}
if(avn_uri==NULL){
error="avn-post must come after avn-uri";
return 0;
}
if(avn_post!=NULL) free(avn_post);
avn_post=strdup(value);
if(avn_post==NULL) die("avn-post strdup");
return 2;
}
break;
} else if(!strcmp(option, "atm")){
pressure_mode=3;
return 1;
} else if(!strcmp(option, "animate")){
start_do_animation=1;
return 1;
}
break;
case 'b':
if(!strcmp(option, "beaufort")){
windspeed_mode=4;
return 1;
}
break;
case 'c':
if(option[1]=='\0') return 2; /* -c handled earlier */
else if(!strcmp(option, "cm")){
length_mode=1;
return 1;
}
break;
case 'd':
if(!strcmp(option, "display-mode")){
if(value==NULL){
error="display-mode given with no mode specified";
return 0;
}
if(!strcasecmp(value, "cur") || !strcasecmp(value, "current")){
starting_mode=0;
return 2;
} else if(!strcasecmp(value, "fcst") || !strcasecmp(value, "forecast")){
starting_mode=1;
return 2;
} else if(!strcasecmp(value, "map") || !strcasecmp(value, "radar")){
starting_mode=2;
return 2;
} else {
error="display-mode given with unrecognized mode";
return 0;
}
} else if(!strcmp(option, "display")){
return 1;
}
break;
case 'e':
if(!strncmp(option, "eta-", 4)){
if(!strcmp(option+4, "station")){
if(value==NULL){
error="eta-station given with no station ID";
return 0;
}
if(eta_station!=NULL) free(eta_station);
eta_station=strdup(value);
if(eta_station==NULL) die("eta-station strdup");
return 2;
} else if(!strcmp(option+4, "uri")){
if(value==NULL){
error="eta-uri given with no URI";
return 0;
}
if(eta_uri!=NULL) free(eta_uri);
eta_uri=strdup(value);
if(eta_uri==NULL) die("eta-uri strdup");
if(eta_post!=NULL) free(eta_post);
eta_post=NULL;
return 2;
} else if(!strcmp(option+4, "post")){
if(value==NULL){
error="eta-post given with no data";
return 0;
}
if(eta_uri==NULL){
error="eta-post must come after eta-uri";
return 0;
}
if(eta_post!=NULL) free(eta_post);
eta_post=strdup(value);
if(eta_post==NULL) die("eta-post strdup");
return 2;
}
break;
} else if(option[1]=='\0' || !strcmp(option, "email")){
if(value==NULL){
error="-e/email given with no address";
return 0;
}
if(email_address!=NULL) free(email_address);
email_address=strdup(value);
if(email_address==NULL) die("email strdup");
return 2;
}
break;
case 'f':
if(!strncmp(option, "forget-", 7)){
if(!strcmp(option+7, "warning-zones")){
if(warning_zones) free(warning_zones);
warning_zones=NULL;
return 1;
}
break;
}
break;
case 'h':
if(!strcmp(option, "hPa")){
pressure_mode=1;
return 1;
}
break;
case 'i':
if(!strcmp(option, "inHg")){
pressure_mode=0;
return 1;
} else if(!strcmp(option, "in")){
length_mode=0;
return 1;
}
break;
case 'k':
if(!strcmp(option, "kph")){
windspeed_mode=1;
return 1;
} else if(!strcmp(option, "knots")){
windspeed_mode=2;
return 1;
}
break;
case 'l':
if(!strcmp(option, "location")){
if(value==NULL){
error="location given with no value";
return 0;
}
if(!str2dd(value, &latitude, &longitude)){
error="location should be of the form \"dd'mm'ssN dd'mm'ssW\" or \"dd.ddddN dd.dddddW\"\n Note that, if you're using '-location' on the command line, you will need\n to quote the value, e.g. '-location \"dd.ddddN dd.dddddW\"'";
return 0;
}
if(latitude>90 || latitude<-90 || longitude>180 || longitude<-180){
error="latitude or longitude out of range";
return 0;
}
return 2;
}
break;
case 'm':
if(option[1]=='\0' || !strcmp(option, "metric")){
pressure_mode=windspeed_mode=temp_mode=length_mode=1;
return 1;
} else if(!strncmp(option, "metar-", 6)){
if(!strcmp(option+6, "station")){
if(value==NULL){
error="metar-station given with no station ID";
return 0;
}
if(metar_station!=NULL) free(metar_station);
metar_station=strdup(value);
if(metar_station==NULL) die("metar-station strdup");
return 2;
} else if(!strcmp(option+6, "uri")){
if(value==NULL){
error="metar-uri given with no URI";
return 0;
}
if(metar_uri!=NULL) free(metar_uri);
metar_uri=strdup(value);
if(metar_uri==NULL) die("metar-uri strdup");
if(metar_post!=NULL) free(metar_post);
metar_post=NULL;
return 2;
} else if(!strcmp(option+6, "post")){
if(value==NULL){
error="metar-post given with no data";
return 0;
}
if(metar_uri==NULL){
error="metar-post must come after metar-uri";
return 0;
}
if(metar_post!=NULL) free(metar_post);
metar_post=strdup(value);
if(metar_post==NULL) die("metar-post strdup");
return 2;
}
break;
} else if(!strncmp(option, "mrf-", 4)){
if(!strcmp(option+4, "station")){
if(value==NULL){
error="mrf-station given with no station ID";
return 0;
}
if(mrf_station!=NULL) free(mrf_station);
mrf_station=strdup(value);
if(mrf_station==NULL) die("mrf-station strdup");
return 2;
} else if(!strcmp(option+4, "uri")){
if(value==NULL){
error="mrf-uri given with no URI";
return 0;
}
if(mrf_uri!=NULL) free(mrf_uri);
mrf_uri=strdup(value);
if(mrf_uri==NULL) die("mrf-uri strdup");
if(mrf_post!=NULL) free(mrf_post);
mrf_post=NULL;
return 2;
} else if(!strcmp(option+4, "post")){
if(value==NULL){
error="mrf-post given with no data";
return 0;
}
if(mrf_uri==NULL){
error="mrf-post must come after mrf-uri";
return 0;
}
if(mrf_post!=NULL) free(mrf_post);
mrf_post=strdup(value);
if(mrf_post==NULL) die("mrf-post strdup");
return 2;
}
break;
} else if(!strcmp(option, "mmHg")){
pressure_mode=2;
return 1;
} else if(!strcmp(option, "mph")){
windspeed_mode=0;
return 1;
} else if(!strcmp(option, "mps")){
windspeed_mode=3;
return 1;
} else if(!strcmp(option, "mbar")){
pressure_mode=1;
return 1;
}
break;
case 'n':
if(!strcmp(option, "noradar")){
if(radar_uri!=NULL) free(radar_uri);
radar_uri=NULL;
return 1;
} else if(!strcmp(option, "noanimate")){
start_do_animation=0;
return 1;
}
break;
case 'r':
if(!strcmp(option, "radar")){
warn("'radar' is deprecated, please use 'radar-uri' instead");
return parse_option("radar-uri", value);
} else if(!strncmp(option, "radar-", 6)){
if(!strcmp(option+6, "uri")){
if(value==NULL){
error="radar-uri given with no URI";
return 0;
}
if(radar_uri!=NULL) free(radar_uri);
radar_uri=strdup(value);
if(radar_uri==NULL) die("radar-uri strdup");
if(radar_post!=NULL) free(radar_post);
radar_post=NULL;
return 2;
} else if(!strcmp(option+6, "post")){
if(value==NULL){
error="radar-post given with no data";
return 0;
}
if(radar_uri==NULL){
error="radar-post must come after radar-uri";
return 0;
}
if(radar_post!=NULL) free(radar_post);
radar_post=strdup(value);
if(radar_post==NULL) die("radar-post strdup");
return 2;
} else if(!strcmp(option+6, "crop")){
if(value==NULL){
error="radar-crop given with no value";
return 0;
}
if(radar_crop!=NULL) free(radar_crop);
radar_crop=strdup(value);
if(radar_crop==NULL) die("radar-crop strdup");
return 2;
} else if(!strcmp(option+6, "cross")){
if(value==NULL){
error="radar-cross given with no value";
return 0;
}
if(radar_cross!=NULL) free(radar_cross);
radar_cross=strdup(value);
if(radar_cross==NULL) die("radar-cross strdup");
return 2;
}
break;
}
break;
case 's':
if(option[1]=='\0' || !strcmp(option, "station")){
if(value==NULL){
error="-s/station given with no value";
return 0;
}
if(parse_option("metar-station", value)==2
&& parse_option("avn-station", value)==2
&& parse_option("eta-station", value)==2
&& parse_option("mrf-station", value)==2)
return 2;
return 0;
}
break;
case 't':
if(!strcmp(option, "tempf")){
temp_mode=0;
return 1;
} else if(!strcmp(option, "tempc")){
temp_mode=1;
return 1;
}
break;
case 'v':
if(option[1]=='\0' || !strcmp(option, "version")){
printversion();
exit(0);
} else if(!strcmp(option, "viewer")){
if(value==NULL){
error="viewer given with no value";
return 0;
}
if(viewer!=NULL) free(viewer);
viewer=strdup(value);
if(viewer==NULL) die("viewer strdup");
return 2;
}
break;
case 'w':
if(!strncmp(option, "warning-", 8)){
if(!strcmp(option+8, "zone")){
if(value==NULL){
error="warning-zone given with no zone ID";
return 0;
}
if(warning_zones!=NULL){
for(i=0; warning_zones[i]!=NULL; i++);
} else {
i=0;
}
v=realloc(warning_zones, sizeof(*warning_zones)*(i+2));
if(v==NULL) die("warning-zone realloc");
warning_zones=v;
warning_zones[i+1]=NULL;
warning_zones[i]=strdup(value);
if(warning_zones[i]==NULL) die("warning-zone strdup");
return 2;
} else if(!strcmp(option+8, "uri")){
if(value==NULL){
error="warning-uri given with no URI";
return 0;
}
if(warning_uri!=NULL) free(warning_uri);
warning_uri=strdup(value);
if(warning_uri==NULL) die("warning-uri strdup");
if(warning_post!=NULL) free(warning_post);
warning_post=NULL;
return 2;
} else if(!strcmp(option+8, "post")){
if(value==NULL){
error="warning-post given with no data";
return 0;
}
if(warning_uri==NULL){
error="warning-post must come after warning-uri";
return 0;
}
if(warning_post!=NULL) free(warning_post);
warning_post=strdup(value);
if(warning_post==NULL) die("warning-post strdup");
return 2;
}
break;
}
break;
case 'z':
if(!strcmp(option, "zone")){
warn("'zone' is deprecated, please use 'warning-zone' instead");
return parse_option("warning-zone", value);
}
break;
default:
break;
}
return 0;
}
int readconf(char *file){
char *c, *d;
int i, l, flag=1;
FILE *fp;
if(file==NULL){
flag=0;
file=get_filename("conf");
}
if((fp=fopen(file, "r"))==NULL){
if(!flag){
free(file);
return 0;
}
return 1;
}
l=0;
while(fgets(bigbuf, BIGBUF_LEN, fp)!=NULL){
l++;
for(i=strlen(bigbuf)-1; i>=0; i--){
if (!isspace(bigbuf[i])) break;
bigbuf[i]='\0';
}
c=bigbuf+strspn(bigbuf, " \t");
if(*c=='#' || *c=='\0') continue;
d=c+strcspn(c, " \t");
if(*d=='\0') d=NULL;
else {
*d='\0';
d++;
d+=strspn(d+1, " \t");
if(*d=='\0') d=NULL;
}
if(!parse_option(c, d)){
warn("%s[%d]: %s", file, l, error);
return 2;
}
}
fclose(fp);
if(!flag) free(file);
return 0;
}
int check_dir(void){
char *c;
struct stat statbuf;
int i;
c=get_filename("");
i=stat(c, &statbuf);
if(i<0){
if(errno==ENOENT){
if(mkdir(c, 0777)<0) die("Couldn't create directory %s", c);
errno=0;
warn("Created directory %s", c);
i=stat(c, &statbuf);
}
if(i<0) die("Couldn't stat %s", c);
}
if(!S_ISDIR(statbuf.st_mode)) die("%s is not a directory", c);
free(c);
c=get_filename(".dir-test");
if(unlink(c)<0 && errno!=ENOENT) die("Couldn't delete %s", c);
if((i=stat(c, &statbuf))!=-1 || errno!=ENOENT){
if(i!=-1) errno=EEXIST;
die("Couldn't verify nonexistence of %s", c);
}
if((i=creat(c, 0))<0) die("Couldn't create %s", c);
close(i);
if(stat(c, &statbuf)<0) die("Couldn't stat %s", c);
unlink(c);
free(c);
return 1;
}
void sigint(int i){
exit(0);
}
int main(int argc, char **argv){
int i, j;
char *c;
ProgName = argv[0];
if((c=strrchr(ProgName, '/'))!=NULL && *(c+1)!='\0'){
ProgName=c+1;
}
if((bigbuf=malloc(BIGBUF_LEN))==NULL) die("bigbuf malloc");
check_dir();
devnull=open("/dev/null", O_RDWR);
if(devnull<0) die("opening /dev/null");
/* Parse Command Line */
c=NULL;
for(i=1;i<argc;i++){
if(!strcmp(argv[i], "-c")){
i++;
if(!(i<argc)){
F("-c given with no value");
exit(1);
}
c=argv[i];
break;
}
}
if(readconf("/etc/wmweather+.conf")>1) exit(1);
if((i=readconf(c))==1) warn("Couldn't open %s", c);
if(i) exit(1);
for(i=1;i<argc;i++){
char *arg = argv[i];
if(*arg=='-'){
j=parse_option(argv[i], (i+1<argc)?argv[i+1]:NULL);
if(j==0){
if(error==unknown_option) usage(1);
fprintf(stderr, "%s\n", error);
exit(1);
}
i+=j-1;
}
}
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler=sigchld;
act.sa_flags=SA_RESTART;
sigaction(SIGCHLD, &act, NULL);
act.sa_handler=sigint;
sigaction(SIGINT, &act, NULL);
}
i=0;
if(metar_station==NULL){
i=1;
F("Please specify a METAR station.\n See http://www.nws.noaa.gov/tg/siteloc.shtml\n");
}
if(latitude==999){{
time_t t;
int flag=0;
/* note: if time_t isn't an arithmetic type, mkgmtime is screwed
* anyway. So t=0 is as appropriate as anything else. */
t=0;
longitude=-mkgmtime(localtime(&t))/240.0;
latitude=0;
if(longitude<0){
flag=1;
longitude=-longitude;
}
fprintf(stderr, "-location not given. Guessing you're at 0N %d'%d'%d%c\n", (int)longitude, (int)(longitude*60)%60, (int)(longitude*3600)%60, flag?'E':'W');
if(flag) longitude=-longitude;
}} else if(latitude>89.8){
F("Latitude greater then 89.9N automatically truncated.\n");
latitude=89.8;
} else if(latitude<-89.8){
F("Latitude greater then 89.9S automatically truncated.\n");
latitude=-89.8;
}
if(i) exit(1);
if(viewer==NULL) viewer="xless";
if(metar_uri==NULL) metar_uri="http://weather.noaa.gov/pub/data/observations/metar/stations/%s.TXT";
if(avn_uri==NULL) avn_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmav.pl?sta=%s";
if(eta_uri==NULL) eta_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmet.pl?sta=%s";
if(mrf_uri==NULL) mrf_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmex.pl?sta=%s";
if(warning_uri==NULL) warning_uri="http://weather.noaa.gov/pub/data/watches_warnings/%f/%.2z/%z.txt";
download_init(email_address);
init_dock(argc, argv);
while(1){
update_dock();
download_process(100000);
}
}
void usage(int i) {
F("Option Value Description");
F("------ ----- -----------");
F("-c <file> Specify a configuration file");
F("-e <address> Alias for -email");
F("-email <address> Specify anonymous FTP password");
F("-location <lat+lon> Specify latitude and longitude. See manpage.");
F("-v Alias for -version");
F("-version Display version number");
F("-viewer <program> Program to display text from stdin");
F("-[no]animate Turn animation on or off");
F("");
F("-s <ID> Alias for -station");
F("-station <ID> Station ID (all stations)");
F("-metar-station <ID> Station ID for METAR observations");
F("-avn-station <ID> Station ID for AVN forecasts");
F("-eta-station <ID> Station ID for ETA forecasts");
F("-mrf-station <ID> Station ID for MRF forecasts");
F("-warning-zone <zoneID> Zone ID for weather warnings");
F("-*-uri <URI> URI for the weather data (see docs for details)");
F("-*-post <DATA> Post data for the weather data (see docs)");
F(" '*' can be metar, avn, eta, mrf, warning");
F("-noradar Do not display a radar image.");
F("-radar-uri <URI> URI for radar image");
F("-radar-post <DATA> Post data for radar image");
F("-radar-crop <string> How to crop the radar image. XxY+W+H format.");
F("-radar-cross <string> Where to draw radar crosshairs. XxY format.");
F("");
F("-m Alias for -metric");
F("-metric Same as -cm -hPa -kph -tempc");
F("");
F("-in Display precipitation amounts in inches");
F("-cm Display precipitation amounts in centimeters");
F("");
F("-inHg Display pressure in inHg");
F("-hPa Display pressure in hPa (millibars)");
F("-mbar Alias for -hPa");
F("-mmHg Display pressure in mmHg");
F("-atm Display pressure in atmospheres");
F("");
F("-mph Display windspeed in miles/hour");
F("-kph Display windspeed in kilometers/hour");
F("-knots Display windspeed in knots");
F("-mps Display windspeed in meters/second");
F("-beaufort Display windspeed on the Beaufort scale");
F("");
F("-tempf Display temperature in degrees Fahrenheit");
F("-tempc Display temperature in degrees Celcius");
exit(i);
}
void printversion(void) {
fprintf(stderr, "%s\n", VERSION);
}
char *get_filename(char *file){
char *f, *c;
c=getenv("HOME");
if((f=malloc(strlen(c)+strlen(file)+14))==NULL) die("get_filename");
strcpy(f, c);
strcat(f, "/.wmweather+/");
strcat(f, file);
return f;
}
char *get_pid_filename(char *file){
char *f, *c;
static unsigned short seq=0;
char buf[15];
snprintf(buf, sizeof(buf), "%08X.%04X-", getpid(), seq++);
c=getenv("HOME");
if((f=malloc(strlen(c)+strlen(file)+14+14))==NULL) die("get_pid_filename");
strcpy(f, c);
strcat(f, "/.wmweather+/");
strcat(f, buf);
strcat(f, file);
return f;
}

View file

@ -1,41 +0,0 @@
#define BIGBUF_LEN 4096
char *get_filename(char *file);
char *get_pid_filename(char *file);
extern char *ProgName;
extern int devnull;
extern char *bigbuf;
extern char *monthnames[];
extern char *monthnames2[];
extern char *wdaynames[];
extern char *directions[];
extern char *email_address;
extern char *metar_station;
extern char *metar_uri;
extern char *metar_post;
extern char **warning_zones;
extern char *warning_uri;
extern char *warning_post;
extern char *avn_station;
extern char *avn_uri;
extern char *avn_post;
extern char *eta_station;
extern char *eta_uri;
extern char *eta_post;
extern char *mrf_station;
extern char *mrf_uri;
extern char *mrf_post;
extern char *radar_uri;
extern char *radar_post;
extern char *radar_crop;
extern char *radar_cross;
extern char *viewer;
extern int pressure_mode;
extern int windspeed_mode;
extern int temp_mode;
extern int length_mode;
extern double latitude, longitude;
extern int start_do_animation;
extern int starting_mode;

View file

@ -1,221 +0,0 @@
/* XPM */
static char * wmweather_master_xpm[] = {
"190 129 89 1",
" c None",
". c #F6F2FE",
"+ c #82828A",
"@ c #AEAAAE",
"# c #020202",
"$ c #AAAAAA",
"% c #C6C6C6",
"& c #CACACA",
"* c #1EC2FE",
"= c #FE7E7E",
"- c #FEFEFE",
"; c #FEC202",
"> c #B2B2B2",
", c #B6B6B6",
"' c #767602",
") c #C2C202",
"! c #FEFA02",
"~ c #FEDA02",
"{ c #FEFE02",
"] c #828202",
"^ c #AEAEAF",
"/ c #DADADA",
"( c #E6E6E6",
"_ c #FAFAFA",
": c #F2F2F2",
"< c #6A5E22",
"[ c #D2D2D2",
"} c #EAEAEA",
"| c #CECECE",
"1 c #C2C2C2",
"2 c #9AFEFA",
"3 c #DEDEDE",
"4 c #E2E2E2",
"5 c #06021A",
"6 c #060216",
"7 c #22222A",
"8 c #767677",
"9 c #D6D6D6",
"0 c #828282",
"a c #090616",
"b c #45464B",
"c c #9E9E9F",
"d c #929293",
"e c #969696",
"f c #A2A2A2",
"g c #A6A6A6",
"h c #5D5E61",
"i c #0A0A16",
"j c #EEEEEE",
"k c #4E4E4E",
"l c #9A9A99",
"m c #6A6A6B",
"n c #626265",
"o c #7C7C7A",
"p c #F6F6F6",
"q c #36363A",
"r c #65666A",
"s c #565656",
"t c #6E6E6F",
"u c #89898A",
"v c #727273",
"w c #161622",
"x c #7F7E7E",
"y c #8E8E8D",
"z c #BABABA",
"A c #504F52",
"B c #4A4A4B",
"C c #5A5A5E",
"D c #505056",
"E c #BEBEBE",
"F c #1E1D21",
"G c #EAEAE6",
"H c #FA02FE",
"I c #323232",
"J c #028AFE",
"K c #0296FE",
"L c #029AFE",
"M c #027AFE",
"N c #0286FE",
"O c #0276FE",
"P c #0266E2",
"Q c #029EFE",
"R c #026EF5",
"S c #0292FE",
"T c #0282FE",
"U c #027EFE",
"V c #026AEE",
"W c #0262DE",
"X c #025ED2",
" .................+.................+.................+ ",
" .@@@@@@@@@@@@@@@@#.@@@@@@@@@@@@@@@@#.@@@@@@@@@@@@@@@@# ",
" .$$$##$#$#$##$$$$#.$###$$##$##$###$#.$$##$##$$#$$##$$# ",
" .@@#$$@#@#@#$#@@@#.@#$$@#$$@#$@$#$@#.@@#$#$#@#$#@#$#@# ",
" ######################################################## ######################################################## .$$#@$$#$#$##$$$$#.$##$$#@$$##@$#$$#.$$#$#$#$###$##$$# ",
" #.................+.................+.................+% #.................+.................+.................+% .@@#$@@#@#@#$#@@@#.@#$@@#$@@$#$@#@@#.@@#@#@#@#$#@#$@@# ",
" #.$$$$$$$$$$$$$$$$#.$$$$$$$$$$$$$$$$#.$$$$$$$$$$$$$$$$#& #.$$$$$$$$$$$$$$$$#.$$$$$$$$$$$$$$$$#.$$$$$$$$$$$$$$$$#& .$$@##$###$#$#$$$#.$#$$$@##@##$$#$$#.$$#$#$#$#$#$#$$$# ",
" #.@@@##@#@#@##@@@@#.@###@@##@##@###@#.@@##@##@@#@@##@@#% #.@@@##@#@#@##@@@@#.@###@@##@##@###@#.@@##@##@@#@@##@@#% .@@$$$@$$$@$@$@@@#.@$@@@$$$$$$@@$@@#.@@$@$@$@$@$@$@@@# ",
" #.$$#$$$#$#$#$#$$$#.$#$$$#$$$#$$$#$$#.$$#$#$#$#$#$#$#$#& #.$$#$$$#$#$#$#$$$#.$#$$$#$$$#$$$#$$#.$$#$#$#$#$#$#$#$#& +#################+#################+################# ",
" #.@@#@@@#@#@##$@@@#.@##@@#@@@##@@#@@#.@@#@#@#@###@##$@#% #.@@#@@@#@#@##$@@@#.@##@@#@@@##@@#@@#.@@#@#@#@###@##$@#% #################+#################+#################+ ",
" #.$$#$$$#$#$#@#$$$#.$#$$$#$$$$#$$#$$#.$$#$#$#$#$#$#@$$#& #.$$#$$$#$#$#@#$$$#.$#$$$#$$$$#$$#$$#.$$#$#$#$#$#$#@$$#& #$$$$$$$$$$$$$$$$.#$$$$$$$$$$$$$$$$.#$$$$$$$$$$$$$$$$. ",
" #.@@$##@###@#$#@@@#.@#@@@$##@##@@#@@#.@@#@#@#@#@#@#$@@#% #.@@$##@###@#$#@@@#.@#@@@$##@##@@#@@#.@@#@#@#@#@#@#$@@#% #@@@##@#@#@##@@@@.#@###@@##@##@###@.#@@##@##@@#@@##@@. ",
" #.$@$$$$$$$$@$$$$$#.$$$$@$$$$$$$$$$$#.$$$$$$$$$$$$@$$$#& #.$@$$$$$$$$@$$$$$#.$$$$@$$$$$$$$$$$#.$$$$$$$$$$$$@$$$#& #$$#$$$#$#$#$#$$$.#$#$$$#$$$#$$$#$$.#$$#$#$#$#$#$#$#@. ",
" #+#################+#################+#################% #+#################+#################+#################% #@@#@@@#@#@##$@@@.#@##@@#@@@##@@#@@.#@@#@#@#@###@##$$. ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%& %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%& #$$#$$$#$#$#@#$$$.#$#$$$#$$$$#$$#$$.#$$#$#$#$#$#$#@@@. ",
" #@@$##@###@#$#@@@.#@#@@@$##@##@@#@@.#@@#@#@#@#@#@#$$$. ",
" ######################################################## ######## ###################################### ######## #$@$$$$$$$$@$$$$$.#$$$$@$$$$$$$$$$$.#$$$$$$$$$$$$@@@@. ",
" #######################################################% #.....+% #####################################% #.....+% +.................+.................+................. ",
" #######################################################& #.$$$$#& #####################################& #.$$$$#& ###################################################### ",
" #######################################################% #.@@#@#% #####################################% #.@#@@#% ###################################################### ",
" #######################################################& #.$##$#% #####################################% #.$##$#& ###################################################### ",
" #######################################################% #.@$#@#& #####################################& #.@#$@#% ###################################################### ",
" #######################################################& #.@$$$#% #####################################% #.$@$$#& ###################################################### ",
" #######################################################% #+#####& #####################################& #+#####% ###################################################### ",
" #######################################################& %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%& ###################################################### ",
" #######################################################% ###################################################### ",
" #######################################################& ######################################################## ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" #######################################################% #######################################################% ###################################################### ",
" #######################################################& #######################################################& ###################################################### ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ###################################################### ",
" ****************************************************** ",
" ====================================================== ",
" ",
" ",
" ########-################# #####################-#### *=############;#############",
" ######--->################ ########-->>>>>>>>>>-,#### *=############;#############",
" ####------>#####>--####### ########,,,,-------->>#### *=######;####;;;####;#######",
" ####>-----,>>->-,---###### ########>-->,,,,,,,,,##### *=######;;###;;;###;;#######",
" ##--,------,--------###### ########,,,>>>>>->--###### *=######;;;')!!!)';;;#######",
" >> ##---,------,--------##### ########>>>,,--,,,>>###### *=#######~!{{{{!{!!~########",
" ,,,,,, ,->>>>>> ,>,>>> >>> ##---,------,,--------#### ########,->--,>>>--####### *=##;;##]{{{{{{{{{{{];;;;###",
" ,>------, >-------,,------>>--->> > #------------>,,------#### ########>,,,----,,######## *=##;;;~{{{{{{{{{{{{!~;;####",
" ------------, ,,--------------------, ^>>>>>> #-------------------->-### ########>---,,,>>>######## *=###;;!{{{{{{{{{{{{{!;#####",
" >>,,,,,,,,,,> ,--,>,,,,,,--,,-,,,> >>,----> #---------------,,,----### ########-,>,>>----######## *=####~{{{{{{{{{{{{{{!'#####",
" ,> ,> > ,------> >> #,--,,-,------->>-,----### ########>,>---,,,######### *=####){{{{{{{{{{{{{{{)#####",
" >,>------,>-> ->----,>---------->,-,#### ########--,,,,>>########## *=##;;!{{{{{{{{{{{{{{{!;;###",
" ,>----------->> -,----,----------,>,>>#### ########,>>>>,->########## *=;;;;{{{{{{{{{{{{{{{{{;;;;#",
" ,>-------------> -------,,,,,---------->### ########>,,---,########### *=##;;!{{{{{{{{{{{{{{{!;;###",
" ,--------------> ----------------------->># ########>-,,,>############ *=####){{{{{{{{{{{{{{{)#####",
" ,,,,,, ,,,,,, >>>>>-,-----,,-,,--> ,,-------------------,>### ########-->>-,############ *=####'{{{{{{{{{{{{{{{~#####",
" ,>------, ,>------, ,-,-----,,---,>---->> #,,,---------,,,,--,>,#### ########,,,->############# *=####;{{{{{{{{{{{{{{{;#####",
" ------------, ------------, >------,,>>--,>------> #>>>,,----,,,>>>>,,>,>#### #########--,,############# *=###;;~{{{{{{{{{{{{{~;;;###",
" >>,,,,,,,,,,> >>,,,,,,,,,,> ,-,---------->,-------> #,,>>,,,,>>>,,,,>>,>,##### ########,,>>############## *=##;;##]{{{{{{{{{{{]##;;###",
" ,>,---------------,,,, ##>,,>>>>,,,>####,>####### ########>>,############### *=######;~{{{{{{{{{~########",
" >,,,,----------,>>>> ######,,>>################ #########>>############### *=######;;;'){{{)';;########",
" ,>>>>,,,,,,,,,,>,,,> ########################## ########################## *=######;;###;;;###;;#######",
" ,>>>>>>>>>>,>>>, ########################## ########################## *=######;####;;;####;#######",
" ,,,,,,,,,> ########################## ########################## *=############;#############",
" ########################## ########################## *=############;#############",
"&/(____------------:&%%%%> < < < <<<<< <<<< < < < ###-##-##-#####.....+.....+ *=##########################",
"[/}----------------:|1111% <<< <<<< << <<< < < < ###--#-#-#-####.$$$$#.$$$$# *=##########################",
"[/(_---------------:[%%%1% << << < <<< << << 22222222222 ###-#--#-#-####.@@#$#.@#@$# *=##########################",
"|/(_---------------}|%%%%% <<<<<< < < <<< < 22 2222 ###-##-#-#-####.$##@#.$##@# *=##########################",
"3_----------------------4% < <<< < < < <<< 222222222 222 ###-##-##-#####.$$#$#.$#$$# *=####566678$&9&^076655#####",
"-------------------------/ < << <<<< < 222 ###############.@@$@#.@$@@# *=####55abc$defedg1hi55#####",
"-------------------------j <<<< < << < < 222 222 ###############+#####+##### *=####55k8lmn8l^$e$,oi5#####",
"-------------------------p < < <<<< < << < << 222222 2222 2 ####################+#####+ *=####aqnmrsntucvod,1h6#####",
"-------------------------_ < << < << < << 222222 ################$$$$.#$$$$. *=####wnttrnmxyonn0%zz7#####",
"-------------------------p <<<<<< < < 22 22222 --###-##---##-##@@#@.#@#@@. *=####bAmnvvvtcvhhmy$tn#####",
"-------------------------p <<< < << < <<<< << 222222 22 22222222 22 -#-#-#-##-##-#-#$##$.#$##$. *=####mbsvuge8tnxskBfru#####",
"-------------------------( < << <<< < <<< < < 222222 -#-#---##-##---#@$#@.#@#$@. *=####cBCu0exncl$CDDocg#####",
"p-----------------------_[ < < << << << < < 22 22222 222 -#-#-#-##-##-#-#@$$$.#$@$$. *=####gBBhv08yl%EemdvCc#####",
"(:_---------------------_% <<<< <<< < < < 22 222 22 --##-#-##-##-#-+.....+..... *=####gCDs8vu^,|E&u^otg#####",
"/44j_-------------------_> <<< << < << < < < < << 222 22 22 *=####dd8vnm8d>EE&>0c0d#####",
"fffE:__-----------------pe < < < < < < < 222 22 2 2 ####nEcCxxrez,E,zyefn#####",
"fff^(__-----------------jt <<<< << << < <<< < << < 2222 222 ####FzE8x08g9[E%%z[zF#####",
"fff,4:-----------------pEB < < <<<< << < < << < ####ak1gf$[}G[1E,19s6#####",
"f$|jpp_---------------_3%^ << < <<< < < <<<< < < 22 222222222222 ####6at,^E9G4|1E|Era6#####",
"z4}:__pp__-----------_j&%^ < B< < < < <<< 222222222 2222 ####65ak^z%4[&1&,ka56#####",
"4}}:pp:jpj:_-----_____}%E^ < << < < < < < << 22 2222 ####5666Fmf99[gmF6555#####",
"[9/3}}}}}}[}pp}((_ppp:9E^f <<<<< < <<< < < < < 22222 H{{{{H ##########################",
"%1%%/(}}}}z1[9334pppp(1^ff << < <B < < < <<<< 2 H{{{{H ##########################",
"1%%%&/4}((f0e^%[/jp.4z@ffl < <<< < << << < < << 22222222 H{{{{H ##########################",
"E%%%%%|//ECFItd>z13[>fffff < <<< <<< < << < 22222 H{{{{H ##########################",
" H{{{H ",
" # H{{{H H{{{H ",
" #J# H{{{H H{{{H ",
" ### # #K# H{{{H H{{{H ",
" -- #-#-#-# ##L## H{{{H H{{{H ",
" -- -- -- -- #--###--# #KKJ# H{{{H H{{{H ",
"-- -- -- -- #--#-#-#--# #KLM# H{{{H H{{{H ",
"-- ###-----### #LKM# H{{{H H{{{H ",
" -- -- -- #--###-###--# #LLNOP# H{{{{{H H{{{{{H ",
" -- -- -- -- -#----#---- - QKNMR# H{{{H H{{{H ",
"- -- -- - -- KSTUORP H{{{H H{{{H ",
"- -- -- -----## JTTUOVP H{{HH H{{H{{H ",
" -- -- -- -- -- -- -#- -- JNTMRVW# H{{H H{{H H{{H ",
" -- -- -- -- #-- ##-- MMVWP## H{{H H{{H H{{H ",
" -- - - - WXX H{{H H{{H H{{H "};