Upstream tarball

This commit is contained in:
Juhani Krekelä 2021-04-19 13:47:21 +03:00
commit 21863d7241
134 changed files with 40816 additions and 0 deletions

965
CHANGES Normal file
View File

@ -0,0 +1,965 @@
2.0
---
alpha 19 - 19990530
--------
Cancelling a blocked source caused a NULL function to get called...should be
fixed. Changed chimera/source.c.
Portability changes for the NEC EWS4800/360PX.
Yozo Toda <yozo@aohakobe.ipc.chiba-u.ac.jp>
Portability changes to make gcc quieter when compiling. Fixed function
type errors. Alexander Mai <st002279@hrzpub.tu-darmstadt.de>
NULL return from malloc() in common/mempool.c at least triggers an error
message now but doesn't handle it.
Fixed a problem which caused a cached entry to get bypassed. Changes made
to TryMemoryCache() in chimera/source.c.
alpha 18 - 19990527
-------------------
Fixed bug in proto/file.c that caused chimera to crash when large
directory listings were being processed.
Hostnames entered in the URL field or with the Open dialog are transformed
into http://hostname/. Change made to chimera/request.c.
alpha 16/17 - 19990408
----------------------
Added <Meta> to the beginning of the key bindings so that they didn't
conflict with regular keystrokes.
alpha 15 - 19980517
-------------------
Reload flag was ignored in SinkCreate() in chimera/source.c which caused
reloads to fail if the document was in core.
Started hacking on CSS parser thing. Created html/css.c and html/css.h
with some integration with existing html/ code.
Image load concurrance increased in html/inline.c.
Added patch to chimera/resource.c. Content could be accessed
uninitialized in TryMemoryCache().
smarry@pantransit.smar.reptiles.org
Problem with uninitialized variable in AddObject() in htm/html.c.
smarry@pantransit.smar.reptiles.org
Localhost and hostname weren't allowed as proxy hosts. This caused
trouble with local proxies like wwwoffle.
wr->pup wasn't being passed to HTTPCreateInfo() from HTTPInit().
The request sent to HTTP proxies was not complete. Fixed HTTPGetFilename().
Keyboard accelerators added. Changes in chimera/WWW.c and chimera/head.c
Andrew M. Bishop <amb@gedanken.demon.co.uk>
alpha 14 - 19980103
-------------------
Fixed the authorization handling code in proto/http.c that was
broken in the previous release.
Included string.h in common/mime.c
Alexander Mai <st002279@hrzpub.tu-darmstadt.de>
Modified chimera/Imakefile to work better with OS/2.
Alexander Mai <st002279@hrzpub.tu-darmstadt.de>
Worked on chimera/source.c to make handling of downloads less buggy.
Worked on chimera/view.c and chimera/stack.c to make handling of
external viewers less buggy.
alpha 13 - 19971217
-------------------
Changed common/mime.c to do a better job of parsing the headers that
appear in MIMEish streams. Required modifications to other
bits of code that called the functions in common/mime.c.
Added patch to fix portability problems in image/jpegp.h and image/jpeg.c.
Tom Lane <tgl@sss.pgh.pa.us>
Removed buggy error checking abort() thing in html/html.c.
Tom Lane <tgl@sss.pgh.pa.us>
Code in proto/http.c reworked a bit to account for changes in common/mime.c
and to simplify it a bit.
alpha 12 - 19971211
-------------------
Added mention that app-defaults files should be avoided for v2 and that
a wrapper should be created if v1 and v2 are being used on the
same system to point v2 away from the v1 app-defaults file.
Added patch to html/misc.c to fix problems with bold and strong text.
Russell King <rmk@ecs.soton.ac.uk>
Chimera now looks at the last argument on the command line as the URL.
Regis Rampnoux <regisr@tmn.sofrecom.fr>
Added patches for missing common.h in files in image/
Alexander Mai <st002279@hrzpub.tu-darmstadt.de>
Fixed prototype in chimera/ChimeraSource.h
"Nelson H. F. Beebe" <beebe@math.utah.edu>
Patch to frame code in html/frame.c.
Dave Davey <daved@physiol.usyd.edu.au>
alpha 11
--------
Fixed memory leak at chimera/stack.c:280. Frame-related memory leak still
exists.
Fixed access of NULL ptr caused by lack of rows/cols attribute in frameset
in html/frame.c.
alpha 10
--------
Added patch for EMX/OS2. Alexander Mai <st002279@hrzpub.tu-darmstadt.de>
Added patch to allow filenames as the initial URL. <mbaker@iee.org>
Added patch to fix relative URLs for redirects in proto/http.c.
Julian Coleman <J.D.Coleman@newcastle.ac.uk>
alpha 9
-------
Fixed HTMLTitleEnd in html/head.c.
Patch for QNX in common/uproc.c and bug in proto/http.c.
"D. J. Hawkey Jr." <hawkeyd@visi.com>
Fixed initialization of parent_url in chimera/request.c.
Dave Davey <daved@physiol.usyd.edu.au>
Resource user.email added to use as value for the From: field in
proto/mailto.c.
alpha 8
-------
prototype for snprintf() added to port_after.h. trouble expected.
more prototypes added.
ChimeraRequest destroyed twice in chimera/source.c.
"Bradley G. Kaiser" <bkaiser@edge.edge.net>
Added font fixup code to html/font.c
"Bradley G. Kaiser" <bkaiser@edge.edge.net>
Tag IDs are now compared instead of tag structure addresses in html/html.c
which fixes environment disaster bug spotted by
john kraft <jkraft@solti.mcis.washington.edu>
NULL filename part in URL caused URLs to be resolved incorrectly.
common/url.c:resolve_filename() changed.
Added mailto code from. Big win.
Dave Davey <daved@physiol.usyd.edu.au>
Resource added to allow new head to get triggered on a type of URL.
Example: mailto.newhead: true
Resource added to allow the user to specify something besides sendmail
in proto/mailto.c.
alpha 7
-------
Added "find" button.
Added string find capability to plain text renderer. Bg/fg color broken.
Changed search and query callbacks so they aren't such a pain to deal with.
Cleaned up some compiler complaints about functions without prototypes.
alpha 6
-------
RequestCreate in chimera/request.c now properly calls the custom URL
parser callbacks and allows a URL to be handled completely
by a proxy.
Moved architecture specific debugging flag selections from the toplevel
Imakefile to Common.tmpl.dist.
Added patch to html/form.c to fix problem with call to RenderAction.
Erik Johannessen <erjohann@sn.no>
Patch provided so that if the path is not defined by the resource
view.path then the PATH environment variable is used when
the path for external programs is specified. Also, added
'/' in mytmpnam in common/util.c.
Sander van Malssen <svm@kozmix.ow.nl>
Added '()' to the command passed to system() in chimera/view.c.
Added popup to display the progress of downloads that will be viewed
with external viewers and to allow them to be cancelled.
Frame 'src' had to be an absolute URL. Now it can be a relative URL.
Made other random hacks in chimera/ and html/ to make the
target attribute work. Whoops, it doesn't work yet.
Form image submit works better.
alpha 5
-------
More work on HTML frames.
Added various patches by J.D.Coleman@newcastle.ac.uk
Fixed problems with using FILENAME_MAX. Reported by
roessner@rbg.informatik.th-darmstadt.de
External viewers now work. Bug reported by
Yozo Toda <yozo@aohakobe.ipc.chiba-u.ac.jp>
Moving to name anchors should work now.
The previous position of a document should be remembered correctly now.
HTTP basic authentication should work.
alpha 4
-------
Moved files from www/ and main/ into chimera/. Reworked stuff and
gratituously changed names to satisfy my inner child.
Added HTML frames.
alpha 3
-------
Added '#include <stdio>' to common/mime.c.
Removed (XPointer *) from mxw/TextField.c. Older versions of X don't
define XPointer.
alpha 2
-------
Added patch to www/io.c for HPUX.
Tom Lane <tgl@sss.pgh.pa.us>
Added new jpeg.c and jpegp.h.
Tom Lane <tgl@sss.pgh.pa.us>
Added linebreak after <hr>
Fixed problem in html/flow.c:WidthFlow(). Width was not calculated
correctly after linebreak.
Added code in html/flow.c:LayoutFlow() to make <br clear=mumble> work.
Fixed a few type mismatches lurking in html/*.c.
Added modifier for library names in Common.tmpl.dist in case system
library names clash.
Stuck 'x' on the front of chimera library names to prevent clashes.
alpha 1
-------
Added patch to html/font.c to make font weight selection better.
Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>
Added patch to HTMLTDInsert() to deal with missing <tr> correctly.
Added another tag handling kludge function to HTMLTag. This one is used
to figure out how to clamp down end tags for things like <ul>
and <table>.
cfh-2.0
-------
alpha 171-190
-------------
Entities are case sensitive. Changed strncasecmp to strncmp.
Erik <erjohann@sn.no>
Fixed code in common/mime.c to find the HTTP status.
Fixed code for setting path in main/view.c.
Various fixes from "D. J. Hawkey Jr." <hawkeyd@visi.com> for
PRE tags, URL handling, and QNX.
Created a bunch of resource access functions to make it easier to access
resource values. Made cache resource dealings more reasonable
as suggested by Yozo Toda <yozo@aohakobe.ipc.chiba-u.ac.jp>
Added chimera.urlLogFile resource. If set to a valid writable file will
append a log of URLs that were loaded at the toplevel.
Discovered reentrancy problem in main/download.c.
Same problem in main/view.c. (should be fixed now)
Smarasderagd <smar@reptiles.org>
Removed JCONFIG_INCLUDED from image/jpeg.c because it caused definitions
to get messed up in jpeg.h. Tom Lane <tgl@sss.pgh.pa.us>
Resources should now be correctly free'd when a head is destroyed in
main/widget.c.
Added support for 'Host' field in proto/http.c.
Fixed a bunch of memory leaks (but not even close to all of them).
Added tracking code to common/list.c and common/mempool.c.
Added a 'reusable' flag to the Scheme structure in www/data.c to indicate
cached documents can be reused without setting the cache
flag which would cause them to be recached.
Added argument to WWWCancelData() to allow a distinction between cancelling
callbacks and actually cancelling the data. Also hacked around
to make sure the code kept track of downloads more correctly.
Added code to html/inline.c to make sure that when the reload flag is set
that an inline is only reloaded once.
Added code to www/context.c to look for the www.maxDownloads resource to
set the maximum number of concurrent downloads.
Added/fixed the code that actually limits the number of concurrent downloads.
Whoops.
FTP code communicates failures back up the handler chain. Probably needs
more work but should work better.
Code in common/ml.c took a dump when untagged text showed up.
Should be fixed now.
The accept list is now taken in account when searching to see if a current
download can be used instead of starting a new download. See
TryMemoryCache in data.c for details.
Added code to look at www.printLoadMessages resource.
Markup language parser code in common/ml.c revised to work a bit better.
Mostly changed to make comment handling work better.
Patch to add keyboard editting commands to the text widget. Joy!
"J.D.Coleman" <J.D.Coleman@newcastle.ac.uk>
Added code to highlight tags when selected.
If the first document is not HTML then no HTML fonts are created but
the HTML class code still tried to free them. Should be fixed now.
Added config for AIX 3.2.5.
mark olesen <olesen@weber.me.queensu.ca>
Lots of reworked code in html/.
alpha 169-170
-------------
-lsocket -lnsl added to OS_LIBS in Common.tmpl.dist for Solaris.
Yozo Toda <yozo@aohakobe.ipc.chiba-u.ac.jp>
Modified Common.tmpl.dist install directories as suggested by
Jean-Marc.Lasgouttes@inria.fr
Made config changes for QNX. "D. J. Hawkey Jr." <hawkeyd@visi.com>
Switched URLParse back to putting NULL in filename if it is zero-length.
Doesn't change it if it is NULL.
Changed the file: code to change a NULL filename to "/".
Added endianism for 68xxx. David Wolfskill <david@dhw.vip.best.com>
Changed column scaling in html/table.c:TablePosition1.
Scaled box width didn't include the width of all of the columns when
colspan > 1. Changed html/table.c:TablePosition1.
Fixed another problem in common/mempool.c and rearranged things a bit.
Worked on main/download.c to make downloads behave a little better.
Added patch for 1x1 interlaced GIF problem.
Smarasderagd <smar@reptiles.org>
Changed the MIME code to try to make it a bit faster. Changes had to
be made all over the place.
alpha 166-168
-------------
Added file.autoLoad resource. If defined then the file protocol checks
to see if the URL specifies a directory and, if it does, checks to
see if the file specified in file.autoLoad exists in that
directory and loads it instead of a directory listing.
Added patch to fix alignment problem in mempool.c.
"J.D.Coleman" <J.D.Coleman@newcastle.ac.uk>
Code in proto/http.c no longer cares about the useRedirect resource.
Let HTTP error messages display instead of trying to trap the messages
in proto/http.c.
Fixed cache flag bug in proto/http.c.
Removed -Wmissing-* because it caused old versions of gcc to become upset.
Made sure inputs for forms are removed from any lists they might be
in when they're destroyed because the two-pass thing that
happens for tables causes a whole heap of trouble.
If a cache directory can't be found then a message is printed on stderr.
The environment variable WWW_HOME can be used to specify the first document.
URLParse always returns "/" instead of a NULL or zero-length filename.
Listened to Jonny Quest theme by Reverend Horton Heat. Liked it.
alpha 165
---------
Added __convex__ to image/image_endian.h. Added ConvexArchitecture to
Common.tmpl.dist. David DeSimone <fox@convex.hp.com>
Hopefully Common.tmpl.dist will deal with Solaris more reasonably.
Help from lots of people from bug-chimera.
Added HPArchitecture based on tip from
Otmar Stahl <O.Stahl@lsw.uni-heidelberg.de>
Cut buffer cleared if there is a valid URL inside that is used to
start a new shell.
Fixed problem with horizontal scrollbar introduced when the
trouble-causing arguments were removed from www/WWW.c
Replaced 'clock' with 'time' in common/util.c
Added DIV tag to html/misc.c.
Finally found a really annoying bug in the table code. Rowspan > 1
in the middle of a row caused trouble.
Dialogs now have one label area instead of two.
alpha 164
---------
Switched over to Alignment struct/union thing in common/mempool.c.
Markku Savela <msa@hemuli.tte.vtt.fi>.
Got rid of trouble-causing arguments in www/WWW.c.
alpha 163
---------
Commented out table debugging code.
Re-enabled comment parsing in common/ml.c.
common/mempool.c uses MEMPOOL_ALIGNSIZE to determine the alignment size.
The default is sizeof(size_t).
Boxes accessing related data after the data was destroyed causing
seg violation in html/module.c:HTMLDestroy. Do box destruction
first.
Messages for downloading and other activities should appear in the
shell(s) that apply. Added extra field to the file dialog so that
file operation messages will appear in the right spot.
Patch for URL escaping in common/url.c and html/form.c
Jake Kesinger <kesinger@math.ttu.edu>
Patch for broken font handling in plain/plain.c
"T. Alexander Popiel" <popiel@rintintin.Colorado.EDU>
Fakes <tr> before <td> or <th> more reasonably.
Fixed bad declaration for HTMLAttributeToID in html/html.h.
Steven E Lumos <slumos@CS.UNLV.EDU>
Made Common.tmpl.dist style a bit more consistent.
Added patch submitted in 1994(!) to map URLs to other URLs using
regular expressions. Theodore Ts'o <tytso@ATHENA.MIT.EDU>
This has been disabled for now for performance reasons.
When a new head/shell is started the cut buffer is examined for a URL.
If there is a valid URL at the beginning then it will be loaded.
Changed main/main.c.
In url.c:URLParse look for other separators not just '/' before ':'.
Revampled www/request.c:WWWBuildRequest to make it more efficient hopefully.
Baseline should be fixed for forms widgets.
Switched over to using snprintf and fixed size buffers in a few
places. Mostly in message handling. Included code for snprintf
from LPRng-2.4.2.
www/mime.c:MIMEFindData searched one byte too far which caused really
all sorts of irritating trouble.
alpha 162
---------
Added LinuxArchitecture to Common.tmpl.dist
Proportional scaling of table columns added to html/table.c.
Added BSD386Architecture to Common.tmpl.dist
Baseline code for inline images fixed.
Referenced NULL pointer in SubmitCallback fixed in html/form.c.
Table width was ending up as 0 (probably a bug) which was later used
in a division. Fixed to not cause SIGFPE.
All traces of the app-defaults file removed (hopefully).
Right floating objects should now float to the right hand side even if there
aren't enough objects to push it to the edge.
<td> or <th> before a <tr> looks bad but shouldn't cause a core file
to appear.
Missing 'l' in 'lenv' in HTMLOListEnd in html/list.c.
Added NetBSDArchitecture to Common.tmpl.dist
Added missing definitions to common/common.h for functions in
common/list.c "J.D.Coleman" <J.D.Coleman@newcastle.ac.uk>
Fixed other random table weirdness (my powers of description are stretched
to the max with some of this sludge I'm writing).
alpha 112-161
-------------
Lots of code reworked, moved around, and other fun stuff.
Added GPL.
Added Rob McMullen's TextField widget.
Incorporated patch for numbering ordered lists.
Jake Kesinger <kesinger@math.ttu.edu> ?
Added patch for dealing with malloc failures to the image/ code.
Smarasderagd <smar@reptiles.org>
Frames disappeared
alpha 111
---------
Made changes with the way frame position is set. The position of
a document is passed to the renderer for it to deal with.
Fixed anchor handling in the HTML code.
Added for check "id" attribute. Erik Corry <erik@kroete2.freinet.de>
The HTML code now has a timeout that will destroy an inline if it
takes too long to find its size.
Moved the cache code into www/.
alpha 110
---------
Frames are refreshed when they are resized.
Made changes to html/* to improve HTML handling.
Comments are handled slightly differently in common/ml.c.
FreeBSD added to Common.tmpl.dist.
Added support for the dreaded <center> tag.
alpha 109
---------
Fixed MEMPOOL_DEBUG usage in the defintion of pool. common/mempool.c.
NULL pointer accessed in www/frame.c:FrameQuery() sometimes when
source requested. Ben Taylor <bent@snm.com>
Added http.useRedirect resource which makes HTTP 302s act like 301s.
Fixed SELECT form problems and cleaned up the code. Did the same for
the textarea code.
Fixed MxwGetFont()...was always returning NULL.
Reworked CallTagHandler() a bit.
XMP added...acts like PRE.
Clone will really do a clone now...the URL is taken from the cloned
window. The resource chimera.cloneHome can be set to force the
clone to use the home page.
Listing and XMP should work correctly now.
HTML code reworked a bit.
Line 235 in www/frame.c used frame->fcontext instead of value like it
was supposed to.
Fixed a problem with bookmarks...the element handler wasn't handling
elements correctly.
alpha 108
---------
Fixed problems in html/form.c. Reworked things a bit. Still in bad
shape.
alpha 107
---------
Changed proportional font default pattern in html/font.c. Big win.
Rob McMullen <rwmcm@hydra.ae.utexas.edu>
Added patch to fix 'ENDIAN' preprocessor goodies in image/ and
fix homeless startup crash. Erik Corry <erik@kroete2.freinet.de>
Cleaned up frame and proto handling code in www/proto.c and www/frame.c
Made the connection count code in www/proto.c work.
Pressing "source" won't cause a reload. Created FrameRedisplay().
Doing a reload caused all subsequent loads to inherit the reload flag.
Put a line in Common.tmpl to show where you can force a special compiler.
Added margins to the HTML renderer. Defaults to 20.
Tags are handled the old way...if tags are overlapped then end tags
are simulated to eliminate overlap.
Changed font code so that the fixed fonts work the same way as the
proportional fonts.
Fixed bookmark create problems. Strings were not being allocated
correctly...they were auto vars that got wiped out.
Worked on the markup parsing. Seems to handle comments and stuff in
general more correctly. Simplified Element handling and made all of
the 'common/ml' types opaque. More function calls! Less mucking
with internals!
Worked on HTML list handling...didn't handle bad HTML as well as it
could.
Added better isspace() called isspace8().
Erik Corry <erik@kroete2.freinet.de>
alpha 106
---------
Parentless frames needed a fake parent ID to prevent collions with
real parent IDs. Solves all sorts of terrible problems.
Added external viewer code. Had to rearrange www/proto.c, www/frame.c, and
create src/view.c. Should be faster.
Made a whole bunch of changes to the HTML renderer to better deal with
errors and to a problem that caused paragraphs (and other tags) to wipe
out previous tag environments.
Redirect URLs are correctly passed back from protocol handlers to the URL
stack. HTTP passes it back for status "Moved permanently" only.
Forms fixed. Multi-selects work internally (how useful!). Form image
works.
Won't crash if no bookmarks are available.
Cache now uses an integer ID for the filename that is kept in the
cache index. Unfortunately, you can only have 2^31 cache entries
on most machines.
HTTP code was looking for the location: field and ignoring the status.
Nexus server returns location field even when status was not 300-399.
This caused a nifty loop.
GET /something?mumble queries failed because it was assumed to be NULL
terminated but wasn't necessarily NULL terminated.
FrameDestroy() was not free'ing everything.
Bookmark now works when there is no bookmark file.
alpha 104-105
-------------
InitModule_Message() was not initializing ProtoHooks correctly.
Smarasderagd <smar@reptiles.org>
Source button works now.
Simplified the code in www/io.c...it was getting too hairy without
providing any benefits.
Renamed functions in www/ and other places to something more reasonable.
Changed the behavior of MLMultiGetText() so that it is more reasonable
to use.
Reworked the forms code a bit: textarea and option text collection
is simpler.
I note the following typo:
cfh102-2.0/www/mime.c: { image/x-xpimap, xpm },
Michael Kellen <michael@xph029.physics.montana.edu>
Moved the stuff in misc/ to proto/.
Updated README.hints.
Changed the download code so that a save file requester appears at the
end of the transfer instead of an entire screen in the main display.
<tr> causes a line break.
HTMLQuery() in module/html.c could not deal with a NULL title.
Rearranged and messed around with code to try to get the memory
usage down a bit.
Bookmark code now works pretty much the way it did in 1.65. Bookmark file
is an HTML-like file. changes in src/
Added resource to set the maximum length of a cache filename length.
See lib/resources for details. I can't remember who asked me for this.
Messed around with Common.tmpl and the Imakefiles to make it easier for
me.
Fixed line layout code to take baselines into account to make
the "align" attribute work. Changed a bunch of stuff in html/
*/* is added to the end of the accept string. Changed proto/http.c.
URL resolution fixed and simplified slightly. '..' caused problems
and things like '//' were not removed which messed up the cache.
Added common/dir.c and modified www/url.c.
Made lots of worthless cosmetic changes to the functions in html/.
Added check for _SSIZE_T and _SIZE_T to common/common.h
Added image input field to forms support.
Fixed FTP. Broke in 103.
InitModule_File wasn't initializing structure properly. proto/file.c changed.
Forms code memory overrun. html/form.c changed.
alpha 103
---------
Readded code to use the base filename of a URL as the default name
for saving stuff.
aXe scrolling text widget removed.
The title was not being terminated at the right time in AddBookmark() in
src/bookmark.c.
Support for <note> tag added.
Jake Kesinger <kesinger@math.ttu.edu>
alpha 102
---------
A colon delimited list of filenames can be specified for the dbFiles
resource.
URL failure was not being reported back to the parent frame. This caused
HTML rendering to stop forever waiting for the image. Partially fixed.
Reported by Karl Eichwalder <ke@ke.Central.DE>.
Added support for the size attribute for form text input.
Larry Doolittle <doolitt@recycle.cebaf.gov>
Paragraph align attribute was being carried over into the following
paragraphs if the aligned paragraph didn't have an end tag. Fixed.
Reported by Karl Eichwalder <ke@ke.Central.DE>
Feeling silly...added some support for frames. html/frame.c.
Cleaned up the URL load code in HTML and shoved it in html/load.c.
HandleSelect() was causing trouble if called for </select> but there
was never a <select>. Should be fixed. Lycos needs a better
HTML editor.
Added PNG patches/additions. Smarasderagd <smar@reptiles.org>
Changed www/mime.c to add PNG filename extensions.
Cache index file format is HTML.
Fixed the blockquote nesting stuff. Looks like it was coded to
prevent nested blockquotes. Probably sleepy that night.
Spotted by Jake Kesinger (kesinger@math.ttu.edu)
Ordered lists kind of work. "Regular" Decimal only. Formatting needs work.
Spotted by Jake Kesinger (kesinger@math.ttu.edu)
alpha 101
---------
Fixed problem where an element was being created for text for the empty
string between two tags.
Rearranged frame.c and proto.c internals.
HTML module only resizes every 10th line.
Cache now keeps an index file to make the cache startup faster.
HTML module now looks for '#' goodies on URLs.
The scrollbar position is remembered.
IOCreateStream now checks for NULL hostname.
Changed the name of libimage.a to libximage.a and libmisc.a to libxmisc.a
because IRIX has libraries with the reason names.
alpha 100
---------
In TextareaText() and OptionText(), the length was initialized wrong
the first time around. Smarasderagd <smar@reptiles.org>
Fixed problem in url.c...input data was being copied incorrectly.
Smarasderagd <smar@reptiles.org>
MemPoolCreate() allocates space with the initial descriptor to
reduce the number of malloc()'s.
proto/http.c looks for "Pragma: no-cache".
FrameEndData() was checking for the add hook when it wanted to call
the end hook.
Cache changes:
Added size limit, persistence flag, and cleaned up the header
read code. Still need to add TTL code.
common/common.h makes sure that FILENAME_MAX is defined.
Added patch to proto/ftp.c and www/url.c to make non-anonymous FTP work.
Michael Kellen <michael@xph029.physics.montana.edu>
Textarea text and option text/values are now allocated with the mempool
functions. Changes in html/form.c.
Title and style text (I ran into an HTML3 document with style and it was
annoying...) are collected in one chunk instead of realloc'd. Changes
in layout.c, layout.h, test.c, layout.c, form.c.
Moved the markup language parsing thing to common/ml.c so that it can
be used easily in other places. Made gratuitous changes at the same
time to structure names. Required thrashing around in html/.
Probably introduced a whole bunch of new bugs.
Readded bookmark feature. Bookmarks can be added and loaded but not
editted. Bookmark file is an HTML file.
Added code to allow mempool to revert to malloc()'s for every memory grab
so that Electric Fence/dmalloc/whatever will make more sense with chimera.
Downloads are no longer associated with frames. This is to allow multiple
frames to access the same document without having to hit the cache
for their own copy. Reduces memory usage and eliminates a lot of disk cache
accesses.
Handling of HTTP redirects changed.
alpha 99
--------
free_mem() was called too soon in ImageDestroy()
Smarasderagd <smar@reptiles.org>
For loop counter initialized incorrectly in LayoutSetupFonts().
Smarasderagd <smar@reptiles.org>
Readded #ifdef HAVE_JPEG to image/image.c.
Probably fixed the problem with a word appearing at the end of the line
and at the beginning of the next because it was drawn too soon.
Fixed problem in image/jpeg.c:
lf_finish_decompress() doesn't check the return value of
jpeg_finish_output(), which sometimes leaves things in the wrong
state. Smarasderagd <smar@reptiles.org>
alpha 98
--------
Fixed problem pointer problem in html/font.c.
Smarasderagd <smar@reptiles.org>
Straightened out common/mempool.c and combined common.h and mempool.h.
URLParts are allocated using the MemPool functions.
MIME functions use MemPool for allocations.
Cache no longer caches documents with auth information or return
data.
Fixed (I think) endless loop problem when a HTTP redirect occurred.
Added a resolver function to the protocol and render module search.
Allows the application to define a function that can load modules
on the fly.
Added callback definitions to catch stupid mistakes.
Reworked the I/O messages a bit.
alpha 97
--------
Added code to allow a module to override the render hooks for a frame.
Reason: the HTML module needs to trap button presses for inline images.
Required changes to the Frame definition, html/inline.c, www/action.c,
and www/frame.c.
alpha 96
--------
Made more changes to every directory for the Frame type change.
Made buffer allocations for the next stream read larger to reduce the number
of allocations.
alpha 95
--------
Added size_t in some places.
Added HAVE_STDDEF_H (check out common/common.h).
Frames are no longer widgets. This is to allow modules to create
invisible frames for non-X renderers (audio, postscript, ...).
Required a lot of changes in www/.
alpha 94
--------
Fixed a problem where the widgets used by the download renderer were not
removed. Michael Kellen <michael@xph029.physics.montana.edu>
Cache simplified...removed memory caching.
Fixed problem in HTTP: data was being wiped out by the buffer
replacement code when content-length is found.
DocumentDestroy() now does the whole job.
Removed the render caching from the image module.
Commented the special color allocator in image/image.c because it was
having troubles with narrow images...fix later.
Sort of fixed the FTP code.
Added some resource string lookups to reduce the dependency on
hardcoded strings.
Hacked the font code in the HTML module. Attempts to pick the best
choices from a list specified by a pattern.
Fixed a problem in TitleText() and AuthorText() in html/text.c. The running
length was wrong.
Fixed a potential memory leak problem and other things in proto/file.c.
Fixed URLHash()...length given to MD5 function was wrong.
Mucked around misc/cache.c.
alpha 93
--------
Made memory cache read gradual.
Changed www/io.c to act more like the alpha 80 version (more stable)
and it also returns growing buffers which requires content handlers
to keep track of offsets instead of addresses into the buffer
before FrameEndData() is called because realloc_mem() could cause
the addresses to become invalid.
Fixed the HTML code to deal with the new www/io.c buffer policy.
Applied patch to proto/http.c that fixed an initialization problem and
added NULL checks to www/proxy.c. Erik Corry ehcorry@inet.uni-c.dk
Inserted missing 'else' in CacheMemRead().
URL display works correctly again.
WM_PROTOCOL delete is handled again.
Added all sorts of swell progress messages.
A file based XrmDatabase is used for the message database.
Handling HTTP/0.x in proto/http.c fixed.
alpha 92
--------
Forms stuff has been reenabled. Sort of works.
The download stuff is a bit more reasonable but not by much.
Noodled around a bit...added a defintion for conversion modules.
Moved the message protocol to misc.
alpha 91
--------
FrameEndData wasn't checking the closure argument which caused seg fault.
Smarasderagd <smar@reptiles.org>
Added patch that added comments to image/image.c, proxy matching code,
and bug fixes. Erik Corry <ehcorry@inet.uni-c.dk>
Changed the image code endian header stuff so that I don't get
yelled at again :) Michael Kellen <michael@xph029.physics.montana.edu>
The cancel button sort of works. The inlines don't get cancelled.
GIF patches that fixed the endless loop problem and some other
problems. Shigeru Yamamoto <shige-y@is.aist-nara.ac.jp>
GIF patch that fixed problems with interfaced 2-color GIFs.
Erik Corry <ehcorry@inet.uni-c.dk>
Added patch that reduced memory usage in proto/file.c, added
HAVE_STRING_H to proto/error.c (now message.c), and fixed prototype
in image/image.c. Larry Doolittle <doolitt@recycle.cebaf.gov>
Downloading sort of works. The filename is hardcoded.
Cache code got rearranged. The cache read code is a protocol module
and the cache write code is a render module.
Error/status messages are now loaded with a URL of the form
x-message:message_name.
alpha 81-90
-----------
Rearranged everything. Look at the code.
alpha 78-80
-----------
Tons of patches for the color/image handling code.
Erik Corry ehcorry@inet.uni-c.dk
The y coordinate of the rectangle to refresh in CreateRenderLine() was
set to the x coordinate which caused the bottom edge of the
visible area to not be refreshed.
Placement of text and other items has changed. Changes in text.c and
layout.c.
alpha 77
--------
Incorporated the second big patch to the color/image handling code.
Erik Corry ehcorry@inet.uni-c.dk
Problem with anchor text having leading spaces fixed.
Added patch to WWWLayout() that makes it smarter when picking the next
part to handle. Larry Doolittle <doolitt@recycle.cebaf.gov>
Various other changes that I don't remember.
Fixed problem with start anchor tag and missing end anchor tag.
alpha 76
--------
Revised the way inline.c handles inline images mostly to deal with the
changes below...
xloadimage/ is now image/ and now has a generic interface to the image
code.
Code changes for dealing with determining when a part can be rendered.
Always use IsRenderable().
alpha 75
--------
Added a big wad of important changes for much improved color
handling. Patches made in common, www, and xloadimage.
Erik Corry ehcorry@inet.uni-c.dk
alpha 74
--------
Number of inputs miscounted in form.c which caused overrun of malloc'd
space in SubmitCallback().
NameValueToURLEncoded() in form.c fixed.
Bug in the select/option tags fixed. Without a value attribute the
option value got screwed up.
Added an error message in LoadDocument() for when the URL is invalid.
Readded the external protocol stuff except that the name is kind of
changing to "local proxy" and it is specified using environment
variables like the regular proxy.
alpha 73
--------
Moved the HandleMumble() functions from layout.c just because.
Added patch to wwwio/document.c to fix a problem with "no_proxy"
handling. Erik Corry <erik@kroete2.freinet.de>
Added patch to xloadimage/gif.c to make it deal with broken GIFs
better. Erik Corry <erik@kroete2.freinet.de>
Fixed space insertion in filled text. Its slow but it works.
Fixed introduced problem with <hr>.
Blockquote was formatted wrong.
Erik Corry <erik@kroete2.freinet.de>
Fixed problem with anchor not being terminated by beginning of
next anchor.
Missing #include <sys/types.h> added.
Kenichi Chinen <k-chinen@is.aist-nara.ac.jp>
Error messages should show up more often (instead of never).
alpha 72
--------
Resizing is still a disaster. Reloads a document completely. Have to
leave it for now.
Made some improvements (hopefully) to the resizing of the clip, child,
and scrollbar widgets. Right margin should look correct now.
alpha 71
--------
Improved memory situation. Memory for the rendering stuff is allocated
in chunks of BUFSIZ. Makes things simpler, I hope. Makes it
faster for huge documents.
Fixed problem in tag parser. Trailing whitespace caused a problem.
Added event callbacks for render parts.
Removed all cache code.
URL handling changed. Input data is passed in one big junk instead of in
name/value pairs.
Added authentication stuff. Something is wrong but its close.
alpha 70
--------
Cache setup simplified. Got rid of the cache info files. Cache still
disabled by default, though, because the widget is messed up and
image stuff doesn't work right with the cache for some reason.
<LI> indents are nicer.
brokenHTML is True by default.
Fixed problem in TextareaText() in forms.c. Length wrong in realloc
section. Same problem in OptionText()!
Fixed silly problem in AddEntry() in form.c.
Messed around in WWW.c. Added a PreferredGeometry function. Still
messed up.
Changed the way memory is allocated for RenderParts and the element
specific structure. Required changes in lots of places. Simplified
some stuff.
PREText and PlainText have been combined and made more efficient (hopefully)
in text.c.
Took out DestroyURLParts() in SubmitCallback() in form.c. Caused
a seg fault sometimes. Now we have another memory leak.
Fixed ConfigureWidgets() so that the width and height of the document
are kept within the range of Dimensions. It really sucks that
Dimension is a 16 bit value. Need to get rid of the hardcoded
values.
alpha 69
--------
Added brokenHTML resource to relax the HTML parser.
The request field was not being initialized in http_main.
On the first pass of rendering/layout objects are not drawn if they are
not on the screen. Duh.
alpha 68
--------
Check boxes were broken. Should be fixed now.
Radio boxes should work now.
Weird whitespace in forms is turned into a space.
Fixed HTML parsing problems. Probably introduced more problems but now
it survives at least one test page :) Need to get SGML manual from
Allen.
alpha 65-67
-----------
More forms work. Mucked with internal tag handling stuff. Nothing fun.
Made image refreshing work a little better, hopefully.
Added BLOCKQUOTE.
Fixed tag handling again.
Added blank lines in front of some block structure tags to flush a line of
text before the new attributes take effect.
Check for NULL method added in wwwio/http.c.
alpha 63-64
-----------
Started work on forms. Some stuff works. Does not do well on Digital's
test.
Fixed bad problem in DestroyRenderPartList(). Who's stupid idea was it
to put similarly named next fields in RenderPart?
Made some other changes. Don't remember what they were.
Removed what little support there was for old versions of X stuff.
alpha 62
--------
Fixed redirection handling. Handles "Location". Needs to handle "URI".
Did some work to the scrollbars.
Widget now handles title and author.
Adding bookmarks works.
Reworked the refresh code. Should be faster. Images won't refresh much
faster because XImage is used so my 4MB X terminal doesn't poop out.
URL window allows user entry again.
alpha 58-61
-----------
An I/O stream will timeout after 10 seconds.
Number of downloads can be limited.
Source works. Problem is that it reloads the document which is a problem
if the document is regenerated each time it is accessed and you don't
get a cache hit and you need to see the original.
Changed the names of some structures with bad historical names.
Rearranged layout handling code to trigger as a callback to the
HTML parsing code.
FillText() uses unsigned char so that isspace() doesn't get confused.
This fixes (I hope) the problem with some entity goodies not showing
up.
ReadStreamHandler() allocates memory in multiples of BUFSIZ.
Fixed/broke/rearranged a bunch of stuff that I don't remember.
Source changed so that an editor is fork()'d. I'll try to change it
back later. Problem is that switching source during a download can
cause big trouble and I didn't want to do an IOStop().
Resize works. Same problems as with source so I do an IOStop(). Grrr.
alpha 11-57
-----------
Rewrote everything (almost). Got rid of NCSA's HTML widget and rolled
my own HTML parsing and rendering code.
ftp_error_message free()'d a string literal.
Dick Streefland <dicks@knoware.nl>
alpha 10
--------
HTML widget changed a lot. Expose and reformat code changed.
Changed the title/message widget to just a plain pane (basically).
Added anchor URL display.
Roman Czyborra <czyborra@cs.tu-berlin.de>
alpha 1-9
---------
Complete rewrite of the I/O handling code. Socket select is now handled
by the Xt event loop. Moved net code, pseudo-MIME stuff, and caching
code to its own directory. The main UI code has been reworked to
deal with the event-based I/O code. HTML widget image handling
heavily modified.
Added patch to HTMLimages.c to fix scanline padding and depth
handling. Or something. Jim Rees <rees@umich.edu>
Added patch to make the download filename the same as the URL filename.
Roman Czyborra <czyborra@cs.tu-berlin.de>
Made changes to content-type handling as per the suggestion of Roman who
went and read RFC 1521 and 1524.
Made patch to url.c.
Martin Stiftinger <stifting@iue.tuwien.ac.at>
Added strlen(anchor) to MakeURL. I think Martin made this fix too. I
don't remember. Thanks to both of course.
Larry Doolittle <doolitt@recycle.cebaf.gov>
Added patch to local.c so that local file directory listings contain
lots of useful information. Didn't include the FTP part because it
won't work on all FTP servers. Patch is at
http://xph029.physics.montana.edu/chimera/filesize.patch if you
would like to try it. It needs work for 2.0...
Added patch for SGML escape stuff. Jim Rees <rees@umich.edu>
Patch to HTML.c to make scrolling work right.
Leonard N. Zubkoff <lnz@dandelion.com>
Made attempt to make sure POSIX header files are included. Not done
yet.
2.x
---
Complete rewrite.
1.x
---
See the chimera-1.x distribution for changes.

229
Common.tmpl.dist Normal file
View File

@ -0,0 +1,229 @@
/*
* Common config file
*/
/*
* Installation directories.
*
* CHIMERA_BINDIR - chimera's executable gets installed here.
* CHIMERA_LIBDIR - configuration files. someday.
* CHIMERA_MANDIR - directory to hold the outdated man page.
*/
/*
CHIMERA_PREFIX = /usr/local
CHIMERA_BINDIR = $(CHIMERA_PREFIX)/bin
CHIMERA_LIBDIR = $(CHIMERA_PREFIX)/lib/chimera
CHIMERA_MANDIR = $(CHIMERA_PREFIX)/man
*/
#if !defined(__QNX__)
LIBPRE=lib
LIBEXT=.a
#else
LIBPRE=
LIBEXT=3r.lib
#endif
/*
* Add a bit of fluff to the end of the image library name if
* you need it. For example, on IRIX and Linux boxes its nice
* to use it to differentiate from the vendor libraries of the same
* name.
*/
/*
IMGLEXT = _local
*/
/* Uncomment and modify if you have the JPEG 6 library */
/*
#define Use_JPEG
JPEGDIR = /usr/local
JPEGINCLUDE = -I$(JPEGDIR)/include
JPEGLIB = -L$(JPEGDIR)/lib -ljpeg$(IMGLEXT)
JPEGDEPLIB = $(JPEGDIR)/lib/libjpeg$(IMGLEXT).a
*/
/* Uncomment and modify if you have the PNG library */
/*
#define Use_PNG
PNGDIR = /usr/local
PNGINCLUDE = -I$(PNGDIR)/include
PNGLIB = -L$(PNGDIR)/lib -lpng$(IMGLEXT) -lz$(IMGLEXT)
PNGDEPLIB = $(PNGDIR)/lib/libpng$(IMGLEXT).a $(PNGDIR)/lib/libz$(IMGLEXT).a
*/
/* Tells Imakefile to set the flags for debugging. Comment for -O. */
#define CDebugging 1
/* You might need to force the compiler to gcc */
/*
CC = gcc
*/
/* Add site stuff here */
SITE_DEFINES =
SITE_LIBS =
SITE_DEPLIBS =
SITE_LDFLAGS =
/*
* You should not have change anything below unless you add a new
* OS feature section or add your own module.
*/
/*
*
* OS features
*
*/
/* Sparcs */
#if defined(SunArchitecture)
#if OSMajorVersion > 4 /* Solaris */
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_SSIZE_T -DHAVE_STDARG_H
OS_LIBS = -lsocket -lnsl
#else /* SunOS 4.1.4 X11R6, gcc */
#define NEED_MEMMOVE 1
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_STDARG_H
OS_LIBS =
#endif
#define CConfigSet 1
#endif
/* DEC UNIX */
#if defined(AlphaArchitecture)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UTIME -DHAVE_MKTIME -D_BSD -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H
OS_LIBS = -lbsd
OS_DEBUG_FLAGS = -std1
#define CConfigSet 1
#endif
/* IRIX */
#if defined(SGIArchitecture)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H
OS_LIBS =
OS_DEBUG_FLAGS = -fullwarn
#define CConfigSet 1
#endif
/* FreeBSD, BSDI, NetBSD */
#if defined(FreeBSDArchitecture) || defined(BSD386Architecture) || defined(NetBSDArchitecture)
#define HAVE_SNPRINTF 1
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H -DHAVE_SNPRINTF
OS_LIBS =
#define CConfigSet 1
#endif
/* Linux */
#if defined(LinuxArchitecture)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H
OS_LIBS =
#define CConfigSet 1
#endif
/* Convex */
#if defined(ConvexArchitecture)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_STDARG_H
OS_LIBS =
#define CConfigSet 1
#endif
/* HP */
#if defined(HPArchitecture)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_STDARG_H \
-DHAVE_SSIZE_T
OS_LIBS =
#define CConfigSet 1
#endif
/* QNX */
#if defined(__QNX__)
CC = cc -Otx -mf -zp1 -w4
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H
OS_LIBS =
#define CConfigSet 1
#endif
/* AIX 3.2.5 */
#if defined(RsArchitecture)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H
OS_LIBS =
#define CConfigSet 1
#endif
/* OS/2, XFree86 & EMX gcc */
#if defined(OS2Architecture) && !defined(CConfigSet)
#define NEED_SNPRINTF 1
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H \
-DHAVE_STDDEF_H -DHAVE_SIZE_T -DHAVE_SSIZE_T \
-DHAVE_STDARG_H
OS_LIBS =-lsocket
#define CConfigSet 1
#endif
/* NEC EWS4800 with ansi cc -- yozo. Fri Apr 9 09:23:42 JST 1999 */
#if defined(_nec_ews_svr4) && !defined(CConfigSet)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SSIZE_T -DHAVE_SIZE_T \
-DHAVE_STDARG_H
OS_LIBS = -lsocket -lnsl
OS_DEBUG_FLAGS =
#define CConfigSet 1
#endif
/* everything else hopefully */
#if !defined(CConfigSet)
OS_DEFINES = -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_UNISTD_H -DHAVE_STDDEF_H \
-DHAVE_UNAME -DHAVE_MKTIME -DHAVE_SIZE_T -DHAVE_STDARG_H
OS_LIBS =
OS_DEBUG_FLAGS =
#define CConfigSet 1
#endif
/*
*
* Glue together the various flags for compiling and linking
*
*/
CHIMERA_DEFINES = $(OS_DEFINES) $(SITE_DEFINES)
CHIMERA_LOAD_FLAGS = $(OS_LDFLAGS) $(SITE_LDFLAGS)
IMAGELIB = -L../image -lximage $(JPEGLIB) $(PNGLIB)
IMAGEDEPLIB = ../image/$(LIBPRE)ximage$(LIBEXT) $(JPEGDEPLIB) $(PNGDEPLIB)
HTMLLIB = -L../html -lxhtml
HTMLDEPLIB = ../html/$(LIBPRE)xhtml$(LIBEXT)
PLAINLIB = -L../plain -lxplain
PLAINDEPLIB = ../plain/$(LIBPRE)xplain$(LIBEXT)
PROTOLIB = -L../proto -lxproto
PROTODEPLIB = ../proto/$(LIBPRE)xproto$(LIBEXT)
OTHERLIB = -L../common -lxcommon -L../mxw -lmxw \
-L../port -lxport \
XawClientLibs -lm
OTHERDEPLIB = ../common/$(LIBPRE)xcommon$(LIBEXT) \
../port/$(LIBPRE)xport$(LIBEXT) \
../mxw/$(LIBPRE)mxw$(LIBEXT)
CHIMERA_LIBS = $(IMAGELIB) $(HTMLLIB) $(PROTOLIB) $(PLAINLIB) \
$(OTHERLIB) $(OS_LIBS) $(SITE_LIBS)
CHIMERA_DEPLIBS = $(IMAGEDEPLIB) $(HTMLDEPLIB) $(PROTODEPLIB) \
$(PLAINDEPLIB) $(OTHERDEPLIB) $(SITE_DEPLIBS)
#define MyNull

32
Imakefile Normal file
View File

@ -0,0 +1,32 @@
#include <./Common.tmpl>
#define IHaveSubDirs
#if HasGcc
#ifdef CDebugging
#define PassCDebugFlags "CDEBUGFLAGS=-g -Wall"
#else
#define PassCDebugFlags "CDEBUGFLAGS=-O -Wall"
#endif
#else
#ifdef CDebugging
#define PassCDebugFlags "CDEBUGFLAGS=-g $(OS_DEBUG_FLAGS)"
#else
#define PassCDebugFlags "CDEBUGFLAGS=-O $(OS_DEBUG_FLAGS)"
#endif
#endif
SUBDIRS = port common image html plain proto mxw chimera
MakeSubdirs($(SUBDIRS))
InstallSubdirs($(SUBDIRS))
DependSubdirs($(SUBDIRS))
CleanSubdirs($(SUBDIRS))
MakefileSubdirs($(SUBDIRS))
InstallManSubdirs($(SUBDIRS))
myclean: clean
$(RM) Common.tmpl Makefile Makefile.bak make.err make.out .depend
for i in $(SUBDIRS); do \
$(RM) $$i/Makefile $$i/Makefile.bak $$i/.depend; \
done

4
README Normal file
View File

@ -0,0 +1,4 @@
This is chimera version 2. Please look in doc/ for license information,
build information, and other bits.
-john

70
chimera/Chimera.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Chimera.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERA_H__
#define __CHIMERA_H__ 1
#include "common.h"
#include "url.h"
typedef struct ChimeraResourcesP *ChimeraResources;
typedef struct ChimeraContextP *ChimeraContext;
typedef struct ChimeraTaskP *ChimeraTask;
typedef void (*ChimeraTaskProc) _ArgProto((void *));
#define TaskSchedule(a, b, c) TaskScheduleX(a, b, c, __LINE__, __FILE__);
ChimeraTask TaskScheduleX _ArgProto((ChimeraResources,
ChimeraTaskProc, void *, int, char *));
void TaskRemove _ArgProto((ChimeraResources, ChimeraTask));
typedef struct ChimeraTimeOutP *ChimeraTimeOut;
typedef void (*ChimeraTimeOutProc) _ArgProto((ChimeraTimeOut, void *));
ChimeraTimeOut TimeOutCreate _ArgProto((ChimeraResources, unsigned int,
ChimeraTimeOutProc, void *));
void TimeOutDestroy _ArgProto((ChimeraTimeOut));
char *ResourceGetString _ArgProto((ChimeraResources, char *));
int ResourceAddFile _ArgProto((ChimeraResources, char *));
int ResourceAddString _ArgProto((ChimeraResources, char *));
char *ResourceGetBool _ArgProto((ChimeraResources, char *, bool *));
char *ResourceGetInt _ArgProto((ChimeraResources, char *, int *));
char *ResourceGetUInt _ArgProto((ChimeraResources, char *, unsigned int *));
char *ResourceGetFilename _ArgProto((ChimeraResources, MemPool, char *));
void CMethodVoidDoom();
void *CMethodVoidPtrDoom();
int CMethodIntDoom();
char CMethodCharDoom();
char *CMethodCharPtrDoom();
byte *CMethodBytePtrDoom();
bool CMethodBoolDoom();
#define CMethod(x) ((x) != NULL ? (x):CMethodVoidDoom)
#define CMethodChar(x) ((x) != NULL ? (x):CMethodCharDoom)
#define CMethodCharPtr(x) ((x) != NULL ? (x):CMethodCharPtrDoom)
#define CMethodBytePtr(x) ((x) != NULL ? (x):CMethodBytePtrDoom)
#define CMethodBool(x) ((x) != NULL ? (x):CMethodBoolDoom)
#define CMethodInt(x) ((x) != NULL ? (x):CMethodIntDoom)
#define CMethodVoid(x) ((x) != NULL ? (x):CMethodVoidDoom)
#define CMethodVoidPtr(x) ((x) != NULL ? (x):CMethodVoidPtrDoom)
#endif

31
chimera/ChimeraAuth.h Normal file
View File

@ -0,0 +1,31 @@
/*
* ChimeraAuth.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERAAUTH_H__
#define __CHIMERAAUTH_H__ 1
typedef struct ChimeraAuthP *ChimeraAuth;
typedef void (*ChimeraAuthCallback) _ArgProto((void *, char *, char *));
ChimeraAuth AuthCreate _ArgProto((ChimeraResources, char *, char *,
ChimeraAuthCallback, void *));
void AuthDestroy _ArgProto((ChimeraAuth));
#endif

60
chimera/ChimeraGUI.h Normal file
View File

@ -0,0 +1,60 @@
/*
* ChimeraGUI.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERAGUI_H__
#define __CHIMERAGUI_H__ 1
typedef struct ChimeraGUIP *ChimeraGUI;
typedef struct ChimeraGUIScrollPosP *ChimeraGUIScrollPos;
typedef void (*GUISizeCallback) _ArgProto((ChimeraGUI, void *,
unsigned int, unsigned int));
ChimeraGUI GUICreate _ArgProto((ChimeraContext, ChimeraGUI,
GUISizeCallback, void *));
void GUIDestroy _ArgProto((ChimeraGUI));
void GUIMap _ArgProto((ChimeraGUI, int, int));
void GUIUnmap _ArgProto((ChimeraGUI));
void GUISetInitialDimensions _ArgProto((ChimeraGUI,
unsigned int, unsigned int));
void GUIGetOnScreenDimensions _ArgProto((ChimeraGUI,
int *, int *,
unsigned int *, unsigned int *));
int GUIGetDimensions _ArgProto((ChimeraGUI,
unsigned int *, unsigned int *));
void GUISetDimensions _ArgProto((ChimeraGUI,
unsigned int, unsigned int));
Display *GUIToDisplay _ArgProto((ChimeraGUI));
Window GUIToWindow _ArgProto((ChimeraGUI));
Pixel GUIBackgroundPixel _ArgProto((ChimeraGUI));
Widget GUIToWidget _ArgProto((ChimeraGUI));
void GUISetScrollBar _ArgProto((ChimeraGUI, bool));
void GUIGetScrollPosition _ArgProto((ChimeraGUI, int *, int *));
void GUISetScrollPosition _ArgProto((ChimeraGUI, int, int));
int GUIGetNamedColor _ArgProto((ChimeraGUI, char *, Pixel *));
#endif

217
chimera/ChimeraP.h Normal file
View File

@ -0,0 +1,217 @@
/*
* ChimeraP.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERAP_H__
#define __CHIMERAP_H__
#include "common.h"
#include "Chimera.h"
#include "ChimeraSource.h"
#include "ChimeraGUI.h"
#include "ChimeraRender.h"
#include "ChimeraAuth.h"
#include "ChimeraStack.h"
typedef struct ChimeraCacheP *ChimeraCache;
typedef struct BookmarkContextP *BookmarkContext;
typedef struct ChimeraSchedulerP *ChimeraScheduler;
struct ChimeraContextP
{
MemPool mp;
Widget toplevel;
Widget file;
Widget www;
Widget open;
Widget back;
Widget reload;
Widget cancel;
Widget quit;
Widget home;
Widget addmark;
Widget viewmark;
Widget message;
Widget dup;
Widget source;
Widget save;
Widget openpop;
Widget savepop;
Widget findpop;
Widget bookpop;
Widget url;
Widget help;
Widget bookmark;
Widget find;
ChimeraStack tstack; /* top stack */
ChimeraStack cstack; /* current stack */
MemPool tmp;
ChimeraResources cres;
char *button1Box; /* list of widgets in the first button box */
char *button2Box; /* list of widgets in the second button box */
};
/*
* Chimera runtime context
*/
struct ChimeraResourcesP
{
int maxiocnt; /* maximum IOs */
bool printLoadMessages;
bool printTaskInfo;
MemPool mp; /* memory pool */
XrmDatabase db; /* message database */
ChimeraCache cc;
/* Lists of stuff we need to know about */
GList sourcehooks; /* list of registered sources */
GList renderhooks; /* list of registered renderers */
GList mimes; /* list of mimes */
GList renderers; /* list of active renderers */
GList sources; /* list of active sources */
GList timeouts; /* list of timeouts */
GList oldtimeouts; /* list of old timeouts */
GList heads; /* list of heads */
GList stacks; /* list of stacks */
/* */
void (*authui_callback)();
void *authui_closure;
XtAppContext appcon; /* X application context */
size_t id; /* next unique ID */
Display *dpy;
ChimeraScheduler cs; /* task scheduler context */
ChimeraContext bmcontext; /* head associated with bookmarks */
ChimeraRenderHooks *plainhooks; /* plain text renderer */
BookmarkContext bc; /* bookmark routines context */
FILE *logfp; /* log file */
int refcount; /* reference count */
};
/*
*
* Prototypes
*
*/
/*
* cache.c
*/
ChimeraCache CacheCreate _ArgProto((ChimeraResources));
void CacheDestroy _ArgProto((ChimeraCache));
bool CacheIsDiskCached _ArgProto((ChimeraCache, char *));
int CacheWrite _ArgProto((ChimeraCache, ChimeraSource));
ChimeraSourceHooks *CacheGetHooks _ArgProto((ChimeraCache));
/*
* data.c
*/
void SourceGetData _ArgProto((ChimeraSource,
byte **, size_t *, MIMEHeader *));
/*
* gui.c
*/
ChimeraGUI GUICreateToplevel _ArgProto((ChimeraContext, Widget,
GUISizeCallback, void *));
void GUIReset _ArgProto((ChimeraGUI));
void GUIAddRender _ArgProto((ChimeraGUI, ChimeraRender));
/*
* bookmark.c
*/
BookmarkContext BookmarkCreateContext _ArgProto((ChimeraResources));
void BookmarkDestroyContext _ArgProto((BookmarkContext));
void BookmarkAdd _ArgProto((BookmarkContext, char *, char *));
void BookmarkShow _ArgProto((BookmarkContext));
/*
* head.c
*/
void HeadCreate _ArgProto((ChimeraResources, ChimeraRequest *,
ChimeraRequest *));
void HeadDestroy _ArgProto((ChimeraContext));
void HeadPrintMessage _ArgProto((ChimeraContext, char *));
void HeadPrintURL _ArgProto((ChimeraContext, char *));
Widget CreateDialog _ArgProto((Widget, char *,
void (*)(), void (*)(), void (*)(), XtPointer));
Widget GetDialogWidget _ArgProto((Widget));
/*
* main.c
*/
void ChimeraAddReference _ArgProto((ChimeraResources));
void ChimeraRemoveReference _ArgProto((ChimeraResources));
/*
* callback.c
*/
bool MessageCallback _ArgProto((void *, char *));
bool ActionCallback _ArgProto((void *, ChimeraRequest *, char *));
bool RedrawCallback _ArgProto((void *));
bool ResizeCallback _ArgProto((void *));
/*
* builtin.c
*/
void InitChimeraBuiltins _ArgProto((ChimeraResources));
/*
* view.c
*/
void ViewOpen _ArgProto((ChimeraResources, ChimeraRequest *));
/*
* download.c
*/
void DownloadOpen _ArgProto((ChimeraResources, ChimeraRequest *));
/*
* stack.c
*/
ChimeraStack StackCreateToplevel _ArgProto((ChimeraContext, Widget));
ChimeraGUI StackToGUI _ArgProto((ChimeraStack));
ChimeraRender StackToRender _ArgProto((ChimeraStack));
void StackSetRender _ArgProto((ChimeraStack, ChimeraRenderHooks *));
/*
* resource.c
*/
char *ResourceGetStringP _ArgProto((ChimeraResources, char *));
/*
* cmisc.c
*/
ChimeraSourceHooks *SourceGetHooks _ArgProto((ChimeraResources, char *));
/*
* task.c
*/
ChimeraScheduler SchedulerCreate _ArgProto((void));
#endif

103
chimera/ChimeraRender.h Normal file
View File

@ -0,0 +1,103 @@
/*
* ChimeraRender.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERARENDER_H__
#define __CHIMERARENDER_H__ 1
#include "common.h"
#include "url.h"
#include "ChimeraGUI.h"
#include "ChimeraSource.h"
/*
* A whole bunch of types with which to cause trouble and confuse.
*/
typedef struct ChimeraRenderP *ChimeraRender;
typedef struct
{
char *content;
void *class_context;
void *(*init) _ArgProto((ChimeraRender, void *, void *));
void (*add) _ArgProto((void *));
void (*end) _ArgProto((void *));
void (*destroy) _ArgProto((void *));
void (*cancel) _ArgProto((void *));
void *(*getstate) _ArgProto((void *));
void (*class_destroy) _ArgProto((void *));
byte *(*query) _ArgProto((void *, char *));
int (*search) _ArgProto((void *, char *, int));
bool (*select) _ArgProto((void *, int, int, char *));
bool (*motion) _ArgProto((void *, int, int));
bool (*expose) _ArgProto((void *, int, int, unsigned int, unsigned int));
} ChimeraRenderHooks;
/*
* render.c
*/
typedef void (*ChimeraRenderActionProc) _ArgProto((void *, ChimeraRender,
ChimeraRequest *,
char *));
/* Called by the render user/caller */
ChimeraRender RenderCreate _ArgProto((ChimeraContext,
ChimeraGUI, ChimeraSink,
ChimeraRenderHooks *,
ChimeraRenderHooks *,
void *, void *,
ChimeraRenderActionProc,
void *));
void RenderAdd _ArgProto((ChimeraRender));
void RenderEnd _ArgProto((ChimeraRender));
void RenderDestroy _ArgProto((ChimeraRender));
void RenderCancel _ArgProto((ChimeraRender));
char *RenderQuery _ArgProto((ChimeraRender, char *));
/*
* Returns -1 for not found
* Returns -2 for end of document
* Returns 0 for found
*
* third argument 0 for continue search
* third argument 1 for start search from beginning
*/
int RenderSearch _ArgProto((ChimeraRender, char *, int));
void RenderSelect _ArgProto((ChimeraRender, int, int, char *));
void RenderMotion _ArgProto((ChimeraRender, int, int));
void RenderExpose _ArgProto((ChimeraRender, int, int,
unsigned int, unsigned int));
void *RenderGetState _ArgProto((ChimeraRender));
ChimeraGUI RenderToGUI _ArgProto((ChimeraRender));
ChimeraSink RenderToSink _ArgProto((ChimeraRender));
ChimeraContext RenderToContext _ArgProto((ChimeraRender));
void RenderSendMessage _ArgProto((ChimeraRender, char *));
void RenderAction _ArgProto((ChimeraRender, ChimeraRequest *, char *));
int RenderAddHooks _ArgProto((ChimeraResources, ChimeraRenderHooks *));
ChimeraRenderHooks *RenderGetHooks _ArgProto((ChimeraResources, char *));
ChimeraResources RenderToResources _ArgProto((ChimeraRender));
#endif

115
chimera/ChimeraSource.h Normal file
View File

@ -0,0 +1,115 @@
/*
* ChimeraSource.h
*
* Copyright (c) 1995-1997,1999, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERASOURCE_H__
#define __CHIMERASOURCE_H__ 1
#include "common.h"
#include "mime.h"
#include "url.h"
typedef struct ChimeraSourceP *ChimeraSource;
typedef struct ChimeraSinkP *ChimeraSink;
typedef struct ChimeraRequestP ChimeraRequest;
typedef struct
{
void *closure;
int (*init) _ArgProto((ChimeraSink, void *)); /* returns 0 for success */
void (*add) _ArgProto((void *));
void (*end) _ArgProto((void *));
void (*message) _ArgProto((void *, char *));
} ChimeraSinkHooks;
typedef struct
{
char *name;
void *class_closure;
void *(*init) _ArgProto((ChimeraSource, ChimeraRequest *, void *));
void (*stop) _ArgProto((void *));
void (*destroy) _ArgProto((void *));
void (*class_destroy) _ArgProto((void *));
void (*getdata) _ArgProto((void *, byte **, size_t *, MIMEHeader *));
char *(*resolve_url) _ArgProto((MemPool, char *, char *));
} ChimeraSourceHooks;
struct ChimeraRequestP
{
MemPool mp; /* */
char *url; /* Absolute URL not-parsed */
URLParts *up; /* Absolute URL parsed */
URLParts *pup; /* Absolute proxy URL parsed */
void *input_data; /* input data */
size_t input_len; /* input data len */
char *input_type; /* input data MIME content-type */
char *input_method; /* input method GET/POST */
bool reload; /* don't use cache? */
GList contents; /* acceptable contents, NULL = '*' */
ChimeraSourceHooks hooks; /* */
char *scheme; /* convienence */
char *parent_url; /* parent/base url saved from RequestCreate */
};
/*
* Source
*
* Functions called by the source implementation.
*/
void SourceInit _ArgProto((ChimeraSource, bool));
void SourceAdd _ArgProto((ChimeraSource));
void SourceEnd _ArgProto((ChimeraSource));
void SourceStop _ArgProto((ChimeraSource, char *));
void SourceSendMessage _ArgProto((ChimeraSource, char *));
ChimeraResources SourceToResources _ArgProto((ChimeraSource));
int SourceAddHooks _ArgProto((ChimeraResources cres,
ChimeraSourceHooks *shooks));
/*
* Sink
*
* Functions called by the sink creator.
*/
ChimeraSink SinkCreate _ArgProto((ChimeraResources, ChimeraRequest *));
void SinkSetHooks _ArgProto((ChimeraSink, ChimeraSinkHooks *, void *));
void SinkDestroy _ArgProto((ChimeraSink));
void SinkCancel _ArgProto((ChimeraSink));
void SinkGetData _ArgProto((ChimeraSink, byte **, size_t *, MIMEHeader *));
char *SinkGetInfo _ArgProto((ChimeraSink, char *));
ChimeraResources SinkToResources _ArgProto((ChimeraSink));
bool SinkWasReloaded _ArgProto((ChimeraSink));
/*
* request.c
*/
ChimeraRequest *RequestCreate _ArgProto((ChimeraResources, char *, char *));
int RequestAddRegexContent _ArgProto((ChimeraResources,
ChimeraRequest *, char *));
void RequestAddContent _ArgProto((ChimeraRequest *, char *));
void RequestDestroy _ArgProto((ChimeraRequest *));
void RequestReload _ArgProto((ChimeraRequest *, bool));
bool RequestCompareURL _ArgProto((ChimeraRequest *, ChimeraRequest *));
bool RequestCompareAccept _ArgProto((ChimeraRequest *, ChimeraRequest *));
bool RequestMatchContent _ArgProto((MemPool, char *, char *));
bool RequestMatchContent2 _ArgProto((ChimeraRequest *, char *));
char *ChimeraExt2Content _ArgProto((ChimeraResources, char *));
#endif

41
chimera/ChimeraStack.h Normal file
View File

@ -0,0 +1,41 @@
/*
* ChimeraStack.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERASTACK_H__
#define __CHIMERASTACK_H__
typedef struct ChimeraStackP *ChimeraStack;
ChimeraStack StackCreate _ArgProto((ChimeraStack, int, int,
unsigned int, unsigned int,
ChimeraRenderActionProc, void *));
char *StackGetCurrentURL _ArgProto((ChimeraStack));
void StackBack _ArgProto((ChimeraStack));
void StackForward _ArgProto((ChimeraStack));
void StackHome _ArgProto((ChimeraStack));
void StackOpen _ArgProto((ChimeraStack, ChimeraRequest *));
void StackReload _ArgProto((ChimeraStack));
void StackCancel _ArgProto((ChimeraStack));
void StackRedraw _ArgProto((ChimeraStack));
void StackDestroy _ArgProto((ChimeraStack));
ChimeraStack StackFromGUI _ArgProto((ChimeraContext, ChimeraGUI));
ChimeraStack StackGetParent _ArgProto((ChimeraStack));
void StackAction _ArgProto((ChimeraStack, ChimeraRequest *, char *));
#endif

42
chimera/ChimeraStream.h Normal file
View File

@ -0,0 +1,42 @@
/*
* ChimeraStream.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CHIMERASTREAM_H__
#define __CHIMERASTREAM_H__ 1
typedef struct ChimeraStreamP *ChimeraStream;
/*
* io.c
*/
typedef void (*ChimeraStreamCallback) _ArgProto((ChimeraStream,
ssize_t, void *));
ChimeraStream StreamCreateINet _ArgProto((ChimeraResources, char *, int));
ChimeraStream StreamCreateINet2 _ArgProto((ChimeraResources));
ChimeraStream StreamCreateFD _ArgProto((ChimeraResources, int));
void StreamDestroy _ArgProto((ChimeraStream));
void StreamWrite _ArgProto((ChimeraStream, byte *, size_t,
ChimeraStreamCallback, void *));
void StreamRead _ArgProto((ChimeraStream, byte *, size_t,
ChimeraStreamCallback, void *));
int StreamGetINetPort _ArgProto((ChimeraStream));
unsigned long StreamGetINetAddr _ArgProto((ChimeraStream));
#endif

119
chimera/Geom.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Geom.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "GeomP.h"
static void GeomInitialize _ArgProto((Widget, Widget, ArgList, Cardinal *));
static XtGeometryResult GeomGeometryManager _ArgProto((Widget,
XtWidgetGeometry *,
XtWidgetGeometry *));
static XtGeometryResult GeomPreferredGeometry _ArgProto((Widget,
XtWidgetGeometry *,
XtWidgetGeometry *));
GeomClassRec geomClassRec =
{
{ /* core_class fields */
/* superclass */ (WidgetClass)&compositeClassRec,
/* class_name */ "Geom",
/* widget_size */ sizeof(GeomRec),
/* class_initialize */ NULL,
/* class_part_init */ NULL,
/* class_inited */ FALSE,
/* initialize */ GeomInitialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ NULL,
/* num_resources */ 0,
/* xrm_class */ NULLQUARK,
/* compress_motion */ FALSE,
/* compress_exposure */ FALSE,
/* compress_enterleave*/ FALSE,
/* visible_interest */ FALSE,
/* destroy */ NULL,
/* resize */ NULL,
/* expose */ NULL,
/* set_values */ NULL,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ NULL,
/* query_geometry */ GeomPreferredGeometry,
/* display_accelerator*/ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* composite_class fields */
/* geometry_manager */ GeomGeometryManager,
/* change_managed */ NULL,
/* insert_child */ XtInheritInsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL
},
{ /* geom_class fields */
NULL,
}
};
WidgetClass geomWidgetClass = (WidgetClass)&geomClassRec;
static XtGeometryResult
GeomPreferredGeometry(w, con, reply)
Widget w;
XtWidgetGeometry *con, *reply;
{
return(XtGeometryYes);
}
/*
* GeomGeometryManager
*/
static XtGeometryResult
GeomGeometryManager(w, request, reply)
Widget w;
XtWidgetGeometry *request;
XtWidgetGeometry *reply;
{
return(XtGeometryNo);
}
/*
* GeomInitialize
*/
static void
GeomInitialize(r, n, args, count)
Widget r, n;
ArgList args;
Cardinal *count;
{
return;
}

28
chimera/Geom.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Geom.h
*
* Copyright (c) 1995-1997 John D. Kilburg (john@cs.unlv.edu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __Geom_H__
#define __Geom_H__ 1
typedef struct _GeomClassRec *GeomWidgetClass;
typedef struct _GeomRec *GeomWidget;
extern WidgetClass geomWidgetClass;
#endif

51
chimera/GeomP.h Normal file
View File

@ -0,0 +1,51 @@
/*
* GeomP.h
*
* Copyright (c) 1995-1997 John D. Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __GeomP_H__
#define __GeomP_H__
#include "Geom.h"
typedef struct
{
XtPointer extension;
} GeomClassPart;
typedef struct _GeomClassRec
{
CoreClassPart core_class;
CompositeClassPart composite_class;
GeomClassPart geom_class;
} GeomClassRec;
extern GeomClassRec geomClassRec;
typedef struct _GeomPart
{
XtPointer mumble;
} GeomPart;
typedef struct _GeomRec
{
CorePart core;
CompositePart composite;
GeomPart geom;
} GeomRec;
#endif

25
chimera/Imakefile Normal file
View File

@ -0,0 +1,25 @@
#include <../Common.tmpl>
SRCS = Geom.c WWW.c gui.c bookmark.c builtin.c cache.c \
cmisc.c source.c download.c \
fallback.c io.c main.c render.c request.c resource.c \
stack.c timeout.c view.c head.c auth.c task.c
OBJS = Geom.o WWW.o gui.o bookmark.o builtin.o cache.o \
cmisc.o source.o download.o \
fallback.o io.o main.o render.o request.o resource.o \
stack.o timeout.o view.o head.o auth.o task.o
EXTRA_DEFINES = $(CHIMERA_DEFINES) $(RXDEFINES)
EXTRA_INCLUDES = -I./ -I../mxw -I../common -I../port
EXTRA_LOAD_FLAGS = $(CHIMERA_LOAD_FLAGS)
EXTRA_LIBRARIES = $(CHIMERA_LIBS)
AllTarget(ProgramTargetName(chimera))
NormalProgramTarget(chimera, $(OBJS), $(CHIMERA_DEPLIBS), MyNull, MyNull)
InstallProgram(chimera,$(CHIMERA_BINDIR))
InstallManPage(chimera,$(CHIMERA_MANDIR))
DependTarget()

946
chimera/WWW.c Normal file
View File

@ -0,0 +1,946 @@
/*
* WWW.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
Some of the code was borrowed from the Viewport widget:
Copyright (c) 1989, 1994 X Consortium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/keysym.h>
#include "port_after.h"
#include "WWWP.h"
#include "Geom.h"
#define WMethod(x) ((x) != NULL ? (x):10)
/*
* Action prototypes
*/
static void WWWMotionAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWSelectAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWExposeAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWPageUpAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWPageDownAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWPageLeftAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWPageRightAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWScrollUpAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWScrollDownAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWScrollLeftAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static void WWWScrollRightAction _ArgProto((Widget, XEvent *,
String *, Cardinal *));
static char defaultTranslations[] =
"<Btn1Up>: select() \n\
<Btn2Up>: select() \n\
<Btn3Up>: select() \n\
<Expose>: expose() \n\
<Motion>: motion() \n\
:<Key>BackSpace: page_up()\n\
:<Key>Page_Up: page_up()\n\
:<Key>KP_Page_Up: page_up()\n\
:<Key>0x20: page_down()\n\
:<Key>Page_Down: page_down()\n\
:<Key>KP_Page_Down: page_down()\n\
:s<Key>Up: page_up()\n\
:s<Key>KP_Up: page_up()\n\
:s<Key>Down: page_down()\n\
:s<Key>KP_Down: page_down()\n\
:s<Key>Left: page_left()\n\
:s<Key>KP_Left: page_left()\n\
:s<Key>Right: page_right()\n\
:s<Key>KP_Right: page_right()\n\
:<Key>Up: scroll_up()\n\
:<Key>KP_Up: scroll_up()\n\
:<Key>Down: scroll_down()\n\
:<Key>KP_Down: scroll_down()\n\
:<Key>Left: scroll_left()\n\
:<Key>KP_Left: scroll_left()\n\
:<Key>Right: scroll_right()\n\
:<Key>KP_Right: scroll_right()\n\
";
static XtActionsRec actionsList[] =
{
{ "expose", WWWExposeAction },
{ "select", WWWSelectAction },
{ "motion", WWWMotionAction },
{ "page_up", WWWPageUpAction },
{ "page_down", WWWPageDownAction },
{ "page_left", WWWPageLeftAction },
{ "page_right", WWWPageRightAction},
{ "scroll_up", WWWScrollUpAction },
{ "scroll_down", WWWScrollDownAction },
{ "scroll_left", WWWScrollLeftAction },
{ "scroll_right", WWWScrollRightAction},
};
#define offset(field) XtOffsetOf(WWWRec, www.field)
static XtResource resources[] =
{
{ XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
offset(background), XtRString, (XtPointer)"moccasin" },
{ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(foreground), XtRString, (XtPointer)"black" },
};
#undef offset
static void WWWInitialize _ArgProto((Widget, Widget, ArgList, Cardinal *));
void WWWResize _ArgProto((Widget));
static void WWWRealize _ArgProto((Widget, XtValueMask *,
XSetWindowAttributes *));
static Boolean WWWSetValues _ArgProto((Widget, Widget, Widget,
ArgList, Cardinal *));
static XtGeometryResult WWWGeometryManager _ArgProto((Widget,
XtWidgetGeometry *,
XtWidgetGeometry *));
static XtGeometryResult WWWPreferredGeometry _ArgProto((Widget,
XtWidgetGeometry *,
XtWidgetGeometry *));
static void WWWGetValuesHook _ArgProto((Widget, ArgList, Cardinal *));
static Dimension FixDim _ArgProto((unsigned int));
static void ConfigureWidgets _ArgProto((WWWWidget,
unsigned int, unsigned int));
/* Scrollbar handling functions */
static void RedrawThumbs _ArgProto((WWWWidget));
static void ScrollUpDownProc _ArgProto((Widget, XtPointer, XtPointer));
static void ThumbProc _ArgProto((Widget, XtPointer, XtPointer));
WWWClassRec wwwClassRec =
{
{ /* core_class fields */
/* superclass */ (WidgetClass) &compositeClassRec,
/* class_name */ "WWW",
/* widget_size */ sizeof(WWWRec),
/* class_initialize */ NULL,
/* class_part_init */ NULL,
/* class_inited */ FALSE,
/* initialize */ WWWInitialize,
/* initialize_hook */ NULL,
/* realize */ WWWRealize,
/* actions */ actionsList,
/* num_actions */ XtNumber(actionsList),
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ FALSE,
/* compress_exposure */ FALSE,
/* compress_enterleave*/ FALSE,
/* visible_interest */ FALSE,
/* destroy */ NULL,
/* resize */ WWWResize,
/* expose */ NULL,
/* set_values */ WWWSetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ WWWGetValuesHook,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ NULL,
/* query_geometry */ WWWPreferredGeometry,
/* display_accelerator*/ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* composite_class fields */
/* geometry_manager */ WWWGeometryManager,
/* change_managed */ NULL,
/* insert_child */ XtInheritInsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL
},
{ /* www_class fields */
NULL,
}
};
WidgetClass wwwWidgetClass = (WidgetClass)&wwwClassRec;
/*
* WWWGetValuesHook
*/
static void
WWWGetValuesHook(w, args, num_args)
Widget w;
ArgList args;
Cardinal * num_args;
{
WWWWidget rw = (WWWWidget)w;
int i;
for (i = 0; i < *num_args; i++)
{
if (strcmp(args[i].name, XtNbackground) == 0)
{
*((Pixel *)args[i].value) = rw->www.background;
}
if (strcmp(args[i].name, XtNforeground) == 0)
{
*((Pixel *)args[i].value) = rw->www.foreground;
}
}
return;
}
/*
* WWWResize
*/
void
WWWResize(w)
Widget w;
{
WWWWidget rw;
if (XtClass(w) != wwwWidgetClass) return;
rw = (WWWWidget)w;
if (rw->www.resize_callback != NULL)
{
(rw->www.resize_callback)(w, rw->www.resize_closure, NULL);
}
return;
}
/*
* WWWRealize
*/
static void
WWWRealize(w, valueMask, attributes)
Widget w;
XtValueMask *valueMask;
XSetWindowAttributes *attributes;
{
(*wwwWidgetClass->core_class.superclass->core_class.realize)
(w, valueMask, attributes);
return;
}
static XtGeometryResult
WWWPreferredGeometry(w, con, reply)
Widget w;
XtWidgetGeometry *con, *reply;
{
WWWWidget rw = (WWWWidget)w;
XtResizeWidget(rw->www.clip, con->width > 0 ? con->width:100,
con->height > 0 ? con->height:100, 0);
return(XtGeometryYes);
}
/*
* WWWGeometryManager
*/
static XtGeometryResult
WWWGeometryManager(w, request, reply)
Widget w;
XtWidgetGeometry *request;
XtWidgetGeometry *reply;
{
return(XtGeometryNo);
}
/*
* WWWSetValues
*/
Boolean
WWWSetValues(c, r, n, args, count)
Widget c, r, n;
ArgList args;
Cardinal *count;
{
return(False);
}
static void
RedrawThumbs(rw)
WWWWidget rw;
{
Widget child = rw->www.child;
Widget clip = rw->www.clip;
Dimension length, total;
Position top;
if (rw->www.horiz_bar != (Widget)NULL)
{
top = -(child->core.x);
length = clip->core.width;
total = child->core.width;
XawScrollbarSetThumb(rw->www.horiz_bar,
(float)top/(float)total,
(float)length/(float)total);
}
if (rw->www.vert_bar != (Widget)NULL)
{
top = -(child->core.y);
length = clip->core.height;
total = child->core.height;
XawScrollbarSetThumb(rw->www.vert_bar,
(float)top/(float)total,
(float)length/(float)total);
}
return;
}
void
WWWMoveChild(w, x, y)
Widget w;
int x, y;
{
WWWWidget rw = (WWWWidget)w;
register Widget child = rw->www.child;
register Widget clip = rw->www.clip;
if (-x + (int)clip->core.width > (int)child->core.width)
{
x = -(child->core.width - clip->core.width);
}
if (-y + (int)clip->core.height > (int)child->core.height)
{
y = -(child->core.height - clip->core.height);
}
if (x >= 0) x = 0;
if (y >= 0) y = 0;
/* Mmmm hairy cast */
XtMoveWidget(child, (Position)x, (Position)y);
RedrawThumbs(rw);
return;
}
static void
ScrollUpDownProc(widget, closure, call_data)
Widget widget;
XtPointer closure;
XtPointer call_data;
{
WWWWidget rw = (WWWWidget)XtParent(widget);
register Widget child = rw->www.child;
int pix = (int)call_data;
Position x, y;
if (child == NULL) return; /* no child to scroll. */
x = child->core.x - ((widget == rw->www.horiz_bar) ? pix : 0);
y = child->core.y - ((widget == rw->www.vert_bar) ? pix : 0);
WWWMoveChild((Widget)rw, (int)x, (int)y);
return;
}
static void
ThumbProc(widget, closure, call_data)
Widget widget;
XtPointer closure;
XtPointer call_data;
{
WWWWidget rw = (WWWWidget)XtParent(widget);
register Widget child = rw->www.child;
Position x, y;
float *percent = (float *)call_data;
if (child == NULL) return; /* no child to scroll. */
if (widget == rw->www.horiz_bar) x = -(int)(*percent * child->core.width);
else x = child->core.x;
if (widget == rw->www.vert_bar) y = -(int)(*percent * child->core.height);
else y = child->core.y;
WWWMoveChild((Widget)rw, (int)x, (int)y);
return;
}
/*
* WWWInitialize
*/
static void
WWWInitialize(r, n, args, count)
Widget r, n;
ArgList args;
Cardinal *count;
{
WWWWidget new = (WWWWidget)n;
/*
* Avoid zero.
*/
if (new->core.width < 5) new->core.width = 5;
if (new->core.height < 5) new->core.height = 5;
new->www.use_scroll = false;
new->www.resize_closure = NULL;
new->www.resize_callback = NULL;
new->www.motion_callback = NULL;
new->www.motion_closure = NULL;
new->www.select_callback = NULL;
new->www.select_closure = NULL;
new->www.expose_callback = NULL;
new->www.expose_closure = NULL;
/*
* Create scrollbars, clip, and the child widget. The child widget is
* the one that we draw into.
*/
new->www.vert_bar = XtVaCreateWidget("vert_bar",
scrollbarWidgetClass, n,
XtNorientation, XtorientVertical,
XtNmappedWhenManaged, False,
NULL);
XtManageChild(new->www.vert_bar);
XtAddCallback(new->www.vert_bar, XtNscrollProc,
ScrollUpDownProc, (XtPointer)new);
XtAddCallback(new->www.vert_bar, XtNjumpProc,
ThumbProc, (XtPointer)new);
new->www.horiz_bar = XtVaCreateWidget("horiz_bar",
scrollbarWidgetClass, n,
XtNorientation, XtorientHorizontal,
XtNmappedWhenManaged, False,
NULL);
XtManageChild(new->www.horiz_bar);
XtAddCallback(new->www.horiz_bar, XtNscrollProc,
ScrollUpDownProc, (XtPointer)new);
XtAddCallback(new->www.horiz_bar, XtNjumpProc,
ThumbProc, (XtPointer)new);
new->www.clip = XtVaCreateWidget("clip",
geomWidgetClass, n,
XtNwidth, new->core.width,
XtNheight, new->core.height,
XtNborderWidth, 0,
NULL);
XtManageChild(new->www.clip);
new->www.child = XtVaCreateWidget("child",
geomWidgetClass, new->www.clip,
XtNwidth, new->www.clip->core.width,
XtNheight, new->www.clip->core.height,
XtNborderWidth, 0,
NULL);
XtManageChild(new->www.child);
XtAugmentTranslations(new->www.child,
XtParseTranslationTable(defaultTranslations));
return;
}
/*
* FixDim
*/
static Dimension
FixDim(d)
unsigned int d;
{
if (d > 0x7ffd) return(0x7ffd);
return((Dimension)d);
}
/*
* ConfigureWidgets
*/
static void
ConfigureWidgets(rw, width, height)
WWWWidget rw;
unsigned int width, height;
{
Dimension child_width, child_height;
Dimension clip_width, clip_height;
Dimension vx, hy;
Dimension vw, hh;
float shown;
if (!XtIsRealized((Widget)rw)) return;
vw = rw->www.vert_bar->core.width;
hh = rw->www.horiz_bar->core.height;
child_width = FixDim(width);
child_height = FixDim(height);
clip_width = rw->core.width - vw;
clip_height = rw->core.height - hh;
if (child_width > clip_width) hy = hh;
else
{
hy = 0;
child_width = clip_width;
}
if (child_height > clip_height) vx = vw;
else
{
vx = 0;
child_height = clip_height;
}
if (child_height > clip_height)
{
XtConfigureWidget(rw->www.vert_bar,
0, hy,
vw, rw->core.height - hy, 0);
shown = (float)clip_height / (float)child_height;
XawScrollbarSetThumb(rw->www.vert_bar, (float)-1.0, shown);
XtSetMappedWhenManaged(rw->www.vert_bar, True);
}
else XtSetMappedWhenManaged(rw->www.vert_bar, False);
if (child_width > clip_width)
{
XtConfigureWidget(rw->www.horiz_bar,
vx, 0,
rw->core.width - vx, hh, 0);
shown = (float)clip_width / (float)child_width;
XawScrollbarSetThumb(rw->www.horiz_bar, (float)-1.0, shown);
XtSetMappedWhenManaged(rw->www.horiz_bar, True);
}
else XtSetMappedWhenManaged(rw->www.horiz_bar, False);
XtConfigureWidget(rw->www.clip,
vw, hh,
clip_width, clip_height, 0);
XtResizeWidget(rw->www.child, child_width, child_height, 0);
return;
}
/*
* WWWGetDrawWidget
*/
Widget
WWWGetDrawWidget(w)
Widget w;
{
WWWWidget rw = (WWWWidget)w;
return(rw->www.child);
}
/*
* WWWGetSize
*/
int
WWWGetDrawSize(w, width, height)
Widget w;
unsigned int *width, *height;
{
WWWWidget rw = (WWWWidget)w;
*width = (unsigned int)rw->www.child->core.width;
*height = (unsigned int)rw->www.child->core.height;
return(0);
}
/*
* WWWSetDrawSize
*/
int
WWWSetDrawSize(w, width, height)
Widget w;
unsigned int width, height;
{
WWWWidget rw = (WWWWidget)w;
if (!rw->www.use_scroll)
{
XtSetMappedWhenManaged(rw->www.vert_bar, False);
XtSetMappedWhenManaged(rw->www.horiz_bar, False);
XtConfigureWidget(rw->www.clip, 0, 0, FixDim(width), FixDim(height), 0);
XtConfigureWidget(rw->www.child, 0, 0, FixDim(width), FixDim(height), 0);
}
else
{
ConfigureWidgets(rw, width, height);
}
return(0);
}
/*
* WWWSetScrollBar
*/
void
WWWSetScrollBar(w, use_scroll)
Widget w;
bool use_scroll;
{
WWWWidget rw = (WWWWidget)w;
rw->www.use_scroll = use_scroll;
if (!rw->www.use_scroll)
{
XtSetMappedWhenManaged(rw->www.vert_bar, False);
XtSetMappedWhenManaged(rw->www.horiz_bar, False);
XtConfigureWidget(rw->www.clip, 0, 0,
rw->core.width, rw->core.height, 0);
XtConfigureWidget(rw->www.child, 0, 0,
rw->core.width, rw->core.height, 0);
}
return;
}
/*
* WWWSetResizeCallback
*/
void
WWWSetResizeCallback(w, callback, closure)
Widget w;
void (*callback)();
void *closure;
{
WWWWidget rw = (WWWWidget)w;
rw->www.resize_callback = callback;
rw->www.resize_closure = closure;
return;
}
/*
* WWWSetMotionCallback
*/
void
WWWSetMotionCallback(w, callback, closure)
Widget w;
void (*callback)();
void *closure;
{
WWWWidget rw = (WWWWidget)w;
rw->www.motion_callback = callback;
rw->www.motion_closure = closure;
return;
}
/*
* WWWSetSelectCallback
*/
void
WWWSetSelectCallback(w, callback, closure)
Widget w;
void (*callback)();
void *closure;
{
WWWWidget rw = (WWWWidget)w;
rw->www.select_callback = callback;
rw->www.select_closure = closure;
return;
}
/*
* WWWSetExposeCallback
*/
void
WWWSetExposeCallback(w, callback, closure)
Widget w;
void (*callback)();
void *closure;
{
WWWWidget rw = (WWWWidget)w;
rw->www.expose_callback = callback;
rw->www.expose_closure = closure;
return;
}
/*
* WWWExposeAction
*/
static void
WWWExposeAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
if (rw->www.expose_callback != NULL)
{
(rw->www.expose_callback) (w, rw->www.expose_closure,
xe->xexpose.x, xe->xexpose.y,
xe->xexpose.width, xe->xexpose.height);
}
return;
}
/*
* WWWSelectAction
*/
static void
WWWSelectAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
if (rw->www.select_callback != NULL)
{
(rw->www.select_callback) (w, rw->www.select_closure,
xe->xbutton.x, xe->xbutton.y,
xe->xbutton.button);
}
return;
}
/*
* WWWMotionAction
*/
static void
WWWMotionAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
if (rw->www.motion_callback != NULL)
{
(rw->www.motion_callback) (w, rw->www.motion_closure,
xe->xmotion.x, xe->xmotion.y);
}
return;
}
/*
* WWWGetScrollPosition
*/
void
WWWGetScrollPosition(w, x, y)
Widget w;
int *x, *y;
{
WWWWidget rw = (WWWWidget)w;
*x = (int)(rw->www.child->core.x);
*y = (int)(rw->www.child->core.y);
return;
}
/*
* WWWPageUpAction
*/
static void
WWWPageUpAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
Widget clip = rw->www.clip;
WWWMoveChild((Widget)rw,child->core.x,child->core.y+clip->core.height/2);
}
/*
* WWWPageDownAction
*/
static void
WWWPageDownAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
Widget clip = rw->www.clip;
WWWMoveChild((Widget)rw,child->core.x,child->core.y-clip->core.height/2);
}
/*
* WWWPageLeftAction
*/
static void
WWWPageLeftAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
Widget clip = rw->www.clip;
WWWMoveChild((Widget)rw,child->core.x+clip->core.width/2,child->core.y);
}
/*
* WWWPageRightAction
*/
static void
WWWPageRightAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
Widget clip = rw->www.clip;
WWWMoveChild((Widget)rw,child->core.x-clip->core.width/2,child->core.y);
}
/*
* WWWScrollUpAction
*/
static void
WWWScrollUpAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
WWWMoveChild((Widget)rw,child->core.x,child->core.y+10);
}
/*
* WWWScrollDownAction
*/
static void
WWWScrollDownAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
WWWMoveChild((Widget)rw,child->core.x,child->core.y-10);
}
/*
* WWWScrolLeftAction
*/
static void
WWWScrollLeftAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
WWWMoveChild((Widget)rw,child->core.x+10,child->core.y);
}
/*
* WWWScrollRightAction
*/
static void
WWWScrollRightAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
WWWWidget rw = (WWWWidget)XtParent(XtParent(w));
Widget child = rw->www.child;
WWWMoveChild((Widget)rw,child->core.x-10,child->core.y);
}

48
chimera/WWW.h Normal file
View File

@ -0,0 +1,48 @@
/*
* WWW.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WWW_H__
#define __WWW_H__ 1
/*
* Xt widget type definitions
*/
typedef struct _WWWClassRec *WWWWidgetClass;
typedef struct _WWWRec *WWWWidget;
extern WidgetClass wwwWidgetClass;
/*
* Prototypes
*/
Widget WWWGetDrawWidget _ArgProto((Widget));
int WWWSetDrawSize _ArgProto((Widget, unsigned int, unsigned int));
int WWWGetDrawSize _ArgProto((Widget, unsigned int *, unsigned int *));
void WWWMoveChild _ArgProto((Widget, int, int));
void WWWSetScrollBar _ArgProto((Widget, bool));
void WWWSetResizeCallback _ArgProto((Widget, void (*)(), void *));
void WWWSetExposeCallback _ArgProto((Widget, void (*)(), void *));
void WWWSetSelectCallback _ArgProto((Widget, void (*)(), void *));
void WWWSetMotionCallback _ArgProto((Widget, void (*)(), void *));
void WWWGetScrollPosition _ArgProto((Widget, int *, int *));
#endif

74
chimera/WWWP.h Normal file
View File

@ -0,0 +1,74 @@
/*
* WWWP.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WWWP_H__
#define __WWWP_H__
#include "WWW.h"
/*
* More Xt definitions
*/
typedef struct _WWWClassPart
{
XtPointer extension;
} WWWClassPart;
typedef struct _WWWClassRec
{
CoreClassPart core_class;
CompositeClassPart composite_class;
WWWClassPart www_class;
} WWWClassRec;
extern WWWClassRec wwwClassRec;
typedef struct _WWWPart
{
/* Public */
Pixel foreground;
Pixel background;
/* X Private */
Widget vert_bar, horiz_bar; /* scroll bars */
Widget clip; /* clips the child */
Widget child; /* the drawing window */
Widget menu; /* menu widget */
bool use_scroll;
/* other private */
void *resize_closure; /* garbage */
void (*resize_callback)(); /* more garbage */
void *select_closure; /* garbage */
void (*select_callback)(); /* more garbage */
void *motion_closure; /* garbage */
void (*motion_callback)(); /* more garbage */
void *expose_closure; /* garbage */
void (*expose_callback)(); /* more garbage */
} WWWPart;
typedef struct _WWWRec
{
CorePart core;
CompositePart composite;
WWWPart www;
} WWWRec;
#endif

166
chimera/auth.c Normal file
View File

@ -0,0 +1,166 @@
/*
* auth.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include "port_after.h"
#include "AuthDialog.h"
#include "ChimeraP.h"
struct ChimeraAuthP
{
MemPool mp;
ChimeraAuthCallback callback;
void *closure;
ChimeraResources cres;
Widget w;
};
static void AuthOKCallback _ArgProto((Widget, XtPointer, XtPointer));
static void AuthActivateCallback _ArgProto((Widget, XtPointer, XtPointer));
static void AuthDismissCallback _ArgProto((Widget, XtPointer, XtPointer));
/*
* AuthOKCallback
*/
static void
AuthOKCallback(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraAuth wa = (ChimeraAuth)cldata;
char *username;
char *password;
username = AuthDialogGetUsername(XtParent(w));
password = AuthDialogGetPassword(XtParent(w));
CMethod(wa->callback)(wa->closure, username, password);
/* don't access wa after this since AuthDestroy may have been called */
return;
}
/*
* AuthActivateCallback
*/
static void
AuthActivateCallback(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraAuth wa = (ChimeraAuth)cldata;
char *username;
char *password;
username = AuthDialogGetUsername(w);
password = AuthDialogGetPassword(w);
CMethod(wa->callback)(wa->closure, username, password);
/* don't access wa after this since AuthDestroy may have been called */
return;
}
/*
* AuthDismissCallback
*/
static void
AuthDismissCallback(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraAuth wa = (ChimeraAuth)cldata;
CMethod(wa->callback)(wa->closure, NULL, NULL);
/* don't access wa after this since AuthDestroy may have been called */
return;
}
/*
* AuthCreate
*/
ChimeraAuth
AuthCreate(cres, message, username, callback, closure)
ChimeraResources cres;
char *message;
char *username;
ChimeraAuthCallback callback;
void *closure;
{
ChimeraAuth wa;
MemPool mp;
Widget dw;
Window rw, cw;
int rx, ry, wx, wy;
unsigned int mask;
mp = MPCreate();
wa = (ChimeraAuth)MPCGet(mp, sizeof(struct ChimeraAuthP));
wa->mp = mp;
wa->callback = callback;
wa->closure = closure;
wa->cres = cres;
XQueryPointer(cres->dpy, DefaultRootWindow(cres->dpy),
&rw, &cw,
&rx, &ry,
&wx, &wy,
&mask);
wa->w = XtVaAppCreateShell("authorization", "Authorization",
topLevelShellWidgetClass,
cres->dpy,
XtNx, rx - 2,
XtNy, ry - 2,
NULL);
dw = XtVaCreateManagedWidget("dialog",
authdialogWidgetClass, wa->w,
XtNlabel, message,
"username", username,
NULL);
AuthDialogAddButton(dw, "ok", AuthOKCallback, wa);
AuthDialogAddButton(dw, "dismiss", AuthDismissCallback, wa);
XtAddCallback(dw, XtNcallback, AuthActivateCallback, wa);
XtRealizeWidget(wa->w);
return(wa);
}
/*
* AuthDestroy
*/
void
AuthDestroy(wa)
ChimeraAuth wa;
{
XtDestroyWidget(wa->w);
MPDestroy(wa->mp);
return;
}

849
chimera/bookmark.c Normal file
View File

@ -0,0 +1,849 @@
/*
* bookmark.c
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Viewport.h>
#include "port_after.h"
#include "ChimeraP.h"
#include "ml.h"
#include "MyDialog.h"
typedef struct
{
char *title;
char *url;
} BMark;
typedef struct
{
char *name;
GList mlist;
} BGroup;
struct BookmarkContextP
{
MemPool mp;
GList glist;
GList nel; /* name element list <h3></h3> or <a></a> */
bool is_group_element;
bool is_mark_element;
MLState ml;
char *filename; /* bookmark filename */
Widget bw; /* bookmark shell widget */
Widget glw;
Widget mlw;
Widget ampop;
bool ampopped;
Widget agpop;
bool agpopped;
char **gnames; /* group name array for list widget */
int glen;
char **mnames; /* bookmark array for list widget */
int mlen;
char *header;
char *footer;
ChimeraResources cres;
};
static BGroup *GroupCreate _ArgProto((BookmarkContext, char *, bool));
static void BMChangeGroupList _ArgProto((BookmarkContext));
static void BMChangeMarkList _ArgProto((BookmarkContext));
static BGroup *BMFindGroup _ArgProto((BookmarkContext));
static BMark *BMFindMark _ArgProto((BookmarkContext));
static void BMWrite _ArgProto((BookmarkContext));
static void BMCreate _ArgProto((BookmarkContext, BGroup *,
char *, char *));
static void BMElementHandler _ArgProto((void *, MLElement));
static char *BMGetText _ArgProto((MemPool, GList));
static void BMDAddGroup _ArgProto((Widget, XtPointer, XtPointer));
static void BMDAddMark _ArgProto((Widget, XtPointer, XtPointer));
/*
* BMChangeGroupList
*/
static void
BMChangeGroupList(bc)
BookmarkContext bc;
{
int cnt;
BGroup *g;
for (cnt = 0, g = (BGroup *)GListGetHead(bc->glist); g != NULL;
cnt++, g = (BGroup *)GListGetNext(bc->glist))
{
;
}
if (bc->gnames == NULL)
{
bc->gnames = (char **)alloc_mem(sizeof(char *) * (cnt + 1));
bc->glen = cnt;
}
else if (bc->glen < cnt)
{
bc->gnames = (char **)realloc_mem(bc->gnames, sizeof(char *) * (cnt + 1));
bc->glen = cnt;
}
for (g = (BGroup *)GListGetHead(bc->glist), cnt = 0; g != NULL;
g = (BGroup *)GListGetNext(bc->glist))
{
bc->gnames[cnt++] = g->name;
}
bc->gnames[cnt] = NULL;
XawListChange(bc->glw, bc->gnames, 0, 0, True);
if (cnt > 0) XawListHighlight(bc->glw, 0);
BMChangeMarkList(bc);
return;
}
/*
* BMChangeMarkList
*/
static void
BMChangeMarkList(bc)
BookmarkContext bc;
{
int cnt;
BMark *m;
BGroup *g;
if ((g = BMFindGroup(bc)) == NULL) return;
for (cnt = 0, m = (BMark *)GListGetHead(g->mlist); m != NULL;
cnt++, m = (BMark *)GListGetNext(g->mlist))
{
;
}
if (bc->mnames == NULL)
{
bc->mnames = (char **)alloc_mem(sizeof(char *) * (cnt + 2));
bc->mlen = cnt;
}
else if (bc->mlen < cnt)
{
bc->mnames = (char **)realloc_mem(bc->mnames, sizeof(char *) * (cnt + 2));
bc->mlen = cnt;
}
for (m = (BMark *)GListGetHead(g->mlist), cnt = 0; m != NULL;
m = (BMark *)GListGetNext(g->mlist))
{
bc->mnames[cnt++] = m->title;
}
if (cnt > 0)
{
bc->mnames[cnt] = NULL;
XawListChange(bc->mlw, bc->mnames, 0, 0, True);
XawListHighlight(bc->mlw, 0);
}
else
{
bc->mnames[cnt] = "";
bc->mnames[cnt + 1] = NULL;
XawListChange(bc->mlw, bc->mnames, 0, 0, True);
}
return;
}
/*
* BMWrite
*/
static void
BMWrite(bc)
BookmarkContext bc;
{
FILE *fp;
const char *brec = "<li><a href=\"%s\">%s</a>\n";
BMark *c;
BGroup *g;
if ((fp = fopen(bc->filename, "w")) != NULL)
{
fprintf (fp, bc->header);
fprintf (fp, "\n");
for (g = (BGroup *)GListGetHead(bc->glist); g != NULL;
g = (BGroup *)GListGetNext(bc->glist))
{
fprintf (fp, "<h3>%s</h3>\n<ul>\n", g->name);
for (c = (BMark *)GListGetHead(g->mlist); c != NULL;
c = (BMark *)GListGetNext(g->mlist))
{
fprintf (fp, brec, c->url, c->title);
}
fprintf (fp, "</ul>\n");
}
fprintf (fp, bc->footer);
fprintf (fp, "\n");
fclose(fp);
}
return;
}
/*
* GroupCreate
*/
static BGroup *
GroupCreate(bc, group, top)
BookmarkContext bc;
char *group;
bool top;
{
BGroup *g;
g = (BGroup *)MPCGet(bc->mp, sizeof(BGroup));
g->name = MPStrDup(bc->mp, group);
g->mlist = GListCreateX(bc->mp);
if (top) GListAddHead(bc->glist, g);
else GListAddTail(bc->glist, g);
BMChangeGroupList(bc);
return(g);
}
/*
* BMCreate
*/
static void
BMCreate(bc, g, title, url)
BookmarkContext bc;
BGroup *g;
char *title;
char *url;
{
BMark *n;
n = (BMark *)MPCGet(bc->mp, sizeof(BMark));
n->url = MPStrDup(bc->mp, url);
if (title == NULL) n->title = MPStrDup(bc->mp, url);
else n->title = MPStrDup(bc->mp, title);
GListAddTail(g->mlist, n);
BMChangeMarkList(bc);
return;
}
/*
* BMGetText
*/
static char *
BMGetText(mp, list)
MemPool mp;
GList list;
{
MLElement c;
char *text, *str;
size_t tlen = 0;
size_t len;
if (GListEmpty(list)) return(NULL);
/* Skip first element...it is the opening tag */
GListGetHead(list);
for (c = (MLElement)GListGetNext(list); c != NULL;
c = (MLElement)GListGetNext(list))
{
MLGetText(c, &str, &len);
tlen += len;
}
text = MPGet(mp, tlen + 1);
tlen = 0;
GListGetHead(list);
for (c = (MLElement)GListGetNext(list); c != NULL;
c = (MLElement)GListGetNext(list))
{
MLGetText(c, &str, &len);
strncpy(text + tlen, str, len);
tlen += len;
}
text[tlen] = '\0';
return(text);
}
/*
* BMElementHandler
*/
static void
BMElementHandler(closure, p)
void *closure;
MLElement p;
{
BookmarkContext bc = (BookmarkContext)closure;
char *value;
char *title;
char *name;
MLElementType mt;
MLElement h;
mt = MLGetType(p);
if (mt == ML_EOF) return;
if ((name = MLTagName(p)) == NULL)
{
if (bc->is_group_element || bc->is_mark_element) GListAddTail(bc->nel, p);
return;
}
if (strlen(name) == 2 && strcasecmp("h3", name) == 0)
{
if (MLGetType(p) == ML_ENDTAG)
{
if (bc->is_group_element)
{
GroupCreate(bc, BMGetText(bc->mp, bc->nel), false);
bc->is_group_element = false;
}
}
else
{
bc->is_group_element = true;
GListClear(bc->nel);
GListAddHead(bc->nel, p);
}
}
else if (strlen(name) == 1 && strcasecmp("a", name) == 0)
{
if (MLGetType(p) == ML_ENDTAG)
{
if (bc->is_mark_element)
{
bc->is_mark_element = false;
h = (MLElement)GListGetHead(bc->nel);
if (h == NULL) return;
if ((value = MLFindAttribute(h, "href")) != NULL)
{
title = BMGetText(bc->mp, bc->nel);
if (title == NULL || title[0] == '\0')
{
title = MPStrDup(bc->mp, value);
}
if (GListEmpty(bc->glist)) GroupCreate(bc, "default", true);
BMCreate(bc, (BGroup *)GListGetTail(bc->glist),
title, MPStrDup(bc->mp, value));
}
}
}
else
{
bc->is_mark_element = true;
GListClear(bc->nel);
GListAddHead(bc->nel, p);
}
}
return;
}
/*
* BookmarkAdd
*/
void
BookmarkAdd(bc, title, url)
BookmarkContext bc;
char *title;
char *url;
{
BGroup *g;
if ((g = BMFindGroup(bc)) == NULL) return;
BMCreate(bc, g, title, url);
return;
}
/*
* BookmarkDestroyContext
*/
void
BookmarkDestroyContext(bc)
BookmarkContext bc;
{
XtDestroyWidget(bc->bw);
if (bc->mnames != NULL) free_mem(bc->mnames);
if (bc->gnames != NULL) free_mem(bc->gnames);
MPDestroy(bc->mp);
return;
}
/*
* BookmarkShow
*/
void
BookmarkShow(bc)
BookmarkContext bc;
{
XtMapWidget(bc->bw);
return;
}
/*
* BMFindGroup
*/
static BGroup *
BMFindGroup(bc)
BookmarkContext bc;
{
int i;
BGroup *g;
XawListReturnStruct *lrs;
if ((lrs = XawListShowCurrent(bc->glw)) == NULL) return(NULL);
if (lrs->list_index < 0) return(NULL);
for (i = 0, g = (BGroup *)GListGetHead(bc->glist);
i < lrs->list_index && g != NULL;
i++, g = (BGroup *)GListGetNext(bc->glist))
{
;
}
return(g);
}
/*
* BMFindMark
*/
static BMark *
BMFindMark(bc)
BookmarkContext bc;
{
int i;
BMark *m;
BGroup *g;
XawListReturnStruct *lrs;
if ((g = BMFindGroup(bc)) == NULL) return(NULL);
if ((lrs = XawListShowCurrent(bc->mlw)) == NULL) return(NULL);
if (lrs->list_index < 0) return(NULL);
for (i = 0, m = (BMark *)GListGetHead(g->mlist);
i < lrs->list_index && m != NULL;
i++, m = (BMark *)GListGetNext(g->mlist))
{
;
}
return(m);
}
/*
* BMDAddGroup
*/
static void
BMDAddGroup(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
XtPopdown(bc->agpop);
bc->agpopped = false;
return;
}
/*
* BMOAddGroup
*/
static void
BMOAddGroup(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
char *name;
if ((name = MyDialogGetValue(GetDialogWidget(bc->agpop))) == NULL ||
name[0] == '\0')
{
return;
}
GroupCreate(bc, name, true);
BMDAddGroup(w, cldata, cbdata);
BMWrite(bc);
return;
}
/*
* BMAddGroup
*/
static void
BMAddGroup(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
if (bc->agpopped) return;
if (bc->agpop == NULL)
{
bc->agpop = CreateDialog(bc->bw, "agpop",
BMOAddGroup, BMDAddGroup, BMOAddGroup, bc);
}
MyDialogSetValue(GetDialogWidget(bc->agpop), "");
XtPopup(bc->agpop, XtGrabNone);
bc->agpopped = true;
return;
}
/*
* BMRMGroup
*/
static void
BMRMGroup(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
BGroup *g;
if ((g = BMFindGroup(bc)) != NULL)
{
GListRemoveItem(bc->glist, g);
if (GListEmpty(bc->glist)) GroupCreate(bc, "default", true);
BMChangeGroupList(bc);
BMChangeMarkList(bc);
BMWrite(bc);
}
return;
}
/*
* BMDAddMark
*/
static void
BMDAddMark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
XtPopdown(bc->ampop);
bc->ampopped = false;
return;
}
/*
* BMOAddMark
*/
static void
BMOAddMark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
char *name;
char *url;
if ((name = MyDialogGetValue(GetDialogWidget(bc->ampop))) == NULL ||
name[0] == '\0')
{
return;
}
if ((url = StackGetCurrentURL(bc->cres->bmcontext->tstack)) != NULL)
{
BookmarkAdd(bc, name, url);
}
BMDAddMark(w, cldata, cbdata);
BMWrite(bc);
return;
}
/*
* BMAddMark
*/
static void
BMAddMark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
char *title;
ChimeraRender wn;
if (bc->ampopped) return;
if (bc->cres->bmcontext == NULL) return;
wn = StackToRender(bc->cres->bmcontext->tstack);
if ((title = RenderQuery(wn, "title")) == NULL)
{
if ((title = StackGetCurrentURL(bc->cres->bmcontext->tstack)) == NULL)
{
title = "unknown";
}
}
if (bc->ampop == NULL)
{
bc->ampop = CreateDialog(bc->bw, "ampop",
BMOAddMark, BMDAddMark, BMOAddMark, bc);
}
MyDialogSetValue(GetDialogWidget(bc->ampop), title);
XtPopup(bc->ampop, XtGrabNone);
bc->ampopped = true;
return;
}
/*
* BMRMMark
*/
static void
BMRMMark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
BMark *m;
BGroup *g;
if ((g = BMFindGroup(bc)) == NULL) return;
if ((m = BMFindMark(bc)) != NULL)
{
GListRemoveItem(g->mlist, m);
BMChangeMarkList(bc);
BMWrite(bc);
}
return;
}
/*
* BMDismiss
*/
static void
BMDismiss(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
if (bc->ampop != NULL) XtPopdown(bc->ampop);
if (bc->agpop != NULL) XtPopdown(bc->agpop);
XtUnmapWidget(bc->bw);
return;
}
/*
* BMGroupList
*/
static void
BMGroupList(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
BMChangeMarkList(bc);
return;
}
/*
* BMMarkList
*/
static void
BMMarkList(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
BookmarkContext bc = (BookmarkContext)cldata;
BMark *m;
if ((m = BMFindMark(bc)) == NULL) return;
StackOpen(bc->cres->bmcontext->tstack,
RequestCreate(bc->cres, m->url, NULL));
return;
}
/*
* BookmarkCreateContext
*/
BookmarkContext
BookmarkCreateContext(cres)
ChimeraResources cres;
{
Widget fw, w, gvw, mvw;
BookmarkContext bc;
struct stat s;
FILE *fp;
char *bdata;
char *filename;
MemPool mp;
Window rw, cw;
int rx, ry, wx, wy;
unsigned int mask;
if ((filename = ResourceGetString(cres, "bookmark.filename")) == NULL)
{
return(NULL);
}
mp = MPCreate();
bc = (BookmarkContext)MPCGet(mp, sizeof(struct BookmarkContextP));
bc->mp = mp;
bc->cres = cres;
XQueryPointer(cres->dpy, DefaultRootWindow(cres->dpy),
&rw, &cw,
&rx, &ry,
&wx, &wy,
&mask);
bc->bw = XtVaAppCreateShell("bookmark", "Bookmark",
transientShellWidgetClass, cres->dpy,
XtNx, rx, XtNy, ry,
NULL);
/* group widgets */
fw = XtVaCreateManagedWidget("form",
formWidgetClass, bc->bw,
NULL);
gvw = XtVaCreateManagedWidget("groupview",
viewportWidgetClass, fw,
NULL);
bc->glw = XtVaCreateManagedWidget("grouplist",
listWidgetClass, gvw,
NULL);
XtAddCallback(bc->glw, XtNcallback, BMGroupList, (XtPointer)bc);
w = XtVaCreateManagedWidget("addgroup",
commandWidgetClass, fw,
XtNfromVert, gvw,
NULL);
XtAddCallback(w, XtNcallback, BMAddGroup, (XtPointer)bc);
w = XtVaCreateManagedWidget("rmgroup",
commandWidgetClass, fw,
XtNfromVert, gvw,
XtNfromHoriz, w,
NULL);
XtAddCallback(w, XtNcallback, BMRMGroup, (XtPointer)bc);
/* Mark widgets */
mvw = XtVaCreateManagedWidget("markview",
viewportWidgetClass, fw,
XtNfromVert, w,
NULL);
bc->mlw = XtVaCreateManagedWidget("marklist",
listWidgetClass, mvw,
NULL);
XtAddCallback(bc->mlw, XtNcallback, BMMarkList, (XtPointer)bc);
w = XtVaCreateManagedWidget("addmark",
commandWidgetClass, fw,
XtNfromVert, mvw,
NULL);
XtAddCallback(w, XtNcallback, BMAddMark, (XtPointer)bc);
w = XtVaCreateManagedWidget("rmmark",
commandWidgetClass, fw,
XtNfromVert, mvw,
XtNfromHoriz, w,
NULL);
XtAddCallback(w, XtNcallback, BMRMMark, (XtPointer)bc);
w = XtVaCreateManagedWidget("dismiss",
commandWidgetClass, fw,
XtNfromVert, mvw,
XtNfromHoriz, w,
NULL);
XtAddCallback(w, XtNcallback, BMDismiss, (XtPointer)bc);
if ((bc->header = ResourceGetString(cres, "bookmark.header")) == NULL)
{
bc->header = "";
}
if ((bc->footer = ResourceGetString(cres, "bookmark.footer")) == NULL)
{
bc->footer = "";
}
bc->glist = GListCreateX(bc->mp);
bc->nel = GListCreateX(bc->mp);
bc->filename = FixPath(bc->mp, filename);
if (stat(bc->filename, &s) == 0)
{
if ((fp = fopen(bc->filename, "r")) != NULL)
{
bdata = (char *)alloc_mem(s.st_size);
if (fread(bdata, 1, s.st_size, fp) == s.st_size)
{
bc->ml = MLInit(BMElementHandler, bc);
MLEndData(bc->ml, bdata, s.st_size);
MLDestroy(bc->ml);
}
free_mem(bdata);
fclose(fp);
}
}
if (GListEmpty(bc->glist)) GroupCreate(bc, "default", true);
XtSetMappedWhenManaged(bc->bw, False);
XtRealizeWidget(bc->bw);
return(bc);
}

51
chimera/builtin.c Normal file
View File

@ -0,0 +1,51 @@
/*
* builtin.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <X11/Intrinsic.h>
#include "port_after.h"
#include "Chimera.h"
extern void InitModule_HTML _ArgProto((ChimeraResources));
extern void InitModule_Plain _ArgProto((ChimeraResources));
extern void InitModule_HTTP _ArgProto((ChimeraResources));
extern void InitModule_FTP _ArgProto((ChimeraResources));
extern void InitModule_File _ArgProto((ChimeraResources));
extern void InitModule_Image _ArgProto((ChimeraResources));
extern void InitModule_Mailto _ArgProto((ChimeraResources));
void
InitChimeraBuiltins(cres)
ChimeraResources cres;
{
InitModule_Plain(cres);
InitModule_Image(cres);
InitModule_HTML(cres);
InitModule_HTTP(cres);
InitModule_FTP(cres);
InitModule_File(cres);
InitModule_Mailto(cres);
return;
}

637
chimera/cache.c Normal file
View File

@ -0,0 +1,637 @@
/*
* cache.c
*
* Copyright (C) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <X11/IntrinsicP.h>
#include "port_after.h"
#include "ChimeraP.h"
#include "mime.h"
#include "ml.h"
typedef struct
{
MemPool mp; /* memory descriptor */
char *filename; /* name of cache file */
char *url; /* URL string */
int cid; /* cache ID */
time_t atime; /* last access time */
time_t expires; /* expires time */
time_t mtime; /* modified time */
off_t size; /* diskspace used */
ChimeraCache cc;
} CacheEntry;
struct ChimeraCacheP
{
MemPool mp; /* memory descriptor */
char *dirname; /* name of cache directory */
char *cindex; /* cache index file */
GList cachelist; /* list of cache entries */
bool persist; /* clear cache on exit ? */
off_t max_size; /* maximum size of cache */
off_t curr_size; /* current size of cache */
bool ignore_expires; /* ignore expiration info */
time_t ttl; /* time-to-live */
MLState ml;
int refcount; /* so multiple class destroys work */
int next_cid; /* next cache entry ID */
ChimeraSourceHooks *chooks;
ChimeraResources cres;
};
typedef struct
{
MemPool mp;
CacheEntry *ce;
FILE *fp;
ChimeraSource ws;
ChimeraResources cres;
byte *buffer;
size_t len;
size_t doff;
struct stat s;
MIMEHeader mh;
ChimeraTask wt;
} CRInfo;
static void CacheEntryDestroy _ArgProto((ChimeraCache, CacheEntry *, bool));
static CacheEntry *AddCacheEntry _ArgProto((ChimeraCache, char *, int));
static void ReadCacheIndex _ArgProto((ChimeraCache));
static CacheEntry *FindCacheEntry _ArgProto((ChimeraCache, char *));
static void CacheElementHandler _ArgProto((void *, MLElement));
static void CRRead _ArgProto((void *));
static void CRGetData _ArgProto((void *, byte **, size_t *, MIMEHeader *));
static void *CRInit _ArgProto((ChimeraSource, ChimeraRequest *, void *));
static void CRDestroy _ArgProto((void *));
static void CRStop _ArgProto((void *));
static void *CSInit _ArgProto((ChimeraSource, ChimeraRequest *, void *));
static char *CSResolve _ArgProto((MemPool, char *, char *));
/*
* FindCacheEntry
*/
static CacheEntry *
FindCacheEntry(cc, url)
ChimeraCache cc;
char *url;
{
CacheEntry *ce;
GList list;
list = cc->cachelist;
for (ce = (CacheEntry *)GListGetHead(list); ce != NULL;
ce = (CacheEntry *)GListGetNext(list))
{
if (strlen(url) == strlen(ce->url) &&
strcasecmp(url, ce->url) == 0) return(ce);
}
return(NULL);
}
/*
* CacheIsDiskCached
*/
bool
CacheIsDiskCached(cc, url)
ChimeraCache cc;
char *url;
{
return(FindCacheEntry(cc, url) != NULL ? true:false);
}
/*
* CRGetData
*/
static void
CRGetData(closure, data, len, mh)
void *closure;
byte **data;
size_t *len;
MIMEHeader *mh;
{
CRInfo *cr = (CRInfo *)closure;
if (cr->mh == NULL)
{
*data = NULL;
*len = 0;
*mh = NULL;
}
else
{
*data = cr->buffer + cr->doff;
*len = cr->s.st_size - cr->doff;
*mh = cr->mh;
}
return;
}
/*
* CRStop
*/
static void
CRStop(closure)
void *closure;
{
CRInfo *cr = (CRInfo *)closure;
if (cr->wt != NULL)
{
TaskRemove(cr->cres, cr->wt);
cr->wt = NULL;
}
return;
}
/*
* CRDestroy
*/
static void
CRDestroy(closure)
void *closure;
{
CRInfo *cr = (CRInfo *)closure;
CRStop(cr);
if (cr->buffer != NULL) free_mem(cr->buffer);
if (cr->mh != NULL) MIMEDestroyHeader(cr->mh);
MPDestroy(cr->mp);
return;
}
/*
* CRRead
*/
static void
CRRead(closure)
void *closure;
{
ssize_t rval;
CRInfo *cr = (CRInfo *)closure;
cr->wt = NULL;
cr->buffer = (byte *)alloc_mem(cr->s.st_size);
rval = fread(cr->buffer, 1, cr->s.st_size, cr->fp);
if (rval == cr->s.st_size)
{
if (MIMEFindData(cr->mh, cr->buffer, cr->s.st_size, &cr->doff) == 0)
{
MIMEParseBuffer(cr->mh, cr->buffer, cr->doff);
SourceInit(cr->ws, true);
SourceEnd(cr->ws);
}
else SourceStop(cr->ws, "");
}
else SourceStop(cr->ws, "");
fclose(cr->fp);
cr->fp = NULL;
return;
}
/*
* CRInit
*/
static void *
CRInit(ws, wr, closure)
ChimeraSource ws;
ChimeraRequest *wr;
void *closure;
{
ChimeraCache cc = (ChimeraCache)closure;
CRInfo *cr;
CacheEntry *ce;
MemPool mp;
if ((ce = FindCacheEntry(cc, wr->url)) == NULL) return(NULL);
mp = MPCreate();
cr = (CRInfo *)MPCGet(mp, sizeof(CRInfo));
cr->mp = mp;
cr->ws = ws;
cr->ce = ce;
cr->cres = cc->cres;
cr->mh = MIMECreateHeader();
if (ce->filename == NULL || stat(ce->filename, &cr->s) == -1 ||
(cr->fp = fopen(ce->filename, "r")) == NULL)
{
CRDestroy(cr);
return(NULL);
}
cr->wt = TaskSchedule(cr->cres, CRRead, cr);
return(cr);
}
/*
* AddCacheEntry
*/
static CacheEntry *
AddCacheEntry(cc, url, cid)
ChimeraCache cc;
char *url;
int cid;
{
CacheEntry *ce;
char *filename;
MemPool mp;
size_t len;
mp = MPCreate();
ce = (CacheEntry *)MPCGet(mp, sizeof(CacheEntry));
ce->mp = mp;
ce->cc = cc;
GListAddHead(cc->cachelist, ce);
len = strlen(cc->dirname) + strlen("/.ccf") + 26;
filename = (char *)MPGet(mp, len);
if (cid == -1) ce->cid = cc->next_cid++;
else
{
ce->cid = cid;
if (cid > cc->next_cid) cc->next_cid = cid + 1;
}
snprintf (filename, len, "%s/%d.ccf", cc->dirname, ce->cid);
ce->filename = filename;
ce->url = MPStrDup(mp, url);
return(ce);
}
/*
* CacheWrite
*/
int
CacheWrite(cc, ws)
ChimeraCache cc;
ChimeraSource ws;
{
FILE *fp;
struct stat s;
CacheEntry *ce;
char *url;
byte *data;
size_t len;
MIMEHeader mh;
SourceGetData(ws, &data, &len, &mh);
if (data == NULL || len == 0 || mh == NULL) return(-1);
if (MIMEGetField(mh, "x-url", &url) != 0 || url == NULL) return(-1);
if ((ce = FindCacheEntry(cc, url)) != NULL)
{
CacheEntryDestroy(cc, ce, false);
}
ce = AddCacheEntry(cc, url, -1);
if ((fp = fopen(ce->filename, "w")) == NULL)
{
CacheEntryDestroy(cc, ce, false);
return(-1);
}
MIMEWriteHeader(mh, fp);
if (fwrite(data, 1, len, fp) < len)
{
fclose(fp);
CacheEntryDestroy(cc, ce, false);
return(-1);
}
fclose(fp);
s.st_size = 0;
stat(ce->filename, &s);
ce->size = s.st_size;
cc->curr_size += ce->size;
return(0);
}
/*
* CacheEntryDestroy
*/
void
CacheEntryDestroy(cc, ce, persist)
ChimeraCache cc;
CacheEntry *ce;
bool persist;
{
GListRemoveItem(cc->cachelist, ce);
cc->curr_size -= ce->size;
if (!persist && ce->filename != NULL) unlink(ce->filename);
MPDestroy(ce->mp);
return;
}
/*
* CacheDestroy
*/
void
CacheDestroy(cc)
ChimeraCache cc;
{
FILE *fp;
CacheEntry *ce;
GList list;
list = cc->cachelist;
cc->refcount--;
if (cc->refcount > 0) return;
if (cc->persist)
{
/*
* This can take a really long time so its only done once at the end.
*/
if ((fp = fopen(cc->cindex, "w")) != NULL)
{
fprintf (fp, "<html>\n");
fprintf (fp, "<head><title>Chimera Cache Index</title></head>\n");
fprintf (fp, "<body>\n");
fprintf (fp, "<ul>\n");
for (ce = (CacheEntry *)GListGetHead(list); ce != NULL;
ce = (CacheEntry *)GListGetNext(list))
{
fprintf (fp, "<li><a size=%lu cid=%d href=\"%s\">%s</a>\n",
(unsigned long)ce->size, ce->cid, ce->url, ce->url);
}
fprintf (fp, "</ul>\n");
fprintf (fp, "</body>\n");
fprintf (fp, "</html>\n");
fclose(fp);
}
}
else unlink(cc->cindex);
while ((ce = GListPop(list)) != NULL)
{
CacheEntryDestroy(cc, ce, cc->persist);
}
MPDestroy(cc->mp);
return;
}
/*
* CacheElementHandler
*/
static void
CacheElementHandler(closure, p)
void *closure;
MLElement p;
{
ChimeraCache cc = (ChimeraCache)closure;
CacheEntry *ce;
char *href;
char *sstr;
char *cidstr;
size_t size;
char *name;
if ((name = MLTagName(p)) == NULL || MLGetType(p) == ML_ENDTAG) return;
if (strcasecmp("a", name) == 0)
{
if ((href = MLFindAttribute(p, "href")) != NULL &&
(sstr = MLFindAttribute(p, "size")) != NULL &&
(cidstr = MLFindAttribute(p, "cid")) != NULL)
{
size = (size_t)atoi(sstr);
if (size > 0 && (ce = AddCacheEntry(cc, href, atoi(cidstr))) != NULL)
{
ce->size = size;
cc->curr_size += size;
}
}
}
return;
}
/*
* ReadCacheIndex
*/
static void
ReadCacheIndex(cc)
ChimeraCache cc;
{
FILE *fp;
struct stat s;
char *bdata;
if (stat(cc->cindex, &s) != -1 && (fp = fopen(cc->cindex, "r")) != NULL)
{
bdata = (char *)alloc_mem(s.st_size);
if (fread(bdata, 1, s.st_size, fp) == s.st_size)
{
cc->ml = MLInit(CacheElementHandler, cc);
MLEndData(cc->ml, bdata, (size_t)s.st_size);
MLDestroy(cc->ml);
}
free_mem(bdata);
fclose(fp);
}
return;
}
/*
* CSInit
*/
static void *
CSInit(ws, wr, closure)
ChimeraSource ws;
ChimeraRequest *wr;
void *closure;
{
ChimeraCache cc = (ChimeraCache)closure;
CRInfo *cr;
CacheEntry *ce;
MemPool mp;
char *url;
for (url = wr->url; *url != '\0' && *url != ':'; url++)
;
if (*url == '\0') return(NULL);
url++;
if ((ce = FindCacheEntry(cc, url)) == NULL) return(NULL);
mp = MPCreate();
cr = (CRInfo *)MPCGet(mp, sizeof(CRInfo));
cr->mp = mp;
cr->ws = ws;
cr->ce = ce;
if (ce->filename == NULL || stat(ce->filename, &cr->s) == -1 ||
(cr->fp = fopen(ce->filename, "r")) == NULL)
{
CRDestroy(cr);
return(NULL);
}
cr->wt = TaskSchedule(cc->cres, CRRead, cr);
return(cr);
}
/*
* CSResolve
*/
static char *
CSResolve(mp, url, base)
MemPool mp;
char *url;
char *base;
{
return(MPStrDup(mp, url));
}
/*
* CacheGetHooks
*/
ChimeraSourceHooks *
CacheGetHooks(cc)
ChimeraCache cc;
{
return(cc->chooks);
}
/*
* CacheCreate
*/
ChimeraCache
CacheCreate(cres)
ChimeraResources cres;
{
ChimeraCache cc;
char *dirname;
MemPool mp;
char filename[MAXFILENAMELEN + 1];
ChimeraSourceHooks hooks;
struct stat s;
int t;
mp = MPCreate();
if ((dirname = ResourceGetFilename(cres, mp, "cache.directory")) == NULL)
{
fprintf (stderr, "Cache resource not found. Not caching.\n");
MPDestroy(mp);
return(NULL);
}
if (stat(dirname, &s) != 0)
{
fprintf (stderr, "Cache directory not found. Not caching.\n");
MPDestroy(mp);
return(NULL);
}
cc = (ChimeraCache)MPCGet(mp, sizeof(struct ChimeraCacheP));
cc->mp = mp;
cc->dirname = dirname;
strcpy(filename, cc->dirname);
strcat(filename, "/");
strcat(filename, "ccfindex.html");
cc->cindex = FixPath(mp, filename);
cc->cachelist = GListCreateX(cc->mp);
cc->cres = cres;
ResourceGetBool(cres, "cache.persist", &cc->persist);
ResourceGetBool(cres, "cache.ignoreExpires", &cc->ignore_expires);
if (ResourceGetInt(cres, "cache.maxSize", &t) == NULL || t < 0)
{
cc->max_size = 0;
}
else cc->max_size = (off_t)t;
if (ResourceGetInt(cres, "cache.ttl", &t) == NULL || t < 0)
{
cc->ttl = 0;
}
else cc->ttl = (time_t)t;
ReadCacheIndex(cc);
cc->chooks = (ChimeraSourceHooks *)MPCGet(cres->mp,
sizeof(ChimeraSourceHooks));
cc->chooks->init = CRInit;
cc->chooks->destroy = CRDestroy;
cc->chooks->stop = CRStop;
cc->chooks->getdata = CRGetData;
cc->chooks->class_closure = cc;
memset(&hooks, 0, sizeof(hooks));
hooks.name = "x-cache";
hooks.init = CSInit;
hooks.destroy = CRDestroy;
hooks.stop = CRStop;
hooks.getdata = CRGetData;
hooks.class_closure = cc;
hooks.resolve_url = CSResolve;
SourceAddHooks(cres, &hooks);
return(cc);
}

38
chimera/chimera.man Normal file
View File

@ -0,0 +1,38 @@
.TH chimera 1 "26 October 1994"
.IX chimera
.SH NAME
chimera - X/Athena World-Wide Web Client
.SH SYNOPSIS
.B chimera
.RI [ URL ]
.SH DESCRIPTION
Chimera is a program which allows a user to access World-Wide Web servers
and other information servers. It presents the user with a point-and-click
graphical interface using the X Window System and the Athena Widgets.
.SH COMMAND LINE
A single URL can be specified on the command line for indicating the
initial Chimera document.
The usual Xt options like geometry can also be specified on the command
line.
.SH RESOURCES
The following resources are Chimera specific resources:
.IP "\fBhomeURL\fP"
This string is used to specify the URL for the page displayed by default
when chimera is first started. The default is defined at compile time.
.SH "SEE ALSO"
lynx(1), Mosaic(1), netscape(1)
.SH "BUGS"
Zillions for sure.
This man page is really old, possibly wrong, and not even close to complete.
.SH AUTHOR
Copyright 1993, 1994, 1995 by John Kilburg (john@cs.unlv.edu)

326
chimera/cmisc.c Normal file
View File

@ -0,0 +1,326 @@
/*
* cmisc.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "ChimeraP.h"
/*
* SourceAddHooks
*/
int
SourceAddHooks(cres, shooks)
ChimeraResources cres;
ChimeraSourceHooks *shooks;
{
ChimeraSourceHooks *nhooks;
myassert(shooks->name != NULL, "Protocol not set in data hooks.");
myassert(shooks->init != NULL, "Init function is NULL");
myassert(shooks->stop != NULL, "Stop function is NULL");
myassert(shooks->destroy != NULL, "Destroy function is NULL");
myassert(shooks->getdata != NULL, "Getdata function is NULL");
nhooks = (ChimeraSourceHooks *)MPCGet(cres->mp, sizeof(ChimeraSourceHooks));
memcpy(nhooks, shooks, sizeof(ChimeraSourceHooks));
GListAddHead(cres->sourcehooks, nhooks);
return(0);
}
/*
* RenderAddHooks
*/
int
RenderAddHooks(cres, rhooks)
ChimeraResources cres;
ChimeraRenderHooks *rhooks;
{
ChimeraRenderHooks *nr;
nr = (ChimeraRenderHooks *)MPCGet(cres->mp, sizeof(ChimeraRenderHooks));
memcpy(nr, rhooks, sizeof(ChimeraRenderHooks));
GListAddHead(cres->renderhooks, nr);
return(0);
}
/*
* RenderGetHooks
*/
ChimeraRenderHooks *
RenderGetHooks(cres, content)
ChimeraResources cres;
char *content;
{
ChimeraRenderHooks *rh;
size_t rlen;
GList list;
if (content == NULL) return(NULL);
rlen = strlen(content);
list = cres->renderhooks;
for (rh = (ChimeraRenderHooks *)GListGetHead(list); rh != NULL;
rh = (ChimeraRenderHooks *)GListGetNext(list))
{
if (strlen(rh->content) == rlen && strcasecmp(rh->content, content) == 0)
{
return(rh);
}
}
return(NULL);
}
/*
* SourceGetHooks
*/
ChimeraSourceHooks *
SourceGetHooks(cres, proto)
ChimeraResources cres;
char *proto;
{
ChimeraSourceHooks *shooks;
size_t plen;
GList list;
plen = strlen(proto);
list = cres->sourcehooks;
for (shooks = (ChimeraSourceHooks *)GListGetHead(list); shooks != NULL;
shooks = (ChimeraSourceHooks *)GListGetNext(list))
{
if (strlen(shooks->name) == plen &&
strcasecmp(shooks->name, proto) == 0)
{
return(shooks);
}
}
return(NULL);
}
struct ChimeraType
{
char *content;
char *ext;
};
static struct ChimeraType def_mtlist[] =
{
{ "text/html", "html" },
{ "text/html", "htm" },
{ "text/plain", "txt" },
{ "image/gif", "gif" },
{ "image/png", "png" },
{ "image/xbm", "xbm" },
{ "image/x-xpixmap", "xpm" },
{ "image/x-portable-anymap", "pnm" },
{ "image/x-portable-bitmap", "pbm" },
{ "image/x-portable-graymap", "pgm" },
{ "image/x-portable-pixmap", "ppm" },
{ "image/jpeg", "jpg" },
{ "image/jpeg", "jpeg" },
{ "image/tiff", "tiff" },
{ "image/tiff", "tif" },
{ "image/x-fits", "fit" },
{ "image/x-fits", "fits" },
{ "image/x-fits", "fts" },
{ "image/x-png", "png" },
{ "image/png", "png" },
{ "audio/basic", "au" },
{ "audio/basic", "snd" },
{ "text/x-compress-html", "html.Z" },
{ "text/x-gzip-html", "html.gz" },
{ "application/postscript", "ps" },
{ "application/x-dvi", "dvi" },
{ "application/x-gzip", "gz" },
{ "application/x-compress", "Z" },
{ "application/x-tar", "tar" },
{ "video/mpeg", "mpeg" },
{ "video/mpeg", "mpg" },
{ NULL, NULL },
};
/*
* ChimeraReadTypes
*/
void
ChimeraReadTypeFiles(cres, filelist)
ChimeraResources cres;
char *filelist;
{
FILE *fp;
char *f;
char *cp;
char buffer[256];
char content[256];
char exts[256];
struct ChimeraType *c;
char *filename, *e;
MemPool mp;
mp = MPCreate();
cres->mimes = GListCreate();
f = filelist;
while ((filename = mystrtok(f, ':', &f)) != NULL)
{
filename = FixPath(mp, filename);
if (filename == NULL) continue;
fp = fopen(filename, "r");
if (fp == NULL) continue;
while (fgets(buffer, sizeof(buffer), fp))
{
if (buffer[0] == '#' || buffer[0] == '\n') continue;
if (sscanf(buffer, "%s %[^\n]", content, exts) == 2)
{
cp = exts;
while ((e = mystrtok(cp, ' ', &cp)) != NULL)
{
c = (struct ChimeraType *)alloc_mem(sizeof(struct ChimeraType));
memset(c, 0, sizeof(struct ChimeraType));
c->content = alloc_string(content);
c->ext = alloc_mem(strlen(e) + 2);
strcpy(c->ext, ".");
strcat(c->ext, e);
GListAddTail(cres->mimes, c);
}
}
}
fclose(fp);
}
MPDestroy(mp);
return;
}
/*
* ChimeraExt2Content
*/
char *
ChimeraExt2Content(cres, ext)
ChimeraResources cres;
char *ext;
{
int elen, flen;
struct ChimeraType *c;
int i;
GList list;
list = cres->mimes;
flen = strlen(ext);
for (c = (struct ChimeraType *)GListGetHead(list); c != NULL;
c = (struct ChimeraType *)GListGetNext(list))
{
elen = strlen(c->ext);
if (elen > 0)
{
if (elen <= flen &&
strncasecmp(ext + flen - elen, c->ext, elen) == 0)
{
return(c->content);
}
}
}
for (i = 0; def_mtlist[i].content != NULL; i++)
{
elen = strlen(def_mtlist[i].ext);
if (elen > 0)
{
if (elen <= flen &&
strncasecmp(ext + flen - elen, def_mtlist[i].ext, elen) == 0)
{
return(def_mtlist[i].content);
}
}
}
return(NULL);
}
void
CMethodVoidDoom()
{
abort();
return;
}
void *
CMethodVoidPtrDoom()
{
abort();
return(NULL);
}
int
CMethodIntDoom()
{
abort();
return(0);
}
char
CMethodCharDoom()
{
abort();
return(0);
}
char *
CMethodCharPtrDoom()
{
abort();
return(0);
}
byte *
CMethodBytePtrDoom()
{
abort();
return(0);
}
bool
CMethodBoolDoom()
{
abort();
return(0);
}

310
chimera/download.c Normal file
View File

@ -0,0 +1,310 @@
/*
* download.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include "port_after.h"
#include "MyDialog.h"
#include "ChimeraP.h"
typedef struct
{
MemPool mp;
ChimeraSink wp;
Widget pop, dialog;
bool okd;
char *filename;
bool ended;
Widget ok;
ChimeraTask wt;
ChimeraResources cres;
} DownloadInfo;
static void DoSaveTask _ArgProto((DownloadInfo *));
static void SaveTask _ArgProto((void *));
static void DownloadDestroy _ArgProto((DownloadInfo *));
static void DownloadMakePop _ArgProto((DownloadInfo *));
static int DownloadInit _ArgProto((ChimeraSink, void *));
static void DownloadAdd _ArgProto((void *));
static void DownloadEnd _ArgProto((void *));
static void DownloadMessage _ArgProto((void *, char *));
/*
* DownloadDestroy
*/
static void
DownloadDestroy(di)
DownloadInfo *di;
{
ChimeraResources cres = di->cres;
if (di->pop != NULL) XtDestroyWidget(di->pop);
if (di->wp != NULL) SinkDestroy(di->wp);
MPDestroy(di->mp);
ChimeraRemoveReference(cres);
return;
}
/*
* DownloadClear
*/
static void
DownloadClear(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
DownloadInfo *di = (DownloadInfo *)cldata;
MyDialogSetValue(di->dialog, "");
XtVaSetValues(di->ok, XtNsensitive, True, NULL);
di->okd = false;
return;
}
/*
* DownloadDSave
*/
static void
DownloadDSave(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
DownloadDestroy((DownloadInfo *)cldata);
return;
}
/*
* SaveTask
*/
static void
SaveTask(closure)
void *closure;
{
char *filename;
byte *data;
size_t len;
MIMEHeader mh;
FILE *fp;
DownloadInfo *di = (DownloadInfo *)closure;
if ((filename = MyDialogGetValue(di->dialog)) == NULL)
{
XBell(di->cres->dpy, 100);
XtVaSetValues(di->ok, XtNsensitive, True, NULL);
di->okd = false;
di->wt = NULL;
return;
}
filename = FixPath(di->mp, filename);
if ((fp = fopen(filename, "w")) == NULL)
{
XBell(di->cres->dpy, 100);
XtVaSetValues(di->ok, XtNsensitive, True, NULL);
di->okd = false;
di->wt = NULL;
MyDialogSetValue(di->dialog, di->filename);
return;
}
SinkGetData(di->wp, &data, &len, &mh);
fwrite(data, 1, len, fp);
fclose(fp);
DownloadDestroy(di);
return;
}
/*
* DoSaveTask
*/
static void
DoSaveTask(di)
DownloadInfo *di;
{
myassert(di->wt == NULL, "Save task already started.");
di->wt = TaskSchedule(di->cres, SaveTask, di);
return;
}
/*
* DownloadOSave
*/
static void
DownloadOSave(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
DownloadInfo *di = (DownloadInfo *)cldata;
if (di->okd) return;
if (di->ended) DoSaveTask(di);
else
{
di->okd = true;
XtVaSetValues(di->ok, XtNsensitive, False, NULL);
}
return;
}
static void
DownloadMakePop(di)
DownloadInfo *di;
{
Window rw, cw;
int rx, ry, wx, wy;
unsigned int mask;
XQueryPointer(di->cres->dpy, DefaultRootWindow(di->cres->dpy),
&rw, &cw,
&rx, &ry,
&wx, &wy,
&mask);
di->pop = XtVaAppCreateShell("download", "Download",
transientShellWidgetClass, di->cres->dpy,
XtNx, rx - 2,
XtNy, ry - 2,
NULL);
di->dialog = XtVaCreateManagedWidget("dialog",
mydialogWidgetClass, di->pop,
NULL);
di->ok = MyDialogAddButton(di->dialog, "ok", DownloadOSave, di);
MyDialogAddButton(di->dialog, "Clear", DownloadClear, di);
MyDialogAddButton(di->dialog, "dismiss", DownloadDSave, di);
XtAddCallback(di->dialog, XtNcallback, DownloadOSave, di);
XtRealizeWidget(di->pop);
MyDialogSetValue(di->dialog, di->filename);
return;
}
/*
* DownloadAdd
*/
void
DownloadAdd(closure)
void *closure;
{
return;
}
/*
* DownloadEnd
*/
void
DownloadEnd(closure)
void *closure;
{
DownloadInfo *di = (DownloadInfo *)closure;
di->ended = true;
if (di->okd) DoSaveTask(di);
return;
}
/*
* DownloadMessage
*/
void
DownloadMessage(closure, message)
void *closure;
char *message;
{
DownloadInfo *di = (DownloadInfo *)closure;
if (di->dialog != NULL) MyDialogSetMessage(di->dialog, message);
return;
}
/*
* DownloadInit
*/
static int
DownloadInit(wp, closure)
ChimeraSink wp;
void *closure;
{
return(0);
}
void
DownloadOpen(cres, wr)
ChimeraResources cres;
ChimeraRequest *wr;
{
DownloadInfo *di;
MemPool mp;
ChimeraSinkHooks hooks;
char *filename;
myassert(wr != NULL, "NULL request not allowed.");
mp = MPCreate();
di = (DownloadInfo *)MPCGet(mp, sizeof(DownloadInfo));
di->mp = mp;
if ((filename = GetBaseFilename(wr->url)) == NULL) filename = "";
di->filename = MPStrDup(di->mp, filename);
di->cres = cres;
memset(&hooks, 0, sizeof(hooks));
hooks.init = DownloadInit;
hooks.add = DownloadAdd;
hooks.end = DownloadEnd;
hooks.message = DownloadMessage;
ChimeraAddReference(cres);
if ((di->wp = SinkCreate(cres, wr)) != NULL)
{
SinkSetHooks(di->wp, &hooks, di);
DownloadMakePop(di);
}
else
{
DownloadDestroy(di);
RequestDestroy(wr);
}
return;
}

105
chimera/fallback.c Normal file
View File

@ -0,0 +1,105 @@
/*
* fallback.c
*
* Copyright 1993-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
char *fallback_resources[] =
{
"*background: moccasin",
"*showGrip: false",
"*Scrollbar.background: burlywood2",
"*Command.background: burlywood2",
"*Toggle.background: burlywood2",
"*MenuButton.background: burlywood2",
"*SimpleMenu.background: burlywood2",
"*SmeBSB.background: burlywood2",
"*Box.orientation: horizontal",
"*Label.borderWidth: 0",
"*allowHoriz: true",
"*allowVert: true",
/* labels for commands */
"*open.label: Open",
"*quit.label: Quit",
"*reload.label: Reload",
"*help.label: Help",
"*home.label: Home",
"*back.label: Back",
"*cancel.label: Cancel",
"*dup.label: Clone",
"*addmark.label: Add Mark",
"*viewmark.label: View Mark",
"*bookmark.label: Bookmark",
"*save.label: Save",
"*source.label: Source",
"*addgroup.label: Add Group",
"*rmgroup.label: Remove Group",
"*rmmark.label: Remove Mark",
"*mlabel.label: Mark",
"*glabel.label: Groups",
"*dismiss.label: Dismiss",
"*www_toplevel.height: 600",
"*www_toplevel.width: 650",
/* message widget */
"*message.width: 600",
"*message.editable: false",
"*message.displayCaret: false",
"*message.borderWidth: 0",
/* bookmark */
"*grouplist.defaultColumns: 1",
"*grouplist.verticalList: true",
"*groupview.width: 400",
"*groupview.height: 100",
"*groupview.allowVert: true",
"*marklist.defaultColumns: 1",
"*marklist.verticalList: true",
"*markview.width: 400",
"*markview.height: 100",
"*markview.allowVert: true",
/* resources for dialog widget */
"*dialog.ok.label: OK",
"*dialog.clear.label: Clear",
"*dialog.dismiss.label: Dismiss",
"*dialog.value.length: 80",
"*openpop.dialog.label: Enter URL",
"*savepop.dialog.label: Enter Filename",
"*download.dialog.label: Enter Filename",
"*agpop.dialog.label: Enter Group Name",
"*ampop.dialog.label: Enter Mark Name",
"*urllabel.label: URL:",
"*urllabel.left: ChainLeft",
"*urllabel.right: ChainLeft",
"*url.left: ChainLeft",
"*url.right: ChainRight",
"*url.fromHoriz: urllabel",
"*Label.font: -*-lucidatypewriter-medium-r-normal-*-*-120-*-*-*-*-iso8859-1",
"*Text.font: -*-lucidatypewriter-medium-r-normal-*-*-120-*-*-*-*-iso8859-1",
"*Command.font: -*-lucida-bold-r-normal-sans-*-120-*-*-*-*-iso8859-1",
"*Toggle.font: -*-lucida-bold-r-normal-sans-*-120-*-*-*-*-iso8859-1",
NULL
};

490
chimera/gui.c Normal file
View File

@ -0,0 +1,490 @@
/*
* gui.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "ChimeraP.h"
#include "WWWP.h"
struct ChimeraGUIP
{
Widget www; /* Xt widget */
MemPool mp; /* memory pool */
ChimeraContext wc;
ChimeraRender wn;
/* state flags */
bool position_set;
bool size_set;
unsigned int width, height;
GUISizeCallback size_callback;
void *size_closure;
ChimeraTask resize_task;
};
static void ResizeTask _ArgProto((void *));
void GUIToplevelResize _ArgProto((Widget, void *, void *));
static void GUIExpose _ArgProto((Widget, void *, int, int,
unsigned int, unsigned int));
static void GUIMotion _ArgProto((Widget, void *, int, int, int));
static void GUISelect _ArgProto((Widget, void *, int, int, int));
/*
* GUIAddRender
*/
void
GUIAddRender(wd, wn)
ChimeraGUI wd;
ChimeraRender wn;
{
wd->wn = wn;
return;
}
/*
* GUICreate
*/
ChimeraGUI
GUICreate(wc, parent, size_callback, size_closure)
ChimeraContext wc;
ChimeraGUI parent;
GUISizeCallback size_callback;
void *size_closure;
{
ChimeraGUI wd;
MemPool mp;
myassert(parent != NULL, "NULL parent not allowed");
mp = MPCreate();
wd = (ChimeraGUI)MPCGet(mp, sizeof(struct ChimeraGUIP));
wd->mp = mp;
wd->wc = wc;
wd->size_set = false;
wd->position_set = false;
wd->size_callback = size_callback;
wd->size_closure = size_closure;
wd->www = XtVaCreateManagedWidget("www_child",
wwwWidgetClass,
WWWGetDrawWidget(parent->www),
XtNmappedWhenManaged, False,
NULL);
WWWSetSelectCallback(wd->www, GUISelect, wd);
WWWSetMotionCallback(wd->www, GUIMotion, wd);
WWWSetExposeCallback(wd->www, GUIExpose, wd);
return(wd);
}
/*
* GUIDestroy
*/
void
GUIDestroy(wd)
ChimeraGUI wd;
{
MemPool mp = wd->mp;
if (wd->www != NULL) XtDestroyWidget(wd->www);
if (wd->resize_task != NULL) TaskRemove(wd->wc->cres, wd->resize_task);
memset(wd, 0, sizeof(struct ChimeraGUIP));
MPDestroy(mp);
return;
}
/*
* GUIToWindow
*/
Window
GUIToWindow(wd)
ChimeraGUI wd;
{
return(XtWindow(WWWGetDrawWidget(wd->www)));
}
/*
* GUIToDisplay
*/
Display *
GUIToDisplay(wd)
ChimeraGUI wd;
{
return(XtDisplay(wd->www));
}
/*
* GUICreateToplevel
*/
ChimeraGUI
GUICreateToplevel(wc, parent, size_callback, size_closure)
ChimeraContext wc;
Widget parent;
GUISizeCallback size_callback;
void *size_closure;
{
ChimeraGUI wd;
MemPool mp;
mp = MPCreate();
wd = (ChimeraGUI)MPCGet(mp, sizeof(struct ChimeraGUIP));
wd->mp = mp;
wd->wc = wc;
wd->size_set = true;
wd->position_set = true;
wd->size_callback = size_callback;
wd->size_closure = size_closure;
wd->www = XtVaCreateManagedWidget("www_toplevel",
wwwWidgetClass, parent,
NULL);
WWWSetResizeCallback(wd->www, GUIToplevelResize, wd);
WWWSetSelectCallback(wd->www, GUISelect, wd);
WWWSetMotionCallback(wd->www, GUIMotion, wd);
WWWSetExposeCallback(wd->www, GUIExpose, wd);
return(wd);
}
/*
* GUISetScrollBar
*/
void
GUISetScrollBar(wd, use_scroll)
ChimeraGUI wd;
bool use_scroll;
{
WWWSetScrollBar(wd->www, use_scroll);
return;
}
/*
* GUIGetDimenions
*/
int
GUIGetDimensions(wd, width, height)
ChimeraGUI wd;
unsigned int *width, *height;
{
if (!wd->size_set) return(-1);
WWWGetDrawSize(wd->www, width, height);
return(0);
}
/*
* GUISetDimensions
*/
void
GUISetDimensions(wd, width, height)
ChimeraGUI wd;
unsigned int width, height;
{
WWWSetDrawSize(wd->www, width, height);
return;
}
int
GUIGetNamedColor(wd, name, pixel)
ChimeraGUI wd;
char *name;
Pixel *pixel;
{
XColor sxc, exc;
Display *dpy = XtDisplay(wd->www);
XAllocNamedColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
name, &sxc, &exc);
*pixel = sxc.pixel;
return(0);
}
/*
* GUIGetOnScreenDimensions
*/
void
GUIGetOnScreenDimensions(wd, x, y, width, height)
ChimeraGUI wd;
int *x, *y;
unsigned int *width, *height;
{
WWWWidget rw = (WWWWidget)wd->www;
*x = -(int)rw->www.child->core.x;
*y = -(int)rw->www.child->core.y;
*width = (unsigned int)rw->www.child->core.width;
*height = (unsigned int)rw->www.clip->core.height;
return;
}
/*
* GUIReset
*/
void
GUIReset(wd)
ChimeraGUI wd;
{
WWWWidget rw = (WWWWidget)wd->www;
wd->wn = NULL;
XClearWindow(XtDisplay(rw->www.child), XtWindow(rw->www.child));
WWWMoveChild(wd->www, 0, 0);
WWWSetDrawSize(wd->www, 0, 0);
return;
}
/*
* GUIExpose
*/
static void
GUIExpose(w, closure, x, y, width, height)
Widget w;
void *closure;
int x, y;
unsigned int width, height;
{
ChimeraGUI wd = (ChimeraGUI)closure;
if (wd->wn != NULL) RenderExpose(wd->wn, x, y, width, height);
return;
}
/*
* GUISelect
*/
static void
GUISelect(w, closure, x, y, button)
Widget w;
void *closure;
int x, y;
int button;
{
ChimeraGUI wd = (ChimeraGUI)closure;
char *action;
if (wd->wn != NULL)
{
if (button == 1) action = "open";
else if (button == 2) action = "download";
else if (button == 3) action = "external";
else action = "open";
RenderSelect(wd->wn, x, y, action);
}
return;
}
/*
* GUIMotion
*/
static void
GUIMotion(w, closure, x, y, button)
Widget w;
void *closure;
int x, y;
int button;
{
ChimeraGUI wd = (ChimeraGUI)closure;
if (wd->wn != NULL) RenderMotion(wd->wn, x, y);
return;
}
/*
* GUIToplevelResize
*/
void
GUIToplevelResize(w, closure, junk)
Widget w;
void *closure;
void *junk;
{
ChimeraGUI wd = (ChimeraGUI)closure;
if (wd->size_callback != NULL)
{
Dimension width, height;
XtVaGetValues(wd->www, XtNwidth, &width, XtNheight, &height, NULL);
wd->width = width;
wd->height = height;
CMethod(wd->size_callback)(wd, wd->size_closure, wd->width, wd->height);
}
return;
}
/*
* GUIMap
*/
void
GUIMap(wd, x, y)
ChimeraGUI wd;
int x, y;
{
if (!wd->size_set)
{
fprintf (stderr, "GUIMap: GUI dimensions not set yet.\n");
return;
}
if (wd->position_set)
{
fprintf (stderr, "GUIMap: already mapped.\n");
return;
}
XtConfigureWidget(wd->www, (Position)x, (Position)y,
(Dimension)wd->width, (Dimension)wd->height, 0);
XtSetMappedWhenManaged(wd->www, True);
return;
}
/*
* GUIUnmap
*/
void
GUIUnmap(wd)
ChimeraGUI wd;
{
XtSetMappedWhenManaged(wd->www, False);
wd->size_set = false;
wd->position_set = false;
return;
}
/*
* ResizeTask
*/
static void
ResizeTask(closure)
void *closure;
{
ChimeraGUI wd = (ChimeraGUI)closure;
if (wd->size_callback != NULL)
{
wd->resize_task = NULL;
CMethod(wd->size_callback)(wd, wd->size_closure, wd->width, wd->height);
}
return;
}
/*
* GUISetInitialDimensions
*/
void
GUISetInitialDimensions(wd, width, height)
ChimeraGUI wd;
unsigned int width, height;
{
myassert(!wd->size_set, "GUISetInitialDimensions: dimensions already set");
if (wd->resize_task != NULL) TaskRemove(wd->wc->cres, wd->resize_task);
wd->width = width;
wd->height = height;
wd->size_set = true;
XtResizeWidget(wd->www, (Dimension)width, (Dimension)height, 0);
WWWSetDrawSize(wd->www, width, height);
wd->resize_task = TaskSchedule(wd->wc->cres, ResizeTask, wd);
return;
}
/*
* GUISetScrollPosition
*/
void
GUISetScrollPosition(wd, x, y)
ChimeraGUI wd;
int x, y;
{
WWWMoveChild(wd->www, x, y);
return;
}
/*
* GUIGetScrollPosition
*/
void
GUIGetScrollPosition(wd, x, y)
ChimeraGUI wd;
int *x, *y;
{
WWWGetScrollPosition(wd->www, x, y);
return;
}
/*
* GUIBackgroundPixel
*/
Pixel
GUIBackgroundPixel(wd)
ChimeraGUI wd;
{
Pixel bg;
XtVaGetValues(wd->www, XtNbackground, &bg, NULL);
return(bg);
}
/*
* GUIToWidget
*/
Widget
GUIToWidget(wd)
ChimeraGUI wd;
{
return(WWWGetDrawWidget(wd->www));
}

849
chimera/head.c Normal file
View File

@ -0,0 +1,849 @@
/*
* head.c
*
* Copyright (C) 1993-1997, John D. Kilburg <john@cs.unlv.edu>
*
* The button table code written by Jim.Rees@umich.edu.
* The messed up parts were written by john.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Label.h>
#include "port_after.h"
#include "TextField.h"
#include "common.h"
#include "MyDialog.h"
#include "ChimeraP.h"
static void Quit _ArgProto((Widget, XtPointer, XtPointer));
static void Back _ArgProto((Widget, XtPointer, XtPointer));
static void Reload _ArgProto((Widget, XtPointer, XtPointer));
static void Cancel _ArgProto((Widget, XtPointer, XtPointer));
static void Home _ArgProto((Widget, XtPointer, XtPointer));
static void Dup _ArgProto((Widget, XtPointer, XtPointer));
static void Help _ArgProto((Widget, XtPointer, XtPointer));
static void AddMark _ArgProto((Widget, XtPointer, XtPointer));
static void ViewMark _ArgProto((Widget, XtPointer, XtPointer));
static void Bookmark _ArgProto((Widget, XtPointer, XtPointer));
static void Source _ArgProto((Widget, XtPointer, XtPointer));
static void Save _ArgProto((Widget, XtPointer, XtPointer));
static void OOpen _ArgProto((Widget, XtPointer, XtPointer));
static void DOpen _ArgProto((Widget, XtPointer, XtPointer));
static void Open _ArgProto((Widget, XtPointer, XtPointer));
static void OFind _ArgProto((Widget, XtPointer, XtPointer));
static void DFind _ArgProto((Widget, XtPointer, XtPointer));
static void Find _ArgProto((Widget, XtPointer, XtPointer));
static void CreateWidgets _ArgProto((ChimeraContext, char *));
static void AddButtons _ArgProto((ChimeraContext, Widget, char *));
static void InstallAccelerators _ArgProto((Widget));
static struct ButtonTable
{
char *name;
Boolean toggle;
Widget w;
void (*cb)();
char *accel;
} ButtonTable[] =
{
{ "quit", False, NULL, Quit, ":Meta<KeyUp>q"},
{ "open", False, NULL, Open, ":Meta<KeyUp>o" },
{ "home", False, NULL, Home, ":Meta<KeyUp>h" },
{ "back", False, NULL, Back, ":Meta<KeyUp>b" },
{ "reload", False, NULL, Reload, ":Meta<KeyUp>r" },
{ "cancel", False, NULL, Cancel, ":Meta<KeyUp>c"},
{ "dup", False, NULL, Dup, ":Meta<KeyUp>c" },
{ "help", False, NULL, Help, ":Meta<KeyUp>H" },
{ "addmark", False, NULL, AddMark, ":Meta<KeyUp>a" },
{ "viewmark", False, NULL, ViewMark, ":Meta<KeyUp>v" },
{ "bookmark", False, NULL, Bookmark, ":Meta<KeyUp>m" },
{ "find", False, NULL, Find, ":Meta<KeyUp>f" },
{ "source", True, NULL, Source, ":Meta<KeyUp>s" },
{ "save", False, NULL, Save, ":Meta<KeyUp>S" },
{ NULL, False, NULL, NULL, NULL},
};
static void
AddButtons(wc, box, list)
ChimeraContext wc;
Widget box;
char *list;
{
char name[256];
struct ButtonTable *btp;
char accel[256];
while (sscanf(list, " %[^,]", name) == 1)
{
/*
* Find the listed button and create its widget
*/
for (btp = &ButtonTable[0]; btp->name != NULL; btp++)
{
if (!strcasecmp(btp->name, name))
{
if (btp->toggle)
{
snprintf(accel, sizeof(accel) - 1,
"%s: toggle() notify()", btp->accel);
btp->w = XtVaCreateManagedWidget(btp->name,
toggleWidgetClass, box,
XtNaccelerators,
XtParseAcceleratorTable(accel),
NULL);
}
else
{
snprintf(accel, sizeof(accel) - 1,
"%s: set() notify() unset()", btp->accel);
btp->w = XtVaCreateManagedWidget(btp->name,
commandWidgetClass, box,
XtNaccelerators,
XtParseAcceleratorTable(accel),
NULL);
}
XtAddCallback(btp->w, XtNcallback, btp->cb, (XtPointer)wc);
break;
}
}
if (!strcasecmp(name, "open")) wc->open = btp->w;
else if (!strcasecmp(name, "back")) wc->back = btp->w;
else if (!strcasecmp(name, "reload")) wc->reload = btp->w;
else if (!strcasecmp(name, "cancel")) wc->cancel = btp->w;
else if (!strcasecmp(name, "quit")) wc->quit = btp->w;
else if (!strcasecmp(name, "home")) wc->home = btp->w;
else if (!strcasecmp(name, "help")) wc->help = btp->w;
else if (!strcasecmp(name, "dup")) wc->dup = btp->w;
else if (!strcasecmp(name, "addmark")) wc->addmark = btp->w;
else if (!strcasecmp(name, "viewmark")) wc->viewmark = btp->w;
else if (!strcasecmp(name, "source")) wc->source = btp->w;
else if (!strcasecmp(name, "save")) wc->save = btp->w;
else if (!strcasecmp(name, "find")) wc->find = btp->w;
else if (!strcasecmp(name, "bookmark")) wc->bookmark = btp->w;
/*
* Skip to the next comma-delimited item in the list
*/
while (*list && *list != ',')
list++;
if (*list == ',')
list++;
}
return;
}
/*
* InstallAccelerators
*/
static void
InstallAccelerators(w)
Widget w;
{
struct ButtonTable *btp;
for (btp = &ButtonTable[0]; btp->name != NULL; btp++)
if(btp->w)
XtInstallAllAccelerators(w,btp->w);
}
#define BUTTON_LIST "quit, open, home, back, reload, source, save, bookmark, dup, find, cancel"
/*
* These are initialized in fallback.c
*/
#define offset(field) XtOffset(ChimeraContext, field)
static XtResource resource_list[] =
{
{ "button1Box", "BoxList", XtRString, sizeof(char *),
offset(button1Box), XtRString, BUTTON_LIST },
{ "button2Box", "BoxList", XtRString, sizeof(char *),
offset(button2Box), XtRString, NULL },
};
/*
* HeadCreate
*
* Setup chimera in a widget.
*/
static void
CreateWidgets(wc, name)
ChimeraContext wc;
char *name;
{
Widget paned, box, form;
Atom delete;
wc->toplevel = XtVaAppCreateShell(name, "Chimera",
topLevelShellWidgetClass,
wc->cres->dpy,
NULL);
XtGetApplicationResources(wc->toplevel, wc,
resource_list, XtNumber(resource_list),
NULL, 0);
/*
* Main window pane
*/
paned = XtCreateManagedWidget("paned",
panedWidgetClass, wc->toplevel,
NULL, 0);
/*
* Button pane(s)
*/
if (wc->button1Box && *wc->button1Box)
{
box = XtCreateManagedWidget("box1", boxWidgetClass, paned, NULL, 0);
AddButtons(wc, box, wc->button1Box);
}
if (wc->button2Box && *wc->button2Box)
{
box = XtCreateManagedWidget("box2", boxWidgetClass, paned, NULL, 0);
AddButtons(wc, box, wc->button2Box);
}
/*
* URL pane
*/
form = XtVaCreateManagedWidget("urlform", formWidgetClass, paned, NULL);
XtVaCreateManagedWidget("urllabel", labelWidgetClass, form, NULL);
wc->url = XtVaCreateManagedWidget("url",
textfieldWidgetClass, form,
XtNstring, "",
NULL);
XtOverrideTranslations(wc->url,
XtParseTranslationTable
("<Key>Return: ReturnAction()"));
/*
* Message pane.
*/
box = XtCreateManagedWidget("box4", boxWidgetClass, paned, NULL, 0);
wc->message = XtVaCreateManagedWidget("message",
textfieldWidgetClass, box,
NULL);
/*
* WWW widget
*/
wc->tstack = StackCreateToplevel(wc, paned);
XtRealizeWidget(wc->toplevel);
delete = XInternAtom(XtDisplay(wc->toplevel), "WM_DELETE_WINDOW", False);
XSetWMProtocols (wc->cres->dpy, XtWindow(wc->toplevel), &delete, 1);
XtOverrideTranslations (wc->toplevel,
XtParseTranslationTable
("<Message>WM_PROTOCOLS: DeleteAction()"));
/*
* Accelerators
*/
InstallAccelerators(paned);
return;
}
/*
* HeadDestroy
*/
void
HeadDestroy(wc)
ChimeraContext wc;
{
StackDestroy(wc->tstack);
GListRemoveItem(wc->cres->heads, wc);
XtDestroyWidget(wc->toplevel);
MPDestroy(wc->mp);
ChimeraRemoveReference(wc->cres);
return;
}
/*
* ClearDialogValue
*/
static void
ClearDialogValue(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
if ((w = XtParent(w)) != NULL) MyDialogSetValue(w, "");
return;
}
/*
* CreateDialog
*/
Widget
CreateDialog(p, name, ofunc, dfunc, rfunc, closure)
Widget p;
char *name;
void (*ofunc)();
void (*dfunc)();
void (*rfunc)();
XtPointer closure;
{
Widget w, dw;
Window rw, cw;
int rx, ry, wx, wy;
unsigned int mask;
XQueryPointer(XtDisplay(p), DefaultRootWindow(XtDisplay(p)),
&rw, &cw,
&rx, &ry,
&wx, &wy,
&mask);
w = XtVaCreatePopupShell(name,
transientShellWidgetClass, p,
XtNx, rx - 2,
XtNy, ry - 2,
NULL);
dw = XtVaCreateManagedWidget("dialog",
mydialogWidgetClass, w,
XtNvalue, "",
NULL);
MyDialogAddButton(dw, "ok", ofunc, closure);
MyDialogAddButton(dw, "clear", ClearDialogValue, closure);
MyDialogAddButton(dw, "dismiss", dfunc, closure);
XtAddCallback(dw, XtNcallback, rfunc, closure);
XtRealizeWidget(w);
return(w);
}
/*
* GetDialogWidget
*/
Widget
GetDialogWidget(w)
Widget w;
{
return(XtNameToWidget(w, "dialog"));
}
/*
* OOpen
*/
static void
OOpen(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
char *url;
if ((url = MyDialogGetValue(GetDialogWidget(wc->openpop))) == NULL) return;
StackOpen(wc->tstack, RequestCreate(wc->cres, url, NULL));
XtPopdown(wc->openpop);
return;
}
/*
* DOpen
*/
static void
DOpen(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
XtPopdown(wc->openpop);
return;
}
/*
* Open
*/
static void
Open(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
if (wc->openpop == NULL)
{
wc->openpop = CreateDialog(wc->toplevel, "openpop",
OOpen, DOpen, OOpen, (XtPointer)wc);
}
XtPopup(wc->openpop, XtGrabNone);
return;
}
/*
* Back
*/
static void
Back(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
StackBack(wc->tstack);
return;
}
/*
* Reload
*/
static void
Reload(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
StackReload(wc->tstack);
return;
}
/*
* Cancel
*/
static void
Cancel(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
StackCancel(wc->tstack);
return;
}
/*
* Quit
*/
static void
Quit(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
HeadDestroy((ChimeraContext)cldata);
return;
}
/*
* Source
*/
static void
Source(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
if (wc->cres->plainhooks == NULL) XtVaSetValues(w, XtNstate, False, NULL);
else
{
if (cbdata) StackSetRender(wc->tstack, wc->cres->plainhooks);
else StackSetRender(wc->tstack, NULL);
StackRedraw(wc->tstack);
}
return;
}
/*
* Save
*/
static void
Save(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
char *url;
ChimeraRequest *wr;
if ((url = StackGetCurrentURL(wc->tstack)) == NULL) return;
if ((wr = RequestCreate(wc->cres, url, NULL)) == NULL)
{
TextFieldSetString(wc->message, "Invalid URL.");
return;
}
DownloadOpen(wc->cres, wr);
return;
}
/*
* Home
*/
static void
Home(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
StackHome(wc->tstack);
return;
}
/*
* Help
*/
static void
Help(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
char *url;
if ((url = ResourceGetString(wc->cres, "chimera.helpURL")) != NULL)
{
StackOpen(wc->tstack, RequestCreate(wc->cres, url, NULL));
}
return;
}
/*
* Dup
*/
static void
Dup(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
char *url;
ChimeraRequest *wr;
/* grab URL from to-be-cloned window */
if ((url = ResourceGetString(wc->cres, "chimera.cloneHome")) == NULL)
{
url = StackGetCurrentURL(wc->tstack);
}
if (url != NULL) wr = RequestCreate(wc->cres, url, NULL);
else wr = NULL;
HeadCreate(wc->cres, NULL, wr);
return;
}
/*
* AddMark
*/
void
AddMark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
char *title;
char *url;
ChimeraRender wn;
if (wc->cres->bc == NULL) return;
wn = StackToRender(wc->tstack);
if ((url = RenderQuery(wn, "url")) == NULL) return;
if ((title = RenderQuery(wn, "title")) == NULL) title = url;
BookmarkAdd(wc->cres->bc, title, url);
return;
}
/*
* ViewMark
*/
void
ViewMark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
MemPool mp;
char *filename;
char *url;
const char *fformat = "file:%s";
mp = MPCreate();
if ((filename = ResourceGetFilename(wc->cres,
mp, "bookmark.filename")) == NULL)
{
return;
}
url = (char *)MPGet(mp, strlen(fformat) + strlen(filename) + 1);
sprintf (url, fformat, filename);
StackOpen(wc->tstack, RequestCreate(wc->cres, url, NULL));
MPDestroy(mp);
return;
}
/*
* Bookmark
*/
static void
Bookmark(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
wc->cres->bmcontext = wc;
if (wc->cres->bc != NULL) BookmarkShow(wc->cres->bc);
return;
}
/*
* OFind
*/
static void
OFind(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
char *str;
if ((str = MyDialogGetValue(GetDialogWidget(wc->findpop))) == NULL)
{
return;
}
RenderSearch(StackToRender(wc->tstack), str, 0);
XtPopdown(wc->findpop);
return;
}
/*
* DFind
*/
static void
DFind(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
XtPopdown(wc->findpop);
return;
}
/*
* Find
*/
static void
Find(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ChimeraContext wc = (ChimeraContext)cldata;
if (wc->findpop == NULL)
{
wc->findpop = CreateDialog(wc->toplevel, "findpop",
OFind, DFind, OFind, (XtPointer)wc);
}
XtPopup(wc->findpop, XtGrabNone);
return;
}
/*
* HeadCreate
*
* Frontend that sorts out which URL to use for a new head and then
* creates a new head.
*/
void
HeadCreate(cres, first, lastresort)
ChimeraResources cres;
ChimeraRequest *first;
ChimeraRequest *lastresort;
{
ChimeraContext wc;
char *buffer;
char *url;
int count;
MemPool mp;
ChimeraRequest *wr = NULL;
char base_url[255];
/*
* Default base URL; this allows filenames to be used on the
* command line
*/
strcpy( base_url, "file:" ) ;
getcwd( base_url + 5, sizeof(base_url) - 5 ) ;
strcat( base_url, "/" ) ;
ChimeraAddReference(cres);
mp = MPCreate();
wc = (ChimeraContext)MPCGet(mp, sizeof(struct ChimeraContextP));
wc->mp = mp;
wc->cres = cres;
GListAddHead(cres->heads, wc);
CreateWidgets(wc, "chimera");
/*
* If an override URL is supplied then try to use that.
*/
if (first != NULL) wr = first;
/*
* Look inside the cutbuffer for a valid URL.
*/
if (wr == NULL)
{
buffer = XFetchBytes(cres->dpy, &count);
if (count > 0)
{
mp = MPCreate();
url = (char *)MPCGet(mp, count + 1);
memcpy(url, buffer, count);
url[count] = '\0';
XFree(buffer);
if ((wr = RequestCreate(wc->cres, url, base_url)) != NULL)
{
XStoreBytes(cres->dpy, "", 0);
}
MPDestroy(mp);
}
}
/*
* Look for the caller-supplied last resort.
*/
if (wr == NULL && lastresort != NULL) wr = lastresort;
/*
* Check the standard environment variable.
*/
if (wr == NULL)
{
if ((url = getenv("WWW_HOME")) != NULL)
{
if ((wr = RequestCreate(wc->cres, url, base_url)) == NULL)
{
fprintf (stderr, "WWW_HOME (%s) is invalid.\n", url);
}
}
}
/*
* Check the chimera resource variable.
*/
if (wr == NULL)
{
if ((url = ResourceGetString(wc->cres, "chimera.homeURL")) != NULL)
{
if ((wr = RequestCreate(wc->cres, url, base_url)) == NULL)
{
fprintf (stderr, "chimera.homeURL (%s) is invalid.\n", url);
}
}
}
/*
* This better work...
*/
if (wr == NULL)
{
wr = RequestCreate(wc->cres, "file:/", NULL);
}
myassert(wr != NULL, "ERROR: No valud URLs found for new head.\n");
StackOpen(wc->tstack, wr);
return;
}
/*
* HeadPrintMessage
*/
void
HeadPrintMessage(wc, message)
ChimeraContext wc;
char *message;
{
if (message == NULL) message = "";
TextFieldSetString(wc->message, message);
return;
}
/*
* HeadPrintURL
*/
void
HeadPrintURL(wc, url)
ChimeraContext wc;
char *url;
{
if (url == NULL) url = "";
TextFieldSetString(wc->url, url);
return;
}

440
chimera/io.c Normal file
View File

@ -0,0 +1,440 @@
/*
* io.c
*
* Copyright (C) 1994-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <time.h>
#include <errno.h>
#ifdef __QNX__
#include <ioctl.h>
#include <unix.h> /* for O_NDELAY/O_NONBLOCK, gethostname() */
#define FNDELAY O_NDELAY
#else
#ifdef __EMX__
#define FNDELAY O_NDELAY
#endif
#include <fcntl.h>
#endif
#if (defined(SYSV) || defined(SVR4)) && (defined(sun) || defined(hpux) || defined(_nec_ews_svr4))
#include <sys/file.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <X11/IntrinsicP.h>
#include "port_after.h"
#include "ChimeraP.h"
#include "ChimeraStream.h"
struct ChimeraStreamP
{
bool destroyed;
MemPool mp;
ChimeraResources cres;
int s;
int as;
unsigned long addr;
int port;
bool bound;
bool accepted;
/* read callback */
ChimeraStreamCallback rdfunc;
void *rdclosure;
byte *rdb;
size_t rdlen;
XtInputId rdid;
/* write callback */
ChimeraStreamCallback wrfunc;
void *wrclosure;
byte *wrb;
size_t wrmax;
size_t wri;
XtInputId wrid;
};
static void WriteStreamHandler _ArgProto((XtPointer, int *, XtInputId *));
static void ReadStreamHandler _ArgProto((XtPointer, int *, XtInputId *));
/*
* WriteStreamHandler
*/
static void
WriteStreamHandler(cldata, netfd, xid)
XtPointer cldata;
int *netfd;
XtInputId *xid;
{
ChimeraStream ps = (ChimeraStream)cldata;
ssize_t wlen;
int s;
if (ps->bound) s = ps->as;
else s = ps->s;
wlen = write(s, ps->wrb + ps->wri, ps->wrmax - ps->wri);
if (wlen < 0)
{
if (errno != EWOULDBLOCK)
{
XtRemoveInput(ps->wrid);
ps->wrid = 0;
CMethod(ps->wrfunc)(ps, -1, ps->wrclosure);
}
}
else
{
ps->wri += wlen;
if (ps->wri == ps->wrmax)
{
XtRemoveInput(ps->wrid);
ps->wrid = 0;
CMethod(ps->wrfunc)(ps, 0, ps->wrclosure);
}
}
return;
}
/*
* ReadStreamHandler
*/
static void
ReadStreamHandler(cldata, netfd, xid)
XtPointer cldata;
int *netfd;
XtInputId *xid;
{
ChimeraStream ps = (ChimeraStream)cldata;
ssize_t rlen;
struct sockaddr addr;
int s;
int namlen;
if (ps->bound)
{
if (!ps->accepted)
{
namlen = sizeof(addr);
if ((ps->as = accept(ps->s, &addr, &namlen)) < 0)
{
XtRemoveInput(ps->rdid);
ps->rdid = 0;
CMethod(ps->rdfunc)(ps, -1, ps->rdclosure);
}
ps->accepted = true;
}
s = ps->as;
}
else s = ps->s;
rlen = read(s, ps->rdb, ps->rdlen);
if (rlen < 0)
{
if (errno != EWOULDBLOCK)
{
XtRemoveInput(ps->rdid);
ps->rdid = 0;
CMethod(ps->rdfunc)(ps, rlen, ps->rdclosure);
}
}
else
{
XtRemoveInput(ps->rdid);
ps->rdid = 0;
CMethod(ps->rdfunc)(ps, rlen, ps->rdclosure);
}
return;
}
/*
* StreamRead
*/
void
StreamRead(ps, b, blen, func, closure)
ChimeraStream ps;
byte *b;
size_t blen;
ChimeraStreamCallback func;
void *closure;
{
int s;
myassert(!ps->destroyed, "ChimeraStream destroyed");
if (ps->bound && ps->accepted) s = ps->as;
else s = ps->s;
ps->rdb = b;
ps->rdlen = blen;
ps->rdfunc = func;
ps->rdclosure = closure;
ps->rdid = XtAppAddInput(ps->cres->appcon, s,
(XtPointer)XtInputReadMask,
ReadStreamHandler, (XtPointer)ps);
return;
}
/*
* StreamWrite
*/
void
StreamWrite(ps, b, blen, func, closure)
ChimeraStream ps;
byte *b;
size_t blen;
ChimeraStreamCallback func;
void *closure;
{
myassert(!ps->destroyed, "ChimeraStream destroyed.");
ps->wrb = b;
ps->wri = 0;
ps->wrmax = blen;
ps->wrfunc = func;
ps->wrclosure = closure;
ps->wrid = XtAppAddInput(ps->cres->appcon,
ps->s,
(XtPointer)XtInputWriteMask,
WriteStreamHandler, (XtPointer)ps);
return;
}
/*
* StreamCreateINet
*/
ChimeraStream
StreamCreateINet(cres, host, port)
ChimeraResources cres;
char *host;
int port;
{
ChimeraStream ps;
int s;
int rval;
struct sockaddr_in addr;
struct hostent *hp;
MemPool mp;
if (host == NULL) return(NULL);
memset(&addr, 0, sizeof(addr));
/* fix by Jim Rees so that numeric addresses are dealt with */
if ((addr.sin_addr.s_addr = inet_addr(host)) == -1)
{
if ((hp = (struct hostent *)gethostbyname(host)) == NULL)
{
return(NULL);
}
memcpy(&(addr.sin_addr), hp->h_addr, hp->h_length);
}
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s < 0) return(NULL);
#ifdef __QNX__
ioctl(s, FNDELAY, 0);
#else
fcntl(s, F_SETFL, FNDELAY);
#endif
if ((rval = connect(s, (struct sockaddr *)&addr, sizeof(addr))) != 0)
{
if (errno != EINPROGRESS)
{
close(s);
return(NULL);
}
}
mp = MPCreate();
ps = (ChimeraStream)MPCGet(mp, sizeof(struct ChimeraStreamP));
ps->mp = mp;
ps->cres = cres;
ps->s = s;
return((ChimeraStream)ps);
}
/*
* StreamCreateINet2
*/
ChimeraStream
StreamCreateINet2(cres)
ChimeraResources cres;
{
MemPool mp;
ChimeraStream ps;
int s;
struct sockaddr_in addr;
struct sockaddr_in xaddr;
struct hostent *hp;
int namlen;
char host[BUFSIZ];
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s < 0) return(NULL);
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = 0;
if (bind(s, (struct sockaddr *) &addr, sizeof (addr)) < 0)
{
close(s);
return(NULL);
}
if (listen(s, 1) < 0)
{
close(s);
return(NULL);
}
if (gethostname(host, sizeof(host) - 1) == 0)
{
/* fix by Jim Rees so that numeric addresses are dealt with */
if ((xaddr.sin_addr.s_addr = inet_addr(host)) == -1)
{
if ((hp = (struct hostent *)gethostbyname(host)) == NULL)
{
close(s);
return(NULL);
}
memcpy(&(xaddr.sin_addr), hp->h_addr, hp->h_length);
}
}
else
{
close(s);
return(NULL);
}
namlen = sizeof(addr);
if (getsockname(s, (struct sockaddr *)&addr, &namlen) < 0)
{
close(s);
return(NULL);
}
#ifdef __QNX__
ioctl(s, FNDELAY, 0);
#else
fcntl(s, F_SETFL, FNDELAY);
#endif
mp = MPCreate();
ps = (ChimeraStream)MPCGet(mp, sizeof(struct ChimeraStreamP));
ps->mp = mp;
ps->cres = cres;
ps->s = s;
ps->port = (int)addr.sin_port;
ps->addr = xaddr.sin_addr.s_addr;
ps->bound = true;
return((ChimeraStream)ps);
}
/*
* StreamDestroy
*/
void
StreamDestroy(ps)
ChimeraStream ps;
{
myassert(!ps->destroyed, "ChimeraStream destroyed");
ps->destroyed = true;
if (ps->rdid != 0) XtRemoveInput(ps->rdid);
if (ps->wrid != 0) XtRemoveInput(ps->wrid);
close(ps->s);
MPDestroy(ps->mp);
return;
}
/*
* StreamGetINetPort
*/
int
StreamGetINetPort(ps)
ChimeraStream ps;
{
return(ps->port);
}
/*
* StreamGetINetAddr
*/
unsigned long
StreamGetINetAddr(ps)
ChimeraStream ps;
{
return(ps->addr);
}
/*
* StreamCreate
*/
ChimeraStream
StreamCreate(cres, fd)
ChimeraResources cres;
int fd;
{
MemPool mp;
ChimeraStream ps;
fcntl(fd, F_SETFL, FNDELAY);
mp = MPCreate();
ps = (ChimeraStream)MPCGet(mp, sizeof(struct ChimeraStreamP));
ps->mp = mp;
ps->cres = cres;
ps->s = fd;
return((ChimeraStream)ps);
}

368
chimera/main.c Normal file
View File

@ -0,0 +1,368 @@
/*
* main.c
*
* Copyright (C) 1993-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <signal.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Toggle.h>
#include "port_after.h"
#include "TextField.h"
#include "MyDialog.h"
#include "ChimeraP.h"
static void sigigh_handler _ArgProto(());
static void xtWarningHandler _ArgProto((String));
static void xtErrorHandler _ArgProto((String));
static int xErrorHandler _ArgProto((Display *, XErrorEvent *));
static void ChimeraCleanup _ArgProto((ChimeraResources));
static ChimeraResources ResourcesCreate _ArgProto((int *, char **));
static void ResourcesDestroy _ArgProto((ChimeraResources));
extern char *fallback_resources[];
static ChimeraResources globalcres;
void
main(argc, argv)
int argc;
char **argv;
{
char base_url[255];
signal(SIGINT, sigigh_handler);
signal(SIGQUIT, sigigh_handler);
signal(SIGHUP, sigigh_handler);
signal(SIGTERM, sigigh_handler);
signal(SIGPIPE, SIG_IGN);
StartReaper();
globalcres = ResourcesCreate(&argc, argv);
/*
* Default base URL; this allows filenames to be used on the
* command line
*/
strcpy( base_url, "file:" ) ;
getcwd( base_url + 5, sizeof(base_url) - 5 ) ;
strcat( base_url, "/" ) ;
if (argc > 1) HeadCreate(globalcres,
RequestCreate(globalcres, argv[argc - 1], base_url),
NULL);
else HeadCreate(globalcres, NULL, NULL);
/*
* And away we go...
*/
XtAppMainLoop(globalcres->appcon);
}
/*
* sigiqh_handler
*/
static void
sigigh_handler()
{
return;
}
/*
* xErrorHandler
*/
int
xErrorHandler(dpy, xe)
Display *dpy;
XErrorEvent *xe;
{
fprintf (stderr, "X error\n");
fflush(stderr);
return(0);
}
/*
* xtErrorHandler
*/
static void
xtErrorHandler(msg)
String msg;
{
fprintf (stderr, "%s\n", msg);
fflush(stderr);
return;
}
/*
* xtWarningHandler
*/
static void
xtWarningHandler(msg)
String msg;
{
fprintf (stderr, "%s\n", msg);
fflush(stderr);
return;
}
/*
* ChimeraAddReference
*/
void
ChimeraAddReference(cres)
ChimeraResources cres;
{
cres->refcount++;
return;
}
/*
* ChimeraCleanup
*/
static void
ChimeraCleanup(cres)
ChimeraResources cres;
{
if (cres->bc != NULL) BookmarkDestroyContext(cres->bc);
ResourcesDestroy(cres);
if (cres->logfp != NULL) fclose(cres->logfp);
GListDestroy(cres->heads);
MPPrintStatus();
GListPrintStatus();
exit(0);
}
/*
* ChimeraRemoveReference
*/
void
ChimeraRemoveReference(cres)
ChimeraResources cres;
{
cres->refcount--;
if (cres->refcount == 0) ChimeraCleanup(cres);
return;
}
static void DeleteAction(), ReturnAction();
static XtActionsRec actionsList[] =
{
{ "ReturnAction", (XtActionProc)ReturnAction },
{ "DeleteAction", (XtActionProc)DeleteAction },
};
/*
* DeleteAction
*/
static void
DeleteAction()
{
ChimeraCleanup(globalcres);
}
/*
* ReturnAction
*/
static void
ReturnAction(w, xe, params, num_params)
Widget w;
XEvent *xe;
String *params;
Cardinal *num_params;
{
ChimeraContext c;
char *url;
for (c = (ChimeraContext)GListGetHead(globalcres->heads); c != NULL;
c = (ChimeraContext)GListGetNext(globalcres->heads))
{
if (c->url == w)
{
url = TextFieldGetString(c->url);
if (url == NULL || url[0] == '\0')
{
TextFieldSetString(c->url, url);
break;
}
else
{
StackOpen(c->tstack, RequestCreate(globalcres, url, NULL));
}
break;
}
}
return;
}
ChimeraResources
ResourcesCreate(argcp, argv)
int *argcp;
char *argv[];
{
ChimeraResources cres;
MemPool mp, tmp;
char *f, *filename;
char *logfile;
char *dbfiles;
mp = MPCreate();
cres = (ChimeraResources)MPCGet(mp, sizeof(struct ChimeraResourcesP));
cres->mp = mp;
cres->sources = GListCreateX(mp);
cres->sourcehooks = GListCreateX(mp);
cres->renderhooks = GListCreateX(mp);
cres->mimes = GListCreateX(mp);
cres->timeouts = GListCreateX(mp);
cres->oldtimeouts = GListCreateX(mp);
cres->heads = GListCreateX(mp);
cres->stacks = GListCreateX(mp);
cres->cs = SchedulerCreate();
ResourceAddString(cres, "cache.Directory: /tmp");
ResourceAddString(cres, "http.userAgent: Chimera/2.0alpha");
ResourceAddString(cres, "mailto.newhead: true");
if ((dbfiles = getenv("CHIMERA_DBFILES")) == NULL)
{
dbfiles = "~/.chimera/resources";
}
f = dbfiles;
while ((filename = mystrtok(f, ':', &f)) != NULL)
{
ResourceAddFile(cres, filename);
}
cres->cc = CacheCreate(cres);
if (ResourceGetInt(cres, "chimera.maxDownloads", &cres->maxiocnt) == NULL)
{
cres->maxiocnt = 4;
}
else if (cres->maxiocnt <= 1) cres->maxiocnt = 1;
if (ResourceGetBool(cres, "chimera.printLoadMessages",
&cres->printLoadMessages) == NULL)
{
cres->printLoadMessages = false;
}
if (ResourceGetBool(cres, "chimera.printTaskInfo",
&cres->printTaskInfo) == NULL)
{
cres->printTaskInfo = false;
}
/*
* Initialize the Xt stuff.
*/
XtToolkitInitialize();
cres->appcon = XtCreateApplicationContext();
XSetErrorHandler(xErrorHandler);
XtAppSetErrorHandler(cres->appcon, xtErrorHandler);
XtAppSetWarningHandler(cres->appcon, xtWarningHandler);
XtAppSetFallbackResources(cres->appcon, fallback_resources);
cres->dpy = XtOpenDisplay(cres->appcon, NULL,
NULL, "Chimera",
NULL, 0,
argcp, argv);
if (cres->dpy == NULL)
{
fprintf (stderr, "Could not open display.\n");
exit(1);
}
XtAppAddActions(cres->appcon, actionsList, XtNumber(actionsList));
cres->bc = BookmarkCreateContext(cres);
InitChimeraBuiltins(cres);
tmp = MPCreate();
if ((logfile = ResourceGetFilename(cres, tmp,
"chimera.urlLogFile")) != NULL)
{
cres->logfp = fopen(logfile, "a");
}
MPDestroy(tmp);
cres->plainhooks = RenderGetHooks(cres, "text/plain");
return(cres);
}
static void
ResourcesDestroy(cres)
ChimeraResources cres;
{
ChimeraRenderHooks *rhooks;
ChimeraSourceHooks *shooks;
GList list;
if (cres->cc != NULL) CacheDestroy(cres->cc);
list = cres->renderhooks;
for (rhooks = (ChimeraRenderHooks *)GListGetHead(list); rhooks != NULL;
rhooks = (ChimeraRenderHooks *)GListGetNext(list))
{
if (rhooks->class_destroy != NULL)
{
CMethod(rhooks->class_destroy)(rhooks->class_context);
}
}
list = cres->sourcehooks;
for (shooks = (ChimeraSourceHooks *)GListGetHead(list); shooks != NULL;
shooks = (ChimeraSourceHooks *)GListGetNext(list))
{
if (shooks->class_destroy != NULL)
{
CMethod(shooks->class_destroy)(shooks->class_closure);
}
}
if (cres->db != NULL) XrmDestroyDatabase(cres->db);
MPDestroy(cres->mp);
return;
}

299
chimera/render.c Normal file
View File

@ -0,0 +1,299 @@
/*
* render.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "ChimeraP.h"
struct ChimeraRenderP
{
MemPool mp; /* memory pool */
ChimeraRenderHooks rh; /* renderer hooks */
ChimeraRenderHooks orh; /* override renderer hooks */
void *rc; /* renderer context */
void *orc; /* override renderer context */
ChimeraContext wc;
ChimeraGUI wd;
ChimeraSink wp;
ChimeraRenderActionProc rap; /* kludge */
void *rapc; /* kludge context */
};
/*
* RenderDestroy
*/
void
RenderDestroy(wn)
ChimeraRender wn;
{
if (wn->rh.destroy != NULL) CMethod(wn->rh.destroy)(wn->rc);
MPDestroy(wn->mp);
return;
}
/*
* RenderAdd
*/
void
RenderAdd(wn)
ChimeraRender wn;
{
if (wn->rh.add != NULL) CMethod(wn->rh.add)(wn->rc);
return;
}
/*
* RenderEnd
*/
void
RenderEnd(wn)
ChimeraRender wn;
{
if (wn->rh.end != NULL) CMethod(wn->rh.end)(wn->rc);
return;
}
/*
* RenderQuery
*/
char *
RenderQuery(wn, key)
ChimeraRender wn;
char *key;
{
if (wn->rh.query != NULL)
{
return(CMethodBytePtr(wn->rh.query)(wn->rc, key));
}
return(NULL);
}
/*
* RenderSearch
*/
int
RenderSearch(wn, key, mode)
ChimeraRender wn;
char *key;
int mode;
{
if (wn->rh.search != NULL)
{
return(CMethodInt(wn->rh.search)(wn->rc, key, mode));
}
return(-1);
}
/*
* RenderCancel
*/
void
RenderCancel(wn)
ChimeraRender wn;
{
if (wn->rh.cancel != NULL)
{
CMethodVoid(wn->rh.cancel)(wn->rc);
}
return;
}
/*
* RenderCreate
*/
ChimeraRender
RenderCreate(wc, wd, wp, rh, orh, orc, state, rap, rapc)
ChimeraContext wc;
ChimeraGUI wd;
ChimeraSink wp;
ChimeraRenderHooks *rh, *orh;
void *orc;
void *state;
ChimeraRenderActionProc rap;
void *rapc;
{
ChimeraRender wn;
MemPool mp;
myassert(rh->init != NULL, "Callback is NULL.");
myassert(rh->add != NULL, "Callback is NULL.");
myassert(rh->end != NULL, "Callback is NULL.");
myassert(rh->destroy != NULL, "Callback is NULL.");
myassert(rh->expose != NULL, "Callback is NULL.");
myassert(rh->cancel != NULL, "Callback is NULL.");
mp = MPCreate();
wn = (ChimeraRender)MPCGet(mp, sizeof(struct ChimeraRenderP));
wn->mp = mp;
wn->wc = wc;
wn->wd = wd;
wn->wp = wp;
wn->orc = orc;
wn->rap = rap;
wn->rapc = rapc;
memcpy(&(wn->rh), rh, sizeof(ChimeraRenderHooks));
if (orh != NULL) memcpy(&(wn->orh), orh, sizeof(ChimeraRenderHooks));
if ((wn->rc =
CMethodVoidPtr(rh->init)(wn, rh->class_context, state)) == NULL)
{
MPDestroy(wn->mp);
return(NULL);
}
GUIAddRender(wd, wn);
return(wn);
}
void *
RenderGetState(wn)
ChimeraRender wn;
{
if (wn->rh.getstate != NULL)
{
return(CMethodVoidPtr(wn->rh.getstate)(wn->rc));
}
return(NULL);
}
void
RenderAction(wn, wr, action)
ChimeraRender wn;
ChimeraRequest *wr;
char *action;
{
if (wn->rap == NULL)
{
if (strcmp("download", action) == 0) DownloadOpen(wn->wc->cres, wr);
else if (strcmp("external", action) == 0) ViewOpen(wn->wc->cres, wr);
else fprintf (stderr, "Action cannot be taken. Bug.\n");
}
else
{
CMethod(wn->rap)(wn->rapc, wn, wr, action);
}
return;
}
ChimeraGUI
RenderToGUI(wn)
ChimeraRender wn;
{
return(wn->wd);
}
ChimeraSink
RenderToSink(wn)
ChimeraRender wn;
{
return(wn->wp);
}
ChimeraContext
RenderToContext(wn)
ChimeraRender wn;
{
return(wn->wc);
}
void
RenderSendMessage(wn, message)
ChimeraRender wn;
char *message;
{
HeadPrintMessage(wn->wc, message);
return;
}
void
RenderExpose(wn, x, y, width, height)
ChimeraRender wn;
int x, y;
unsigned int width, height;
{
if (wn->rh.expose != NULL)
{
CMethodBool(wn->rh.expose)(wn->rc, x, y, width, height);
}
return;
}
void
RenderSelect(wn, x, y, action)
ChimeraRender wn;
int x, y;
char *action;
{
if (wn->orc != NULL && wn->orh.select != NULL)
{
CMethodBool(wn->orh.select)(wn->orc, x, y, action);
}
else if (wn->rh.select != NULL)
{
CMethodBool(wn->rh.select)(wn->rc, x, y, action);
}
return;
}
void
RenderMotion(wn, x, y)
ChimeraRender wn;
int x, y;
{
if (wn->orc != NULL && wn->orh.motion != NULL)
{
CMethodBool(wn->orh.motion)(wn->orc, x, y);
}
if (wn->rh.motion != NULL)
{
CMethodBool(wn->rh.motion)(wn->rc, x, y);
}
return;
}
/*
* RenderToResources
*/
ChimeraResources
RenderToResources(wn)
ChimeraRender wn;
{
return(wn->wc->cres);
}

644
chimera/request.c Normal file
View File

@ -0,0 +1,644 @@
/*
* request.c
*
* Copyright (c) 1995 Erik Corry ehcorry@inet.uni-c.dk
* Copyright (c) 1996-1997 John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNAME
#include <sys/utsname.h>
#endif
#include <X11/IntrinsicP.h>
#include "port_after.h"
#include "ChimeraP.h"
static bool match_no_proxy _ArgProto((char *, char *));
static bool match_no_proxy_list _ArgProto((char *, char *, char *, char *));
static bool match_host_name _ArgProto((char *, char *));
static URLParts *get_proxy _ArgProto((MemPool, URLParts *));
static bool
match_no_proxy(remote_host, no_proxy_domain)
char *remote_host;
char *no_proxy_domain;
{
int remote_len = strlen(remote_host);
int no_proxy_len = strlen(no_proxy_domain);
int min_len = MIN(remote_len, no_proxy_len);
/*
* avoid matching parts of domain names not divided by dots.
*/
if(remote_len < no_proxy_len)
if(no_proxy_domain[no_proxy_len - min_len - 1] != '.')
return false;
if(remote_len > no_proxy_len)
if(remote_host[remote_len - min_len - 1] != '.')
return false;
/*
* Do ends of strings match?
*/
if (strncmp(remote_host + remote_len - min_len,
no_proxy_domain + no_proxy_len - min_len,
min_len) == 0)
return(true);
else
return(false);
}
/*
* If no_proxy is not defined, then use the part that is common
* between the proxy server's name and the uname of the current host.
* I.e. if the proxy server is wwwproxy.firewall.dreadco.com, and the
* local host is dilbert-sparc.widget-dept.dreadco.com, then the proxy
* is not used for *.dreadco.com addresses. Or if your proxy is set to
* http://wwwcache.hensa.ac.uk#8080/ and your machine is aiai.ed.ac.uk,
* then ac.uk addresses will not go via the cache.
*/
static bool
match_no_proxy_list(remote_host, local_host, no_proxy_list, proxy_host)
char *remote_host;
char *local_host;
char *no_proxy_list;
char *proxy_host;
{
if (no_proxy_list != NULL)
{
char *local_no_proxy_list;
char *no_proxy_elt;
MemPool mp;
int i;
int l = strlen(no_proxy_list);
mp = MPCreate();
/*
* Step through comma-separated list of domains/machines for
* which no proxy should be used
*/
no_proxy_elt = local_no_proxy_list = (char *)MPGet(mp, l + 1);
for (i = 0; i <= l; i++)
{
char temp;
if ((temp = local_no_proxy_list[i] = no_proxy_list[i]) == ',' ||
temp == 0)
{
/* Zero out comma in copy of list */
local_no_proxy_list[i] = 0;
if(match_no_proxy(remote_host, no_proxy_elt))
{
MPDestroy(mp);
return true;
}
/* advance pointer to next element in copy of list */
no_proxy_elt = local_no_proxy_list + i + 1;
}
}
MPDestroy(mp);
return(false);
}
else
{
/*
* Use default no_proxy. See comments above.
*/
int i, j;
int l, pl;
if(!local_host) return false;
l = strlen(local_host);
pl = strlen(proxy_host);
for (i = l - 1, j = pl -1; i && j; i--, j--)
{
if(local_host[i] != proxy_host[i])
{
/* We have found the first point where local_host and proxy_host
* differ (searching back from end). Now find the first '.' in
* the common suffix, since we don't want to match partial
* names
*/
for(; i < l; i++, j++)
if(local_host[i] == '.') break;
/* If the local_host and the proxy_host names don't have
* an parts in common, then use the proxy, ie no match
* with no_proxy, ie return false
*/
if(local_host[i] == 0)
return false;
/* Now local_host + i points to default no_proxy value */
return(match_no_proxy(remote_host, local_host+i));
}
}
/* If we are here, then the entire string matched, Ie we are using
* the local host as a proxy. In that case always use the proxy, ie
* report no match, ie false
*/
return(false);
}
}
/*
* Are they the same host? For example kroete2.freinet.de is the same as
* kroete2. Doesn't match kgb.ussr with kgb.us
*/
static bool
match_host_name(remote_host, local_host)
char *remote_host;
char *local_host;
{
int rl = strlen(remote_host);
int ll = strlen(local_host);
/* Same length, same string */
if(ll == rl) return(strcmp(remote_host, local_host) == 0 ? true : false);
if(ll < rl)
{
/*
* kroete2. matches kroete2.freinet.de and
* kroete2 matches kroete2.freinet.de
*/
if(local_host[ll - 1] == '.' || remote_host[ll] == '.')
{
return(strncmp(remote_host, local_host, ll) == 0 ? true : false);
}
return(false);
}
else
{
/*
* kroete2. matches kroete2.freinet.de and
* kroete2 matches kroete2.freinet.de
*/
if(remote_host[rl - 1] == '.' || local_host[rl] == '.')
{
return(strncmp(remote_host, local_host, rl) == 0 ? true : false);
}
return(false);
}
}
/*
* get_proxy
*
* There is no proxy for 'localhost'.
* There is also no proxy for the local system name (as
* returned by uname(2) or 'uname -n'). Otherwise do the
* no_proxy checking.
*
* I scratched around here...so this is my fault. -john
*/
static URLParts *
get_proxy(mp, up)
MemPool mp;
URLParts *up;
{
URLParts *pup = NULL;
char *pname;
char *apl;
# ifdef HAVE_UNAME
struct utsname thishostname;
# endif
if (up->scheme == NULL) return(NULL);
/*
* Check for protocol specific proxy information.
*/
pname = (char *)MPGet(mp, strlen(up->scheme) + strlen("_proxy") + 1);
strcpy(pname, up->scheme);
strcat(pname, "_proxy");
if (getenv(pname) != NULL) pup = URLParse(mp, getenv(pname));
/*
* Check for "all" proxy information.
*/
if (pup == NULL)
{
/*
* Check the all list to make sure that the protocol should be
* used with "all". If the list doesn't exist then just assume
* "all" really means "all".
*/
if ((apl = getenv("all_proxy_list")) != NULL)
{
pname = apl;
while ((pname = mystrtok(apl, ',', &apl)) != NULL)
{
if (strlen(up->scheme) == strlen(pname) &&
strcmp(up->scheme, pname) == 0) break;
}
if (pname == NULL) return(NULL);
}
if (getenv("all_proxy") != NULL) pup = URLParse(mp, getenv("all_proxy"));
}
/*
* No proxy information?
*/
if (pup == NULL) return(NULL);
/*
* Found proxy information now make sure that it can be used.
*/
# ifdef HAVE_UNAME
uname(&thishostname);
if (up->hostname &&
/*
* Allow localhost and hostname proxies
*
strcmp(up->hostname, "localhost") != 0 &&
! match_host_name(up->hostname, thishostname.nodename) &&
*/
! match_no_proxy_list(up->hostname,
thishostname.nodename,
getenv("no_proxy"),
pup->hostname))
{
return(pup);
}
# else
if (up->hostname &&
/*
* Allow localhost and hostname proxies
*
strcmp(up->hostname, "localhost") != 0 &&
*/
! match_no_proxy_list(up->hostname,
NULL,
getenv("no_proxy"),
pup->hostname))
{
return(pup);
}
# endif
return(NULL);
}
/*
* RequestMatchContent
*
* This is stupid. I swear its because I'm tired. Really.
*/
bool
RequestMatchContent(mp, c1, c2)
MemPool mp;
char *c1, *c2;
{
char *cp;
char *p1, *p2;
bool error;
c1 = MPStrDup(mp, c1);
c2 = MPStrDup(mp, c2);
error = true;
for (cp = c1; *cp != '\0'; cp++)
{
if (*cp == '/')
{
p1 = cp + 1;
*cp = '\0';
error = false;
break;
}
}
if (error) return(false);
error = true;
for (cp = c2; *cp != '\0'; cp++)
{
if (*cp == '/')
{
p2 = cp + 1;
*cp = '\0';
error = false;
break;
}
}
if (error) return(false);
if ((strlen(c1) == 1 && *c1 == '*') ||
(strlen(c1) == strlen(c2) && strcasecmp(c1, c2) == 0))
{
if ((strlen(p1) == 1 && *p1 == '*') ||
(strlen(p1) == strlen(p2) && strcasecmp(p1, p2) == 0))
{
return(true);
}
}
return(false);
}
/*
* RequestCreate
*
* Creates a request that can be passed to a source initializer.
*
* If the base is NULL and the URL is relative then it is assumed to
* be a domain-name which is transformed to http://domain-name/.
*/
ChimeraRequest *
RequestCreate(cres, url, base)
ChimeraResources cres;
char *url;
char *base;
{
MemPool mp;
ChimeraRequest *wr, *tr;
ChimeraSourceHooks *hooks, *phooks;
URLParts *up; /* request url parsed */
URLParts *bup; /* base url parsed */
URLParts *rup; /* result url parsed */
char *rurl; /* result url */
char *uscheme; /* url scheme */
char *bscheme; /* base scheme */
char *jscheme; /* temp/junk scheme */
char *turl; /* temp url */
size_t tlen; /* length of turl */
/* really, really want a URL */
myassert(url != NULL, "URL passed to RequestCreate is NULL");
/*
* All allocations are done with this descriptor.
*/
mp = MPCreate();
wr = (ChimeraRequest *)MPCGet(mp, sizeof(ChimeraRequest));
wr->mp = mp;
if (base != NULL) wr->parent_url = MPStrDup(wr->mp, base);
/*
* First, get the schemes of the request URL and base URL. It should
* always be possible to get the schemes so that the source hooks
* can be found to see if an alternate parsing method is going to
* be used.
*/
uscheme = URLGetScheme(mp, url);
if (base != NULL) bscheme = URLGetScheme(mp, base);
else bscheme = NULL;
/*
* Neither URL is absolute. Pretend that the supplied URL is a domain
* name if it doesn't begin with a '/'.
*/
if (uscheme == NULL && bscheme == NULL)
{
if (url[0] != '/')
{
tlen = strlen(url) + strlen("http:///") + 1;
turl = (char *)MPCGet(mp, tlen);
snprintf (turl, tlen - 1, "http://%s/", url);
tr = RequestCreate(cres, turl, NULL);
}
else tr = NULL;
MPDestroy(mp);
return(tr);
}
/*
* Select the scheme to use. If the request url doesn't have a scheme
* then it must relative...use the base url scheme.
*/
if (uscheme == NULL) jscheme = bscheme;
else
{
jscheme = uscheme;
/*
* If the request url and base url don't have the same scheme then
* ignore the base url (set it to NULL).
*/
if (bscheme == NULL || strlen(uscheme) != strlen(bscheme) ||
strcasecmp(uscheme, bscheme) != 0)
{
base = NULL;
}
}
/*
* If source hooks can't be found or the hooks don't define a resolver
* then use the general resolver.
*/
if ((hooks = SourceGetHooks(cres, jscheme)) != NULL &&
hooks->resolve_url != NULL)
{
/*
* Resolve the URL. If it succeeds parse the URL since we need
* that although that is probably the wrong thing to do because
* the scheme required a unique resolver. Shouldn't hurt unless
* a proxy is needed.
*/
if ((rurl = CMethodCharPtr(hooks->resolve_url)(mp, url, base)) == NULL)
{
MPDestroy(mp);
return(NULL);
}
else rup = URLParse(mp, rurl);
}
else
{
/*
* Try using the general parser.
*/
if ((up = URLParse(mp, url)) == NULL)
{
MPDestroy(mp);
return(NULL);
}
if (base != NULL && (bup = URLParse(mp, base)) != NULL)
{
if ((rup = URLResolve(mp, up, bup)) == NULL)
{
MPDestroy(mp);
return(NULL);
}
}
else rup = up;
rurl = URLMakeString(mp, rup, true);
}
/*
* At this point, "rurl" should contain the text of the URL allocated with
* "mp". "rup" should contain the parsed form of the URL which at least
* gives a scheme.
*/
wr->url = rurl;
wr->up = rup;
/*
* Check for a proxy server.
*/
if ((wr->pup = get_proxy(wr->mp, wr->up)) != NULL)
{
if ((phooks = SourceGetHooks(cres, wr->pup->scheme)) == NULL)
{
wr->pup = NULL;
}
else hooks = phooks;
}
/*
* No hooks at all? No choice but to fail.
*/
if (hooks == NULL)
{
MPDestroy(mp);
return(NULL);
}
memcpy(&(wr->hooks), hooks, sizeof(ChimeraSourceHooks));
wr->scheme = URLGetScheme(wr->mp, wr->url);
return(wr);
}
void
RequestAddContent(wr, content)
ChimeraRequest *wr;
char *content;
{
if (wr->contents == NULL) wr->contents = GListCreateX(wr->mp);
GListAddTail(wr->contents, MPStrDup(wr->mp, content));
return;
}
int
RequestAddRegexContent(cres, wr, ctx)
ChimeraResources cres;
ChimeraRequest *wr;
char *ctx;
{
ChimeraRenderHooks *rh;
GList list;
int count = 0;
MemPool mp;
if (wr->contents == NULL) wr->contents = GListCreateX(wr->mp);
mp = MPCreate();
list = cres->renderhooks;
for (rh = (ChimeraRenderHooks *)GListGetHead(list); rh != NULL;
rh = (ChimeraRenderHooks *)GListGetNext(list))
{
if (RequestMatchContent(mp, ctx, rh->content))
{
GListAddTail(wr->contents, MPStrDup(wr->mp, rh->content));
count++;
}
}
MPDestroy(mp);
return(count);
}
bool
RequestMatchContent2(wr, ct)
ChimeraRequest *wr;
char *ct;
{
char *rx;
GList list;
MemPool mp;
if (wr->contents == NULL || GListEmpty(wr->contents)) return(true);
mp = MPCreate();
list = wr->contents;
for (rx = (char *)GListGetHead(list); rx != NULL;
rx = (char *)GListGetNext(list))
{
if (RequestMatchContent(mp, rx, ct))
{
MPDestroy(mp);
return(true);
}
}
MPDestroy(mp);
return(false);
}
void
RequestDestroy(wr)
ChimeraRequest *wr;
{
MPDestroy(wr->mp);
return;
}
void
RequestReload(wr, reload)
ChimeraRequest *wr;
bool reload;
{
wr->reload = reload;
return;
}
bool
RequestCompareURL(wr1, wr2)
ChimeraRequest *wr1, *wr2;
{
/*
* The comparison should ignore case in the host part and pay attention
* to case in the filename part...
*/
return(strlen(wr1->url) == strlen(wr2->url) &&
strcmp(wr1->url, wr2->url) == 0);
}
bool
RequestCompareAccept(wr1, wr2)
ChimeraRequest *wr1, *wr2;
{
char *c1, *c2;
c1 = (char *)GListGetHead(wr1->contents);
c2 = (char *)GListGetHead(wr2->contents);
while (c1 != NULL && c2 != NULL)
{
if (strlen(c1) != strlen(c2) || strcasecmp(c1, c2) != 0) return(false);
c1 = (char *)GListGetNext(wr1->contents);
c2 = (char *)GListGetNext(wr2->contents);
}
if (c1 != NULL || c2 != NULL) return(false);
return(true);
}

169
chimera/resource.c Normal file
View File

@ -0,0 +1,169 @@
/*
* resource.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "ChimeraP.h"
int
ResourceAddString(cres, str)
ChimeraResources cres;
char *str;
{
XrmDatabase db;
db = XrmGetStringDatabase(str);
if (cres->db != NULL) XrmMergeDatabases(db, &(cres->db));
else cres->db = db;
if (cres->db == NULL) return(-1);
return(0);
}
int
ResourceAddFile(cres, file)
ChimeraResources cres;
char *file;
{
char *dbfile;
MemPool mp;
XrmDatabase db;
if (file == NULL) return(-1);
mp = MPCreate();
if ((dbfile = FixPath(mp, file)) == NULL)
{
MPDestroy(mp);
return(-1);
}
db = XrmGetFileDatabase(dbfile);
if (cres->db != NULL) XrmMergeDatabases(db, &(cres->db));
else cres->db = db;
MPDestroy(mp);
if (cres->db == NULL) return(-1);
return(0);
}
/*
* ResourceGetString
*/
char *
ResourceGetString(cres, name)
ChimeraResources cres;
char *name;
{
char *type;
XrmValue v;
if (cres->db == NULL) return(NULL);
if (!XrmGetResource(cres->db, name, XtNstring, &type, &v)) return(NULL);
return(v.addr);
}
/*
* ResourceGetFilename
*/
char *
ResourceGetFilename(cres, mp, name)
ChimeraResources cres;
MemPool mp;
char *name;
{
char *value;
if ((value = ResourceGetString(cres, name)) == NULL) return(NULL);
return(FixPath(mp, value));
}
/*
* ResourceGetBool
*/
char *
ResourceGetBool(cres, name, value)
ChimeraResources cres;
char *name;
bool *value;
{
char *str;
if ((str = ResourceGetString(cres, name)) == NULL) return(NULL);
*value = false;
if (strncasecmp("true", str, 4) == 0) *value = true;
if (atoi(str) > 0) *value = true;
return(str);
}
/*
* ResourceGetInt
*/
char *
ResourceGetInt(cres, name, value)
ChimeraResources cres;
char *name;
int *value;
{
char *str;
if ((str = ResourceGetString(cres, name)) == NULL) return(NULL);
*value = atoi(str);
return(str);
}
/*
* ResourceGetUInt
*/
char *
ResourceGetUInt(cres, name, value)
ChimeraResources cres;
char *name;
unsigned int *value;
{
char *str;
int bla;
if ((str = ResourceGetString(cres, name)) == NULL) return(NULL);
bla = atoi(str);
if (bla < 0) bla = 0;
*value = bla;
return(str);
}

924
chimera/source.c Normal file
View File

@ -0,0 +1,924 @@
/*
* source.c
*
* Copyright (c) 1996-1998, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/IntrinsicP.h>
#include "port_after.h"
#include "ChimeraP.h"
#include "mime.h"
typedef enum
{
SinkStateWaiting, /* waiting for beginning of data */
SinkStateLoading, /* waiting for completion of data */
SinkStateComplete, /* has received all data */
SinkStateCancelled, /* has been cancelled */
SinkStateIgnore, /* ignore callbacks for this sink */
SinkStateDestroyed /* dead */
} SinkState;
typedef enum
{
SourceStateWaiting,
SourceStateBlocked,
SourceStateComplete,
SourceStateLame,
SourceStateLoading
} SourceState;
struct ChimeraSinkP
{
MemPool mp;
SinkState state;
ChimeraSource ws;
ChimeraSinkHooks dhooks;
void *closure;
ChimeraTask wt;
int debug;
};
struct ChimeraSourceP
{
MemPool mp;
ChimeraResources cres;
ChimeraSourceHooks shooks;
void *closure;
GList sinks;
int debugcount;
/* only used if the source is blocked. do not free in this module. */
ChimeraRequest *wr;
/* Various status goodies */
SourceState sstate; /* transfer state */
bool cachable; /* can this be cached? */
bool fromcache; /* was this fetched from cache? */
};
/*
* Private functions
*/
static ChimeraSource SourceCreate _ArgProto((ChimeraResources,
ChimeraRequest *));
void SourceDestroy _ArgProto((ChimeraSource));
static void SourceInitTask _ArgProto((void *));
static void SourceEndTask _ArgProto((void *));
static void SinkCancelTask _ArgProto((void *));
static char *GetSourceInfo _ArgProto((ChimeraSource, char *));
static void StartBlockedSource _ArgProto((ChimeraResources));
static int StartSource _ArgProto((ChimeraResources, ChimeraSource));
static ChimeraSource TryMemoryCache _ArgProto((ChimeraResources,
ChimeraRequest *));
static void ChangeSinkState _ArgProto((ChimeraSink, ChimeraTaskProc,
SinkState));
/*
* ChangeSinkState
*
* Should check for reasonable transitions?
*/
static void
ChangeSinkState(wp, func, newstate)
ChimeraSink wp;
ChimeraTaskProc func;
SinkState newstate;
{
if (wp->wt != NULL)
{
TaskRemove(wp->ws->cres, wp->wt);
wp->wt = NULL;
}
wp->state = newstate;
if (func != NULL) wp->wt = TaskSchedule(wp->ws->cres, func, wp);
return;
}
/*
* SourceDestroy
*/
void
SourceDestroy(ws)
ChimeraSource ws;
{
ChimeraSink c;
ChimeraResources cres = ws->cres;
if (cres->printLoadMessages)
{
fprintf (stderr, "Source Destroy %s\n", ws->wr->url);
}
for (c = (ChimeraSink)GListGetHead(ws->sinks); c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
myassert(c->state == SinkStateDestroyed, "Sink not destroyed");
if (c->wt != NULL) TaskRemove(cres, c->wt);
MPDestroy(c->mp);
}
if (ws->closure != NULL) CMethod(ws->shooks.destroy)(ws->closure);
GListRemoveItem(cres->sources, ws);
MPDestroy(ws->wr->mp);
MPDestroy(ws->mp);
return;
}
/*
* SourceCreate
*
* This function gobbles up 'wr'.
*/
static ChimeraSource
SourceCreate(cres, wr)
ChimeraResources cres;
ChimeraRequest *wr;
{
ChimeraSource c;
int count;
ChimeraSource ws;
MemPool mp;
mp = MPCreate();
ws = (ChimeraSource)MPCGet(mp, sizeof(struct ChimeraSourceP));
ws->mp = mp;
ws->cres = cres;
ws->cachable = true;
ws->sstate = SourceStateWaiting;
ws->sinks = GListCreateX(mp);
ws->wr = wr;
/*
* Count the number of loading and waiting (active) sources. If there are
* already some number (maxiocnt) of active sources then block this
* source.
*/
count = 0;
for (c = (ChimeraSource)GListGetHead(cres->sources); c != NULL;
c = (ChimeraSource)GListGetNext(cres->sources))
{
if (c->sstate == SourceStateLoading || c->sstate == SourceStateWaiting)
{
count++;
if (count == cres->maxiocnt)
{
ws->sstate = SourceStateBlocked;
GListAddHead(cres->sources, ws);
if (cres->printLoadMessages)
{
fprintf (stderr, "Source Block %s\n", wr->url);
}
return(ws);
}
}
}
GListAddHead(cres->sources, ws);
if (StartSource(cres, ws) == -1) return(NULL);
return(ws);
}
/*
* StartSource
*/
static int
StartSource(cres, ws)
ChimeraResources cres;
ChimeraSource ws;
{
ChimeraSourceHooks *hooks;
ChimeraRequest *wr = ws->wr;
char *detail = "error";
/*
* Look in the cache if the reload flag isn't set. Copy the cache
* source hooks to be used later.
*/
if (!wr->reload && wr->input_data == NULL && cres->cc != NULL)
{
hooks = CacheGetHooks(cres->cc);
if (hooks != NULL)
{
ws->closure = CMethodVoidPtr(hooks->init)(ws, wr, hooks->class_closure);
if (ws->closure != NULL)
{
memcpy(&(ws->shooks), hooks, sizeof(ws->shooks));
ws->fromcache = true;
detail = "Cache";
}
}
}
/*
* Cache could not be attempted or the cache grab failed. Try the
* real handler.
*/
if (ws->closure == NULL)
{
ws->closure = CMethodVoidPtr(wr->hooks.init)(ws,
wr, wr->hooks.class_closure);
memcpy(&(ws->shooks), &(wr->hooks), sizeof(ws->shooks));
if (ws->closure != NULL) detail = wr->hooks.name;
}
/*
* Couldn't start a source. Just give up and return nothing.
*/
if (ws->closure == NULL)
{
if (cres->printLoadMessages)
{
fprintf (stderr, "Source StartFailed %s\n", wr->url);
}
SourceDestroy(ws);
return(-1);
}
ws->sstate = SourceStateWaiting;
if (cres->printLoadMessages)
{
fprintf (stderr, "Source StartSuccess(%s) %s\n", detail, wr->url);
}
return(0);
}
/*
* StartBlockedSource
*/
static void
StartBlockedSource(cres)
ChimeraResources cres;
{
ChimeraSource c;
for (c = (ChimeraSource)GListGetHead(cres->sources); c != NULL; )
{
if (c->sstate == SourceStateBlocked)
{
if (cres->printLoadMessages)
{
fprintf (stderr, "Source StartBlocked %s\n", c->wr->url);
}
if (StartSource(cres, c) == 0) break;
else c = (ChimeraSource)GListGetHead(cres->sources);
}
else c = (ChimeraSource)GListGetNext(cres->sources);
}
return;
}
/*
* SourceEndTask
*/
static void
SourceEndTask(closure)
void *closure;
{
ChimeraSink wp = (ChimeraSink)closure;
myassert(wp->state == SinkStateComplete, "Sink not complete!");
wp->wt = NULL;
CMethod(wp->dhooks.end)(wp->closure);
return;
}
/*
* SourceInitTask
*/
static void
SourceInitTask(closure)
void *closure;
{
ChimeraSink wp = (ChimeraSink)closure;
ChimeraSource ws = wp->ws;
int debug;
wp->wt = NULL;
myassert(wp->state == SinkStateWaiting, "Sink not waiting");
debug = wp->debug;
if (CMethodInt(wp->dhooks.init)(wp, wp->closure) != 0)
{
/*
* Don't make any references to 'wp'. The init routine probably
* wants to do a Cancel or Destroy.
*/
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "Sink(%d) Init failed %s\n", debug, ws->wr->url);
}
return;
}
if (wp->ws->sstate == SourceStateComplete)
{
ChangeSinkState(wp, SourceEndTask, SinkStateComplete);
}
else ChangeSinkState(wp, NULL, SinkStateLoading);
return;
}
/*
* TryMemoryCache
*
* Rummage around in the list of current downloads to see if what we need
* is already being downloaded.
*/
static ChimeraSource
TryMemoryCache(cres, wr)
ChimeraResources cres;
ChimeraRequest *wr;
{
ChimeraSource ws;
char *content;
/*
* Input data can make the output different everytime don't even
* try to find something that has been cached.
*/
if (wr->input_data != NULL) return(NULL);
for (ws = (ChimeraSource)GListGetHead(cres->sources); ws != NULL;
ws = (ChimeraSource)GListGetNext(cres->sources))
{
/*
* Obviously the URL has to match.
*/
if (RequestCompareURL(ws->wr, wr))
{
/*
* Check to make sure the source is usable and then check to make sure
* that the same content-types are desired.
*/
if (ws->sstate != SourceStateLame && ws->cachable)
{
if (RequestCompareAccept(ws->wr, wr)) return(ws);
if (cres->printLoadMessages)
{
fprintf (stderr, "MemCache AcceptListDifferent %s\n", wr->url);
}
}
else if (cres->printLoadMessages)
{
fprintf (stderr, "MemCache ");
switch (ws->sstate)
{
case SourceStateWaiting: fprintf (stderr, "StateWaiting: "); break;
case SourceStateBlocked: fprintf (stderr, "StateBlocked: "); break;
case SourceStateComplete: fprintf (stderr, "StateComplete: "); break;
case SourceStateLame: fprintf (stderr, "StateLame: "); break;
case SourceStateLoading: fprintf (stderr, "StateLoading: "); break;
default: fprintf (stderr, "EvilState(%d): ", ws->sstate);
}
fprintf (stderr, "%s\n", ws->wr->url);
}
}
}
return(NULL);
}
/*
* SourceStop
*
* This function is called by the source implementation to indicate that
* input is stopping for some reason. Since its incomplete the source
* is marked (Lame) so that the in-memory version won't be used again.
* A blocked source is started.
*/
void
SourceStop(ws, reason)
ChimeraSource ws;
char *reason;
{
if (ws->sstate == SourceStateLame) return;
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "Source Stop %s\n", ws->wr->url);
}
ws->sstate = SourceStateLame;
StartBlockedSource(ws->cres);
return;
}
/*
* SourceEnd
*/
void
SourceEnd(ws)
ChimeraSource ws;
{
ChimeraSink c;
myassert(ws->sstate == SourceStateLoading, "End source in wrong state");
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "Source End %s\n", ws->wr->url);
}
ws->sstate = SourceStateComplete;
for (c = (ChimeraSink)GListGetHead(ws->sinks); c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
if (c->state == SinkStateLoading)
{
ChangeSinkState(c, SourceEndTask, SinkStateComplete);
}
}
if (ws->cres->cc != NULL && ws->cachable && !ws->fromcache)
{
CacheWrite(ws->cres->cc, ws);
}
StartBlockedSource(ws->cres);
return;
}
/*
* SourceAddTask
*/
static void
SourceAddTask(closure)
void *closure;
{
ChimeraSink wp = (ChimeraSink)closure;
myassert(wp->state == SinkStateLoading, "Sink not loading!");
wp->wt = NULL;
CMethod(wp->dhooks.add)(wp->closure);
return;
}
/*
* SourceAdd
*/
void
SourceAdd(ws)
ChimeraSource ws;
{
ChimeraSink c;
myassert(ws->sstate == SourceStateLoading, "Add source in wrong state");
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "Source Add %s\n", ws->wr->url);
}
for (c = (ChimeraSink)GListGetHead(ws->sinks); c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
if (c->state == SinkStateLoading)
{
ChangeSinkState(c, SourceAddTask, SinkStateLoading);
}
}
return;
}
/*
* SourceInit
*/
void
SourceInit(ws, usecache)
ChimeraSource ws;
bool usecache;
{
ChimeraSink c;
char *url;
myassert(ws->sstate == SourceStateWaiting, "Init source in wrong state.");
ws->cachable = usecache;
ws->sstate = SourceStateLoading;
myassert((url = GetSourceInfo(ws, "x-url")) != NULL, "URL is NULL");
myassert(GetSourceInfo(ws, "content-type") != NULL, "Content-type is NULL");
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "Source Init %s\n", url);
}
/*
* Check to see if any sinks are listening
*/
if ((c = (ChimeraSink)GListGetHead(ws->sinks)) == NULL)
{
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "No sinks for source! Bad bug! (%s)\n", url);
}
return;
}
/*
* This is broken. The document may not be cacheable and so new
* sources should be created for each sink. This is the first
* time we know if the document is cacheable. Fix later.
*/
for (; c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
/*
* This check has to be done since the sink may have been cancelled
* or othwise messed with before this.
*/
if (c->state == SinkStateWaiting)
{
ChangeSinkState(c, SourceInitTask, SinkStateWaiting);
}
}
return;
}
/*
* SourceSendMessage
*/
void
SourceSendMessage(ws, message)
ChimeraSource ws;
char *message;
{
ChimeraSink c;
for (c = (ChimeraSink)GListGetHead(ws->sinks); c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
if (c->state == SinkStateWaiting || c->state == SinkStateLoading ||
c->state == SinkStateComplete)
{
CMethod(c->dhooks.message)(c->closure, message);
}
}
return;
}
/*
* SourceToResources
*/
ChimeraResources
SourceToResources(ws)
ChimeraSource ws;
{
return(ws->cres);
}
/*
* SourceGetData
*/
void
SourceGetData(ws, data, len, mh)
ChimeraSource ws;
byte **data;
size_t *len;
MIMEHeader *mh;
{
if (ws->shooks.getdata != NULL)
{
CMethod(ws->shooks.getdata)(ws->closure, data, len, mh);
}
return;
}
/*
* GetSourceInfo
*/
static char *
GetSourceInfo(ws, name)
ChimeraSource ws;
char *name;
{
byte *data;
size_t len;
MIMEHeader mh;
char *value;
SourceGetData(ws, &data, &len, &mh);
if (mh == NULL) return(NULL);
if (MIMEGetField(mh, name, &value) != 0) return(NULL);
return(value);
}
/*
* SinkCreate
*
* Create a sink for a source. 'wr' is eaten by this function.
*/
ChimeraSink
SinkCreate(cres, wr)
ChimeraResources cres;
ChimeraRequest *wr;
{
ChimeraSource ws = NULL;
ChimeraSink wp;
MemPool mp;
char *detail;
if (wr->reload || (ws = TryMemoryCache(cres, wr)) == NULL)
{
if ((ws = SourceCreate(cres, wr)) == NULL)
{
if (cres->printLoadMessages)
{
fprintf (stderr, "Sink Create Failed %s\n", wr->url);
}
return(NULL);
}
detail = "New";
}
else
{
/*
* This can be thrown out since the 'ws' obtained from TryMemoryCache
* contains an identical copy.
*/
RequestDestroy(wr);
detail = "Cache";
}
mp = MPCreate();
wp = (ChimeraSink)MPCGet(mp, sizeof(struct ChimeraSinkP));
wp->mp = mp;
wp->state = SinkStateWaiting;
wp->ws = ws;
wp->debug = ws->debugcount++;
memset(&wp->dhooks, 1, sizeof(wp->dhooks));
GListAddTail(ws->sinks, wp);
if (cres->printLoadMessages)
{
fprintf (stderr, "Sink(%d) Create %s %s\n", wp->debug,
detail, ws->wr->url);
}
return(wp);
}
/*
* SinkSetHooks
*/
void
SinkSetHooks(wp, hooks, closure)
ChimeraSink wp;
ChimeraSinkHooks *hooks;
void *closure;
{
/*
* If there are no hooks then ignore this sink. If there are hooks then
* reset it for another go around.
*/
if (hooks == NULL)
{
ChangeSinkState(wp, NULL, SinkStateIgnore);
wp->closure = NULL;
memset(&wp->dhooks, 1, sizeof(wp->dhooks)); /* 0 causes trouble */
}
else
{
myassert(hooks->init != NULL, "Init function is NULL.");
myassert(hooks->add != NULL, "Add function is NULL.");
myassert(hooks->end != NULL, "End function is NULL.");
myassert(hooks->message != NULL, "Message function is NULL.");
memcpy(&wp->dhooks, hooks, sizeof(wp->dhooks));
wp->closure = closure;
if (wp->ws->sstate == SourceStateLoading ||
wp->ws->sstate == SourceStateComplete)
{
ChangeSinkState(wp, SourceInitTask, SinkStateWaiting);
}
else ChangeSinkState(wp, NULL, SinkStateWaiting);
}
return;
}
/*
* SinkDestroyTask
*/
static void
SinkDestroyTask(closure)
void *closure;
{
ChimeraSink wp = (ChimeraSink)closure;
ChimeraSource ws = wp->ws;
ChimeraSink c;
myassert(wp->state == SinkStateDestroyed, "Sink has been undestroyed");
wp->wt = NULL;
if ((c = (ChimeraSink)GListGetHead(ws->sinks)) == NULL)
{
fprintf (stderr, "SinkDestroyTask: source has no sinks!\n");
return;
}
for (; c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
if (c->state != SinkStateDestroyed) break;
}
if (c == NULL) SourceDestroy(ws);
return;
}
/*
* SinkDestroy
*/
void
SinkDestroy(wp)
ChimeraSink wp;
{
ChimeraSource ws = wp->ws;
myassert(wp->state != SinkStateDestroyed, "Sink already destroyed");
if (ws->cres->printLoadMessages)
{
fprintf (stderr, "Sink(%d) Destroy %s\n", wp->debug, ws->wr->url);
}
ChangeSinkState(wp, SinkDestroyTask, SinkStateDestroyed);
return;
}
/*
* SinkWasReloaded
*/
bool
SinkWasReloaded(wp)
ChimeraSink wp;
{
return(wp->ws->wr->reload);
}
/*
* SinkToResources
*/
ChimeraResources
SinkToResources(wp)
ChimeraSink wp;
{
return(wp->ws->cres);
}
/*
* SinkGetData
*/
void
SinkGetData(wp, data, len, mh)
ChimeraSink wp;
byte **data;
size_t *len;
MIMEHeader *mh;
{
if (wp->ws->shooks.getdata != NULL)
{
CMethod(wp->ws->shooks.getdata)(wp->ws->closure, data, len, mh);
}
return;
}
/*
* SinkGetInfo
*/
char *
SinkGetInfo(wp, name)
ChimeraSink wp;
char *name;
{
byte *data;
size_t len;
MIMEHeader mh;
char *value;
SinkGetData(wp, &data, &len, &mh);
if (mh == NULL) return(NULL);
if (MIMEGetField(mh, name, &value) != 0) return(NULL);
return(value);
}
/*
* SinkCancelTask
*
* If all sinks for a source are cancelled then a request is sent to
* the source to stop sending input. The callbacks are
* no longer called for the sink after this function.
*/
static void
SinkCancelTask(closure)
void *closure;
{
ChimeraSink wp = (ChimeraSink)closure;
ChimeraSource ws = wp->ws;
ChimeraSink c;
wp->wt = NULL;
myassert(wp->state == SinkStateCancelled, "Sink not cancelled\n");
/*
* Check to see if all sinks are cancelled. If so then stop the source.
*/
for (c = (ChimeraSink)GListGetHead(ws->sinks); c != NULL;
c = (ChimeraSink)GListGetNext(ws->sinks))
{
if (c->state != SinkStateCancelled && c->state != SinkStateDestroyed)
{
break;
}
}
if (c == NULL)
{
if (ws->shooks.stop != NULL && ws->closure != NULL)
{
CMethod(ws->shooks.stop)(ws->closure);
}
SourceStop(ws, "");
}
return;
}
/*
* SinkCancel
*/
void
SinkCancel(wp)
ChimeraSink wp;
{
myassert(wp->state != SinkStateDestroyed, "Sink can't be cancelled\n");
if (wp->ws->cres->printLoadMessages)
{
fprintf (stderr, "Sink(%d) Cancel %s\n", wp->debug, wp->ws->wr->url);
}
ChangeSinkState(wp, SinkCancelTask, SinkStateCancelled);
return;
}

629
chimera/stack.c Normal file
View File

@ -0,0 +1,629 @@
/*
* stack.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "ChimeraP.h"
typedef enum
{
StackNewAction,
StackBackAction,
StackReloadAction,
StackReplaceAction,
StackRedrawAction,
StackHomeAction
} StackOpAction;
typedef struct
{
char *url;
void *state; /*
* this is the state of the renderer (mostly meant for
* scrollbar position) to be used when the document is
* redisplayed.
*/
} URLInfo;
struct ChimeraStackP
{
MemPool mp, tmp;
ChimeraGUI wd;
ChimeraContext wc;
ChimeraStack parent;
StackOpAction action;
ChimeraRender wn;
ChimeraSink wp;
ChimeraSink pending;
ChimeraRenderActionProc rap;
void *rapc;
ChimeraRenderHooks *rh;
bool toplevel;
/* list for URL stack */
GList urls;
GList ourls;
};
static void StackGUIResize _ArgProto((ChimeraGUI, void *,
unsigned int, unsigned int));
static bool StackPop _ArgProto((ChimeraStack));
static void StackOp _ArgProto((ChimeraStack, ChimeraRequest *,
StackOpAction));
int StackSinkInit _ArgProto((ChimeraSink, void *));
static void StackSinkAdd _ArgProto((void *));
static void StackSinkEnd _ArgProto((void *));
static void StackSinkMessage _ArgProto((void *, char *));
static void StackRenderAction _ArgProto((void *, ChimeraRender,
ChimeraRequest *, char *));
/*
* StackPop
*/
static bool
StackPop(cs)
ChimeraStack cs;
{
void *muck;
if ((muck = GListPop(cs->urls)) != NULL)
{
GListAddHead(cs->ourls, muck);
return(true);
}
return(false);
}
/*
* StackMessage
*/
static void
StackSinkMessage(closure, message)
void *closure;
char *message;
{
ChimeraStack cs = (ChimeraStack)closure;
HeadPrintMessage(cs->wc, message);
return;
}
/*
* StackEnd
*/
static void
StackSinkEnd(closure)
void *closure;
{
ChimeraStack cs = (ChimeraStack)closure;
RenderEnd(cs->wn);
return;
}
/*
* StackSinkAdd
*/
static void
StackSinkAdd(closure)
void *closure;
{
ChimeraStack cs = (ChimeraStack)closure;
RenderAdd(cs->wn);
return;
}
/*
* StackOpen
*/
void
StackOpen(cs, wr)
ChimeraStack cs;
ChimeraRequest *wr;
{
StackOp(cs, wr, StackNewAction);
return;
}
/*
* StackHome
*/
void
StackHome(cs)
ChimeraStack cs;
{
URLInfo *u;
if (GListGetTail(cs->urls) == GListGetHead(cs->urls)) return;
if ((u = (URLInfo *)GListGetTail(cs->urls)) == NULL) return;
StackOp(cs, RequestCreate(cs->wc->cres, u->url, NULL), StackHomeAction);
return;
}
/*
* StackBack
*/
void
StackBack(cs)
ChimeraStack cs;
{
URLInfo *u;
if (GListGetHead(cs->urls) == NULL) return;
if ((u = (URLInfo *)GListGetNext(cs->urls)) == NULL) return;
StackOp(cs, RequestCreate(cs->wc->cres, u->url, NULL), StackBackAction);
return;
}
/*
* StackReload
*/
void
StackReload(cs)
ChimeraStack cs;
{
URLInfo *u;
ChimeraRequest *wr;
if ((u = GListGetHead(cs->urls)) == NULL) return;
wr = RequestCreate(cs->wc->cres, u->url, NULL);
RequestReload(wr, true);
StackOp(cs, wr, StackReloadAction);
return;
}
/*
* StackRedraw
*/
void
StackRedraw(cs)
ChimeraStack cs;
{
URLInfo *u;
if ((u = GListGetHead(cs->urls)) == NULL) return;
StackOp(cs, RequestCreate(cs->wc->cres, u->url, NULL), StackReplaceAction);
return;
}
/*
* StackCancel
*/
void
StackCancel(cs)
ChimeraStack cs;
{
if (cs->wp != NULL) SinkCancel(cs->wp);
if (cs->pending != NULL) SinkCancel(cs->pending);
if (cs->wn != NULL) RenderCancel(cs->wn);
return;
}
/*
* StackAction
*/
void
StackAction(cs, wr, action)
ChimeraStack cs;
ChimeraRequest *wr;
char *action;
{
MemPool mp;
char *rstr;
char *rname;
size_t len;
bool newhead;
/*
* Should probably give an error message here.
*/
if (wr == NULL) return;
if (strcmp("open", action) == 0)
{
mp = MPCreate();
len = strlen(wr->scheme) + strlen(".newhead");
rname = (char *)MPGet(mp, len + 1);
strncpy(rname, wr->scheme, len);
strncat(rname, ".newhead", len);
rname[len] = '\0';
if ((rstr = ResourceGetBool(cs->wc->cres, rname, &newhead)) == NULL ||
!newhead)
{
StackOpen(cs, wr);
}
else
{
HeadCreate(cs->wc->cres, wr, NULL);
}
MPDestroy(mp);
}
else if (strcmp("download", action) == 0) DownloadOpen(cs->wc->cres, wr);
else if (strcmp("external", action) == 0) ViewOpen(cs->wc->cres, wr);
else fprintf (stderr, "Action cannot be taken. Bug.\n");
return;
}
/*
* StackRenderAction
*/
static void
StackRenderAction(closure, wn, wr, action)
void *closure;
ChimeraRender wn;
ChimeraRequest *wr;
char *action;
{
StackAction((ChimeraStack)closure, wr, action);
return;
}
/*
* StackSinkInit
*/
int
StackSinkInit(wp, closure)
ChimeraSink wp;
void *closure;
{
ChimeraStack cs = (ChimeraStack)closure;
URLInfo *u;
void *newstate, *curstate;
char *url;
char *ctype;
ChimeraRenderHooks *rh;
ChimeraRequest *wr;
myassert(wp == cs->pending, "Data init is not the same as data pending.");
url = SinkGetInfo(wp, "x-url");
ctype = SinkGetInfo(wp, "content-type");
if (cs->rh != NULL) rh = cs->rh;
else
{
if ((rh = RenderGetHooks(cs->wc->cres, ctype)) == NULL)
{
if ((wr = RequestCreate(cs->wc->cres, url, NULL)) == NULL)
{
HeadPrintMessage(cs->wc, "Invalid URL.");
}
else ViewOpen(cs->wc->cres, wr);
SinkDestroy(wp);
cs->pending = NULL;
return(-1);
}
}
if (cs->wn != NULL)
{
curstate = RenderGetState(cs->wn);
GUIReset(cs->wd);
RenderDestroy(cs->wn);
cs->wn = NULL;
}
else curstate = NULL;
if (cs->wp != NULL) SinkDestroy(cs->wp);
cs->wp = cs->pending;
cs->pending = NULL;
if (cs->action == StackBackAction)
{
StackPop(cs);
u = (URLInfo *)GListGetHead(cs->urls);
newstate = u->state;
StackPop(cs);
}
else if (cs->action == StackReloadAction ||
cs->action == StackReplaceAction)
{
u = (URLInfo *)GListGetHead(cs->urls);
newstate = u->state;
StackPop(cs);
}
else if (cs->action == StackHomeAction)
{
u = (URLInfo *)GListGetTail(cs->urls);
newstate = u->state;
while (StackPop(cs))
;
MPDestroy(cs->tmp);
cs->tmp = MPCreate();
}
else
{
if ((u = (URLInfo *)GListGetHead(cs->urls)) != NULL)
{
u->state = curstate;
}
newstate = NULL;
}
if ((u = (URLInfo *)GListPop(cs->ourls)) == NULL)
{
u = (URLInfo *)MPCGet(cs->mp, sizeof(URLInfo));
}
u->url = MPStrDup(cs->tmp, url);
u->state = newstate;
GListAddHead(cs->urls, u);
if ((cs->wn = RenderCreate(cs->wc, cs->wd,
cs->wp, rh, NULL, NULL, u->state,
cs->rap, cs->rapc)) == NULL)
{
DownloadOpen(cs->wc->cres, wr);
SinkDestroy(wp);
return(-1);
}
if (cs->toplevel) HeadPrintURL(cs->wc, url);
return(0);
}
/*
* StackGetCurrentURL
*/
char *
StackGetCurrentURL(cs)
ChimeraStack cs;
{
URLInfo *u;
if ((u = (URLInfo *)GListGetHead(cs->urls)) == NULL) return(NULL);
return(u->url);
}
/*
* StackOp
*/
static void
StackOp(cs, wr, action)
ChimeraStack cs;
ChimeraRequest *wr;
StackOpAction action;
{
ChimeraSinkHooks hooks;
if (wr == NULL)
{
HeadPrintMessage(cs->wc, "Invalid URL");
return;
}
StackCancel(cs);
if (cs->pending != NULL)
{
SinkDestroy(cs->pending);
cs->pending = NULL;
}
cs->action = action;
memset(&hooks, 0, sizeof(hooks));
hooks.init = StackSinkInit;
hooks.add = StackSinkAdd;
hooks.end = StackSinkEnd;
hooks.message = StackSinkMessage;
/* First, pick all of the contents we can deal with directly */
RequestAddRegexContent(cs->wc->cres, wr, "*/*");
/* Add whatever we can get onto the end */
RequestAddContent(wr, "*/*");
if (wr->url != NULL && cs->wc->cres->logfp != NULL)
{
fprintf (cs->wc->cres->logfp, "%s\n", wr->url);
}
cs->pending = SinkCreate(cs->wc->cres, wr);
if (cs->pending != NULL) SinkSetHooks(cs->pending, &hooks, cs);
return;
}
/*
* StackGUIResize
*/
static void
StackGUIResize(wd, closure, width, height)
ChimeraGUI wd;
void *closure;
unsigned int width, height;
{
StackRedraw((ChimeraStack)closure);
return;
}
/*
* StackCreateToplevel
*/
ChimeraStack
StackCreateToplevel(wc, widget)
ChimeraContext wc;
Widget widget;
{
ChimeraStack cs;
MemPool mp;
mp = MPCreate();
cs = (ChimeraStack)MPCGet(mp, sizeof(struct ChimeraStackP));
cs->wc = wc;
cs->mp = mp;
cs->tmp = MPCreate();
cs->urls = GListCreateX(mp);
cs->ourls = GListCreateX(mp);
cs->rap = StackRenderAction;
cs->rapc = cs;
GListAddHead(wc->cres->stacks, cs);
cs->wd = GUICreateToplevel(wc, widget, StackGUIResize, cs);
cs->toplevel = true;
return(cs);
}
/*
* StackCreate
*/
ChimeraStack
StackCreate(parent, x, y, width, height, rap, rapc)
ChimeraStack parent;
int x, y;
unsigned int width, height;
ChimeraRenderActionProc rap;
void *rapc;
{
ChimeraStack cs;
MemPool mp;
mp = MPCreate();
cs = (ChimeraStack)MPCGet(mp, sizeof(struct ChimeraStackP));
cs->parent = parent;
cs->wc = parent->wc;
cs->mp = mp;
cs->tmp = MPCreate();
cs->urls = GListCreateX(mp);
cs->ourls = GListCreateX(mp);
if (cs->rap == NULL || cs->rapc == NULL)
{
cs->rap = StackRenderAction;
cs->rapc = cs;
}
GListAddHead(parent->wc->cres->stacks, cs);
cs->wd = GUICreate(parent->wc, parent->wd, StackGUIResize, cs);
GUISetInitialDimensions(cs->wd, width, height);
GUIMap(cs->wd, x, y);
return(cs);
}
/*
* StackToRender
*/
ChimeraRender
StackToRender(cs)
ChimeraStack cs;
{
return(cs->wn);
}
/*
* StackToGUI
*/
ChimeraGUI
StackToGUI(cs)
ChimeraStack cs;
{
return(cs->wd);
}
/*
* StackSetRender
*/
void
StackSetRender(cs, rh)
ChimeraStack cs;
ChimeraRenderHooks *rh;
{
cs->rh = rh;
return;
}
/*
* StackDestroy
*/
void
StackDestroy(cs)
ChimeraStack cs;
{
if (cs->pending != NULL) SinkDestroy(cs->pending);
if (cs->wp != NULL) SinkDestroy(cs->wp);
if (cs->wn != NULL) RenderDestroy(cs->wn);
if (cs->wd != NULL) GUIDestroy(cs->wd);
if (cs->tmp != NULL) MPDestroy(cs->tmp);
GListRemoveItem(cs->wc->cres->stacks, cs);
MPDestroy(cs->mp);
return;
}
/*
* StackFromGUI
*/
ChimeraStack
StackFromGUI(wc, wd)
ChimeraContext wc;
ChimeraGUI wd;
{
ChimeraStack cs;
for (cs = (ChimeraStack)GListGetHead(wc->cres->stacks); cs != NULL;
cs = (ChimeraStack)GListGetNext(wc->cres->stacks))
{
if (cs->wd == wd) return(cs);
}
return(NULL);
}
/*
* StackGetParent
*/
ChimeraStack
StackGetParent(cs)
ChimeraStack cs;
{
return(cs->parent);
}

172
chimera/task.c Normal file
View File

@ -0,0 +1,172 @@
/*
* task.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "port_after.h"
#include "ChimeraP.h"
struct ChimeraTaskP
{
ChimeraTaskProc func;
void *closure;
int line;
char *file;
bool removed;
};
struct ChimeraSchedulerP
{
MemPool mp;
GList oldtasks;
GList tasks;
XtWorkProcId wpid;
};
static Boolean ScheduleTaskProc _ArgProto((XtPointer));
/*
* ScheduleTaskProc
*/
static Boolean
ScheduleTaskProc(closure)
XtPointer closure;
{
ChimeraResources cres = (ChimeraResources)closure;
ChimeraScheduler cs = cres->cs;
ChimeraTask wt;
cs->wpid = 0;
while ((wt = (ChimeraTask)GListPop(cs->tasks)) != NULL)
{
if (!wt->removed)
{
if (cres->printTaskInfo)
{
fprintf (stderr, "Task Called %s, %d\n", wt->file, wt->line);
}
CMethod(wt->func)(wt->closure);
}
GListAddTail(cs->oldtasks, wt);
memset(wt, 1, sizeof(struct ChimeraTaskP));
}
return(True);
}
/*
* TaskSchedule
*/
ChimeraTask
TaskScheduleX(cres, func, closure, line, file)
ChimeraResources cres;
ChimeraTaskProc func;
void *closure;
int line;
char *file;
{
ChimeraTask wt;
char *detail;
if ((wt = (ChimeraTask)GListPop(cres->cs->oldtasks)) == NULL)
{
detail = "New";
wt = (ChimeraTask)MPGet(cres->mp, sizeof(struct ChimeraTaskP));
}
else detail = "Reused";
wt->func = func;
wt->closure = closure;
wt->line = line;
wt->file = file;
wt->removed = false;
GListAddTail(cres->cs->tasks, wt);
if (cres->cs->wpid == 0)
{
cres->cs->wpid = XtAppAddWorkProc(cres->appcon, ScheduleTaskProc, cres);
myassert(cres->cs->wpid != 0, "Bad assumption about XtAppAddWorkProc");
}
if (cres->printTaskInfo)
{
fprintf (stderr, "Task Created %s, %s, %d\n", detail, file, line);
}
return(wt);
}
/*
* TaskRemove
*/
void
TaskRemove(cres, wt)
ChimeraResources cres;
ChimeraTask wt;
{
ChimeraTask c;
GList list;
char *detail = "notfound";
list = cres->cs->tasks;
for (c = (ChimeraTask)GListGetHead(list); c != NULL;
c = (ChimeraTask)GListGetNext(list))
{
if (c == wt)
{
c->removed = true;
detail = "found";
break;
}
}
if (cres->printTaskInfo)
{
fprintf (stderr, "Task Remove %s, %s, %d\n", detail, wt->file, wt->line);
}
return;
}
/*
* SchedulerCreate
*/
ChimeraScheduler
SchedulerCreate()
{
ChimeraScheduler cs;
MemPool mp;
mp = MPCreate();
cs = (ChimeraScheduler)MPCGet(mp, sizeof(struct ChimeraSchedulerP));
cs->mp = mp;
cs->oldtasks = GListCreateX(mp);
cs->tasks = GListCreateX(mp);
return(cs);
}

108
chimera/timeout.c Normal file
View File

@ -0,0 +1,108 @@
/*
* timeout.c
*
* Copyright (C) 1994-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include "port_after.h"
#include "ChimeraP.h"
struct ChimeraTimeOutP
{
ChimeraResources cres;
XtIntervalId iid;
ChimeraTimeOutProc func;
void *closure;
};
static void TimeOutHandler _ArgProto((XtPointer, XtIntervalId *));
/*
* TimeOutCreate
*/
ChimeraTimeOut
TimeOutCreate(cres, interval, func, closure)
ChimeraResources cres;
unsigned int interval;
ChimeraTimeOutProc func;
void *closure;
{
ChimeraTimeOut pto;
if ((pto = (ChimeraTimeOut)GListPop(cres->oldtimeouts)) == NULL)
{
pto = (ChimeraTimeOut)MPCGet(cres->mp, sizeof(struct ChimeraTimeOutP));
}
pto->cres = cres;
pto->closure = closure;
pto->func = func;
GListAddHead(cres->timeouts, pto);
pto->iid = XtAppAddTimeOut(pto->cres->appcon,
(unsigned long)interval,
TimeOutHandler, cres);
return(pto);
}
/*
* TimeOutHandler
*/
static void
TimeOutHandler(closure, iid)
XtPointer closure;
XtIntervalId *iid;
{
ChimeraResources cres = (ChimeraResources)closure;
ChimeraTimeOut pto;
for (pto = (ChimeraTimeOut)GListGetHead(cres->timeouts); pto != NULL;
pto = (ChimeraTimeOut)GListGetNext(cres->timeouts))
{
if (pto->iid == *iid)
{
pto->iid = 0;
(pto->func)(pto, pto->closure);
return;
}
}
myassert(false, "Jam!");
return;
}
/*
* TimeOutDestroy
*/
void
TimeOutDestroy(pto)
ChimeraTimeOut pto;
{
GListRemoveItem(pto->cres->timeouts, pto);
GListAddHead(pto->cres->oldtimeouts, pto);
if (pto->iid != 0) XtRemoveTimeOut(pto->iid);
memset(pto, 1, sizeof(struct ChimeraTimeOutP));
return;
}

331
chimera/view.c Normal file
View File

@ -0,0 +1,331 @@
/*
* view.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Paned.h>
#include "port_after.h"
#include "TextField.h"
#include "ChimeraP.h"
typedef struct
{
MemPool mp;
ChimeraSink wp;
char *command;
ChimeraTask wt;
ChimeraResources cres;
Widget pop, message;
} ViewInfo;
static char *ViewFind _ArgProto((MemPool, char *, char *));
static void ViewDestroy _ArgProto((ViewInfo *));
static int ViewSinkInit _ArgProto((ChimeraSink, void *));
static void ViewSinkAdd _ArgProto((void *));
static void ViewSinkEnd _ArgProto((void *));
static void ViewSinkMessage _ArgProto((void *, char *));
static void ViewMakePop _ArgProto((ViewInfo *));
static void ViewDialogStop _ArgProto((Widget, XtPointer, XtPointer));
/*
* ViewFind
*
* Return a command string for a type.
*/
static char *
ViewFind(mp, filelist, content)
MemPool mp;
char *filelist;
char *content;
{
FILE *fp;
char *f;
char buffer[BUFSIZ];
char ctype[BUFSIZ];
char command[BUFSIZ];
char junk[BUFSIZ];
char *filename;
MemPool tmp;
tmp = MPCreate();
f = filelist;
while ((filename = mystrtok(f, ':', &f)) != NULL)
{
filename = FixPath(mp, filename);
if (filename == NULL) continue;
fp = fopen(filename, "r");
if (fp == NULL) continue;
while (fgets(buffer, sizeof(buffer), fp))
{
if (buffer[0] == '#' || buffer[0] == '\n') continue;
if (sscanf(buffer, "%[^;]%[;]%[^;\n]", ctype, junk, command) == 3)
{
if (RequestMatchContent(tmp, ctype, content))
{
fclose(fp);
MPDestroy(tmp);
return(MPStrDup(mp, command));
}
}
}
fclose(fp);
}
MPDestroy(tmp);
return(NULL);
}
static void
ViewSinkEnd(closure)
void *closure;
{
ViewInfo *vi = (ViewInfo *)closure;
char *filename;
FILE *fp;
char *final;
char *path;
byte *data;
size_t len;
MIMEHeader mh;
size_t finallen;
SinkGetData(vi->wp, &data, &len, &mh);
if (data == NULL || len == 0)
{
ViewDestroy(vi);
return;
}
filename = mytmpnam(vi->mp);
if ((fp = fopen(filename, "w")) != NULL)
{
fwrite(data, len, 1, fp);
fclose(fp);
if ((path = ResourceGetString(vi->cres, "view.path")) == NULL)
{
if ((path = getenv("PATH")) == NULL) path = "";
}
finallen = strlen(" ; rm &") + strlen(path) + strlen(filename) * 2 +
strlen(vi->command) + strlen("PATH=") + 1;
final = (char *)MPGet(vi->mp, finallen);
strcpy(final, "(PATH=");
strcat(final, path);
strcat(final, " ");
sprintf (final + strlen(final), vi->command, filename);
strcat(final, "; rm ");
strcat(final, filename);
strcat(final, ") &");
system(final);
}
ViewDestroy(vi);
return;
}
/*
* ViewSinkMessage
*/
void
ViewSinkMessage(closure, message)
void *closure;
char *message;
{
ViewInfo *vi = (ViewInfo *)closure;
TextFieldSetString(vi->message, message);
return;
}
/*
* ViewDestroy
*/
static void
ViewDestroy(vi)
ViewInfo *vi;
{
ChimeraResources cres = vi->cres;
if (vi->pop != NULL) XtDestroyWidget(vi->pop);
SinkDestroy(vi->wp);
MPDestroy(vi->mp);
ChimeraRemoveReference(cres);
return;
}
/*
* ViewSinkAdd
*/
void
ViewSinkAdd(closure)
void *closure;
{
return;
}
/*
* ViewSinkInit
*/
static int
ViewSinkInit(wp, closure)
ChimeraSink wp;
void *closure;
{
char *url;
char *caplist;
ViewInfo *vi = (ViewInfo *)closure;
ChimeraRequest *wr;
if ((caplist = ResourceGetString(vi->cres, "view.capFiles")) == NULL)
{
caplist = "~/.mailcap";
}
if ((vi->command = ViewFind(vi->mp, caplist,
SinkGetInfo(wp, "content-type"))) == NULL)
{
url = SinkGetInfo(wp, "x-url");
if ((wr = RequestCreate(vi->cres, url, NULL)) == NULL) return(-1);
DownloadOpen(vi->cres, wr);
ViewDestroy(vi);
return(-1);
}
return(0);
}
static void
ViewDialogStop(w, cldata, cbdata)
Widget w;
XtPointer cldata, cbdata;
{
ViewDestroy((ViewInfo *)cldata);
return;
}
static void
ViewMakePop(vi)
ViewInfo *vi;
{
Window rw, cw;
int rx, ry, wx, wy;
unsigned int mask;
Widget paned;
Widget box;
Widget stop;
XQueryPointer(vi->cres->dpy, DefaultRootWindow(vi->cres->dpy),
&rw, &cw,
&rx, &ry,
&wx, &wy,
&mask);
vi->pop = XtVaAppCreateShell("view", "View",
transientShellWidgetClass, vi->cres->dpy,
XtNx, rx - 2,
XtNy, ry - 2,
NULL);
paned = XtCreateManagedWidget("paned",
panedWidgetClass, vi->pop,
NULL, 0);
box = XtCreateManagedWidget("box", boxWidgetClass, paned, NULL, 0);
vi->message = XtVaCreateManagedWidget("message",
textfieldWidgetClass, box,
NULL);
box = XtCreateManagedWidget("box2", boxWidgetClass, paned, NULL, 0);
stop = XtVaCreateManagedWidget("stop", commandWidgetClass, box, NULL, 0);
XtAddCallback(stop, XtNcallback, ViewDialogStop, vi);
XtRealizeWidget(vi->pop);
return;
}
/*
* ViewOpen
*/
void
ViewOpen(cres, wr)
ChimeraResources cres;
ChimeraRequest *wr;
{
ViewInfo *vi;
ChimeraSinkHooks hooks;
MemPool mp;
myassert(wr != NULL, "Request cannot be NULL.");
mp = MPCreate();
vi = (ViewInfo *)MPCGet(mp, sizeof(ViewInfo));
vi->mp = mp;
vi->cres = cres;
memset(&hooks, 0, sizeof(hooks));
hooks.init = ViewSinkInit;
hooks.add = ViewSinkAdd;
hooks.end = ViewSinkEnd;
hooks.message = ViewSinkMessage;
if ((vi->wp = SinkCreate(cres, wr)) == NULL) MPDestroy(mp);
else
{
SinkSetHooks(vi->wp, &hooks, vi);
ViewMakePop(vi);
ChimeraAddReference(vi->cres);
}
return;
}

11
common/Imakefile Normal file
View File

@ -0,0 +1,11 @@
#include <../Common.tmpl>
SRCS = mime.c list.c ml.c mempool.c dmem.c util.c dir.c url.c uproc.c
OBJS = mime.o list.o ml.o mempool.o dmem.o util.o dir.o url.o uproc.o
EXTRA_DEFINES = $(CHIMERA_DEFINES)
EXTRA_INCLUDES = -I./ -I../port
NormalLibraryTarget(xcommon, $(OBJS))
DependTarget()

84
common/common.h Normal file
View File

@ -0,0 +1,84 @@
/*
* common.h
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __COMMON_H__
#define __COMMON_H__ 1
/* mempool.c */
typedef struct MemPoolP *MemPool;
#define MPCreate() MPCreateTrack(__LINE__, __FILE__)
MemPool MPCreateTrack _ArgProto((int, char *));
void *MPGet _ArgProto((MemPool, size_t));
void *MPCGet _ArgProto((MemPool, size_t));
char *MPStrDup _ArgProto((MemPool, const char *));
void MPDestroy _ArgProto((MemPool));
void MPPrintStatus _ArgProto((void));
/* dmem.c */
void free_mem _ArgProto((void *));
void *alloc_mem _ArgProto((size_t));
void *calloc_mem _ArgProto((size_t, size_t));
void *realloc_mem _ArgProto((void *, size_t));
char *alloc_string _ArgProto((char *));
/* util.c */
char *FixPath _ArgProto((MemPool, char *));
char *mystrtok _ArgProto((char *, size_t, char **));
char *GetBaseFilename _ArgProto((char *));
char *mytmpnam _ArgProto((MemPool));
#ifdef NDEBUG
#define myassert(a, b)
#else
#define myassert(a, b) xmyassert(a, b, __FILE__, __LINE__)
void xmyassert _ArgProto((bool, char *, char *, int));
#endif
/* dir.c */
char *compress_path _ArgProto((MemPool, char *, char *));
char *whack_filename _ArgProto((MemPool, char *));
/* list.c */
typedef struct GListP *GList;
#define GListCreate() GListCreateTrack(__LINE__, __FILE__)
GList GListCreateTrack _ArgProto((int, char *));
GList GListCreateX _ArgProto((MemPool));
void GListAddHead _ArgProto((GList, void *));
#define GListPush(a, b) GListAddHead(a, b)
void GListAddTail _ArgProto((GList, void *));
void GListDestroy _ArgProto((GList));
void *GListGetHead _ArgProto((GList));
void *GListGetTail _ArgProto((GList));
void *GListGetNext _ArgProto((GList));
void *GListGetPrev _ArgProto((GList));
void GListRemoveItem _ArgProto((GList, void *));
bool GListEmpty _ArgProto((GList));
void *GListPop _ArgProto((GList));
void *GListGetCurrent _ArgProto((GList));
void GListPrintStatus _ArgProto((void));
void GListClear _ArgProto((GList));
void *GListCurrent _ArgProto((GList));
/* uproc.c */
void StartReaper _ArgProto((void));
int PipeCommand _ArgProto((char *, int *));
#endif /* __COMMON_H__ */

135
common/dir.c Normal file
View File

@ -0,0 +1,135 @@
/*
* dir.c
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "port_after.h"
#include "common.h"
/*
* whack_filename
*/
char *
whack_filename(mp, p)
MemPool mp;
char *p;
{
char *n = MPStrDup(mp, p);
size_t last;
last = strlen(n) - 1;
if (*(n + last) != '/')
{
for (p = n + last; p >= n; p--)
{
if (*p == '/')
{
*(p + 1) = '\0';
break;
}
}
}
return(n);
}
/*
* compress_path
*
* This assumes sizeof(char) == 1 which is probably a really bad idea.
*/
char *
compress_path(mp, c, cwd)
MemPool mp;
char *c;
char *cwd;
{
char *r;
char *p, *p1, *p2, *p3;
char *ps;
if (*c != '/')
{
if (*cwd != '/') return(NULL);
r = (char *)MPGet(mp, strlen("/") + strlen(c) + strlen(cwd) + 1);
strcpy(r, cwd);
strcat(r, "/");
strcat(r, c);
}
else r = MPStrDup(mp, c);
for (p = r; *p != '\0'; )
{
if (*p == '/')
{
p1 = p + 1;
if (*p1 == '/')
{
memmove(p, p1, strlen(p1) + 1);
continue;
}
else if (*p1 == '.')
{
p2 = p1 + 1;
if (*p2 == '/')
{
memmove(p, p2, strlen(p2) + 1);
continue;
}
else if (*p2 == '\0')
{
*p1 = '\0';
return(r);
}
else if (*p2 == '.')
{
p3 = p2 + 1;
if (*p3 == '/' || *p3 == '\0')
{
for (ps = p - 1; ps >= r; ps--)
{
if (*ps == '/') break;
}
if (ps < r) ps = r;
if (*p3 == '/') memmove(ps, p3, strlen(p3) + 1);
else
{
*(ps + 1) = '\0';
return(r);
}
p = ps;
continue;
}
}
}
}
p++;
}
return(r);
}

87
common/dmem.c Normal file
View File

@ -0,0 +1,87 @@
/*
* dmem.c
*
* Copyright (C) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
/*
* free_mem
*/
void
free_mem(m)
void *m;
{
free(m);
return;
}
/*
* calloc_mem
*/
void *
calloc_mem(len, elen)
size_t len, elen;
{
return(calloc(len, elen));
}
/*
* alloc_mem
*/
void *
alloc_mem(len)
size_t len;
{
return(malloc(len));
}
/*
* realloc_mem
*/
void *
realloc_mem(s, len)
void *s;
size_t len;
{
return(realloc(s, len));
}
/*
* alloc_string
*/
char *
alloc_string(str)
char *str;
{
char *ns;
ns = (char *)malloc(strlen(str) + 1);
strcpy(ns, str);
return(ns);
}

353
common/list.c Normal file
View File

@ -0,0 +1,353 @@
/*
* list.c
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "port_after.h"
#include "common.h"
struct GNodeP
{
void *thing;
struct GNodeP *prev, *next;
};
struct GListP
{
bool localmp;
MemPool mp;
struct GNodeP *f;
struct GNodeP *head, *tail;
struct GNodeP *c;
};
/*
#define TRACKER 1
*/
#ifdef TRACKER
struct track
{
GList gl;
int line;
char *file;
struct track *next;
};
static struct track *track_list = NULL;
#endif
static void FreeListNode _ArgProto((GList, struct GNodeP *));
static struct GNodeP *GetFreedNode _ArgProto((GList));
static void
FreeListNode(gl, f)
GList gl;
struct GNodeP *f;
{
#ifdef TRACKER
memset(f, 0, sizeof(struct GNodeP));
#endif
f->next = gl->f;
gl->f = f;
return;
}
static struct GNodeP *
GetFreedNode(gl)
GList gl;
{
struct GNodeP *f;
return(NULL);
if (gl->f == NULL) return(NULL);
f = gl->f;
gl->f = f->next;
memset(f, 0, sizeof(struct GNodeP));
return(f);
}
GList
GListCreateX(mp)
MemPool mp;
{
GList gl;
gl = (GList)MPCGet(mp, sizeof(struct GListP));
gl->mp = mp;
gl->localmp = false;
return(gl);
}
GList
GListCreateTrack(line, file)
int line;
char *file;
{
MemPool mp;
GList gl;
#ifdef TRACKER
struct track *f;
#endif
mp = MPCreate();
gl = (GList)MPCGet(mp, sizeof(struct GListP));
gl->mp = mp;
gl->localmp = true;
#ifdef TRACKER
f = (struct track *)malloc(sizeof(struct track));
f->gl = gl;
f->line = line;
f->file = file;
f->next = track_list;
track_list = f;
#endif
return(gl);
}
void *
GListPop(gl)
GList gl;
{
void *thing;
struct GNodeP *f;
if (gl->head != NULL)
{
thing = gl->head->thing;
f = gl->head;
if (gl->head != NULL) gl->head = gl->head->next;
if (gl->head != NULL) gl->head->prev = NULL;
gl->c = gl->head;
FreeListNode(gl, f);
return(thing);
}
return(NULL);
}
void
GListAddHead(gl, thing)
GList gl;
void *thing;
{
struct GNodeP *gn;
if ((gn = GetFreedNode(gl)) == NULL)
{
gn = (struct GNodeP *)MPCGet(gl->mp, sizeof(struct GNodeP));
}
gn->next = gl->head;
if (gl->head != NULL) gl->head->prev = gn;
gl->head = gn;
if (gl->tail == NULL) gl->tail = gn;
gn->thing = thing;
return;
}
void
GListAddTail(gl, thing)
GList gl;
void *thing;
{
struct GNodeP *gn;
if ((gn = GetFreedNode(gl)) == NULL)
{
gn = (struct GNodeP *)MPCGet(gl->mp, sizeof(struct GNodeP));
}
gn->prev = gl->tail;
if (gl->tail != NULL) gl->tail->next = gn;
gl->tail = gn;
if (gl->head == NULL) gl->head = gn;
gn->thing = thing;
return;
}
void
GListDestroy(gl)
GList gl;
{
#ifdef TRACKER
struct track *f;
#endif
if (gl->localmp) MPDestroy(gl->mp);
#ifdef TRACKER
for (f = track_list; f != NULL; f = f->next)
{
if (f->gl == gl)
{
f->gl = NULL;
break;
}
}
#endif
return;
}
void *
GListGetHead(gl)
GList gl;
{
if (gl->head == NULL) return(NULL);
gl->c = gl->head;
return(gl->head->thing);
}
void *
GListGetTail(gl)
GList gl;
{
if (gl->tail == NULL) return(NULL);
gl->c = gl->tail;
return(gl->tail->thing);
}
void *
GListGetNext(gl)
GList gl;
{
if (gl->c == NULL) return(NULL);
gl->c = gl->c->next;
if (gl->c == NULL) return(NULL);
return(gl->c->thing);
}
void *
GListGetPrev(gl)
GList gl;
{
if (gl->c == NULL) return(NULL);
gl->c = gl->c->prev;
if (gl->c == NULL) return(NULL);
return(gl->c->thing);
}
void *
GListGetCurrent(gl)
GList gl;
{
if (gl->c == NULL) return(NULL);
return(gl->c->thing);
}
void
GListRemoveItem(gl, thing)
GList gl;
void *thing;
{
struct GNodeP *c, *n;
for (c = gl->head; c != NULL; )
{
if (c->thing == thing)
{
if (gl->c == c) gl->c = NULL;
n = c->next;
if (c == gl->head) gl->head = c->next;
if (c == gl->tail) gl->tail = c->prev;
if (c->next != NULL) c->next->prev = c->prev;
if (c->prev != NULL) c->prev->next = c->next;
FreeListNode(gl, c);
c = n;
}
else c = c->next;
}
return;
}
bool
GListEmpty(gl)
GList gl;
{
return(gl == NULL || gl->head == NULL);
}
MemPool
GListMP(gl)
GList gl;
{
return(gl->mp);
}
void
GListPrintStatus()
{
#ifdef TRACKER
struct track *f;
for (f = track_list; f != NULL; f = f->next)
{
if (f->gl != NULL)
{
fprintf (stderr, "GList unfreed: Line %d, File %s\n", f->line, f->file);
}
}
#endif
return;
}
void
GListClear(gl)
GList gl;
{
struct GNodeP *c, *t;
gl->c = NULL;
c = gl->head;
t = NULL;
while (c != NULL)
{
t = c;
c = c->next;
}
if (t != NULL)
{
t->next = gl->f;
gl->f = gl->head;
}
gl->head = NULL;
gl->tail = NULL;
return;
}

318
common/mempool.c Normal file
View File

@ -0,0 +1,318 @@
/*
* mempool.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "port_after.h"
#include "common.h"
/*
* MPDEBUG - If this is defined then all memory pooling goes away and
* malloc is used. This is useful if you suspect problems
* with the memory pooling code (e.g. alignment problems)
* or you want to use a malloc checker.
*
* MPALIGN - If the alignment size is guessed wrong then this can be
* defined to be the appropriate alignment size to override
* the automatic thing.
*
* MPPOOLSIZE - This is the minimum allocation size. Maybe changing
* it would result in better performance. Must be
* larger than sizeof(struct pool)...probably much larger.
*/
/*
#define MPDEBUG 1
*/
#define MPPOOLSIZE BUFSIZ
#ifndef MPALIGN
typedef struct Alignment
{
union { int a; char *b; size_t c; off_t d; long e; } align;
} Alignment;
#define MPALIGNSIZE(x) ((x / sizeof(Alignment) + 1) * sizeof(Alignment))
#else
#define MPALIGNSIZE(x) ((x / MPALIGN + 1) * MPALIGN)
#endif
/*
#define TRACKER 1
*/
#ifdef TRACKER
struct track
{
MemPool mp;
int line;
char *file;
struct track *next;
};
static struct track *track_list = NULL;
#endif
struct pool
{
size_t used, len;
#ifdef MPDEBUG
void *mem;
#endif
struct pool *next;
};
struct MemPoolP
{
struct pool *plist;
size_t len;
};
#ifndef MPDEBUG
static struct pool *create_pool _ArgProto((size_t));
static void *use_pool _ArgProto((struct pool *, size_t));
/*
* create_pool
*/
static struct pool *
create_pool(alen)
size_t alen;
{
size_t blen, len, plen;
struct pool *pool;
plen = MPALIGNSIZE(sizeof(struct pool));
len = MPALIGNSIZE(alen) + plen;
blen = (len / MPPOOLSIZE + 1) * MPPOOLSIZE;
pool = (struct pool *)malloc(blen);
if (pool == NULL)
{
fprintf (stderr, "create_pool malloc failed: %ld\n", (long)blen);
return(NULL);
}
pool->len = blen;
pool->used = plen;
pool->next = NULL;
return(pool);
}
/*
* use_pool
*/
static void *
use_pool(pool, len)
struct pool *pool;
size_t len;
{
byte *mem;
len = MPALIGNSIZE(len);
if (pool->used + len > pool->len) return(NULL);
mem = (byte *)pool + pool->used;
pool->used += len;
return((void *)mem);
}
#endif
/*
* MPCreate
*/
MemPool
MPCreateTrack(line, file)
int line;
char *file;
{
MemPool mp;
struct pool *pool;
#ifdef TRACKER
struct track *f;
#endif
#ifndef MPDEBUG
pool = create_pool(sizeof(struct MemPoolP));
if (pool == NULL) return(NULL);
mp = (MemPool)use_pool(pool, sizeof(struct MemPoolP));
myassert(mp != NULL, "MPCreate: use_pool failed!");
mp->plist = pool;
mp->len = pool->len;
#else
mp = (MemPool)malloc(sizeof(struct MemPoolP));
if (mp == NULL) return(NULL);
memset(mp, 0, sizeof(struct MemPoolP));
#endif
#ifdef TRACKER
f = (struct track *)malloc(sizeof(struct track));
if (f == NULL) abort();
f->mp = mp;
f->line = line;
f->file = file;
f->next = track_list;
track_list = f;
#endif
return(mp);
}
/*
* MPGet
*/
void *
MPGet(mp, len)
MemPool mp;
size_t len;
{
struct pool *pool;
void *mem;
myassert(len > 0, "MPGet: must allocate sizes greater than zero!");
#ifndef MPDEBUG
pool = mp->plist;
if ((mem = use_pool(pool, len)) == NULL)
{
pool = create_pool(len);
pool->next = mp->plist;
mp->len += pool->len;
mp->plist = pool;
mem = use_pool(pool, len);
myassert(mem != NULL, "MPGet: use_pool failed!");
}
#else
pool = (struct pool *)malloc(sizeof(struct pool));
if (pool == NULL) return(NULL);
pool->next = mp->plist;
mp->plist = pool;
mem = pool->mem = malloc(len);
#endif
return(mem);
}
/*
* MPCGet
*/
void *
MPCGet(mp, len)
MemPool mp;
size_t len;
{
void *m;
m = MPGet(mp, len);
memset(m, 0, len);
return(m);
}
/*
* MPStrDup
*/
char *
MPStrDup(mp, s)
MemPool mp;
const char *s;
{
size_t len;
char *ns;
if (s == NULL) return(NULL);
len = strlen(s);
ns = (char *)MPGet(mp, len + 1);
strcpy(ns, s);
return(ns);
}
/*
* MPDestroy
*/
void
MPDestroy(mp)
MemPool mp;
{
struct pool *m, *t;
#ifdef TRACKER
struct track *f;
#endif
for (m = mp->plist; m != NULL; )
{
t = m;
m = m->next;
#ifdef MPDEBUG
free(t->mem);
#endif
free(t);
}
#ifdef MPDEBUG
free(mp);
#endif
#ifdef TRACKER
for (f = track_list; f != NULL; f = f->next)
{
if (f->mp == mp)
{
f->mp = NULL;
break;
}
}
#endif
return;
}
/*
* MPPrintStats
*/
void
MPPrintStatus()
{
#ifdef TRACKER
struct track *f;
size_t total;
total = 0;
for (f = track_list; f != NULL; f = f->next)
{
if (f->mp != NULL)
{
fprintf (stderr, "MP unfreed: Line %d, File %s, Length %ld\n",
f->line, f->file, (long)f->mp->len);
total += f->mp->len;
}
}
fprintf (stderr, "Total unfreed: %ld\n", (long)total);
#endif
return;
}

432
common/mime.c Normal file
View File

@ -0,0 +1,432 @@
/*
* mime.c
*
* Copyright (c) 1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "mime.h"
typedef struct MIMEFieldP *MIMEField;
typedef struct MIMEParamP *MIMEParam;
/*
* MIMEish parsing thing.
*
* Tries to deal with stuff of the form:
*
* field-name: field-value; param[=value]; param[=value]; ...
*/
struct MIMEHeaderP
{
GList list; /* list of MIMEField */
MemPool mp;
size_t i;
size_t len;
bool data_found;
};
struct MIMEFieldP
{
char *name;
char *value;
GList list; /* list of param */
};
struct MIMEParamP
{
char *name;
char *value;
};
static MIMEParam parse_param _ArgProto((char *));
static MIMEField parse_line _ArgProto((MemPool, char *));
MIMEHeader
MIMECreateHeader()
{
MemPool mp;
MIMEHeader mh;
mp = MPCreate();
mh = MPCGet(mp, sizeof(struct MIMEHeaderP));
mh->mp = mp;
mh->list = GListCreateX(mp);
mh->data_found = false;
return(mh);
}
static MIMEParam
parse_param(line)
char *line;
{
MIMEParam p = NULL;
return(p);
}
static MIMEField
parse_line(mp, line)
MemPool mp;
char *line;
{
MIMEField mf = NULL;
MIMEParam param;
char *cp;
char *ps = NULL;
bool inquote = false;
char *t;
for (cp = line; *cp != '\0'; cp++)
{
if (mf != NULL)
{
if (inquote)
{
if (*cp == '"') inquote = false;
}
else
{
if (*cp == '"') inquote = true;
else if (*cp == ';' || *cp == '\0')
{
while (isspace8(*ps) && ps < cp) ps++;
if (ps < cp)
{
t = (char *)MPGet(mp, cp - ps + 1);
strncpy(t, ps, cp - ps);
t[cp - ps] = '\0';
if (mf->value == NULL) mf->value = t;
else
{
if (mf->list == NULL) mf->list = GListCreateX(mp);
if ((param = parse_param(t)) != NULL)
{
GListAddTail(mf->list, param);
}
}
}
ps = cp + 1;
}
}
}
else if (*cp == ':')
{
mf = (MIMEField)MPCGet(mp, sizeof(struct MIMEFieldP));
mf->name = (char *)MPGet(mp, cp - line + 1);
strncpy(mf->name, line, cp - line);
mf->name[cp - line] = '\0';
ps = cp + 1;
}
}
/*
* Catch the value or parameter that is terminated with \0
*/
if (mf != NULL && ps < cp)
{
while (isspace8(*ps) && ps < cp) ps++;
if (ps < cp)
{
t = (char *)MPGet(mp, cp - ps + 1);
strncpy(t, ps, cp - ps);
t[cp - ps] = '\0';
if (mf->value == NULL) mf->value = t;
else
{
if (mf->list == NULL) mf->list = GListCreateX(mp);
if ((param = parse_param(t)) != NULL)
{
GListAddTail(mf->list, param);
}
}
}
}
return(mf);
}
/*
* MIMEParseBuffer
*
* This is the entry point for code to parse a buffer that contains
* a MIME-like thing chunk of chars.
*/
int
MIMEParseBuffer(mh, buf, len)
MIMEHeader mh;
char *buf;
size_t len;
{
MIMEField mf;
size_t j;
char *cp, *pcp, *ls, *le;
char *line;
size_t usedlen;
size_t linelen;
myassert(mh->data_found, "Must call MIMEFindData before MIMEParseBuffer");
usedlen = 0;
linelen = BUFSIZ;
line = (char *)alloc_mem(linelen);
le = NULL;
ls = cp = buf;
pcp = "";
for (j = 0; j < len; j++, pcp = cp, cp++)
{
if (*cp != '\n') continue;
/*
* If line ends with \r\n then shift EOL back one character so that
* \r doesn't get included in the line.
*/
if (*pcp == '\r') le = pcp;
else le = cp;
/*
* If the line start is the same as the line end then it must be
* a blank line and its time to bail out.
*/
if (ls == le) break;
/*
* If the line doesn't begin with a space character then flush the
* previous line (if there was a previous) as a complete field.
* Otherwise remove the blank space from the continuation line.
*/
if (!isspace8(*ls))
{
if (usedlen > 0)
{
if ((mf = parse_line(mh->mp, line)) != NULL)
{
GListAddTail(mh->list, mf);
}
usedlen = 0;
}
}
else
{
while(isspace8(*ls) && ls < le) ls++;
}
/*
* If there is something besides whitespace then stick it in the line
* buffer.
*/
if (ls < le)
{
if (linelen < usedlen + (le - ls))
{
linelen += ((le - ls) / BUFSIZ + 1) * BUFSIZ;
line = (char *)realloc(line, linelen);
}
strncpy(line + usedlen, ls, le - ls);
usedlen += le - ls;
line[usedlen] = '\0';
}
/*
* Start the next line after the \n
*/
ls = cp + 1;
}
if (usedlen > 0)
{
if ((mf = parse_line(mh->mp, line)) != NULL)
{
GListAddTail(mh->list, mf);
}
usedlen = 0;
}
free_mem(line);
return(0);
}
/*
* MIMEDestroyHeader
*/
void
MIMEDestroyHeader(mh)
MIMEHeader mh;
{
MPDestroy(mh->mp);
return;
}
/*
* MIMEFindData
*
* Searches for \n\n and \r\n\r\n in a string. Returns the offset after
* the pattern;
*/
int
MIMEFindData(mh, data, len, doff)
MIMEHeader mh;
char *data;
size_t len;
size_t *doff;
{
char *cp;
char n[4];
size_t j;
myassert(mh->i < len, "MIMEFindData: Inconsistent buffer sizes");
memset(n, 0, sizeof(n));
j = 0;
for (cp = data + mh->i; mh->i < len; mh->i++, j++, cp++)
{
n[j % 4] = *cp;
/*
* Mmmm fun. If there are two or more characters and the current
* and previous character are '\n' (i.e. blank line) then the end
* of the header has been reached. If there are 4 or more characters
* and the sequence of characters (in reverse order) is \n\r\n\r then
* the end of header has been reached.
*/
if (j >= 2 && n[j % 4] == '\n' &&
(n[(j - 1) % 4] == '\n' ||
(j >= 4 && n[(j - 1) % 4] == '\r' && n[(j - 2) % 4] == '\n' &&
n[(j - 3) % 4] == '\r')))
{
mh->data_found = true;
*doff = mh->i + 1;
return(0);
}
}
return(-1);
}
/*
* MIMEGetField
*/
int
MIMEGetField(mh, name, value)
MIMEHeader mh;
char *name;
char **value;
{
MIMEField f;
for (f = (MIMEField)GListGetHead(mh->list); f != NULL;
f = (MIMEField)GListGetNext(mh->list))
{
if (strlen(f->name) == strlen(name) && strcasecmp(f->name, name) == 0)
{
*value = f->value;
return(0);
}
}
return(-1);
}
/*
* MIMEAddLine
*
* Adds a field to a header. Parses out parameters into structures.
*/
void
MIMEAddLine(mh, line)
MIMEHeader mh;
char *line;
{
MIMEField f;
if ((f = parse_line(mh->mp, line)) != NULL)
{
GListAddTail(mh->list, f);
}
return;
}
/*
* MIMEAddField
*/
void
MIMEAddField(mh, name, value)
MIMEHeader mh;
char *name;
char *value;
{
MIMEField mf;
mf = (MIMEField)MPCGet(mh->mp, sizeof(struct MIMEFieldP));
mf->name = MPStrDup(mh->mp, name);
mf->value = MPStrDup(mh->mp, value);
GListAddTail(mh->list, mf);
return;
}
/*
* MIMEWriteHeader
*
* This doesn't break long lines.
*/
int
MIMEWriteHeader(mh, fp)
MIMEHeader mh;
FILE *fp;
{
MIMEField mf;
MIMEParam param;
for (mf = (MIMEField)GListGetHead(mh->list); mf != NULL;
mf = (MIMEField)GListGetNext(mh->list))
{
fprintf (fp, "%s: %s", mf->name, mf->value);
if (mf->list != NULL)
{
for (param = (MIMEParam)GListGetHead(mf->list); param != NULL;
param = (MIMEParam)GListGetNext(mf->list))
{
fprintf (fp, "; %s", param->name);
if (param->value != NULL) fprintf (fp, "=%s", param->value);
}
}
fprintf (fp, "\n");
}
fprintf (fp, "\n");
return(0);
}

37
common/mime.h Normal file
View File

@ -0,0 +1,37 @@
/*
* mime.h
*
* Copyright (c) 1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MIME_H__
#define __MIME_H__ 1
typedef struct MIMEHeaderP *MIMEHeader;
MIMEHeader MIMECreateHeader _ArgProto((void));
int MIMEParseBuffer _ArgProto((MIMEHeader, char *, size_t));
void MIMEDestroyHeader _ArgProto((MIMEHeader));
int MIMEGetField _ArgProto((MIMEHeader, char *, char **));
void MIMEAddField _ArgProto((MIMEHeader, char *, char *));
void MIMEAddLine _ArgProto((MIMEHeader, char *));
int MIMEGetHeaderEnd _ArgProto((MIMEHeader, size_t *));
int MIMEFindData _ArgProto((MIMEHeader, char *, size_t, size_t *));
int MIMEWriteHeader _ArgProto((MIMEHeader, FILE *));
#endif

788
common/ml.c Normal file
View File

@ -0,0 +1,788 @@
/*
* ml.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* Bogus parser for things that kind of maybe look like HTML/SGML.
* Or something.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "ml.h"
typedef enum
{
MLS_TAG, /* inside tag */
MLS_AVS, /* inside attribute value (single quote) */
MLS_AVD, /* inside attribute value (double quote) */
MLS_PSCOMMENT, /* possible start comment */
MLS_PECOMMENT, /* possible end comment */
MLS_COMMENT, /* inside comment */
MLS_DATA, /* between tags */
MLS_START /* start state */
} MLStateID;
#define IN_STATE(a, b) ((a)->plist->state == (b))
struct MLAttributeP
{
char *name;
char *value;
struct MLAttributeP *next;
};
struct MLElementP
{
MLElementType type;
char *ptext; /* processed text */
size_t plen; /* processed text length */
MLAttribute ta; /* attribute list */
};
struct PState
{
MLStateID state;
size_t off;
struct PState *next;
};
struct MLStateP
{
MemPool tmp; /* temporary memory pool */
MemPool mp; /* memory pool descriptor */
char *data; /* address of HTML buffer */
size_t len; /* length of HTML buffer */
size_t off; /* offset of parse */
MLElementHandler func; /* called when part created */
void *closure; /* state info for callback */
MLElement head, tail; /* element list */
MLElement curr; /* next unprocessed element */
struct PState *plist; /* parser state stack */
int count; /* call count */
};
static MLAttribute hs_parse_tag _ArgProto((MLState, char *, size_t));
static void hs_add_element _ArgProto((MLState, MLElement));
static MLElement hs_create_element _ArgProto((MLState, char *, size_t));
static MLElement hs_create_text _ArgProto((MLState, char *, size_t));
static MLElement hs_create_tag _ArgProto((MLState, char *, size_t));
static char *hs_condense _ArgProto((MLState, char *, size_t, size_t *));
static MLAttribute hs_create_attribute _ArgProto((MLState, char *, size_t));
static void hs_push _ArgProto((MLState, int));
static size_t hs_pop _ArgProto((MLState));
static void hs_handle_data _ArgProto((MLState, char *, size_t, bool));
/*
* hs_push
*/
static void
hs_push(hs, state)
MLState hs;
int state;
{
struct PState *ps;
ps = (struct PState *)MPCGet(hs->tmp, sizeof(struct PState));
ps->off = hs->off;
ps->state = state;
ps->next = hs->plist;
hs->plist = ps;
return;
}
/*
* hs_pop
*/
static size_t
hs_pop(hs)
MLState hs;
{
size_t off;
if (hs->plist == NULL) abort();
off = hs->plist->off;
hs->plist = hs->plist->next;
return(off);
}
/*
* hs_create_attribute
*/
static MLAttribute
hs_create_attribute(hs, text, len)
MLState hs;
char *text;
size_t len;
{
MLAttribute ta;
ta = (MLAttribute)MPCGet(hs->mp, sizeof(struct MLAttributeP));
ta->name = (char *)MPGet(hs->mp, len + 1);
strncpy(ta->name, text, len);
ta->name[len] = '\0';
return(ta);
}
struct entity
{
char *text;
int len;
unsigned char c;
} clist[] =
{
{ "amp", 3, '&' },
{ "lt", 2, '<' },
{ "gt", 2, '>' },
{ "copy", 4, 169 },
{ "AElig", 5, 198 },
{ "Aacute", 6, 193 },
{ "Acirc", 5, 194 },
{ "Agrave", 6, 192 },
{ "Aring", 5, 197 },
{ "Atilde", 6, 195 },
{ "Auml", 4, 196 },
{ "Ccedil", 6, 199 },
{ "ETH", 3, 208 },
{ "Eacute", 6, 201 },
{ "Ecirc", 5, 202 },
{ "Egrave", 6, 200 },
{ "Euml", 4, 203 },
{ "Iacute", 6, 205 },
{ "Icirc", 5, 206 },
{ "Igrave", 6, 204 },
{ "Iuml", 4, 207 },
{ "Ntilde", 6, 209 },
{ "Oacute", 6, 211 },
{ "Ocirc", 5, 212 },
{ "Ograve", 6, 210 },
{ "Oslash", 6, 216 },
{ "Otilde", 6, 213 },
{ "Ouml", 4, 214 },
{ "THORN", 5, 222 },
{ "Uacute", 6, 218 },
{ "Ucirc", 5, 219 },
{ "Ugrave", 6, 217 },
{ "Uuml", 4, 220 },
{ "Yacute", 6, 221 },
{ "aacute", 6, 225 },
{ "acirc", 5, 226 },
{ "aelig", 5, 230 },
{ "agrave", 6, 224 },
{ "aring", 5, 229 },
{ "atilde", 6, 227 },
{ "auml", 4, 228 },
{ "ccedil", 6, 231 },
{ "eacute", 6, 233 },
{ "ecirc", 5, 234 },
{ "egrave", 6, 232 },
{ "eth", 3, 240 },
{ "euml", 4, 235 },
{ "iacute", 6, 237 },
{ "icirc", 5, 238 },
{ "igrave", 6, 236 },
{ "iuml", 4, 239 },
{ "ntilde", 6, 241 },
{ "oacute", 6, 243 },
{ "ocirc", 5, 244 },
{ "ograve", 6, 242 },
{ "oslash", 6, 248 },
{ "otilde", 6, 245 },
{ "ouml", 4, 246 },
{ "szlig", 5, 223 },
{ "thorn", 5, 254 },
{ "uacute", 6, 250 },
{ "ucirc", 5, 251 },
{ "ugrave", 6, 249 },
{ "uuml", 4, 252 },
{ "yacute", 6, 253 },
{ "yuml", 4, 255 },
{ "reg", 3, 174 },
{ "comma", 5, 44 },
{ "colon", 5, 58 },
{ "quot", 4, '\"' },
{ "nbsp", 4, ' ' },
{ NULL, 0, '\0' },
};
/*
* hs_condense
*/
static char *
hs_condense(hs, text, len, newlen)
MLState hs;
char *text;
size_t len;
size_t *newlen;
{
char *cp, *lastcp;
size_t i;
char *b, *bcp;
char *x;
/*
* allocate a buffer for the new text. the new text will be smaller than
* the incoming text
*/
b = (char *)MPGet(hs->mp, len + 1);
bcp = b;
for (cp = text, lastcp = text + len; cp < lastcp; cp++)
{
/*
* Found entity and there is at least one more character?
*/
if (*cp == '&')
{
for (x = cp; x < lastcp && *x != ';' && !isspace8(*x); x++)
;
if (x < lastcp) /* found end of entity ? */
{
if (*x == '\r') x++; /* this may die */
if (*(cp + 1) == '#') /* number given ? */
{
*bcp = (char)atoi(cp + 2); /* get the character */
bcp++;
cp = x;
}
else
{
char *crap;
/* Search in the table of entity names */
for (i = 0, crap = cp + 1; clist[i].text != NULL; i++)
{
if (strncmp(clist[i].text, crap, clist[i].len) == 0)
{
*bcp = clist[i].c;
bcp++;
cp = x;
break;
}
}
}
}
if (cp < x)
{
*bcp = *cp;
bcp++;
}
}
else
{
*bcp = *cp; /* not part of entity */
bcp++;
}
}
*newlen = bcp - b;
*bcp = '\0';
return(b);
}
/*
* hs_parse_tag
*/
MLAttribute
hs_parse_tag(hs, text, len)
MLState hs;
char *text;
size_t len;
{
char *cp, *start, *lastcp;
MLAttribute tahead, tatail, ta;
size_t newlen;
tahead = NULL;
tatail = NULL;
lastcp = text + len;
for (cp = text; cp < lastcp; )
{
/* Eat leading spaces */
for (; cp < lastcp && isspace8(*cp); cp++)
;
if (cp == lastcp) break;
/* Look for value */
for (start = cp; cp < lastcp && !isspace8(*cp) && *cp != '='; cp++)
;
ta = hs_create_attribute(hs, start, cp - start);
if (isspace8(*cp))
{
for (; cp < lastcp && isspace8(*cp); cp++)
;
}
/* Found value */
if (cp < lastcp && *cp == '=')
{
cp++; /* past '=' */
/* Eat leading spaces */
for (; cp < lastcp && isspace8(*cp); cp++)
;
if (cp < lastcp)
{
/* Quoted value */
if (*cp == '"')
{
cp++; /* past '"' */
for (start = cp; cp < lastcp && *cp != '"'; cp++)
;
}
else if (*cp == '\'') /* single quoted value */
{
cp++; /* past ' */
for (start = cp; cp < lastcp && *cp != '\''; cp++)
;
}
else /* Unquoted value */
{
for (start = cp; cp < lastcp && !isspace8(*cp); cp++)
;
}
ta->value = hs_condense(hs, start, cp - start, &newlen);
}
}
if (tatail == NULL) tahead = ta;
else tatail->next = ta;
tatail = ta;
}
return(tahead);
}
/*
* hs_add_element
*/
static void
hs_add_element(hs, p)
MLState hs;
MLElement p;
{
(hs->func)(hs->closure, p);
return;
}
/*
* hs_create_element
*/
static MLElement
hs_create_element(hs, ptext, plen)
MLState hs;
char *ptext;
size_t plen;
{
MLElement p;
p = (MLElement)MPCGet(hs->mp, sizeof(struct MLElementP));
p->ptext = ptext;
p->plen = plen;
return(p);
}
/*
* hs_create_text
*/
static MLElement
hs_create_text(hs, text, len)
MLState hs;
char *text;
size_t len;
{
char *cp;
size_t newlen;
size_t i;
MLElement p;
/* Check for an entity */
for (cp = text, i = 0; i < len && *cp != '&'; cp++, i++)
;
if (i == len) p = hs_create_element(hs, text, len);
else
{
/* found an entity...condense */
cp = hs_condense(hs, text, len, &newlen);
p = hs_create_element(hs, cp, newlen);
}
p->type = ML_DATA;
return(p);
}
/*
* hs_create_tag
*/
static MLElement
hs_create_tag(hs, text, len)
MLState hs;
char *text;
size_t len;
{
MLElement p;
p = hs_create_element(hs, text, len);
p->ta = hs_parse_tag(hs, text + 1, len - 2);
if (p->ta != NULL && p->ta->name != NULL && p->ta->name[0] == '/')
{
p->ta->name++; /* this should be OK because it is not free'd */
p->type = ML_ENDTAG;
}
else p->type = ML_BEGINTAG;
return(p);
}
/*
* MLInit
*/
MLState
MLInit(func, closure)
MLElementHandler func;
void *closure;
{
MLState hs;
MemPool mp;
mp = MPCreate();
hs = (MLState)MPCGet(mp, sizeof(struct MLStateP));
hs->mp = mp;
hs->func = func;
hs->closure = closure;
hs->tmp = MPCreate();
hs_push(hs, MLS_START);
hs_push(hs, MLS_DATA);
return(hs);
}
/*
* MLDestroy
*/
void
MLDestroy(hs)
MLState hs;
{
MPDestroy(hs->mp);
return;
}
/*
* hs_handle_data
*/
void
hs_handle_data(hs, data, len, dend)
MLState hs;
char *data;
size_t len;
bool dend;
{
char *cp;
size_t poff;
MLElement n;
if (data == NULL || len == 0) return;
hs->data = data;
hs->len = len;
while (hs->off < len)
{
cp = data + hs->off;
if (IN_STATE(hs, MLS_DATA))
{
if (*cp == '<')
{
poff = hs_pop(hs);
if (hs->off - poff > 0)
{
n = hs_create_text(hs, hs->data + poff, hs->off - poff);
hs_add_element(hs, n);
}
hs_push(hs, MLS_TAG);
}
hs->off++;
}
else if (IN_STATE(hs, MLS_TAG))
{
if (*cp == '<') hs->off++;
else if (*cp == '>')
{
poff = hs_pop(hs);
n = hs_create_tag(hs, hs->data + poff, hs->off - poff + 1);
hs_add_element(hs, n);
hs->off++;
hs_push(hs, MLS_DATA);
}
else if (*cp == '-')
{
hs_push(hs, MLS_PSCOMMENT);
hs->off++;
}
else if (*cp == '"')
{
hs_push(hs, MLS_AVD);
hs->off++;
}
else if (*cp == '\'')
{
hs_push(hs, MLS_AVS);
hs->off++;
}
else hs->off++;
}
else if (IN_STATE(hs, MLS_PSCOMMENT))
{
hs_pop(hs);
if (*cp == '-')
{
hs_push(hs, MLS_COMMENT);
hs->off++;
}
else if (*cp == '>')
{
poff = hs_pop(hs);
n = hs_create_tag(hs, hs->data + poff, hs->off - poff + 1);
hs_add_element(hs, n);
hs->off++;
hs_push(hs, MLS_DATA);
}
else hs->off++;
}
else if (IN_STATE(hs, MLS_AVS))
{
if (*cp == '\'')
{
hs_pop(hs);
hs->off++;
}
else if (*cp == '>') hs_pop(hs);
else hs->off++;
}
else if (IN_STATE(hs, MLS_AVD))
{
if (*cp == '"')
{
hs_pop(hs);
hs->off++;
}
else if (*cp == '>') hs_pop(hs);
else hs->off++;
}
else if (IN_STATE(hs, MLS_COMMENT))
{
if (*cp == '-') hs_push(hs, MLS_PECOMMENT);
hs->off++;
}
else if (IN_STATE(hs, MLS_PECOMMENT))
{
/* Depends on only COMMENT state pushing PECOMMENT state */
hs_pop(hs);
if (*cp == '-')
{
hs->off++;
hs_pop(hs);
}
else if (*cp == '>')
{
poff = hs_pop(hs);
n = hs_create_tag(hs, hs->data + poff, hs->off - poff + 1);
hs_add_element(hs, n);
hs->off++;
hs_push(hs, MLS_DATA);
}
else hs->off++;
}
else
{
fprintf (stderr, "Invalid markup parser state.\n");
hs->off++;
}
}
return;
}
/*
* MLAddData
*/
void
MLAddData(hs, data, len)
MLState hs;
char *data;
size_t len;
{
hs_handle_data(hs, data, len, false);
return;
}
/*
* MLEndData
*/
void
MLEndData(hs, data, len)
MLState hs;
char *data;
size_t len;
{
MLElement p;
size_t poff;
if (data == NULL || len == 0 || len < hs->off) return;
hs_handle_data(hs, data, len, true);
poff = hs_pop(hs);
if (len - poff > 0)
{
if (IN_STATE(hs, MLS_DATA))
{
p = hs_create_text(hs, hs->data + poff, len - poff);
}
else
{
p = hs_create_tag(hs, hs->data + poff, len - poff);
}
hs_add_element(hs, p);
}
p = (MLElement)MPCGet(hs->mp, sizeof(struct MLElementP));
p->type = ML_EOF;
hs_add_element(hs, p);
MPDestroy(hs->tmp);
hs->tmp = NULL;
return;
}
/*
* MLFindAttribute
*/
char *
MLFindAttribute(p, name)
MLElement p;
char *name;
{
MLAttribute ta;
for (ta = p->ta; ta != NULL; ta = ta->next)
{
if (strcasecmp(ta->name, name) == 0)
{
return(ta->value == NULL ? "":ta->value);
}
}
return(NULL);
}
/*
* MLGetText
*/
void
MLGetText(p, text, len)
MLElement p;
char **text;
size_t *len;
{
*text = p->ptext;
*len = p->plen;
return;
}
/*
* MLGetType
*/
MLElementType
MLGetType(p)
MLElement p;
{
return(p->type);
}
/*
* MLTagName
*/
char *
MLTagName(p)
MLElement p;
{
if ((p->type == ML_BEGINTAG || p->type == ML_ENDTAG) && p->ta != NULL)
{
return(p->ta->name);
}
return(NULL);
}
/*
* MLCreateTag
*/
MLElement
MLCreateTag(hs, text, len)
MLState hs;
char *text;
size_t len;
{
return(hs_create_tag(hs, text, len));
}
/*
* MLAttributeToInt
*/
int
MLAttributeToInt(p, name)
MLElement p;
char *name;
{
char *value;
if ((value = MLFindAttribute(p, name)) == NULL) return(-1);
return(atoi(value));
}

59
common/ml.h Normal file
View File

@ -0,0 +1,59 @@
/*
* ml.h
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
typedef struct MLElementP *MLElement;
typedef struct MLAttributeP *MLAttribute;
typedef struct MLStateP *MLState;
typedef enum
{
ML_BEGINTAG,
ML_ENDTAG,
ML_DATA,
ML_CONTROLTAG,
ML_EOF
} MLElementType;
/*
* Public functions
*/
/*
* Functions for providing raw data to the markup-language code.
*/
typedef void (*MLElementHandler) _ArgProto((void *, MLElement));
MLState MLInit _ArgProto((MLElementHandler, void *));
void MLAddData _ArgProto((MLState, char *, size_t));
void MLEndData _ArgProto((MLState, char *, size_t));
void MLDestroy _ArgProto((MLState));
/*
* Functions for extracting information about elements created
*/
char *MLFindAttribute _ArgProto((MLElement, char *));
char *MLTagName _ArgProto((MLElement));
void MLGetText _ArgProto((MLElement, char **, size_t *));
MLElementType MLGetType(MLElement);
int MLAttributeToInt _ArgProto((MLElement, char *));
/*
* Random stuff
*/
MLElement MLCreateTag _ArgProto((MLState, char *, size_t));

147
common/uproc.c Normal file
View File

@ -0,0 +1,147 @@
/*
* uproc.c
*
* Code grabbed from chimera 1.65.
*/
#include "port_before.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#ifndef __QNX__
#include <sys/signal.h>
#else
#include <signal.h>
#endif
#include <sys/wait.h>
#include <sys/stat.h>
#include "port_after.h"
#include "common.h"
/*
* ReapChild
*
* This code grabs the status from an exiting child process. We really
* don't care about the status, we just want to keep zombie's from
* cropping up.
*/
static void
ReapChild()
{
#if defined(WNOHANG) && !defined(SYSV) && !defined(SVR4)
int pid;
#endif
extern int errno;
int old_errno = errno;
/*
* It would probably be better to use the POSIX mechanism here,but I have not
* checked into it. This gets us off the ground with SYSV. RSE@GMI
*/
#if defined(WNOHANG) && !defined(SYSV) && !defined(SVR4) && !defined(__QNX__) && !defined(__EMX__)
union wait st;
do
{
errno = 0;
pid = wait3(&st, WNOHANG, 0);
}
while (pid <= 0 && errno == EINTR);
#else
int st;
wait(&st);
#endif
StartReaper();
errno = old_errno;
return;
}
/*
* StartReaper
*
* This code inits the code which reaps child processes that where
* fork'd off for external viewers.
*/
void
StartReaper()
{
#ifdef SIGCHLD
signal(SIGCHLD, ReapChild);
#else
signal(SIGCLD, ReapChild);
#endif
return;
}
/*
* PipeCommand
*
* fork and exec to get a program running and supply it with
* a stdin, stdout, stderr that so we can talk to it.
*/
int
PipeCommand(command, fd)
char *command;
int *fd;
{
int pout[2];
int pin[2];
int pid;
/*
if (pipe(pout) == -1) return(-1);
*/
if (pipe(pin) == -1)
{
close(pout[0]);
close(pout[1]);
return(-1);
}
pid = fork();
if (pid == -1)
{
return(-1);
}
else if (pid == 0)
{
/*
if (pout[1] != 1)
{
dup2(pout[1], 1);
close(pout[1]);
}
*/
if (pin[0] != 0)
{
dup2(pin[0], 0);
close(pin[0]);
}
signal(SIGPIPE, SIG_DFL);
execl(command, command, (char *)0);
}
else
{
close(pout[1]);
close(pin[0]);
}
fd[0] = pin[1];
/*
fd[1] = pout[0];
*/
return(0);
}

614
common/url.c Normal file
View File

@ -0,0 +1,614 @@
/*
* url.c
*
* Copyright (C) 1993-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "url.h"
#define URLDELIMS ":/?#"
#ifndef NullString
#define NullString(s) (s == NULL || *s == '\0')
#endif
static URLParts *URLCreate _ArgProto((MemPool));
static char *resolve_filename _ArgProto((MemPool, char *, char *));
/*
* URLcmp
*
* Return 0 if equal.
*/
int
URLcmp(u1, u2)
URLParts *u1, *u2;
{
if (strcasecmp(u1->scheme, u2->scheme) == 0 &&
strcasecmp(u1->hostname, u2->hostname) == 0 &&
u1->port == u2->port &&
strcasecmp(u1->filename, u2->filename) == 0)
{
return(0);
}
return(-1);
}
/*
* URLEscape
*
* Puts escape codes in URLs. NOT complete.
*/
char *
URLEscape(mp, url, s2p)
MemPool mp;
char *url;
bool s2p;
{
char *cp;
char *n, *s;
static char *hex = "0123456789ABCDEF";
/*
* use a bit of memory so i don't have to mess around here
*/
s = n = (char *)MPGet(mp, strlen(url) * 3 + 2);
for (cp = url; *cp; cp++, n++)
{
if (*cp == ' ' && s2p)
{
*n = '+';
}
else if (*cp == '+' && s2p)
{
*n = '%';
n++;
*n = hex[*cp / 16];
n++;
*n = hex[*cp % 16];
}
#ifdef ORIGINAL_CODE
/*
else if (isalnum(*cp) || strchr("$-_.'(),+!*", *cp))
*/
else if (strchr("<>\"#{}|\\^~[]`",*cp))
#else
/* My CGI scripts and the Apache daemon say it's closer the first way - djhjr */
else if (isalnum(*cp) || strchr("$-_.'(),+!*", *cp))
#endif
{
*n = *cp;
}
else
{
*n = '%';
n++;
*n = hex[*cp / 16];
n++;
*n = hex[*cp % 16];
}
}
*n = '\0';
return(s);
}
/*
* UnescapeURL
*
* Converts the escape codes (%xx) into actual characters. NOT complete.
* Could do everthing in place I guess.
*/
char *
URLUnescape(mp, url)
MemPool mp;
char *url;
{
char *cp, *n, *s;
char hex[3];
s = n = (char *)MPGet(mp, strlen(url) + 2);
for (cp = url; *cp; cp++, n++)
{
if (*cp == '%')
{
cp++;
if (*cp == '%')
{
*n = *cp;
}
else
{
hex[0] = *cp;
cp++;
hex[1] = *cp;
hex[2] = '\0';
*n = (char)strtol(hex, NULL, 16);
}
}
else if (*cp == '+') *n = ' ';
else
{
*n = *cp;
}
}
*n = '\0';
return(s);
}
/*
* URLMakeString
*/
char *
URLMakeString(mp, up, addfrag)
MemPool mp;
URLParts *up;
bool addfrag;
{
size_t len;
char *u;
char *delim;
char *delim2;
char *filename;
char *hostname;
char *scheme;
char *delim3;
char *fragment;
if (NullString(up->scheme)) scheme = "file";
else scheme = up->scheme;
if (NullString(up->hostname))
{
delim = "";
hostname = "";
}
else
{
delim = "//";
hostname = up->hostname;
}
if (NullString(up->filename)) filename = "/";
else filename = up->filename;
delim2 = "";
if (up->fragment != NULL && addfrag)
{
fragment = up->fragment;
delim3 = "#";
}
else
{
fragment = "";
delim3 = "";
}
len = strlen(scheme) + strlen(hostname) + strlen(filename) +
strlen(delim) + strlen(fragment) + 11;
u = (char *)MPGet(mp, len + 1);
if (up->port == 0)
{
snprintf (u, len, "%s:%s%s%s%s%s%s", scheme, delim, hostname, delim2,
filename, delim3, fragment);
}
else
{
snprintf (u, len, "%s:%s%s:%d%s%s%s%s", scheme, delim, hostname, up->port,
delim2, filename, delim3, fragment);
}
return(u);
}
/*
* URLCreate
*
* Allocate URLParts and initialize to NULLs
*/
static URLParts *
URLCreate(mp)
MemPool mp;
{
URLParts *up;
up = (URLParts *)MPCGet(mp, sizeof(URLParts));
return(up);
}
/*
* resolve_filename
*
* I'm not sure this is much better than the original.
*/
static char *
resolve_filename(mp, c, p)
MemPool mp;
char *c, *p;
{
char *r;
char *t;
MemPool tmp;
/*
* If current is an absolute path then use it otherwise
* build an absolute path using the parent as a reference.
*/
if (c == NULL || c[0] == '/') r = MPStrDup(mp, c);
else if (c[0] == '~')
{
r = MPGet(mp, strlen(c) + 2);
r[0] = '/';
strcpy(r + 1, c);
}
else
{
tmp = MPCreate();
if (p == NULL || p[0] != '/') p = "/";
else p = whack_filename(tmp, p);
t = compress_path(tmp, c, p);
if (t == NULL) r = MPStrDup(mp, "/");
else r = MPStrDup(mp, t);
MPDestroy(tmp);
}
return(r);
}
/*
* URLResolve
*
* c - current
* p - parent
* r - result
*/
URLParts *
URLResolve(mp, c, p)
MemPool mp;
URLParts *c, *p;
{
URLParts *r;
/*
* If the protocols are different then just return the original with
* some empty fields filled in.
*/
if (c->scheme != NULL && p->scheme != NULL &&
strcasecmp(c->scheme, p->scheme) != 0)
{
r = URLDup(mp, c);
if (r->hostname == NULL) r->hostname = MPStrDup(mp, "localhost");
r->filename = resolve_filename(mp, c->filename, p->filename);
return(r);
}
r = URLCreate(mp);
/*
* If current has a protocol then use it, otherwise
* use the parent's protocol. If the parent doesn't have a protocol for
* some reason then use "file".
*/
if (c->scheme == NULL)
{
if (p->scheme != NULL) r->scheme = MPStrDup(mp, p->scheme);
else r->scheme = MPStrDup(mp, "file");
}
else r->scheme = MPStrDup(mp, c->scheme);
/*
* If current has a hostname then use it, otherwise
* use the parent's hostname. If neither has a hostname then
* fallback to "localhost".
*/
if (c->hostname == NULL)
{
if (p->hostname != NULL)
{
r->hostname = MPStrDup(mp, p->hostname);
r->port = p->port;
}
else
{
r->hostname = MPStrDup(mp, "localhost"); /* fallback */
r->port = 0;
}
}
else
{
r->hostname = MPStrDup(mp, c->hostname);
r->port = c->port;
}
r->filename = resolve_filename(mp, c->filename, p->filename);
/*
* Copy misc. fields.
*/
r->username = MPStrDup(mp, c->username);
r->password = MPStrDup(mp, c->password);
r->fragment = MPStrDup(mp, c->fragment);
return(r);
}
URLParts *
URLDup(mp, up)
MemPool mp;
URLParts *up;
{
URLParts *dp;
dp = URLCreate(mp);
dp->scheme = MPStrDup(mp, up->scheme);
dp->hostname = MPStrDup(mp, up->hostname);
dp->port = up->port;
dp->filename = up->filename != NULL ?
MPStrDup(mp, up->filename):MPStrDup(mp, "/");
dp->fragment = MPStrDup(mp, up->fragment);
dp->username = MPStrDup(mp, up->username);
dp->password = MPStrDup(mp, up->password);
return(dp);
}
/*
* URLParse
*
* Turns a URL into a URLParts structure
*
* The good stuff was written by Rob May <robert.may@rd.eng.bbc.co.uk>
* and heavily mangled/modified by john to suite his own weird style.
*/
URLParts *
URLParse(mp, url)
MemPool mp;
char *url;
{
URLParts *up;
char *start;
char *colon, *slash, *fslash;
char *pound; /* link pound (#) sign */
char *at; /* username/password @ */
char *ucolon; /* username colon */
char *pcolon; /* port number colon */
up = URLCreate(mp);
/* skip leading white-space (if any)*/
for (start = url; isspace8(*start); start++)
;
/*
* Look for indication of a scheme.
*/
colon = strchr(start, ':');
/*
* Search for characters that indicate the beginning of the
* path/params/query/fragment part.
*/
slash = strchr(start, '/');
if (slash == NULL) slash = strchr(start, ';');
if (slash == NULL) slash = strchr(start, '?');
if (slash == NULL) slash = strchr(start, '#');
/*
* Check to see if there is a scheme. There is a scheme only if
* all other separators appear after the colon.
*/
if (colon != NULL && (slash == NULL || colon < slash))
{
up->scheme = MPGet(mp, colon - start + 1);
strncpy(up->scheme, start, colon - start);
up->scheme[colon - start] = '\0';
}
/*
* If there is a slash then sort out the hostname and filename.
* If there is no slash then there is no hostname but there is a
* filename.
*/
if (slash != NULL)
{
/*
* Check for leading //. If its there then there is a host string.
*/
if ((*(slash + 1) == '/') && ((colon == NULL && slash == start) ||
(colon != NULL && slash == colon + 1)))
{
/*
* Check for filename at end of host string.
*/
slash += 2;
if ((fslash = strchr(slash, '/')) != NULL)
{
up->hostname = MPGet(mp, fslash - slash + 1);
strncpy(up->hostname, slash, fslash - slash);
up->hostname[fslash - slash] = '\0';
up->filename = MPStrDup(mp, fslash);
}
else
{ /* there is no filename */
up->hostname = MPStrDup(mp, slash);
}
}
else
{
/*
* the rest is a filename because there is no // or it appears
* after other characters
*/
if (colon != NULL && colon < slash)
{
up->filename = MPStrDup(mp, colon + 1);
}
else up->filename = MPStrDup(mp, start);
}
}
else
{
/*
* No slashes at all so the rest must be a filename.
*/
if (colon == NULL) up->filename = MPStrDup(mp, start);
else up->filename = MPStrDup(mp, colon + 1);
}
/*
* If there is a host string then divide it into
* username:password@hostname:port as needed.
*/
if (up->hostname != NULL)
{
/*
* Look for username:password.
*/
if ((at = strchr(up->hostname, '@')) != NULL)
{
char *mumble;
up->username = MPGet(mp, at - up->hostname + 1);
strncpy(up->username, up->hostname, at - up->hostname);
up->username[at - up->hostname] = '\0';
mumble = MPStrDup(mp, at + 1);
up->hostname = mumble;
if ((ucolon = strchr(up->username, ':')) != NULL)
{
up->password = MPStrDup(mp, ucolon + 1);
*ucolon = '\0';
}
}
/*
* Grab the port.
*/
if ((pcolon = strchr(up->hostname, ':')) != NULL)
{
up->port = atoi(pcolon + 1);
*pcolon = '\0';
}
}
/*
* Check the filename for a '#foo' string.
*/
if (up->filename != NULL)
{
if ((pound = strchr(up->filename, '#')) != NULL)
{
*pound = '\0';
up->fragment = MPStrDup(mp, pound + 1);
if (strlen(up->filename) == 0) up->filename = NULL;
}
}
return(up);
}
/*
* URLIsAbsolute
*/
bool
URLIsAbsolute(up)
URLParts *up;
{
if (up->scheme == NULL) return(false);
return(true);
}
/*
* URLBaseFilename
*/
char *
URLBaseFilename(mp, up)
MemPool mp;
URLParts *up;
{
char *cp;
if (up->filename == NULL) return(NULL);
for (cp = up->filename + strlen(up->filename) - 1;
cp >= up->filename; cp--)
{
if (*cp == '/') break;
}
cp++;
if (*cp == '\0') return(NULL);
return(MPStrDup(mp, cp));
}
/*
* URLGetScheme
*/
char *
URLGetScheme(mp, url)
MemPool mp;
char *url;
{
char *cp, *dp;
char *r;
for (cp = url; *cp != '\0'; cp++)
{
for (dp = URLDELIMS; *dp != '\0'; dp++)
{
if (*cp == *dp)
{
if (*cp == ':')
{
r = (char *)MPCGet(mp, cp - url + 1);
strncpy(r, url, cp - url);
return(r);
}
return(NULL);
}
}
}
return(NULL);
}

61
common/url.h Normal file
View File

@ -0,0 +1,61 @@
/*
* url.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __URL_H__
#define __URL_H__ 1
#include "common.h"
/*
* <scheme>://<net_loc>/<path>;<params>?<query>#<fragment>
*
* net_loc = username:password@hostname:port
*/
typedef struct
{
char *scheme;
char *username;
char *password;
char *hostname;
int port;
char *filename;
char *params;
char *query;
char *fragment;
} URLParts;
int URLcmp _ArgProto((URLParts *, URLParts *));
char *URLMakeString _ArgProto((MemPool, URLParts *, bool));
URLParts *URLResolve _ArgProto((MemPool, URLParts *, URLParts *));
URLParts *URLParse _ArgProto((MemPool, char *));
char *URLUnescape _ArgProto((MemPool, char *));
char *URLEscape _ArgProto((MemPool, char *, bool));
URLParts *URLDup _ArgProto((MemPool, URLParts *));
bool URLIsAbsolute _ArgProto((URLParts *));
char *URLBaseFilename _ArgProto((MemPool, URLParts *));
char *URLGetScheme _ArgProto((MemPool, char *));
/*
* url_translate.c
*/
int URLReadTranslations _ArgProto((GList, char *));
char *URLTranslate _ArgProto((MemPool, GList, char *));
#endif

196
common/util.c Normal file
View File

@ -0,0 +1,196 @@
/*
* util.c
*
* Copyright (C) 1993-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <pwd.h>
#include <errno.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include "port_after.h"
#include "common.h"
/*
* FixPath
*
* The only thing this does right now is to handle the '~' stuff.
*/
char *
FixPath(mp, filename)
MemPool mp;
char *filename;
{
struct passwd *p;
char *cp, *cp2;
char username[BUFSIZ];
char *fname;
char *home;
char *newfilename;
if (filename[0] == '~') fname = filename;
else if (filename[0] == '/' && filename[1] == '~') fname = filename + 1;
else fname = NULL;
if (fname != NULL)
{
if (fname[1] == '/')
{
if ((home = getenv("HOME")) == NULL) return(NULL);
cp = fname + 1;
}
else
{
for (cp = fname + 1, cp2 = username; *cp && *cp != '/'; cp++, cp2++)
{
*cp2 = *cp;
}
*cp2 = '\0';
p = getpwnam(username);
if (p == NULL) return(NULL);
home = p->pw_dir;
}
newfilename = (char *)MPGet(mp, strlen(home) + strlen(cp) + 1);
strcpy(newfilename, home);
strcat(newfilename, cp);
}
else
{
newfilename = MPStrDup(mp, filename);
}
return(newfilename);
}
/*
* mystrtok
*
*/
char *
mystrtok(s, c, cdr)
char *s;
size_t c;
char **cdr;
{
char *cp, *cp2;
static char str[BUFSIZ];
if (s == NULL) return(NULL);
for (cp = s, cp2 = str; ; cp++)
{
if (*cp == '\0') break;
else if (*cp == c)
{
for (cp++; *cp == c; )
{
cp++;
}
break;
}
else *cp2++ = *cp;
if (cp2 == str + BUFSIZ - 1) break;
}
*cp2 = '\0';
if (*cp == '\0') *cdr = NULL;
else *cdr = cp;
return(str);
}
/*
* GetBaseFilename
*/
char *
GetBaseFilename(path)
char *path;
{
char *cp;
if (path == NULL) return(NULL);
for (cp = path + strlen(path) - 1; cp >= path; cp--)
{
if (*cp == '/') break;
}
cp++;
if (*cp == '\0') return(NULL);
return(cp);
}
/*
* xmyassert
*/
void
xmyassert(isok, msg, file, line)
bool isok;
char *msg;
char *file;
int line;
{
if (!isok)
{
fprintf (stderr, "%s: %d\n", file, line);
fprintf (stderr, "%s\n", msg);
fflush(stderr);
abort();
}
return;
}
#ifndef P_tmpdir
#define P_tmpdir "/tmp"
#endif
#ifndef L_tmpnam
#define L_tmpnam 256
#endif
/*
* mytmpnam
*/
char *
mytmpnam(mp)
MemPool mp;
{
char *n;
n = (char *)MPGet(mp, L_tmpnam + 1);
snprintf (n, L_tmpnam, "%s/%d%ld",
P_tmpdir, getpid(), (long)time(NULL));
return(n);
}

339
doc/COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

180
doc/COPYRIGHT Normal file
View File

@ -0,0 +1,180 @@
Most of the code was written by John and Erik and is GPL'd. See COPYING for
details. If I've left anything out below please let me know. Also,
if you see GPL'd replacements for anything not GPL'd please send it
(or a pointer to it) to john@cs.unlv.edu.
Other GPL'd code used:
www/url_translate.c by Theodore Ts'o <tytso@ATHENA.MIT.EDU>
common/snprintf.c by Patrick Powell <papowell@sdsu.edu>
mxw/TextField* was written by Rob McMullen and is LGPL'd.
====
www/
====
WWW.c has some code from the Xaw Viewport widget and is
Copyright (c) 1989, 1994 X Consortium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.
====
mxw/
====
Also, the AuthDialog and MyDialog widgets are based on code from the
Athena Dialog widget are
Copyright (c) 1987, 1988, 1994 X Consortium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
=======
common/
=======
Some string functions were grabbed from the BSD libraries and are
Copyright (c) 1988-1993 The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the University of
California, Berkeley and its contributors.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
memmove.c from the X folks:
Copyright (c) 1987 X Consortium
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the X Consortium.
======
image/
======
gif.c, new.c, imagep.h were derived from code from xloadimage and are
Copyright 1989, 1991 Jim Frost
Copyright 1989 Kirk L. Johnson
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation. The author makes no representations
about the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
USE OR PERFORMANCE OF THIS SOFTWARE.

79
doc/HINTS Normal file
View File

@ -0,0 +1,79 @@
This is really kind of sparse.
---------
Compiling
---------
If you're unsure if chimera will compile then try the simplest thing:
cp Common.tmpl.dist Common.tmpl
xmkmf
make Makefiles depend clean all
I use HAVE_xxx_H defines to allow users with systems that don't
have all of the standard header files to easily weed them out of
the compilation. I also use HAVE_xxx where xxx is a function
that doesn't appear in every system (e.g. the POSIX function mktime())
but the source can make allowances for this.
Some functions are included in common that are required but that
don't appear everywhere. You can have them linked in by specifying
the proper NEED_xxx thing in Common.tmpl. Check common/Imakefile for
a current list.
If you have trouble doing the simplest thing, please let me know
so that I can try to fix the problem. You should only have to
change Common.tmpl. If you figure out what needs to be done to
get it to compile (like adding a #if defined() thing in Common.tmpl
with the proper defines set for a particular machine), please send
it to me so that I can include it. Of course, I can't guarantee that
I will include all contributions.
If you need to specify site-dependent defines or libraries then
search for SITE_* in Common.tmpl and add them there.
Also, if you need to force the compiler to something special (say, gcc)
then remove 'XCOMM' from the line (in Common.tmpl):
XCOMM CC = gcc
and change the compiler to whatever you need.
---------
Resources
---------
There are two types of resources used by chimera. X/GUI resources
and, for lack of a better term, chimera resources. Chimera resources
are formatted exactly like the X resources but are loaded separately.
I strongly recommend that you do not use an app-defaults file unless
you really want to change the appearance. I'm not even going to
try to produce an example...you're on your own here or you can
ask the bug-chimera list for examples (there are clever folks that
will probably get around to this one of these days).
If you install an older version of chimera that installed an app-defaults
file then you should remove it or if you need it because 1.65 or some
other version needs it then you can run 2.0 with the command:
XFILESEARCHPATH="" chimera-2.0
By default, chimera looks for its own resources in ~/.chimera/resources.
I recommend you create the directory ~/.chimera since most of the
defaults for chimera will point to this directory for files. One
possible resources file:
bookmark.filename: ~/.chimera/bookmarks.html
cache.directory: ~/.chimera/cache
cache.persist: true
chimera.homeURL: http://www/
html.propFontPattern: -adobe-helvetica-*-*-*-*-*-*-*-*-*-*-iso8859-1
view.capFiles: ~/.chimera/mailcap:~/.mailcap
------------
app-defaults
------------
Don't use them with Chimera v2. If you have an app-defaults file that
you need for Chimera v1 then you should create a script that
changes XUSERFILESEARCHPATH so that it doesn't look at the default
app-defaults directory.

60
doc/INFO Normal file
View File

@ -0,0 +1,60 @@
Chimera 2.0
X11/Athena World-Wide Web Client
written by John Kilburg and others
Chimera is an X/Athena Web client for UNIX-based workstations.
Chimera does not require Motif.
Chimera can be found at <URL:http://www.unlv.edu/chimera/> or
<URL:ftp://ftp.cs.unlv.edu/pub/chimera>.
There is a mailing list called
bug-chimera@cs.unlv.edu
that is used for bug reports, feature requests, and general chimera
discussion.
If you want to join the list (receive the emails that go to bug-chimera)
send email to
bug-chimera-request@cs.unlv.edu
There is also a mailing list that receives announcements of new chimera
releases. If you want to join the list, send email to
chimera-announce-request@cs.unlv.edu
Read INSTALL for installation instructions. Read README.hints for hints.
Directories:
chimera Chimera Core
doc License information and other stuff.
mxw Miscellaneous Xt widgets.
image Library for GIFs, JPEGs, ...
Nearly all of this was written by
Erik Corry <ehcorry@inet.uni-c.dk>.
html An attempt at an HTML renderer
proto Library for HTTP, FTP, and local file access.
common Generally useful functions
port Contains functions and header files used for portability
purposes
See the file COPYRIGHT for license information.
Jay Nietling (jay@egr.unlv.edu) and Greg Wohletz (greg@egr.unlv.edu)
are the system guys for the engineering college at UNLV.
They have done a really nice job of setting up and maintaining the
computing environment here (Athena stuff and a ton of other goodies
on a wad of architectures).
John Kilburg
john@cs.unlv.edu

19
doc/INSTALL Normal file
View File

@ -0,0 +1,19 @@
-------------------------
INSTALLATION INSTRUCTIONS
-------------------------
To compile chimera, type:
cp Common.tmpl.dist Common.tmpl
# modify Common.tmpl if necessary
xmkmf -a
make
Some releases of xmkmf are broken so you might have to type:
xmkmf
make Makefiles depend clean
make
You'll end up with a binary that should run OK without any other
files.

483
doc/LCOPYING Normal file
View File

@ -0,0 +1,483 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

15
doc/LICENSE Normal file
View File

@ -0,0 +1,15 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Please see the file COPYING for more information.

316
ext/ext.c Normal file
View File

@ -0,0 +1,316 @@
/*
* ext.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <signal.h>
#include <errno.h>
#include "port_after.h"
#include "Chimera.h"
typedef struct
{
char *use;
char *incontent;
char *outcontent;
char *command;
} ConvertEntry;
typedef struct
{
MemPool mp;
ChimeraSink wp;
ChimeraRender wn;
ChimeraGUI wd;
ChimeraRender own;
ChimeraRenderHooks *orh;
ConvertEntry *c;
int fd[2];
size_t i;
} ExtInfo;
typedef struct
{
MemPool mp;
GList list;
} ExtModuleInfo;
static void ExtDestroy _ArgProto((void *));
static void *ExtInit _ArgProto((ChimeraRender, void *));
static void ExtAdd _ArgProto((void *));
static void ExtEnd _ArgProto((void *));
static void ExtCancel _ArgProto((void *));
static GList ReadConvertFiles _ArgProto((MemPool, char *));
/*
* ExtDestroy
*/
static void
ExtDestroy(closure)
void *closure;
{
ExtInfo *ei = (ExtInfo *)closure;
MPDestroy(ei->mp);
return;
}
/*
* ExtAdd
*/
static void
ExtAdd(closure)
void *closure;
{
ExtInfo *ei = (ExtInfo *)closure;
byte *data;
size_t len;
GList mimelist;
ssize_t rval;
SinkGetData(ei->wp, &data, &len, &mimelist);
if (len <= ei->i) return;
if ((rval = write(ei->fd[0], data + ei->i, len - ei->i)) <= 0)
{
perror("ext write add");
return;
}
ei->i += rval;
return;
}
/*
* ExtEnd
*/
static void
ExtEnd(closure)
void *closure;
{
ExtInfo *ei = (ExtInfo *)closure;
byte *data;
size_t len;
GList mimelist;
ssize_t rval;
char buffer[BUFSIZ];
SinkGetData(ei->wp, &data, &len, &mimelist);
while (len > ei->i)
{
if ((rval = write(ei->fd[0], data + ei->i, len - ei->i)) <= 0)
{
perror("ext write end");
return;
}
ei->i += rval;
}
close(ei->fd[0]);
/*
while (read(ei->fd[1], buffer, sizeof(buffer)) > 0)
;
*/
close(ei->fd[1]);
return;
}
/*
* ExtCancel
*/
static void
ExtCancel(closure)
void *closure;
{
return;
}
/*
* ExtInit
*/
static void *
ExtInit(wn, closure)
ChimeraRender wn;
void *closure;
{
SinkData wp;
char *content;
ConvertEntry *c;
ExtModuleInfo *emi = (ExtModuleInfo *)closure;
ExtInfo *ei;
MemPool mp;
ChimeraRenderHooks *orh;
wp = RenderToSink(wn);
content = SinkGetInfo(wp, "content-type");
for (c = (ConvertEntry *)GListGetHead(emi->list); c != NULL;
c = (ConvertEntry *)GListGetNext(emi->list))
{
if (strcasecmp(content, c->incontent) == 0) break;
}
if (c == NULL) return(NULL);
/*
orh = WWWGetRenderHooks(WWWGetRenderContext(wn), c->outcontent);
if (orh == NULL) return(NULL);
*/
mp = MPCreate();
ei = (ExtInfo *)MPCGet(mp, sizeof(ExtInfo));
ei->mp = mp;
ei->c = c;
ei->wd = RenderToGUI(wn);
ei->wp = wp;
ei->wn = wn;
ei->orh = orh;
if (PipeCommand(c->command, ei->fd) == -1)
{
MPDestroy(mp);
return(NULL);
}
return(ei);
}
/*
* ReadConvertFiles
*
* Reads in the convert entries in a list of files separated by colons.
* For example,
*
* ~/.chimera_convert:~john/lib/convert:/local/infosys/lib/convert
*/
GList
ReadConvertFiles(mp, filelist)
MemPool mp;
char *filelist;
{
ConvertEntry *c;
char *f;
char *filename;
char buffer[BUFSIZ];
char use[BUFSIZ];
char incontent[BUFSIZ];
char outcontent[BUFSIZ];
char command[BUFSIZ];
FILE *fp;
GList list;
list = GListCreateX(mp);
f = filelist;
while ((filename = mystrtok(f, ':', &f)) != NULL)
{
filename = FixPath(mp, filename);
if (filename == NULL) continue;
fp = fopen(filename, "r");
if (fp == NULL) continue;
while (fgets(buffer, sizeof(buffer), fp) != NULL)
{
if (buffer[0] == '#' || buffer[0] == '\n') continue;
if (sscanf(buffer, "%s %s %s %[^\n]",
use, incontent, outcontent, command) == 4)
{
c = (ConvertEntry *)MPCGet(mp, sizeof(ConvertEntry));
c->use = MPStrDup(mp, use);
c->incontent = MPStrDup(mp, incontent);
c->outcontent = MPStrDup(mp, outcontent);
c->command = strcasecmp(command, "none") == 0 ?
NULL:MPStrDup(mp, command);
GListAddTail(list, c);
}
}
fclose(fp);
}
return(list);
}
void
InitModule_Ext(cres)
ChimeraResources cres;
{
ChimeraRenderHooks rh;
char *clist;
ExtModuleInfo *emi;
GList list;
MemPool mp;
ConvertEntry *c;
if ((clist = ResourceGetString(cres, "convert.convertFiles")) == NULL)
{
clist = "~/.chimera/convert";
}
mp = MPCreate();
list = ReadConvertFiles(mp, clist);
if (GListEmpty(list))
{
MPDestroy(mp);
return;
}
emi = (ExtModuleInfo *)MPCGet(mp, sizeof(ExtModuleInfo));
emi->mp = mp;
emi->list = list;
for (c = (ConvertEntry *)GListGetHead(list); c != NULL;
c = (ConvertEntry *)GListGetNext(list))
{
memset(&rh, 0, sizeof(ChimeraRenderHooks));
rh.content = c->incontent;
rh.class_context = emi;
rh.class_destroy = ExtDestroy;
rh.init = ExtInit;
rh.add = ExtAdd;
rh.end = ExtEnd;
rh.destroy = ExtDestroy;
rh.cancel = ExtCancel;
RenderAddHooks(cres, &rh);
}
return;
}

26
html/Imakefile Normal file
View File

@ -0,0 +1,26 @@
#include <../Common.tmpl>
HEADERS = html.h htmltags.h
SRCS = module.c html.c layout.c text.c misc.c font.c load.c flow.c \
head.c inline.c list.c form.c hr.c table.c map.c frame.c \
css.c
OBJS = module.o html.o layout.o text.o misc.o font.o load.o flow.o \
head.o inline.o list.o form.o hr.o table.o map.o frame.o \
css.o
EXTRA_DEFINES = $(CHIMERA_DEFINES)
EXTRA_INCLUDES = -I../port -I../mxw -I../common -I../chimera
NormalLibraryTarget(xhtml, $(OBJS))
cssxxx.o: css.c css.h
$(CC) -c $(CDEBUGFLAGS) -DCSSDEBUG $(EXTRA_DEFINES) $(EXTRA_INCLUDES) css.c -o $@
csstest: cssxxx.o
$(CC) cssxxx.o $(CHIMERA_LIBS) -o $@
DependTarget()
install.man::

789
html/css.c Normal file
View File

@ -0,0 +1,789 @@
/*
* css.c
*
* Copyright (c) 1998, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "Chimera.h"
#include "css.h"
struct CSSPropertyP
{
CSSRule cr;
char *name;
char *value;
};
struct CSSSelectorP
{
char *tag;
char *id;
char *class;
char *pclass;
};
struct CSSRuleP
{
GList selectors; /* list of lists of CSSSelector's */
GList properties; /* list of CSSProperty's */
};
/*
* Used to keep track of which buffer to take input from. Since new
* text can be inserted at any time have to be able to store and restore
* buffer context.
*/
struct CSSInputP
{
char *b;
size_t blen;
char *cp;
char *ep;
};
struct CSSContextP
{
MemPool mp;
ChimeraContext cs;
/* parser bookkeeping */
GList inputs;
/* The Result: a list of rules and properties */
GList rules;
GList props;
/* callback information */
CSSProc proc;
void *closure;
ChimeraTask task;
};
typedef struct CSSInputP *CSSInput;
static char *ParseSpace _ArgProto((char *, char *));
static CSSSelector ParseSelector2 _ArgProto((MemPool, char *, size_t));
static GList ParseSelector1 _ArgProto((MemPool, char *, size_t));
static GList ParseSelector _ArgProto((MemPool, char *, size_t));
static CSSProperty ParseProperty _ArgProto((MemPool, char *, size_t));
static GList ParseProperties _ArgProto((MemPool, char *, size_t));
static bool ParseRule _ArgProto((CSSContext, CSSInput));
static bool ParseAt _ArgProto((CSSContext, CSSInput));
static void ParseCSS _ArgProto((CSSContext));
static int scompare _ArgProto((char *, char *));
static bool SelectorListMatch _ArgProto((GList, GList));
static char *ParseToChar _ArgProto((char *, char *, int, bool));
/*
* ParseToChar
*
* Search for an expected character. Deals with escaped characters,
* quoted strings, and pairs of braces/parens/brackets.
*/
static char *
ParseToChar(cp, ep, c, chkws)
char *cp, *ep;
int c;
bool chkws;
{
bool sq, dq, esc;
sq = false; /* in single quote? */
dq = false; /* in double quote? */
esc = false; /* escape mode? */
while (cp < ep)
{
if (esc) esc = false;
else if (*cp == '\\') esc = true;
else if (dq && *cp != '"') dq = false;
else if (sq && *cp != '\'') sq = false;
else if (*cp == '"') dq = true;
else if (*cp == '\'') sq = true;
else if (*cp == c) return(cp);
else if (chkws && isspace8(*cp)) return(cp);
else if (*cp == '{')
{
if ((cp = ParseToChar(cp + 1, ep, '}', false)) == NULL) return(NULL);
}
else if (*cp == '(')
{
if ((cp = ParseToChar(cp + 1, ep, ')', false)) == NULL) return(NULL);
}
else if (*cp == '[')
{
if ((cp = ParseToChar(cp + 1, ep, ']', false)) == NULL) return(NULL);
}
cp++;
}
return(NULL);
}
/*
* ParseAt
*
* This is lame. Handle @ statements later.
*
* Return false if @import occured. Return true if not.
*/
static bool
ParseAt(css, ci)
CSSContext css;
CSSInput ci;
{
while (ci->cp < ci->ep)
{
if (*ci->cp == '{')
{
if ((ci->cp = ParseToChar(ci->cp + 1, ci->ep, '}', false)) == NULL)
{
ci->cp = ci->ep;
}
return(true);
}
else if (*ci->cp == ';')
{
ci->cp++;
return(false);
}
ci->cp++;
}
return(true);
}
/*
* ParseSpace
*
* Look for non-space and deal with comments.
*/
static char *
ParseSpace(s, e)
char *s, *e;
{
bool sc, ec, ic;
sc = false; /* possible start comment? */
ec = false; /* possible end comment? */
ic = false; /* in comment? */
while (s < e)
{
if (ic)
{
if (ec && *s == '/') ic = false;
else if (*s == '*') ec = true;
else ec = false;
}
else if (sc && *s == '*') ic = true;
else if (*s == '/') sc = true;
else if (!isspace8(*s)) return(s);
else sc = false;
s++;
}
return(NULL);
}
static CSSProperty
ParseProperty(mp, s, slen)
MemPool mp;
char *s;
size_t slen;
{
char *ep, *colon, *x;
CSSProperty prop;
ep = s + slen;
/* get rid of space in front of the declaration */
if ((s = ParseSpace(s, ep)) == NULL) return(NULL);
/* search for the required colon or white space */
if ((colon = ParseToChar(s, ep, ':', true)) == NULL) return(NULL);
prop = (CSSProperty)MPCGet(mp, sizeof(struct CSSPropertyP));
prop->name = (char *)MPGet(mp, colon - s + 1);
strncpy(prop->name, s, colon - s);
prop->name[colon - s] = '\0';
/* May have only reached white space before */
if (*colon != ':')
{
/* search for the required colon */
if ((colon = ParseToChar(colon, ep, ':', false)) == NULL) return(NULL);
}
/* remove space in front of the value */
if ((s = ParseSpace(colon + 1, ep)) == NULL) return(NULL);
prop->value = (char *)MPGet(mp, ep - s + 1);
/* Copy the value until end of input or whitespace is seen */
x = prop->value;
while (s < ep)
{
if (isspace8(*s)) break;
*x++ = *s++;
}
*x = '\0';
if (strlen(prop->name) == 0 || strlen(prop->value) == 0) return(NULL);
return(prop);
}
static GList
ParseProperties(mp, s, slen)
MemPool mp;
char *s;
size_t slen;
{
char *last;
char *ep;
GList properties;
CSSProperty prop;
properties = GListCreateX(mp);
ep = s + slen;
while (s < ep)
{
last = s;
s = ParseToChar(s, ep, ';', false);
if (s == NULL) s = ep;
if (last < s && (prop = ParseProperty(mp, last, s - last)) != NULL)
{
GListAddTail(properties, prop);
}
s++;
}
if (GListGetHead(properties) == NULL) return(NULL);
return(properties);
}
static CSSSelector
ParseSelector2(mp, s, slen)
MemPool mp;
char *s;
size_t slen;
{
CSSSelector cs;
char *tag = NULL;
char *id = NULL;
char *class = NULL;
char *pclass = NULL;
char *ep;
char *t;
cs = (CSSSelector)MPCGet(mp, sizeof(struct CSSSelectorP));
t = MPGet(mp, slen + 1);
strncpy(t, s, slen);
t[slen] = '\0';
s = t;
if (*s == '#') id = s + 1;
else if (*s == '.') class = s + 1;
else if (*s == ':') pclass = s + 1;
else
{
tag = s;
ep = s + slen;
while (s < ep)
{
if (*s == '#') { id = s + 1; *s = '\0'; break; }
else if (*s == '.') { class = s + 1; *s = '\0'; break; }
else if (*s == ':') { pclass = s + 1; *s = '\0'; break; }
else s++;
}
}
cs->tag = tag;
cs->id = id;
cs->class = class;
cs->pclass = pclass;
return(cs);
}
static GList
ParseSelector1(mp, s, slen)
MemPool mp;
char *s;
size_t slen;
{
char *ep = s + slen;
char *cp;
char *last;
CSSSelector cs;
GList selectors;
if ((s = ParseSpace(s, ep)) == NULL) return(NULL);
selectors = GListCreateX(mp);
last = s;
cp = s;
while (cp < ep)
{
if (isspace8(*cp))
{
if ((cs = ParseSelector2(mp, last, cp - last)) != NULL)
{
GListAddTail(selectors, cs);
}
if ((cp = ParseSpace(cp, ep)) == NULL) break;
last = cp;
}
else cp++;
}
if (last < cp)
{
if ((cs = ParseSelector2(mp, last, cp - last)) != NULL)
{
GListAddTail(selectors, cs);
}
}
if (GListGetHead(selectors) == NULL) return(NULL);
return(selectors);
}
/*
* ParseSelector
*/
static GList
ParseSelector(mp, s, slen)
MemPool mp;
char *s;
size_t slen;
{
GList slist, xlist;
char *ep;
char *last;
slist = GListCreateX(mp);
ep = s + slen;
while (s < ep)
{
last = s;
s = ParseToChar(s, ep, ',', false);
if (s == NULL) s = ep;
if (last < s && (xlist = ParseSelector1(mp, last, s - last)) != NULL)
{
GListAddTail(slist, xlist);
}
s++;
}
if (GListGetHead(slist) == NULL) return(NULL);
return(slist);
}
/*
* scompare
*
* do the sort of string comparison that we need here
*/
static int
scompare(s1, s2)
char *s1, *s2;
{
if (s1 == s2) return(0);
if (s1 == NULL || s2 == NULL) return(-1);
if (strlen(s1) != strlen(s2)) return(-1);
return(strcasecmp(s1, s2));
}
/*
* ParseRule
*
* Parse a single rule. Return false if parsing error that leads to EOF.
*/
static bool
ParseRule(css, ci)
CSSContext css;
CSSInput ci;
{
char *last;
GList slist;
GList plist;
CSSRule cr;
slist = GListCreateX(css->mp);
last = ci->cp;
if ((ci->cp = ParseToChar(ci->cp, ci->ep, '{', false)) == NULL)
{
ci->cp = ci->ep;
return(false);
}
slist = ParseSelector(css->mp, last, ci->cp - last);
ci->cp++; /* need to get past the '{' from above */
last = ci->cp;
if ((ci->cp = ParseToChar(ci->cp, ci->ep, '}', false)) == NULL)
{
ci->cp = ci->ep;
return(false);
}
plist = ParseProperties(css->mp, last, ci->cp - last);
ci->cp++;
/*
* Return true because parse was successful.
*/
if (plist == NULL || GListGetHead(plist) == NULL ||
slist == NULL || GListGetHead(slist) == NULL) return(true);
cr = (CSSRule)MPCGet(css->mp, sizeof(struct CSSRuleP));
cr->selectors = slist;
cr->properties = plist;
GListAddTail(css->rules, cr);
return(true);
}
/*
* ParseCSS
*
* Toplevel parser loop.
*/
static void
ParseCSS(css)
CSSContext css;
{
CSSInput ci = (CSSInput)GListGetHead(css->inputs);
if (ci == NULL)
{
if (css->proc == NULL) return;
/*
* Should call callback here because this means all CSS text including
* remote text has been parsed. Callback must be made from a toplevel
* task so create a task first.
*/
return;
}
ci->cp = ParseSpace(ci->cp, ci->ep);
while (ci->cp != NULL && ci->cp < ci->ep)
{
if (*ci->cp == '@')
{
if (!ParseAt(css, ci)) return;
}
else if (!ParseRule(css, ci)) return;
ci->cp = ParseSpace(ci->cp, ci->ep);
}
GListPop(css->inputs);
ParseCSS(css);
return;
}
CSSContext
CSSParseBuffer(cs, b, blen, proc, closure)
ChimeraContext cs;
char *b;
size_t blen;
CSSProc proc;
void *closure;
{
CSSContext css;
MemPool mp;
CSSInput ci;
mp = MPCreate();
css = (CSSContext)MPCGet(mp, sizeof(struct CSSContextP));
css->mp = mp;
css->cs = cs;
css->rules = GListCreateX(mp);
css->props = GListCreateX(mp);
css->inputs = GListCreateX(mp);
css->proc = proc;
css->closure = closure;
ci = (CSSInput)MPCGet(mp, sizeof(struct CSSInputP));
ci->b = b;
ci->blen = blen;
ci->cp = b;
ci->ep = b + blen;
GListAddHead(css->inputs, ci);
ParseCSS(css);
return(css);
}
/*
* CSSDestroyContext
*/
void
CSSDestroyContext(css)
CSSContext css;
{
MPDestroy(css->mp);
return;
}
static bool
SelectorListMatch(slist1, slist2)
GList slist1, slist2;
{
CSSSelector cs, ncs;
/*
* This code needs attention. It compares two selector lists.
*/
for (cs = (CSSSelector)GListGetHead(slist1),
ncs = (CSSSelector)GListGetHead(slist2);
cs != NULL && ncs != NULL;
cs = (CSSSelector)GListGetNext(slist1),
ncs = (CSSSelector)GListGetNext(slist2))
{
if (scompare(ncs->tag, cs->tag) != 0 ||
scompare(ncs->id, cs->id) != 0 ||
scompare(ncs->class, cs->class) != 0 ||
scompare(ncs->pclass, cs->pclass) != 0)
{
return(false);
}
}
if (ncs != NULL || cs != NULL) return(false);
return(true);
}
/*
* CSSCreateSelector
*/
CSSSelector
CSSCreateSelector(mp)
MemPool mp;
{
return((CSSSelector)MPCGet(mp, sizeof(struct CSSSelectorP)));
}
/*
* CSSSetSelector
*/
void
CSSSetSelector(cs, tag, id, class, pclass)
CSSSelector cs;
char *tag, *id, *class, *pclass;
{
cs->tag = tag;
cs->id = id;
cs->class = class;
cs->pclass = pclass;
return;
}
/*
* CSSFindProperty
*/
char *
CSSFindProperty(css, selectors, name)
CSSContext css;
GList selectors;
char *name;
{
CSSProperty p;
GList slist, xlist;
CSSSelector h;
if ((h = GListGetHead(selectors)) != GListGetTail(selectors))
{
slist = GListCreate();
GListAddHead(slist, h);
}
else slist = NULL;
for (p = (CSSProperty)GListGetHead(css->props); p != NULL;
p = (CSSProperty)GListGetNext(css->props))
{
if (scompare(p->name, name) == 0)
{
for (xlist = (GList)GListGetHead(p->cr->selectors); xlist != NULL;
xlist = (GList)GListGetNext(p->cr->selectors))
{
if ((slist != NULL && SelectorListMatch(xlist, slist)) ||
SelectorListMatch(xlist, selectors))
{
if (slist != NULL) GListDestroy(slist);
return(p->value);
}
}
}
}
if (slist != NULL) GListDestroy(slist);
return(NULL);
}
/*
* CSSPrintSelectorList
*/
void
CSSPrintSelectorList(slist)
GList slist;
{
CSSSelector s;
for (s = (CSSSelector)GListGetHead(slist); s != NULL;
s = (CSSSelector)GListGetNext(slist))
{
if (s->tag != NULL) fprintf (stderr, "%s ", s->tag);
if (s->id != NULL) fprintf (stderr, "%s ", s->id);
if (s->class != NULL) fprintf (stderr, "%s ", s->class);
if (s->pclass != NULL) fprintf (stderr, "%s ", s->pclass);
fprintf (stderr, "\n");
}
return;
}
/*
* CSSPrint
*/
void
CSSPrint(css)
CSSContext css;
{
CSSRule cr;
CSSSelector cs;
GList slist;
CSSProperty prop;
for (cr = (CSSRule)GListGetHead(css->rules); cr != NULL;
cr = (CSSRule)GListGetNext(css->rules))
{
for (slist = (GList)GListGetHead(cr->selectors); slist != NULL;
slist = (GList)GListGetNext(cr->selectors))
{
for (cs = (CSSSelector)GListGetHead(slist); cs != NULL;
cs = (CSSSelector)GListGetNext(slist))
{
printf ("%s ", cs->tag);
}
printf (", ");
}
printf ("{\n");
for (prop = (CSSProperty)GListGetHead(cr->properties); prop != NULL;
prop = (CSSProperty)GListGetNext(cr->properties))
{
printf ("\t%s : %s;\n", prop->name, prop->value);
}
printf ("}\n");
}
}
#ifdef CSSDEBUG
#include <sys/types.h>
#include <sys/stat.h>
main(argc, argv)
int argc;
char *argv[];
{
CSSContext css;
FILE *fp;
char *b;
char *name;
struct stat st;
GList slist;
CSSSelector cs;
MemPool mp;
if (argc < 2) exit(1);
if (stat(argv[1], &st) != 0) exit(1);
if ((b = (char *)alloc_mem(st.st_size)) == NULL) exit(1);
if ((fp = fopen(argv[1], "r")) == NULL) exit(1);
fread(b, 1, st.st_size, fp);
fclose(fp);
css = CSSParseBuffer(NULL, b, st.st_size, NULL, NULL);
mp = MPCreate();
slist = GListCreate();
cs = CSSCreateSelector(mp);
CSSSetSelector(cs, "H5", NULL, NULL, NULL);
GListAddHead(slist, cs);
name = "white-space";
if ((b = CSSFindProperty(css, slist, name)) != NULL)
{
printf ("%s == %s\n", name, b);
}
else printf ("%s not found\n", name);
CSSPrint(css);
CSSDestroyContext(css);
exit(0);
}
#endif

42
html/css.h Normal file
View File

@ -0,0 +1,42 @@
/*
* css.h
*
* Copyright (c) 1998, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
typedef struct CSSPropertyP *CSSProperty;
typedef struct CSSSelectorP *CSSSelector;
typedef struct CSSRuleP *CSSRule;
typedef struct CSSContextP *CSSContext;
typedef void (*CSSProc) _ArgProto((void *));
void CSSDestroyContext _ArgProto((CSSContext));
CSSContext CSSParseBuffer _ArgProto((ChimeraContext,
char *, size_t, CSSProc, void *));
CSSSelector CSSCreateSelector _ArgProto((MemPool));
void CSSSetSelector _ArgProto((CSSSelector,
char *, char *, char *, char *));
char *CSSFindProperty _ArgProto((CSSContext, GList, char *));
void CSSPrintSelectorList _ArgProto((GList));
void CSSPrint _ArgProto((CSSContext));

BIN
html/csstest Executable file

Binary file not shown.

592
html/flow.c Normal file
View File

@ -0,0 +1,592 @@
/*
* flow.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
typedef struct
{
int x, y;
int bloff;
int bottom;
unsigned int width, height;
unsigned int maxwidth;
GList boxes; /* list of boxes in line */
bool ended;
HTMLFlowAlign ff;
} HLine;
typedef struct
{
GList lines;
GList floaters;
GList pending_floaters;
GList constraints;
unsigned int maxwidth;
int nexty;
int lfloaty;
int rfloaty;
int linecount;
bool linebreak;
} HFlow;
typedef struct
{
int x, y;
unsigned int width, height;
} HCons;
/*
*
* Private functions
*
*/
static void LayoutFlow _ArgProto((HTMLInfo, HTMLBox, HTMLBox));
static unsigned int WidthFlow _ArgProto((HTMLInfo, HTMLBox));
static void SetupFlow _ArgProto((HTMLInfo, HTMLBox));
static void DestroyFlow _ArgProto((HTMLInfo, HTMLBox));
static void RenderFlow _ArgProto((HTMLInfo, HTMLBox, Region));
static void SetupHLine _ArgProto((HTMLInfo, HFlow *, HLine *));
static HLine *StartLine _ArgProto((HTMLInfo, HTMLEnv, HFlow *, HTMLBox));
static void EndLine _ArgProto((HTMLInfo, HFlow *, HLine *, HTMLBox));
static void AddFloater _ArgProto((HTMLInfo, HFlow *, HTMLBox, HTMLBox));
/*
* DestroyFlow
*/
static void
DestroyFlow(li, box)
HTMLInfo li;
HTMLBox box;
{
HFlow *hf = (HFlow *)box->closure;
HLine *hl;
HTMLBox c;
for (hl = (HLine *)GListGetHead(hf->lines); hl != NULL;
hl = (HLine *)GListGetNext(hf->lines))
{
for (c = (HTMLBox)GListGetHead(hl->boxes); c != NULL;
c = (HTMLBox)GListGetNext(hl->boxes))
{
HTMLDestroyBox(li, c);
}
}
for (c = (HTMLBox)GListGetHead(hf->floaters); c != NULL;
c = (HTMLBox)GListGetNext(hf->floaters))
{
HTMLDestroyBox(li, c);
}
return;
}
/*
* RenderFlow
*/
static void
RenderFlow(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
HFlow *hf = (HFlow *)box->closure;
HLine *hl;
HTMLBox c;
HCons *hc;
for (hl = (HLine *)GListGetHead(hf->lines); hl != NULL;
hl = (HLine *)GListGetNext(hf->lines))
{
if (XRectInRegion(r, hl->x, hl->y,
hl->width, hl->height) != RectangleOut)
{
if (li->flowDebug)
{
XDrawRectangle(li->dpy, li->win, li->gc,
hl->x, hl->y, hl->width, hl->height);
}
for (c = (HTMLBox)GListGetHead(hl->boxes); c != NULL;
c = (HTMLBox)GListGetNext(hl->boxes))
{
HTMLRenderBox(li, r, c);
}
}
}
for (c = (HTMLBox)GListGetHead(hf->floaters); c != NULL;
c = (HTMLBox)GListGetNext(hf->floaters))
{
if (XRectInRegion(r, c->x, c->y,
c->width, c->height) != RectangleOut)
{
HTMLRenderBox(li, r, c);
}
}
if (li->constraintDebug)
{
for (hc = (HCons *)GListGetHead(hf->constraints); hc != NULL;
hc = (HCons *)GListGetNext(hf->constraints))
{
XDrawRectangle(li->dpy, li->win, li->gc,
hc->x + box->x, hc->y + box->y,
hc->width, hc->height);
}
}
return;
}
/*
* AddFloater
*/
static void
AddFloater(li, hf, parent, box)
HTMLInfo li;
HFlow *hf;
HTMLBox parent;
HTMLBox box;
{
HCons *hc;
/*
* Determine the location of the floating box.
* The idea here is to push the floater below any other floaters on the
* same side of the flow box and also make sure it clears any existing
* lines. This is probably a bit paranoid but hopefully will prevent
* any chance of overlap.
*/
if (HTMLTestB(box, BOX_FLOAT_LEFT))
{
box->x = 0;
box->y = hf->lfloaty;
if (box->y < hf->nexty) box->y = hf->nexty;
hf->lfloaty = box->y + box->height;
}
else
{
box->x = hf->maxwidth - box->width;
if (box->x < 0) box->x = 0;
box->y = hf->rfloaty;
if (box->y < hf->nexty) box->y = hf->nexty;
hf->rfloaty = box->y + box->height;
}
/*
* Determine the new dimensions of the parent
*/
if (parent->width < box->x + box->width)
{
parent->width = box->x + box->width;
}
if (parent->height < box->y + box->height)
{
parent->height = box->y + box->height;
}
/*
* Add a new constraints box
*/
hc = (HCons *)MPGet(li->mp, sizeof(HCons));
if (HTMLTestB(box, BOX_FLOAT_LEFT)) hc->x = box->width;
else hc->x = 0;
hc->y = box->y;
hc->width = hf->maxwidth - box->width;
hc->height = box->height;
GListAddHead(hf->constraints, hc);
GListAddTail(hf->floaters, box);
if (HTMLTestB(parent, BOX_TOPLEVEL))
{
box->x += parent->x;
box->y += parent->y;
HTMLSetupBox(li, box);
}
return;
}
/*
* StartLine
*/
static HLine *
StartLine(li, env, hf, parent)
HTMLInfo li;
HTMLEnv env;
HFlow *hf;
HTMLBox parent;
{
HLine *hl;
HTMLBox floater;
HCons *hc;
while ((floater = GListPop(hf->pending_floaters)) != NULL)
{
AddFloater(li, hf, parent, floater);
}
/*
* Add a new line to the end.
*/
hl = (HLine *)MPCGet(li->mp, sizeof(HLine));
hl->boxes = GListCreateX(li->mp);
hl->ff = env->ff;
GListAddTail(hf->lines, hl);
hl->y = hf->nexty;
hl->x = 0;
hl->maxwidth = hf->maxwidth;
/*
* Determine if a constraint box has to be taken into account.
*/
for (hc = (HCons *)GListGetHead(hf->constraints); hc != NULL;
hc = (HCons *)GListGetNext(hf->constraints))
{
if (hl->y >= hc->y && hc->y + hc->height >= hl->y)
{
if (hc->x > hl->x) hl->x = hc->x;
if (hc->x + hc->width < hl->x + hl->maxwidth)
{
/*
* Check for extreme trouble. It might be possible for the
* left edge of the line to go beyond the right side of the
* constraint box. If so, try to push the line down past
* everything else to avoid Trouble.
*/
if (hl->x > hc->x + hc->width)
{
hl->x = 0;
hl->y = parent->height;
hl->maxwidth = hf->maxwidth;
break;
}
else hl->maxwidth = hc->x + hc->width;
}
}
}
hl->maxwidth -= hl->x;
return(hl);
}
/*
* EndLine
*/
static void
EndLine(li, hf, hl, parent)
HTMLInfo li;
HFlow *hf;
HLine *hl;
HTMLBox parent;
{
myassert(!hl->ended, "Line already ended");
hf->linecount++;
if (hl->width + hl->x > parent->width) parent->width = hl->width + hl->x;
hf->nexty += hl->height;
if (hf->nexty > parent->height) parent->height = hf->nexty;
if (HTMLTestB(parent, BOX_TOPLEVEL))
{
if (hf->linecount % 50 == 0)
{
GUISetDimensions(li->wd,
parent->width + li->lmargin + li->rmargin,
parent->height + li->tmargin + li->bmargin);
}
hl->x += parent->x;
hl->y += parent->y;
SetupHLine(li, hf, hl);
}
hl->ended = true;
return;
}
/*
* LayoutFlow
*/
static void
LayoutFlow(li, child, parent)
HTMLInfo li;
HTMLBox child;
HTMLBox parent;
{
HFlow *hf = (HFlow *)parent->closure;
HLine *hl;
unsigned int temp;
if (li->framesonly) return;
if (HTMLTestB(parent, BOX_TOPLEVEL)) li->noframeset = true;
/*
* Shove the floating box in a list and deal with it just before a new
* line is started.
*/
if (HTMLTestB(child, BOX_FLOAT_LEFT | BOX_FLOAT_RIGHT))
{
GListAddTail(hf->pending_floaters, child);
return;
}
/*
* Check for clear
*/
if (HTMLTestB(child, BOX_CLEAR_LEFT | BOX_CLEAR_RIGHT))
{
if (HTMLTestB(child, BOX_CLEAR_LEFT) && hf->nexty < hf->lfloaty)
{
hf->nexty = hf->lfloaty;
}
if (HTMLTestB(child, BOX_CLEAR_RIGHT) && hf->nexty < hf->rfloaty)
{
hf->nexty = hf->rfloaty;
}
hf->linebreak = true;
return;
}
/*
* Check for new line.
*/
if ((hl = (HLine *)GListGetTail(hf->lines)) == NULL)
{
if (HTMLTestB(child, BOX_LINEBREAK | BOX_SPACE)) return;
hl = StartLine(li, child->env, hf, parent);
}
else
{
if (HTMLTestB(child, BOX_LINEBREAK))
{
hf->linebreak = true;
return;
}
if (hf->linebreak ||
(child->width + hl->width > hl->maxwidth && !GListEmpty(hl->boxes)))
{
hf->linebreak = false;
if (!hl->ended) EndLine(li, hf, hl, parent);
hl = StartLine(li, child->env, hf, parent);
if (HTMLTestB(child, BOX_SPACE)) return;
}
else hf->linebreak = false;
}
/*
* Figure out how the new box changes the baseline offset (from
* the top) and the bottom;
*/
if (HTMLTestB(child, BOX_VCENTER))
{
temp = child->height / 2;
if (temp > hl->bloff) hl->bloff = temp;
if (temp > hl->bottom) hl->bottom = temp;
}
else
{
if (child->baseline > hl->bloff) hl->bloff = child->baseline;
temp = child->height - child->baseline;
if (temp > hl->bottom) hl->bottom = temp;
}
hl->width += child->width;
hl->height = hl->bloff + hl->bottom;
GListAddTail(hl->boxes, child);
return;
}
/*
* SetupHLine
*/
static void
SetupHLine(li, hf, hl)
HTMLInfo li;
HFlow *hf;
HLine *hl;
{
HTMLBox c;
int x = hl->x;
if (hl->ff & FLOW_CENTER_JUSTIFY)
{
if (hl->width < hl->maxwidth) x += hl->maxwidth / 2 - hl->width / 2;
}
else if (hl->ff & FLOW_RIGHT_JUSTIFY)
{
if (hl->width < hl->maxwidth) x += hl->maxwidth - hl->width;
}
for (c = (HTMLBox)GListGetHead(hl->boxes); c != NULL;
c = (HTMLBox)GListGetNext(hl->boxes))
{
c->x = x;
c->y = hl->y;
HTMLSetupBox(li, c);
x += c->width;
HTMLRenderBox(li, NULL, c);
}
return;
}
/*
* SetupFlow
*/
static void
SetupFlow(li, box)
HTMLInfo li;
HTMLBox box;
{
HFlow *hf = (HFlow *)box->closure;
HLine *hl;
HTMLBox c;
if (HTMLTestB(box, BOX_TOPLEVEL)) return;
for (c = (HTMLBox)GListGetHead(hf->floaters); c != NULL;
c = (HTMLBox)GListGetNext(hf->floaters))
{
c->x += box->x;
c->y += box->y;
HTMLSetupBox(li, c);
}
for (hl = (HLine *)GListGetHead(hf->lines); hl != NULL;
hl = (HLine *)GListGetNext(hf->lines))
{
hl->x += box->x;
hl->y += box->y;
SetupHLine(li, hf, hl);
}
return;
}
/*
* WidthFlow
*/
static unsigned int
WidthFlow(li, box)
HTMLInfo li;
HTMLBox box;
{
HFlow *hf = (HFlow *)box->closure;
HLine *hl;
if ((hl = (HLine *)GListGetTail(hf->lines)) == NULL || hf->linebreak)
{
return(hf->maxwidth);
}
return(hl->maxwidth - hl->width);
}
/*
*
* Public functions
*
*/
/*
* HTMLCreateFlowBox
*/
HTMLBox
HTMLCreateFlowBox(li, env, maxwidth)
HTMLInfo li;
HTMLEnv env;
unsigned int maxwidth;
{
HTMLBox box;
HFlow *hf;
hf = (HFlow *)MPCGet(li->mp, sizeof(HFlow));
hf->lines = GListCreateX(li->mp);
hf->floaters = GListCreateX(li->mp);
hf->pending_floaters = GListCreateX(li->mp);
hf->constraints = GListCreateX(li->mp);
/* woo hoo! */
if (maxwidth == 0) hf->maxwidth = 64000;
else hf->maxwidth = maxwidth;
box = HTMLCreateBox(li, env);
box->setup = SetupFlow;
box->render = RenderFlow;
box->destroy = DestroyFlow;
box->maxwidth = WidthFlow;
box->layout = LayoutFlow;
box->closure = hf;
return(box);
}
/*
* HTMLFinishFlowBox
*/
void
HTMLFinishFlowBox(li, box)
HTMLInfo li;
HTMLBox box;
{
HFlow *hf = (HFlow *)box->closure;
HLine *hl;
HTMLBox child;
if (HTMLTestB(box, BOX_TOPLEVEL) && !li->noframeset) return;
if ((hl = (HLine *)GListGetTail(hf->lines)) != NULL)
{
if (!hl->ended) EndLine(li, hf, hl, box);
}
while ((child = (HTMLBox)GListPop(hf->pending_floaters)) != NULL)
{
AddFloater(li, hf, box, child);
}
if (HTMLTestB(box, BOX_TOPLEVEL))
{
GUISetDimensions(li->wd,
box->width + li->lmargin + li->rmargin,
box->height + li->tmargin + li->bmargin);
HTMLSetFinalPosition(li);
}
return;
}

475
html/font.c Normal file
View File

@ -0,0 +1,475 @@
/*
* font.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
/*
*
* You really don't want to look in here.
*
*/
#define FONT_SCALE_COUNT 6
#define XLFD_FOUNDRY 0
#define XLFD_FAMILY 1
#define XLFD_WEIGHT_NAME 2
#define XLFD_SLANT 3
#define XLFD_SETWIDTH_NAME 4
#define XLFD_STYLE_NAME 5
#define XLFD_PIXEL_SIZE 6
#define XLFD_POINT_SIZE 7
#define XLFD_RES_X 8
#define XLFD_RES_Y 9
#define XLFD_SPACING 9
#define XLFD_AVERAGE_WIDTH 10
#define XLFD_REGISTRY 11
#define XLFD_ENCODING 12
#define XLFD_COUNT 13
/* Silly font information */
struct HTMLFontP
{
bool fixed; /* fixed width? */
int weight; /* bold, medium, ... */
int slant; /* italic, regular, ... */
int scale; /* scale of font */
int size; /* size of font */
XFontStruct *xfi; /* real font info */
};
struct HTMLFontListP
{
HTMLFont fontInfo;
int count;
int scale[FONT_SCALE_COUNT];
char **names;
};
static void ParseXLFD _ArgProto((MemPool, char *, HTMLFont));
static HTMLFontList GetFontList _ArgProto((HTMLClass, char *));
static void FreeFontList _ArgProto((HTMLClass, HTMLFontList));
static XFontStruct *GetFont _ArgProto((HTMLClass, HTMLFontList, int));
/*
* ParseXLFD
*
* Yipe!
*/
static void
ParseXLFD(mp, xlfd, lfi)
MemPool mp;
char *xlfd;
HTMLFont lfi;
{
char *fields[XLFD_COUNT];
int i;
char *t;
t = MPStrDup(mp, xlfd);
t++;
fields[0] = t;
for (i = 1; i < XLFD_COUNT; t++)
{
if (*t == '-')
{
*t = '\0';
fields[i++] = t + 1;
}
}
if (strcmp(fields[XLFD_WEIGHT_NAME], "bold") == 0 ||
strcmp(fields[XLFD_WEIGHT_NAME], "demi") == 0 ||
strcmp(fields[XLFD_WEIGHT_NAME], "demibold") == 0)
{
lfi->weight = 1;
}
else lfi->weight = 0;
lfi->size = atoi(fields[XLFD_PIXEL_SIZE]);
if (strcmp(fields[XLFD_SLANT], "i") == 0 ||
strcmp(fields[XLFD_SLANT], "o") == 0)
{
lfi->slant = 1;
}
else lfi->slant = 0;
return;
}
/*
* GetFont
*/
static XFontStruct *
GetFont(lc, fl, i)
HTMLClass lc;
HTMLFontList fl;
int i;
{
if (fl->fontInfo[i].xfi == NULL)
{
fl->fontInfo[i].xfi = XLoadQueryFont(lc->dpy, fl->names[i]);
if (fl->fontInfo[i].xfi == NULL) return(lc->defaultFont);
}
return(fl->fontInfo[i].xfi);
}
/*
* HTMLGetFont
*/
XFontStruct *
HTMLGetFont(li, env)
HTMLInfo li;
HTMLEnv env;
{
int i;
HTMLClass lc = li->lc;
HTMLFont lfi;
HTMLFontList fl;
lfi = env->fi;
if (lfi == NULL)
{
lfi = HTMLDupFont(li,li->cfi);
env->fi = lfi;
}
/*
* Check spacing
*/
if (lfi->fixed) fl = lc->fixed;
else fl = lc->prop;
/*
* Check slant, size, and weight
*/
for (i = 0; i < fl->count; i++)
{
if (((lfi->weight > 0) == (fl->fontInfo[i].weight > 0)) &&
((lfi->slant > 0) == (fl->fontInfo[i].slant > 0)) &&
fl->scale[lfi->scale] == fl->fontInfo[i].size)
{
return(GetFont(lc, fl, i));
}
}
/*
* Check slant and size
*/
for (i = 0; i < fl->count; i++)
{
if (((lfi->slant > 0) == (fl->fontInfo[i].slant > 0)) &&
fl->scale[lfi->scale] == fl->fontInfo[i].size)
{
return(GetFont(lc, fl, i));
}
}
/*
* Check weight and size
*/
for (i = 0; i < fl->count; i++)
{
if (((lfi->weight > 0) == (fl->fontInfo[i].weight > 0)) &&
fl->scale[lfi->scale] == fl->fontInfo[i].size)
{
return(GetFont(lc, fl, i));
}
}
/*
* Check size
*/
for (i = 0; i < fl->count; i++)
{
if (fl->scale[lfi->scale] == fl->fontInfo[i].size)
{
return(GetFont(lc, fl, i));
}
}
return(lc->defaultFont);
}
/*
* GetFontList
*/
static HTMLFontList
GetFontList(lc, pattern)
HTMLClass lc;
char *pattern;
{
int count;
int scale_count;
int i, j, k;
MemPool mp;
HTMLFontList fl;
fl = (HTMLFontList)MPCGet(lc->mp, sizeof(struct HTMLFontListP));
fl->names = XListFonts(lc->dpy, pattern, 999, &count);
if (fl->names == NULL || count == 0)
{
fprintf (stderr, "Could not get font list\n");
fflush(stderr);
exit(1);
}
fl->fontInfo = (HTMLFont)MPCGet(lc->mp, sizeof(struct HTMLFontP) * count);
/*
* Extract simple information from the XLFD strings.
*/
mp = MPCreate();
for (i = 0; i < count; i++)
{
ParseXLFD(mp, fl->names[i], &(fl->fontInfo[i]));
}
MPDestroy(mp);
/*
* Find sizes for each of the font scales. There must be a better way.
* This should probably not take
*/
scale_count = 0;
for (i = 0; i < count && scale_count < FONT_SCALE_COUNT; i++)
{
if (fl->fontInfo[i].size > 0)
{
for (j = 0; j < scale_count; j++)
{
if (fl->fontInfo[i].size == fl->scale[j]) break;
if (fl->fontInfo[i].size < fl->scale[j])
{
for (k = scale_count - 1; k >= j; k--)
{
fl->scale[k + 1] = fl->scale[k];
}
fl->scale[j] = fl->fontInfo[i].size;
scale_count++;
break;
}
}
if (j == scale_count)
{
fl->scale[j] = fl->fontInfo[i].size;
scale_count++;
}
}
}
/*
* This will probably never happen.
*/
if (scale_count == 0)
{
fl->scale[0] = fl->fontInfo[0].size;
scale_count++;
}
/*
* Fill out the rest if there aren't FONT_SCALE_COUNT
*/
if (scale_count < FONT_SCALE_COUNT)
{
for (i = scale_count; i < FONT_SCALE_COUNT; i++)
{
fl->scale[i] = fl->scale[i - 1];
}
scale_count = FONT_SCALE_COUNT;
}
/*
* Set miscellaneous information.
*/
fl->count = count;
return(fl);
}
/*
* HTMLSetupFonts
*/
void
HTMLSetupFonts(li)
HTMLInfo li;
{
char *name;
HTMLClass lc = li->lc;
/*
* Default HTML font.
*/
li->cfi = (HTMLFont)MPCGet(li->mp, sizeof(struct HTMLFontP));
HTMLSetFontProp(li->cfi);
HTMLSetFontScale(li->cfi, 2);
/*
* Only need to do HTML font information setup once.
*/
if (lc->font_setup_done) return;
lc->dpy = li->dpy;
/*
* Font to use if all else fails
*/
name = ResourceGetString(li->cres, "html.defaultFont");
if (name == NULL) name = "variable";
if ((lc->defaultFont = XLoadQueryFont(li->dpy, name)) == NULL)
{
fprintf (stderr, "Could not get default font.\n");
fflush(stderr);
exit(1);
}
/*
* Get the font list pattern for the proportional fonts. Hopefully
* a reasonable pattern was selected.
*/
name = ResourceGetString(li->cres, "html.propFontPattern");
if (name == NULL) name = "-adobe-times-*-*-*-*-*-*-*-*-*-*-iso8859-1";
lc->prop = GetFontList(lc, name);
/*
* Get the font list pattern for the fixed fonts. Hopefully
* a reasonable pattern was selected.
*/
name = ResourceGetString(li->cres, "html.fixedFontPattern");
if (name == NULL) name = "-misc-fixed-*-*-*-*-*-*-*-*-*-*-iso8859-1";
lc->fixed = GetFontList(lc, name);
lc->font_setup_done = true;
return;
}
/*
* FreeFontList
*/
static void
FreeFontList(lc, fl)
HTMLClass lc;
HTMLFontList fl;
{
int i;
if (fl->fontInfo != NULL)
{
for (i = 0; i < XLFD_COUNT; i++)
{
if (fl->fontInfo[i].xfi != NULL &&
fl->fontInfo[i].xfi != lc->defaultFont)
{
XFreeFont(lc->dpy, fl->fontInfo[i].xfi);
}
}
}
if (fl->names != NULL) XFreeFontNames(fl->names);
return;
}
/*
* HTMLFreeFonts
*/
void
HTMLFreeFonts(lc)
HTMLClass lc;
{
if (lc->prop != NULL) FreeFontList(lc, lc->prop);
if (lc->fixed != NULL) FreeFontList(lc, lc->fixed);
if (lc->defaultFont != NULL) XFreeFont(lc->dpy, lc->defaultFont);
return;
}
HTMLFont
HTMLDupFont(li, f)
HTMLInfo li;
HTMLFont f;
{
HTMLFont n;
n = (HTMLFont)MPCGet(li->mp, sizeof(struct HTMLFontP));
memcpy(n, f, sizeof(struct HTMLFontP));
return(n);
}
void
HTMLAddFontWeight(f)
HTMLFont f;
{
f->weight++;
return;
}
void
HTMLAddFontSlant(f)
HTMLFont f;
{
f->slant++;
return;
}
void
HTMLAddFontScale(f)
HTMLFont f;
{
f->scale++;
return;
}
void
HTMLSetFontScale(f, scale)
HTMLFont f;
int scale;
{
f->scale = scale;
return;
}
void
HTMLSetFontProp(f)
HTMLFont f;
{
f->fixed = false;
return;
}
void
HTMLSetFontFixed(f)
HTMLFont f;
{
f->fixed = true;
return;
}

1099
html/form.c Normal file

File diff suppressed because it is too large Load Diff

542
html/frame.c Normal file
View File

@ -0,0 +1,542 @@
/*
* frame.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
#include "ChimeraStack.h"
#define LASTRESORTSIZE 100
typedef struct HTMLFrameInfoP *HTMLFrameInfo;
typedef struct HTMLFrameSetInfoP *HTMLFrameSetInfo;
typedef struct HTMLFrameSizeP *HTMLFrameSize;
struct HTMLFrameSizeP
{
unsigned int size;
};
struct HTMLFrameInfoP
{
HTMLInfo li;
HTMLBox box;
ChimeraStack cs;
ChimeraRequest *wr;
int x, y;
unsigned int width, height;
char *name;
HTMLFrameSetInfo fset;
};
struct HTMLFrameSetInfoP
{
HTMLInfo li;
bool horiz;
GList sizes;
GList frames;
unsigned int other_size;
HTMLFrameSize current_size;
int x, y;
};
static void SetupIFrame _ArgProto((HTMLInfo, HTMLBox));
static void DestroyIFrame _ArgProto((HTMLInfo, HTMLBox));
static GList GetSizes _ArgProto((HTMLInfo, char *, unsigned int));
/* not used
static void FrameRenderAction _ArgProto((void *, ChimeraRender,
ChimeraRequest *, char *));
static HTMLFrameInfo FindNamedFrame _ArgProto((HTMLInfo, char *));
*/
/*
*
* <FRAMESET><FRAME><FRAMESET> ignores all the usual layout methods and
* blasts the frames right onto the window. No point in messing
* around with that stuff. The old-style frames are evil.
*
*/
/*
* SetupIFrame
*/
static void
SetupIFrame(li, box)
HTMLInfo li;
HTMLBox box;
{
HTMLFrameInfo fi = (HTMLFrameInfo)box->closure;
fi->cs = StackCreate(StackFromGUI(li->wc, li->wd),
box->x, box->y, box->width, box->height,
NULL, NULL);
StackOpen(fi->cs, fi->wr);
return;
}
/*
* DestroyIFrame
*/
static void
DestroyIFrame(li, box)
HTMLInfo li;
HTMLBox box;
{
HTMLFrameInfo fi = (HTMLFrameInfo)box->closure;
if (fi->cs != NULL) StackDestroy(fi->cs);
return;
}
/*
* HTMLIFrame
*/
void
HTMLIFrame(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLBox box;
HTMLAttribID aid;
HTMLFrameInfo fi;
int width, height;
char *url;
ChimeraRequest *wr;
if ((url = MLFindAttribute(p, "src")) == NULL) return;
if ((wr = RequestCreate(li->cres, url, NULL)) == NULL) return;
fi = (HTMLFrameInfo)MPCGet(li->mp, sizeof(struct HTMLFrameInfoP));
if ((width = MLAttributeToInt(p, "width")) < 0) width = 500;
if ((height = MLAttributeToInt(p, "height")) < 0) height = 500;
box = HTMLCreateBox(li, env);
aid = HTMLAttributeToID(p, "align");
if (aid == ATTRIB_MIDDLE) box->baseline = height / 2;
else if (aid == ATTRIB_TOP) box->baseline = 0;
else if (aid == ATTRIB_LEFT) HTMLSetB(box, BOX_FLOAT_LEFT);
else if (aid == ATTRIB_RIGHT) HTMLSetB(box, BOX_FLOAT_RIGHT);
else box->baseline = height;
box->setup = SetupIFrame;
box->destroy = DestroyIFrame;
box->width = width;
box->height = height;
box->closure = fi;
fi->box = box;
fi->li = li;
fi->wr = wr;
HTMLEnvAddBox(li, env, box);
return;
}
/*
* HTMLFrameInsert
*/
HTMLInsertStatus
HTMLFrameInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
if (HTMLTagToID(env->tag) != TAG_FRAMESET) return(HTMLInsertReject);
return(HTMLInsertOK);
}
/*
* HTMLFrame
*/
void
HTMLFrame(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLFrameInfo fi;
char *url;
ChimeraRequest *wr;
HTMLFrameSetInfo fset;
unsigned int size;
fset = (HTMLFrameSetInfo)env->closure;
if ((url = MLFindAttribute(p, "src")) == NULL) return;
if ((wr = RequestCreate(li->cres, url, li->burl)) == NULL) return;
fi = (HTMLFrameInfo)MPCGet(li->mp, sizeof(struct HTMLFrameInfoP));
fi->li = li;
fi->wr = wr;
fi->box = HTMLCreateBox(li, env);
fi->box->destroy = DestroyIFrame;
fi->box->closure = fi;
fi->x = fset->x;
fi->y = fset->y;
fi->name = MLFindAttribute(p, "name");
fi->fset = fset;
if (fset->current_size == NULL) size = LASTRESORTSIZE;
else size = fset->current_size->size;
if (fset->horiz)
{
fi->width = size;
fi->height = fset->other_size;
fset->x += size;
}
else
{
fi->width = fset->other_size;
fi->height = size;
fset->y += size;
}
GListAddHead(fset->frames, fi);
fset->current_size = (HTMLFrameSize)GListGetNext(fset->sizes);
return;
}
/*
* HTMLFrameSetAccept
*/
bool
HTMLFrameSetAccept(li, obj)
HTMLInfo li;
HTMLObject obj;
{
HTMLTag tag;
if (obj->type == HTML_ENV && HTMLTagToID(obj->o.env->tag) != TAG_FRAMESET)
{
return(true);
}
if (obj->type == HTML_TAG)
{
if ((tag = HTMLGetTag(obj->o.p)) != NULL && HTMLTagToID(tag) == TAG_FRAME)
{
return(true);
}
}
return(true);
}
/*
* HTMLFrameSetInsert
*/
HTMLInsertStatus
HTMLFrameSetInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLEnv c;
HTMLTagID tid;
/*
* Quick and dirty way to kill off frames from another location.
*/
if (li->noframeset) return(HTMLInsertReject);
li->framesonly = true;
for (c = (HTMLEnv)GListGetHead(li->envstack); c != NULL;
c = (HTMLEnv)GListGetNext(li->envstack))
{
tid = HTMLTagToID(c->tag);
if (tid != TAG_FRAMESET && tid != TAG_HTML && tid != TAG_DOCUMENT)
{
return(HTMLInsertReject);
}
}
return(HTMLInsertOK);
}
/*
* GetSizes
*/
static GList
GetSizes(li, s, len)
HTMLInfo li;
char *s;
unsigned int len;
{
char *cp;
GList list;
HTMLFrameSize size;
int x;
int totalpc;
list = GListCreateX(li->mp);
size = MPGet(li->mp, sizeof(struct HTMLFrameSizeP));
totalpc = x = atoi(s);
if (x <= 0) size->size = LASTRESORTSIZE;
else size->size = len * x / 100;
GListAddHead(list, size);
for (cp = s; *cp != '\0'; cp++)
{
if (*cp == ',')
{
size = MPGet(li->mp, sizeof(struct HTMLFrameSizeP));
if (*(cp+1) == '*') x = 100 - totalpc;
else x = atoi(cp + 1);
x = atoi(cp + 1);
if (x <= 0) x = 10;
size->size = len * x / 100;
GListAddTail(list, size);
}
}
return(list);
}
/*
* HTMLFrameSetBegin
*/
void
HTMLFrameSetBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLFrameSetInfo pfset, fset;
char *sizestr;
unsigned int width, height;
GUISetScrollBar(li->wd, false);
GUIGetDimensions(li->wd, &width, &height);
fset = (HTMLFrameSetInfo)MPCGet(li->mp, sizeof(struct HTMLFrameSetInfoP));
env->closure = fset;
fset->frames = GListCreateX(li->mp);
if ((sizestr = MLFindAttribute(p, "rows")) != NULL)
{
fset->horiz = false;
fset->sizes = GetSizes(li, sizestr, height);
}
else if ((sizestr = MLFindAttribute(p, "cols")) != NULL)
{
fset->horiz = true;
fset->sizes = GetSizes(li, sizestr, width);
}
else
{
fset->horiz = false;
fset->sizes = GListCreateX(li->mp);
}
if (HTMLTagToID(env->penv->tag) == TAG_FRAMESET)
{
/*
* Frameset inside a frameset so look at the parent to see if there
* is a size given.
*/
pfset = (HTMLFrameSetInfo)env->penv->closure;
if (pfset->current_size == NULL) fset->other_size = LASTRESORTSIZE;
else
{
fset->other_size = pfset->current_size->size;
pfset->current_size = (HTMLFrameSize)GListGetNext(pfset->sizes);
fset->x = pfset->x;
fset->y = pfset->y;
if (pfset->horiz) pfset->x += fset->other_size;
else pfset->y += fset->other_size;
}
}
else
{
/*
* Must be first frameset
*/
if (fset->horiz) fset->other_size = width;
else fset->other_size = height;
}
fset->current_size = (HTMLFrameSize)GListGetHead(fset->sizes);
GListAddHead(li->framesets, fset);
return;
}
/*
* HTMLFrameSetEnd
*/
void
HTMLFrameSetEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLFrameInfo fi;
HTMLFrameSetInfo fset = (HTMLFrameSetInfo)env->closure;
for (fi = (HTMLFrameInfo)GListGetHead(fset->frames); fi != NULL;
fi = (HTMLFrameInfo)GListGetNext(fset->frames))
{
fi->cs = StackCreate(StackFromGUI(li->wc, li->wd),
fi->x, fi->y, fi->width, fi->height,
NULL, NULL);
StackOpen(fi->cs, fi->wr);
}
return;
}
/*
* HTMLNoFramesBegin
*/
void
HTMLNoFramesBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
/*
* HTMLNoFramesEnd
*/
void
HTMLNoFramesEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
/*
* HTMLDestroyFrameSets
*/
void
HTMLDestroyFrameSets(li)
HTMLInfo li;
{
HTMLFrameInfo fi;
HTMLFrameSetInfo fset;
for (fset = (HTMLFrameSetInfo)GListGetHead(li->framesets); fset != NULL;
fset = (HTMLFrameSetInfo)GListGetNext(li->framesets))
{
for (fi = (HTMLFrameInfo)GListGetHead(fset->frames); fi != NULL;
fi = (HTMLFrameInfo)GListGetNext(fset->frames))
{
StackDestroy(fi->cs);
}
}
return;
}
/*
* FindNamedFrame
*/
/* not used
static HTMLFrameInfo
FindNamedFrame(li, name)
HTMLInfo li;
char *name;
{
HTMLFrameSetInfo fset;
HTMLFrameInfo fi;
for (fset = (HTMLFrameSetInfo)GListGetHead(li->framesets); fset != NULL;
fset = (HTMLFrameSetInfo)GListGetNext(li->framesets))
{
for (fi = (HTMLFrameInfo)GListGetHead(fset->frames); fi != NULL;
fi = (HTMLFrameInfo)GListGetNext(fset->frames))
{
if (fi->name != NULL &&
strlen(fi->name) == strlen(name) &&
strcasecmp(fi->name, name) == 0)
{
return(fi);
}
}
}
return(NULL);
}
*/
/*
* HTMLFrameLoad
*
* This could fail in silly ways if there are multiple frames with the
* same name. Worry about this later.
*/
void
HTMLFrameLoad(li, wr, target)
HTMLInfo li;
ChimeraRequest *wr;
char *target;
{
HTMLInfo hi;
HTMLFrameSetInfo fset;
HTMLFrameInfo fi;
for (hi = (HTMLInfo)GListGetHead(li->lc->contexts); hi != NULL;
hi = (HTMLInfo)GListGetNext(li->lc->contexts))
{
for (fset = (HTMLFrameSetInfo)GListGetHead(hi->framesets); fset != NULL;
fset = (HTMLFrameSetInfo)GListGetNext(hi->framesets))
{
for (fi = (HTMLFrameInfo)GListGetHead(fset->frames); fi != NULL;
fi = (HTMLFrameInfo)GListGetNext(fset->frames))
{
if (fi->name != NULL &&
strlen(fi->name) == strlen(target) &&
strcasecmp(fi->name, target) == 0)
{
StackOpen(fi->cs, wr);
}
}
}
}
return;
}

66
html/head.c Normal file
View File

@ -0,0 +1,66 @@
/*
* head.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
void
HTMLTitleEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
li->title = HTMLGetEnvText(li->mp, env);
return;
}
void
HTMLBase(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *url;
if ((url = MLFindAttribute(p, "href")) != NULL) li->burl = url;
return;
}
void
HTMLMeta(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}

92
html/hr.c Normal file
View File

@ -0,0 +1,92 @@
/*
* hr.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
#define HR_HEIGHT 20
#define HR_HALF_HEIGHT 10
/*
*
* Private functions
*
*/
static void RenderHR _ArgProto((HTMLInfo, HTMLBox, Region));
/*
* RenderHR
*/
static void
RenderHR(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
XSetLineAttributes(li->dpy, li->gc,
1, LineSolid, CapNotLast, JoinRound);
XDrawLine(li->dpy, li->win, li->gc,
box->x, box->y + HR_HALF_HEIGHT,
box->x + box->width, box->y + HR_HALF_HEIGHT);
return;
}
/*
*
* Public Functions
*
*/
/*
* HandleHR
*/
void
HTMLHorizontalRule(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLBox box;
HTMLAddLineBreak(li, env);
box = HTMLCreateBox(li, env);
box->render = RenderHR;
box->width = HTMLGetMaxWidth(li, env);
box->height = HR_HEIGHT;
HTMLEnvAddBox(li, env, box);
HTMLAddLineBreak(li, env);
return;
}

822
html/html.c Normal file
View File

@ -0,0 +1,822 @@
/*
* html.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1994-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
static void EndTag _ArgProto((HTMLInfo, HTMLTag, MLElement));
static void StartTag _ArgProto((HTMLInfo, HTMLTag, MLElement));
static void AddObject _ArgProto((HTMLInfo, HTMLObjectType, void *));
static void DoEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
static bool BoxifyObject _ArgProto((HTMLInfo, HTMLEnv, HTMLObject));
static bool Boxify _ArgProto((HTMLInfo, HTMLEnv));
static void HTMLDocumentBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
static void HTMLDocumentEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
static void HTMLDocumentAddBox _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
static unsigned int HTMLDocumentWidth _ArgProto((HTMLInfo, HTMLEnv));
static void Unboxify _ArgProto((HTMLInfo, HTMLEnv));
static void PrintObject _ArgProto((HTMLObject));
#include "htmltags.h"
typedef struct
{
HTMLTag tag;
MLElement p;
} PendingEnd;
struct av
{
char *name;
HTMLAttribID align;
};
struct av alist[] =
{
{ "left", ATTRIB_LEFT },
{ "right", ATTRIB_RIGHT },
{ "center", ATTRIB_CENTER },
{ "top", ATTRIB_TOP },
{ "bottom", ATTRIB_BOTTOM },
{ "middle", ATTRIB_MIDDLE },
{ "all", ATTRIB_ALL },
{ NULL, ATTRIB_UNKNOWN }
};
static int alist_len = sizeof(alist) / sizeof(alist[0]);
/*
* HTMLAttributeToID
*/
HTMLAttribID
HTMLAttributeToID(p, name)
MLElement p;
char *name;
{
char *value;
int i;
if ((value = MLFindAttribute(p, name)) == NULL) return(ATTRIB_UNKNOWN);
for (i = 0; i < alist_len; i++)
{
if (alist[i].name != NULL && strcasecmp(value, alist[i].name) == 0)
{
return(alist[i].align);
}
}
return(ATTRIB_UNKNOWN);
}
/*
* HTMLGetTag
*/
HTMLTag
HTMLGetTag(p)
MLElement p;
{
int i;
char *name;
if ((name = MLTagName(p)) == NULL) return(NULL);
for (i = 0; i < tlist_len; i++)
{
if (tlist[i].name != NULL &&
strlen(name) == strlen(tlist[i].name) &&
strcasecmp(name, tlist[i].name) == 0 &&
!HTMLTestM(&tlist[i], MARKUP_FAKE))
{
return(&tlist[i]);
}
}
return(NULL);
}
/*
* HTMLTagIDToTag
*/
HTMLTag
HTMLTagIDToTag(tagid)
HTMLTagID tagid;
{
int i;
for (i = 0; i < tlist_len; i++)
{
if (tlist[i].id == tagid) return(&tlist[i]);
}
return(NULL);
}
/*
* HTMLFindEnv
*/
HTMLEnv
HTMLFindEnv(li, tagid)
HTMLInfo li;
HTMLTagID tagid;
{
HTMLEnv env;
GList list;
list = li->envstack;
for (env = (HTMLEnv)GListGetHead(list); env != NULL;
env = (HTMLEnv)GListGetNext(list))
{
if (env->tag->id == tagid) return(env);
}
return(NULL);
}
/*
* HTMLDelayLayout
*/
void
HTMLDelayLayout(li)
HTMLInfo li;
{
li->delayed++;
return;
}
/*
* HTMLContinueLayout
*/
void
HTMLContinueLayout(li)
HTMLInfo li;
{
myassert(li->delayed > 0, "Layout was not delayed.");
li->delayed--;
if (li->delayed == 0) Boxify(li, li->topenv);
return;
}
/*
* HTMLTagToID
*/
HTMLTagID
HTMLTagToID(tag)
HTMLTag tag;
{
return(tag->id);
}
/*
* HTMLPopEnv
*/
HTMLEnv
HTMLPopEnv(li, tagid)
HTMLInfo li;
HTMLTagID tagid;
{
HTMLEnv c;
/* if (tagid == TAG_DOCUMENT) abort(); */
for (c = (HTMLEnv)GListGetHead(li->envstack); c != NULL;
c = (HTMLEnv)GListGetNext(li->envstack))
{
if (c->tag->id == tagid) break;
}
if (c == NULL) return(NULL);
while ((c = (HTMLEnv)GListGetHead(li->envstack)) != NULL)
{
if (c->tag->id == tagid) break;
DoEnd(li, c, NULL);
}
return(c);
}
/*
* HTMLStartEnv
*/
void
HTMLStartEnv(li, tagid, p)
HTMLInfo li;
HTMLTagID tagid;
MLElement p;
{
char *str;
HTMLTag tag;
tag = HTMLTagIDToTag(tagid);
if (p == NULL)
{
str = MPGet(li->mp, strlen(tag->name) + 3);
strcpy(str, "<");
strcat(str, tag->name);
strcat(str, ">");
p = MLCreateTag(li->hs, str, strlen(str));
}
StartTag(li, tag, p);
return;
}
/*
* HTMLEndEnv
*/
void
HTMLEndEnv(li, tagid)
HTMLInfo li;
HTMLTagID tagid;
{
EndTag(li, HTMLTagIDToTag(tagid), NULL);
return;
}
/*
* HTMLGetMaxWidth
*/
unsigned int
HTMLGetMaxWidth(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLEnv c;
for (c = env; c != NULL; c = c->penv)
{
if (c->tag->w != NULL) return((c->tag->w)(li, c));
}
return(0);
}
/*
* PrintObject
*/
static void
PrintObject(ho)
HTMLObject ho;
{
char *text;
size_t len;
MLElementType mt;
if (ho->type == HTML_ELEMENT)
{
MLGetText(ho->o.p, &text, &len);
fwrite (text, 1, len, stdout);
printf ("\n");
}
else if (ho->type == HTML_TAG || ho->type == HTML_BEGINTAG ||
ho->type == HTML_ENDTAG)
{
mt = MLGetType(ho->o.p);
if (mt == ML_ENDTAG) printf ("End tag: %s\n", MLTagName(ho->o.p));
else printf ("Begin tag: %s\n", MLTagName(ho->o.p));
}
return;
}
/*
* AddObject
*/
static void
AddObject(li, hot, obj)
HTMLInfo li;
HTMLObjectType hot;
void *obj;
{
HTMLEnv env;
HTMLObject ho;
ho = (HTMLObject)MPGet(li->mp, sizeof(struct HTMLObjectP));
ho->type = hot;
if (hot == HTML_ENV) ho->o.env = (HTMLEnv)obj;
else if (hot == HTML_ELEMENT) ho->o.p = (MLElement)obj;
else if (hot == HTML_TAG) ho->o.p = (MLElement)obj;
else if (hot == HTML_BEGINTAG) ho->o.p = (MLElement)obj;
else if (hot == HTML_ENDTAG) ho->o.p = (MLElement)obj;
else abort();
if (li->printTags) PrintObject(ho);
if (hot != HTML_BEGINTAG && hot != HTML_ENDTAG)
{
for (env = (HTMLEnv)GListGetHead(li->envstack); env != NULL;
env = (HTMLEnv)GListGetNext(li->envstack))
{
if (env->tag->m == NULL || (env->tag->m)(li, ho)) break;
}
if (env == NULL) return;
}
else env = (HTMLEnv)GListGetHead(li->envstack);
if (hot == HTML_ENV) ho->o.env->penv = env;
/*
* Add object to the object list for the environment. The first list
* will be modified later. The second list will always stay the
* same so there is always a place to find all the objects in an
* environment.
*/
GListAddTail(env->olist, ho);
GListAddTail(env->slist, ho);
return;
}
/*
* DoEnd
*/
static void
DoEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *name;
char *str;
if (p == NULL)
{
if (env->tag->name == NULL) name = "internal";
else name = env->tag->name;
str = (char *)MPGet(li->mp, strlen(name) + 4);
strcpy(str, "</");
strcat(str, name);
strcat(str, ">");
p = MLCreateTag(li->hs, str, strlen(str));
}
AddObject(li, HTML_ENDTAG, p);
env = (HTMLEnv)GListPop(li->envstack);
AddObject(li, HTML_ENV, env);
return;
}
/*
* EndTag
*/
static void
EndTag(li, tag, p)
HTMLInfo li;
HTMLTag tag;
MLElement p;
{
HTMLEnv etop;
PendingEnd *pe;
HTMLEnv env;
/*
* If there was no start tag then ignore.
*/
if (HTMLFindEnv(li, tag->id) == NULL) return;
/*
* Check to see if the end tag is supposed to clamp down on all
* unterminated environments.
*/
if (HTMLTestM(tag, MARKUP_CLAMP))
{
if (tag->c != NULL)
{
if ((tag->c)(li, (HTMLEnv)GListGetHead(li->envstack)))
{
while ((env = (HTMLEnv)GListGetHead(li->envstack)) != NULL)
{
DoEnd(li, env, NULL);
if (env->tag->id == tag->id) break;
}
}
}
else
{
while ((env = (HTMLEnv)GListGetHead(li->envstack)) != NULL)
{
DoEnd(li, env, NULL);
if (env->tag->id == tag->id) break;
}
}
if ((pe = (PendingEnd *)GListPop(li->endstack)) != NULL)
{
EndTag(li, pe->tag, pe->p);
return;
}
}
else
{
/*
* Make sure the end tag matches the current environment before
* terminating the environment. If it doesn't match then stick it
* in a list for possible use later.
*/
etop = (HTMLEnv)GListGetHead(li->envstack);
if (tag->id == etop->tag->id)
{
DoEnd(li, etop, p);
if ((pe = (PendingEnd *)GListPop(li->endstack)) != NULL)
{
EndTag(li, pe->tag, pe->p);
return;
}
}
else
{
pe = MPGet(li->mp, sizeof(PendingEnd));
pe->tag = tag;
pe->p = p;
GListAddTail(li->endstack, pe);
}
}
return;
}
/*
* StartTag
*/
static void
StartTag(li, tag, p)
HTMLInfo li;
HTMLTag tag;
MLElement p;
{
HTMLEnv env;
HTMLEnv etop;
HTMLInsertStatus status;
if ((etop = (HTMLEnv)GListGetHead(li->envstack)) != NULL)
{
if (tag->p != NULL)
{
if ((status = (tag->p)(li, etop, p)) == HTMLInsertReject) return;
}
else status = HTMLInsertOK;
}
else status = HTMLInsertOK;
if (!HTMLTestM(tag, MARKUP_EMPTY) || status == HTMLInsertEmpty)
{
env = MPCGet(li->mp, sizeof(struct HTMLEnvP));
env->tag = tag;
env->olist = GListCreateX(li->mp);
env->blist = GListCreateX(li->mp);
env->slist = GListCreateX(li->mp);
if (etop == NULL) li->topenv = env;
GListAddHead(li->envstack, env);
AddObject(li, HTML_BEGINTAG, p);
}
else AddObject(li, HTML_TAG, p);
return;
}
/*
* HTMLHandler
*
* This is where elements from the ML scanner come into the HTML parser.
*/
void
HTMLHandler(closure, p)
void *closure;
MLElement p;
{
HTMLInfo li = (HTMLInfo)closure;
HTMLTag tag;
MLElementType mt;
if ((mt = MLGetType(p)) == ML_EOF)
{
/*
* fake a </xxx-document> tag.
*/
HTMLFinish(li);
/*
* Render the parsed HTML
*/
Boxify(li, li->topenv);
return;
}
else if (mt == ML_DATA) AddObject(li, HTML_ELEMENT, p);
else if ((tag = HTMLGetTag(p)) != NULL)
{
if (mt == ML_ENDTAG) EndTag(li, tag, p);
else StartTag(li, tag, p);
}
else if (li->printTags)
{
printf ("Unknown tag: %s\n", MLTagName(p));
}
return;
}
/*
* BoxifyObject
*/
static bool
BoxifyObject(li, env, obj)
HTMLInfo li;
HTMLEnv env;
HTMLObject obj;
{
HTMLTag tag;
HTMLEnv cenv;
CSSSelector cs;
if (obj->type == HTML_ELEMENT)
{
if (env->tag->d != NULL) (env->tag->d)(li, env, obj->o.p);
}
else if (obj->type == HTML_TAG)
{
if ((tag = HTMLGetTag(obj->o.p)) != NULL)
{
myassert(tag->b != NULL, "No tag handler for lone tag!");
(tag->b)(li, env, obj->o.p);
}
}
else if (obj->type == HTML_ENV)
{
cenv = obj->o.env;
if (!cenv->visited)
{
cenv->ff = env->ff;
cenv->anchor = env->anchor;
cenv->fi = HTMLDupFont(li, env->fi);
if (HTMLTestM(cenv->tag, MARKUP_SPACER))
{
HTMLAddBlankLine(li, env);
}
cenv->visited = true;
}
if ((cs = (CSSSelector)GListPop(li->oldselectors)) == NULL)
{
cs = CSSCreateSelector(li->mp);
}
CSSSetSelector(cs, cenv->tag->name, NULL, NULL, NULL);
GListAddHead(li->selectors, cs);
if (Boxify(li, cenv)) return(true);
GListAddHead(li->oldselectors, GListPop(li->selectors));
if (HTMLTestM(cenv->tag, MARKUP_SPACER))
{
HTMLAddBlankLine(li, env);
}
}
else if (obj->type == HTML_BEGINTAG)
{
if (env->tag->b != NULL) (env->tag->b)(li, env, obj->o.p);
}
else if (obj->type == HTML_ENDTAG)
{
if (env->tag->e != NULL) (env->tag->e)(li, env, obj->o.p);
}
else abort();
if (li->delayed > 0)
{
return(true);
}
return(false);
}
/*
* Unboxify
*/
static void
Unboxify(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLObject c;
GList t;
env->visited = false;
while ((c = (HTMLObject)GListPop(env->olist)) != NULL)
{
GListAddTail(env->blist, c);
}
t = env->olist;
env->olist = env->blist;
env->blist = t;
for (c = (HTMLObject)GListGetHead(env->olist); c != NULL;
c = (HTMLObject)GListGetNext(env->olist))
{
if (c->type == HTML_ENV) Unboxify(li, c->o.env);
}
return;
}
/*
* Boxify
*/
bool
Boxify(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLObject c;
myassert(li->delayed == 0, "yikes");
while ((c = (HTMLObject)GListPop(env->olist)) != NULL)
{
if (BoxifyObject(li, env, c))
{
if (c->type == HTML_ENV) GListAddHead(env->olist, c);
else GListAddTail(env->blist, c);
return(true);
}
else GListAddTail(env->blist, c);
}
if (HTMLTestM(env->tag, MARKUP_TWOPASS) && env->pass == 0)
{
env->pass++;
Unboxify(li, env);
Boxify(li, env);
}
return(false);
}
/*
* HTMLEnvAddBox
*/
void
HTMLEnvAddBox(li, env, box)
HTMLInfo li;
HTMLEnv env;
HTMLBox box;
{
HTMLEnv c;
for (c = env; c != NULL; c = c->penv)
{
if (c->tag->a != NULL)
{
(c->tag->a)(li, c, box);
break;
}
}
return;
}
/*
* HTMLDocumentEnd
*/
static void
HTMLDocumentEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLFinishFlowBox(li, li->firstbox);
return;
}
/*
* HTMLDocumentBegin
*/
static void
HTMLDocumentBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
/*
* HTMLDocumentWidth
*/
static unsigned int
HTMLDocumentWidth(li, env)
HTMLInfo li;
HTMLEnv env;
{
return(HTMLGetBoxWidth(li, li->firstbox));
}
/*
* HTMLDocumentAddBox
*/
static void
HTMLDocumentAddBox(li, env, box)
HTMLInfo li;
HTMLEnv env;
HTMLBox box;
{
HTMLLayoutBox(li, li->firstbox, box);
return;
}
/*
* HTMLFinish
*/
void
HTMLFinish(li)
HTMLInfo li;
{
HTMLPopEnv(li, TAG_DOCUMENT);
HTMLEndEnv(li, TAG_DOCUMENT);
return;
}
/*
* HTMLStart
*/
void
HTMLStart(li)
HTMLInfo li;
{
HTMLStartEnv(li, TAG_DOCUMENT,
MLCreateTag(li->hs,
"<xxx-document>", strlen("<xxx-document>")));
li->topenv->ff = FLOW_LEFT_JUSTIFY;
li->topenv->anchor = NULL;
li->topenv->fi = HTMLDupFont(li, li->cfi);
li->firstbox = HTMLCreateFlowBox(li, li->topenv,
li->maxwidth - (li->lmargin + li->rmargin));
li->firstbox->x = li->lmargin;
li->firstbox->y = li->rmargin;
HTMLSetB(li->firstbox, BOX_TOPLEVEL);
return;
}
/*
* HTMLGetIDEnv
*/
HTMLEnv
HTMLGetIDEnv(env, tid)
HTMLEnv env;
HTMLTagID tid;
{
HTMLEnv penv;
HTMLTagID ptid;
penv = env;
while ((ptid = HTMLTagToID(penv->tag)) != TAG_DOCUMENT)
{
if (ptid == tid) return(penv);
penv = penv->penv;
}
return(NULL);
}

585
html/html.h Normal file
View File

@ -0,0 +1,585 @@
/*
* html.h
*
* libhtml - HTML->X renderer
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __HTML_H__
#define __HTML_H__ 1
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include "common.h"
#include "Chimera.h"
#include "ChimeraRender.h"
#include "ChimeraGUI.h"
#include "ml.h"
#include "css.h"
/* proposed HTML3.2 tags and some internal tags */
typedef enum
{
/* internal tags */
TAG_DOCUMENT,
/* implemented? */
TAG_BR,
TAG_ADDRESS,
TAG_DIV,
TAG_CENTER,
TAG_A,
TAG_MAP,
TAG_AREA,
TAG_IMG,
TAG_HR,
TAG_P,
TAG_PRE,
TAG_XMP,
TAG_LISTING,
TAG_PLAINTEXT,
TAG_BLOCKQUOTE,
TAG_DL,
TAG_DD,
TAG_DT,
TAG_OL,
TAG_UL,
TAG_DIR,
TAG_MENU,
TAG_LI,
TAG_FORM,
TAG_INPUT,
TAG_SELECT,
TAG_OPTION,
TAG_TEXTAREA,
TAG_TABLE,
TAG_TR,
TAG_TH,
TAG_TD,
TAG_TITLE,
TAG_BASE,
TAG_SCRIPT,
TAG_H1,
TAG_H2,
TAG_H3,
TAG_H4,
TAG_H5,
TAG_H6,
TAG_TT,
TAG_I,
TAG_B,
TAG_STRIKE,
TAG_BIG,
TAG_SMALL,
TAG_SUB,
TAG_SUP,
TAG_EM,
TAG_STRING,
TAG_DFN,
TAG_CODE,
TAG_SAMP,
TAG_KBD,
TAG_VAR,
TAG_CITE,
TAG_STRONG,
/* do not implement */
TAG_HTML,
TAG_BODY,
TAG_HEAD,
/* weird stuff? */
TAG_IFRAME,
TAG_FRAME,
TAG_FRAMESET,
TAG_NOFRAMES,
/* unimplemented */
TAG_LINK,
TAG_APPLET,
TAG_META,
TAG_STYLE,
TAG_CAPTION,
TAG_FONT,
TAG_PARAM,
TAG_ISINDEX
} HTMLTagID;
typedef struct HTMLBoxP *HTMLBox;
typedef struct HTMLInfoP *HTMLInfo;
typedef struct HTMLClassP *HTMLClass;
typedef struct HTMLObjectP *HTMLObject;
typedef struct HTMLEnvP *HTMLEnv;
typedef struct HTMLFontP *HTMLFont;
typedef struct HTMLFontListP *HTMLFontList;
typedef struct HTMLAnchorP *HTMLAnchor;
typedef struct HTMLTagP *HTMLTag;
typedef struct HTMLMapP *HTMLMap;
typedef struct HTMLAreaP *HTMLArea;
typedef struct HTMLStateP *HTMLState;
/*
* Box callbacks
*/
typedef void (*HTMLSetupProc) _ArgProto((HTMLInfo, HTMLBox));
typedef void (*HTMLDestroyProc) _ArgProto((HTMLInfo, HTMLBox));
typedef void (*HTMLRenderProc) _ArgProto((HTMLInfo, HTMLBox, Region));
typedef void (*HTMLLayoutProc) _ArgProto((HTMLInfo, HTMLBox, HTMLBox));
typedef unsigned int (*HTMLWidthProc) _ArgProto((HTMLInfo, HTMLBox));
/*
* Tag callbacks
*/
typedef bool (*HTMLTagClampProc) _ArgProto((HTMLInfo, HTMLEnv));
typedef void (*HTMLTagRenderProc) _ArgProto((HTMLInfo, HTMLEnv, MLElement));
typedef bool (*HTMLTagAcceptProc) _ArgProto((HTMLInfo, HTMLObject));
typedef enum
{
HTMLInsertEmpty,
HTMLInsertReject,
HTMLInsertOK
} HTMLInsertStatus;
typedef HTMLInsertStatus (*HTMLTagInsertProc) _ArgProto((HTMLInfo,
HTMLEnv, MLElement));
typedef void (*HTMLTagDataProc) _ArgProto((HTMLInfo, HTMLEnv, MLElement));
typedef void (*HTMLTagAddBoxProc) _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
typedef unsigned int (*HTMLTagWidthProc) _ArgProto((HTMLInfo, HTMLEnv));
typedef enum
{
FLOW_LEFT_JUSTIFY,
FLOW_CENTER_JUSTIFY,
FLOW_RIGHT_JUSTIFY
} HTMLFlowAlign;
/*
* Environment
*/
typedef enum
{
HTML_ENV,
HTML_ELEMENT,
HTML_TAG,
HTML_BEGINTAG,
HTML_ENDTAG
} HTMLObjectType;
struct HTMLObjectP
{
HTMLObjectType type;
union
{
MLElement p;
HTMLEnv env;
} o;
};
struct HTMLEnvP
{
/* Keep track of html structure */
HTMLEnv penv; /* parent environment */
HTMLTag tag; /* tag that defines environment */
GList olist; /* object list */
GList blist; /* boxed object list */
GList slist; /* static object list */
int pass;
/* Keep track of HTML rendering */
bool visited; /* used by boxify functions */
MLElement anchor; /* anchor to use in environment */
HTMLFont fi; /* font to use in environment */
HTMLFlowAlign ff; /* alignment in flow box */
void *closure; /* environment specific data */
};
typedef enum
{
BOX_NONE = 0x00000000, /* no flags set */
BOX_SPACE = 0x00000001, /* horizontal space */
BOX_LINEBREAK = 0x00000002, /* line break, duh. */
BOX_FLOAT_LEFT = 0x00000008, /* float to the left edge */
BOX_FLOAT_RIGHT = 0x00000010, /* float to the right edge */
BOX_VCENTER = 0x00000020, /* vertically center in parent */
BOX_PUSHED_LEFT = 0x00000040, /* box pushed left by floater */
BOX_PUSHED_RIGHT = 0x00000080, /* box pushed right by floater */
BOX_SELECT = 0x00000100, /* anchor box selected */
BOX_TOPLEVEL = 0x00000200, /* toplevel box ? */
BOX_CLEAR_LEFT = 0x00000400, /* clear past left aligned */
BOX_CLEAR_RIGHT = 0x00000800 /* clear past right aligned */
} HTMLBoxFlags;
#define HTMLTestB(a, b) (((a)->bflags & (b)) != 0)
#define HTMLClearB(a, b) ((a)->bflags &= ~(b))
#define HTMLSetB(a, b) ((a)->bflags |= (b))
/* This is still too big */
struct HTMLBoxP
{
HTMLEnv env; /* */
int baseline; /* level of alignment */
int x, y; /* upper-left coordinates */
unsigned int width, height; /* external dimensions */
HTMLBoxFlags bflags; /* misc. worthless flags */
/* rendering functions */
HTMLRenderProc render; /* called when output needed */
HTMLDestroyProc destroy; /* called when destroyed */
HTMLSetupProc setup; /* called by parent box */
HTMLLayoutProc layout; /* child box layout */
HTMLWidthProc maxwidth; /* called to return maximum width */
void *closure; /* state for functions */
};
struct HTMLAnchorP
{
HTMLBox box;
char *name;
MLElement p;
};
struct HTMLStateP
{
int x, y;
};
struct HTMLClassP
{
MemPool mp;
bool font_setup_done;
Display *dpy;
XFontStruct *defaultFont;
HTMLFontList prop;
HTMLFontList fixed;
GList oldstates;
GList fonts;
GList contexts;
CSSContext css;
};
struct HTMLInfoP
{
/* X */
Widget widget;
Display *dpy;
Window win;
GC gc;
Pixel anchor_color;
Pixel anchor_select_color;
Pixel fg, bg;
/* www lib */
ChimeraContext wc;
ChimeraResources cres;
ChimeraGUI wd;
ChimeraSink wp;
ChimeraTask wt;
ChimeraRender wn;
GList sinks;
GList loads;
/* HTML */
CSSContext css;
bool reload;
unsigned int maxwidth, maxheight;
MemPool mp;
MLState hs;
HTMLClass lc;
HTMLFont cfi;
HTMLBox firstbox;
HTMLState ps;
HTMLEnv searchenv;
HTMLObject searchobj;
HTMLEnv topenv; /* document environment */
GList envstack; /* tag hierarchy */
GList selectors; /* CSS selector list */
GList oldselectors; /* old CSS selector list */
GList endstack; /* pending end tags */
GList alist; /* anchor box list */
ChimeraTimeOut sto; /* select timeout */
HTMLAnchor sa; /* selected anchor */
int delayed;
char *url; /* original URL */
char *burl; /* base URL */
char *title; /* title text */
HTMLAnchor over;
GList maps;
bool cancel;
bool formatted; /* inside PRE tags - djhjr */
bool noframeset;
bool framesonly;
GList framesets; /* list of frames */
/* configurable goodies */
int textLineSpace;
bool printHTMLErrors;
int tmargin, bmargin; /* top, bottom margins */
int rmargin, lmargin; /* right, left margins */
unsigned int inlineTimeOut;
unsigned int selectTimeOut; /* select timeout time */
unsigned int tableCellInfinity; /* infinite width for table cell */
bool flowDebug;
bool constraintDebug;
bool printTags; /* print tag and data hierarchy */
};
typedef enum
{
ATTRIB_UNKNOWN,
ATTRIB_LEFT,
ATTRIB_RIGHT,
ATTRIB_TOP,
ATTRIB_BOTTOM,
ATTRIB_CENTER,
ATTRIB_MIDDLE,
ATTRIB_ALL
} HTMLAttribID;
/*
* inline.c
*/
typedef struct
{
MLElement p;
void *closure;
} HTMLInlineInfo;
typedef struct HTMLInlineP *HTMLInline;
HTMLInline HTMLCreateInline _ArgProto((HTMLInfo, HTMLEnv, char *,
HTMLInlineInfo *,
ChimeraRenderHooks *, void *));
HTMLBox HTMLInlineToBox _ArgProto((HTMLInline));
void HTMLInlineDestroy _ArgProto((HTMLInline));
/*
* text.c
*/
HTMLBox HTMLCreateTextBox _ArgProto((HTMLInfo, HTMLEnv, char *, size_t));
char *HTMLGetEnvText _ArgProto((MemPool, HTMLEnv));
void HTMLStringSpacify _ArgProto((char *, size_t));
void HTMLAddLineBreak _ArgProto((HTMLInfo, HTMLEnv));
void HTMLAddBlankLine _ArgProto((HTMLInfo, HTMLEnv));
/*
* layout.c
*/
HTMLBox HTMLCreateBox _ArgProto((HTMLInfo, HTMLEnv));
void HTMLLayoutBox _ArgProto((HTMLInfo, HTMLBox, HTMLBox));
void HTMLSetupBox _ArgProto((HTMLInfo, HTMLBox));
void HTMLRenderBox _ArgProto((HTMLInfo, Region, HTMLBox));
void HTMLDestroyBox _ArgProto((HTMLInfo, HTMLBox));
unsigned HTMLGetBoxWidth _ArgProto((HTMLInfo, HTMLBox));
/*
* html.c
*/
HTMLAttribID HTMLAttributeToID _ArgProto((MLElement, char *));
HTMLTag HTMLGetTag _ArgProto((MLElement));
HTMLTag HTMLTagIDToTag _ArgProto((HTMLTagID));
bool HTMLHandleTag _ArgProto((HTMLInfo, HTMLTag, MLElement));
HTMLEnv HTMLFindEnv _ArgProto((HTMLInfo, HTMLTagID));
void HTMLDelayLayout _ArgProto((HTMLInfo));
void HTMLContinueLayout _ArgProto((HTMLInfo));
HTMLTagID HTMLTagToID _ArgProto((HTMLTag));
void HTMLHandler _ArgProto((void *, MLElement));
HTMLEnv HTMLPopEnv _ArgProto((HTMLInfo, HTMLTagID));
void HTMLStartEnv _ArgProto((HTMLInfo, HTMLTagID, MLElement));
void HTMLEndEnv _ArgProto((HTMLInfo, HTMLTagID));
unsigned int HTMLGetMaxWidth _ArgProto((HTMLInfo, HTMLEnv));
void HTMLEnvAddBox _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
void HTMLStart _ArgProto((HTMLInfo));
void HTMLFinish _ArgProto((HTMLInfo));
HTMLEnv HTMLGetIDEnv _ArgProto((HTMLEnv, HTMLTagID));
/*
* font.c
*/
XFontStruct *HTMLGetFont _ArgProto((HTMLInfo, HTMLEnv));
void HTMLSetupFonts _ArgProto((HTMLInfo));
void HTMLFreeFonts _ArgProto((HTMLClass));
void HTMLAddFontSlant _ArgProto((HTMLFont));
void HTMLAddFontWeight _ArgProto((HTMLFont));
void HTMLAddFontScale _ArgProto((HTMLFont));
void HTMLSetFontScale _ArgProto((HTMLFont, int));
HTMLFont HTMLDupFont _ArgProto((HTMLInfo, HTMLFont));
void HTMLSetFontFixed _ArgProto((HTMLFont));
void HTMLSetFontProp _ArgProto((HTMLFont));
/*
* load.c
*/
int HTMLLoadAnchor _ArgProto((HTMLInfo, HTMLAnchor, int, int, char *, bool));
void HTMLPrintAnchor _ArgProto((HTMLInfo, HTMLAnchor, int, int, bool));
char *HTMLMakeURL _ArgProto((HTMLInfo, MemPool, char *));
int HTMLLoadURL _ArgProto((HTMLInfo, char *, char *, char *));
void HTMLPrintURL _ArgProto((HTMLInfo, char *));
void HTMLFindName _ArgProto((HTMLInfo, char *));
void HTMLAddAnchor _ArgProto((HTMLInfo, HTMLBox, char *, MLElement));
/*
* module.c
*/
void HTMLSetFinalPosition _ArgProto((HTMLInfo));
/*
* flow.c
*/
HTMLBox HTMLCreateFlowBox _ArgProto((HTMLInfo, HTMLEnv, unsigned int));
void HTMLFinishFlowBox _ArgProto((HTMLInfo, HTMLBox));
/*
* map.c
*/
char *HTMLFindMapURL _ArgProto((HTMLInfo, char *, int, int));
/*
*
* Tag/Env handlers
*
*/
/*
* form.c
*/
void HTMLFormBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLFormEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLInput _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLOptionEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLSelectBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLSelectEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLTextareaEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* inline.c
*/
void HTMLImg _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLImgInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* hr.c
*/
void HTMLHorizontalRule _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* list.c
*/
HTMLInsertStatus HTMLLIInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLLIBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLDTInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLDTBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLDDInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLDDBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
bool HTMLListAccept _ArgProto((HTMLInfo, HTMLObject));
bool HTMLDLAccept _ArgProto((HTMLInfo, HTMLObject));
void HTMLULBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLListEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLOLBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLDLBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLListAddBox _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
void HTMLItemAddBox _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
unsigned int HTMLItemWidth _ArgProto((HTMLInfo, HTMLEnv));
void HTMLItemEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* text.c
*/
void HTMLPreBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLPreEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLPlainBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLPlainEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLFillData _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLPreData _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLPlainData _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* misc.c
*/
void HTMLHxBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLHxEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLParaBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLParaEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLParaInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLBreak _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLAddressBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLAddressEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLAnchorBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLAnchorInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLBQBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLBQEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLFontBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLDivBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLDivEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLCenterBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLCenterEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* table.c
*/
bool HTMLTableAccept _ArgProto((HTMLInfo, HTMLObject));
void HTMLTableBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLTableEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
bool HTMLTRAccept _ArgProto((HTMLInfo, HTMLObject));
HTMLInsertStatus HTMLTRInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
bool HTMLTRClamp _ArgProto((HTMLInfo, HTMLEnv));
void HTMLTRBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLTREnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLTDInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
bool HTMLTDClamp _ArgProto((HTMLInfo, HTMLEnv));
void HTMLTDBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLTDEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
unsigned int HTMLTDWidth _ArgProto((HTMLInfo, HTMLEnv));
void HTMLTableAddBox _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
void HTMLTDAddBox _ArgProto((HTMLInfo, HTMLEnv, HTMLBox));
/*
* head.c
*/
void HTMLBase _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLTitleEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLMeta _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* map.c
*/
bool HTMLMapAccept _ArgProto((HTMLInfo, HTMLObject));
HTMLInsertStatus HTMLAreaInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLAreaBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLMapBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLMapEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
/*
* frame.c
*/
void HTMLIFrame _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLFrame _ArgProto((HTMLInfo, HTMLEnv, MLElement));
HTMLInsertStatus HTMLFrameInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLFrameSetBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLFrameSetEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
bool HTMLFrameSetAccept _ArgProto((HTMLInfo, HTMLObject));
HTMLInsertStatus HTMLFrameSetInsert _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLNoFramesBegin _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLNoFramesEnd _ArgProto((HTMLInfo, HTMLEnv, MLElement));
void HTMLDestroyFrameSets _ArgProto((HTMLInfo));
void HTMLFrameLoad _ArgProto((HTMLInfo, ChimeraRequest *, char*));
#endif

253
html/htmltags.h Normal file
View File

@ -0,0 +1,253 @@
/*
* htmltags.h
*
* libhtml - HTML->X renderer
* Copyright (c) 1994-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
typedef enum
{
MARKUP_NONE = 0x00000000,
MARKUP_EMPTY = 0x00000001,
MARKUP_CLAMP = 0x00000002,
MARKUP_FAKE = 0x00000004,
MARKUP_SPACER = 0x00000008,
MARKUP_TWOPASS = 0x00000010
} HTMLMarkupFlags;
struct HTMLTagP
{
char *name;
HTMLTagID id;
/* rendering functions */
HTMLTagRenderProc b, e;
HTMLTagDataProc d;
HTMLTagAddBoxProc a;
HTMLTagWidthProc w;
/* flags for whatever seems convienent to make a flag */
HTMLMarkupFlags mflags;
/* markup handling functions */
HTMLTagAcceptProc m;
HTMLTagInsertProc p;
HTMLTagClampProc c;
};
#define HTMLTestM(a, b) (((a)->mflags & (b)) != 0)
#define HTMLClearM(a, b) ((a)->mflags &= ~(b))
#define HTMLSetM(a, b) ((a)->mflags |= (b))
static struct HTMLTagP tlist[] =
{
/* misc.c */
{ "h1", TAG_H1, HTMLHxBegin, HTMLHxEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "h2", TAG_H2, HTMLHxBegin, HTMLHxEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "h3", TAG_H3, HTMLHxBegin, HTMLHxEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "h4", TAG_H4, HTMLHxBegin, HTMLHxEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "h5", TAG_H5, HTMLHxBegin, HTMLHxEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "h6", TAG_H6, HTMLHxBegin, HTMLHxEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "plaintext", TAG_PLAINTEXT, HTMLPlainBegin, HTMLPlainEnd,
HTMLPlainData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "listing", TAG_LISTING, HTMLPlainBegin, HTMLPlainEnd,
HTMLPlainData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "pre", TAG_PRE, HTMLPreBegin, HTMLPreEnd, HTMLPreData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "xmp", TAG_XMP, HTMLPlainBegin, HTMLPlainEnd,
HTMLPlainData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, NULL, NULL },
{ "center", TAG_CENTER, HTMLCenterBegin, HTMLCenterEnd,
HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "div", TAG_DIV, HTMLDivBegin, HTMLDivEnd, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "blockquote", TAG_BLOCKQUOTE, HTMLBQBegin, HTMLBQEnd,
HTMLFillData, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "p", TAG_P, HTMLParaBegin, HTMLParaEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
NULL, HTMLParaInsert, NULL },
{ "address", TAG_ADDRESS, HTMLAddressBegin, HTMLAddressEnd,
HTMLFillData, NULL, NULL,
MARKUP_NONE, NULL, NULL, NULL },
{ "hr", TAG_HR, HTMLHorizontalRule, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, NULL, NULL },
{ "b", TAG_B, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "em", TAG_EM, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "strong", TAG_STRONG, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE, NULL, NULL, NULL },
{ "tt", TAG_TT, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "cite", TAG_CITE, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "i", TAG_I, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "kbd", TAG_KBD, HTMLFontBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "a", TAG_A, HTMLAnchorBegin, NULL, HTMLFillData, NULL, NULL,
MARKUP_NONE,
NULL, HTMLAnchorInsert, NULL },
{ "br", TAG_BR, HTMLBreak, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, NULL, NULL },
/* inline.c */
{ "img", TAG_IMG, HTMLImg, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, HTMLImgInsert, NULL },
/* list.c */
{ "ul", TAG_UL, HTMLULBegin, HTMLListEnd, NULL, HTMLListAddBox, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
HTMLListAccept, NULL, NULL },
{ "dir", TAG_UL, HTMLULBegin, HTMLListEnd, NULL, HTMLListAddBox, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
HTMLListAccept, NULL, NULL },
{ "menu", TAG_UL, HTMLULBegin, HTMLListEnd, NULL, HTMLListAddBox, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
HTMLListAccept, NULL, NULL },
{ "ol", TAG_OL, HTMLOLBegin, HTMLListEnd, NULL, HTMLListAddBox, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
HTMLListAccept, NULL, NULL },
{ "dl", TAG_DL, HTMLDLBegin, HTMLListEnd, NULL, HTMLListAddBox, NULL,
MARKUP_CLAMP | MARKUP_SPACER,
HTMLDLAccept, NULL, NULL },
{ "li", TAG_LI, HTMLLIBegin, HTMLItemEnd, HTMLFillData, HTMLItemAddBox,
HTMLItemWidth,
MARKUP_CLAMP,
NULL, HTMLLIInsert, NULL },
{ "dt", TAG_DT, HTMLDTBegin, HTMLItemEnd, HTMLFillData, HTMLItemAddBox,
HTMLItemWidth,
MARKUP_CLAMP,
NULL, HTMLDTInsert, NULL },
{ "dd", TAG_DD, HTMLDDBegin, HTMLItemEnd, HTMLFillData,
HTMLItemAddBox, HTMLItemWidth,
MARKUP_CLAMP,
NULL, HTMLDDInsert, NULL },
/* head.c */
{ "title", TAG_TITLE, NULL, HTMLTitleEnd, NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "style", TAG_STYLE, NULL, NULL, NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "script", TAG_SCRIPT, NULL, NULL, NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "base", TAG_BASE, HTMLBase, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, NULL, NULL },
{ "meta", TAG_META, HTMLMeta, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, NULL, NULL },
/* form.c */
{ "input", TAG_INPUT, HTMLInput, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, NULL, NULL },
{ "select", TAG_SELECT, HTMLSelectBegin, HTMLSelectEnd, NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "option", TAG_OPTION, NULL, HTMLOptionEnd, NULL, NULL, NULL,
MARKUP_NONE,
NULL, NULL, NULL },
{ "textarea", TAG_TEXTAREA, NULL, HTMLTextareaEnd, NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "form", TAG_FORM, HTMLFormBegin, HTMLFormEnd, HTMLFillData, NULL, NULL,
MARKUP_CLAMP, NULL, NULL, NULL },
/* table.c */
{ "table", TAG_TABLE, HTMLTableBegin, HTMLTableEnd, NULL, HTMLTableAddBox,
NULL,
MARKUP_CLAMP | MARKUP_SPACER | MARKUP_TWOPASS,
HTMLTableAccept, NULL, NULL },
{ "tr", TAG_TR, HTMLTRBegin, HTMLTREnd, NULL, NULL, NULL,
MARKUP_CLAMP,
HTMLTRAccept, HTMLTRInsert, HTMLTRClamp },
{ "th", TAG_TH, HTMLTDBegin, HTMLTDEnd, HTMLFillData, HTMLTDAddBox,
HTMLTDWidth,
MARKUP_CLAMP,
NULL, HTMLTDInsert, HTMLTDClamp },
{ "td", TAG_TD, HTMLTDBegin, HTMLTDEnd, HTMLFillData, HTMLTDAddBox,
HTMLTDWidth,
MARKUP_CLAMP,
NULL, HTMLTDInsert, HTMLTDClamp },
/* map.c */
{ "map", TAG_MAP, HTMLMapBegin, HTMLMapEnd, NULL, NULL, NULL,
MARKUP_CLAMP,
HTMLMapAccept, NULL, NULL },
{ "area", TAG_AREA, HTMLAreaBegin, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, HTMLAreaInsert, NULL },
/* frame.c */
{ "iframe", TAG_IFRAME, HTMLIFrame, NULL, NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
{ "frame", TAG_FRAME, HTMLFrame, NULL, NULL, NULL, NULL,
MARKUP_EMPTY,
NULL, HTMLFrameInsert, NULL },
{ "frameset", TAG_FRAMESET, HTMLFrameSetBegin, HTMLFrameSetEnd,
NULL, NULL, NULL,
MARKUP_CLAMP,
HTMLFrameSetAccept, HTMLFrameSetInsert, NULL },
{ "noframes", TAG_NOFRAMES, HTMLNoFramesBegin, HTMLNoFramesEnd,
NULL, NULL, NULL,
MARKUP_CLAMP,
NULL, NULL, NULL },
/* Internal tags */
{ "xxx-document", TAG_DOCUMENT, HTMLDocumentBegin, HTMLDocumentEnd,
HTMLFillData, HTMLDocumentAddBox, HTMLDocumentWidth,
MARKUP_FAKE, NULL, NULL, NULL }
};
static int tlist_len = sizeof(tlist) / sizeof(tlist[0]);

558
html/inline.c Normal file
View File

@ -0,0 +1,558 @@
/*
* inline.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
struct HTMLInlineP
{
HTMLInfo li;
ChimeraGUI wd;
ChimeraSink wp;
ChimeraRender wn;
HTMLInlineInfo ii;
bool setupcalled;
HTMLBox box;
unsigned int width, height, border;
unsigned int vspace, hspace;
char *mapurl;
bool ismap;
HTMLEnv env;
bool delayed;
ChimeraRenderHooks orh;
void *rc;
};
static int ImgInit _ArgProto((ChimeraSink, void *));
static void ImgAdd _ArgProto((void *));
static void ImgEnd _ArgProto((void *));
static void ImgMessage _ArgProto((void *, char *));
static void DestroyInline _ArgProto((HTMLInfo, HTMLBox));
static bool InlineSelectCallback _ArgProto((void *, int, int, char *));
static bool InlineMotionCallback _ArgProto((void *, int, int));
void InlineResizeCallback _ArgProto((ChimeraGUI, void *,
unsigned int, unsigned int));
static void InlineContinue _ArgProto((HTMLInline));
static void SetupInline _ArgProto((HTMLInfo, HTMLBox));
static void AddInline _ArgProto((HTMLInline));
static void HandleInlineReload _ArgProto((HTMLInfo, ChimeraRequest *));
/*
* InlineContinue
*/
static void
InlineContinue(isp)
HTMLInline isp;
{
if (isp->delayed)
{
isp->delayed = false;
HTMLContinueLayout(isp->li);
}
return;
}
/*
* SetupInline
*/
static void
SetupInline(li, box)
HTMLInfo li;
HTMLBox box;
{
HTMLInline isp = (HTMLInline)box->closure;
isp->setupcalled = true;
if (isp->wd != NULL)
{
GUIMap(isp->wd, box->x + isp->hspace, box->y + isp->vspace);
}
return;
}
/*
* DestroyInline
*/
static void
DestroyInline(li, box)
HTMLInfo li;
HTMLBox box;
{
HTMLInline isp = (HTMLInline)box->closure;
if (isp->wn != NULL)
{
RenderDestroy(isp->wn);
isp->wn = NULL;
}
if (isp->wp != NULL)
{
SinkSetHooks(isp->wp, NULL, NULL);
isp->wp = NULL;
}
if (isp->wd != NULL)
{
GUIDestroy(isp->wd);
isp->wd = NULL;
}
return;
}
/*
* AddInline
*/
static void
AddInline(isp)
HTMLInline isp;
{
HTMLBox box;
HTMLAttribID aid;
int border;
isp->box = box = HTMLCreateBox(isp->li, isp->env);
if ((border = MLAttributeToInt(isp->ii.p, "border")) < 0) isp->border = 0;
else isp->border = border;
aid = HTMLAttributeToID(isp->ii.p, "align");
if (aid == ATTRIB_MIDDLE) box->baseline = isp->height / 2;
else if (aid == ATTRIB_TOP) box->baseline = 0;
else if (aid == ATTRIB_LEFT) HTMLSetB(box, BOX_FLOAT_LEFT);
else if (aid == ATTRIB_RIGHT) HTMLSetB(box, BOX_FLOAT_RIGHT);
else box->baseline = isp->height;
box->setup = SetupInline;
box->destroy = DestroyInline;
box->width = isp->width + isp->hspace * 2;
box->height = isp->height + isp->vspace * 2;
box->closure = isp;
HTMLEnvAddBox(isp->li, isp->env, box);
return;
}
/*
* InlineResizeCallback
*/
void
InlineResizeCallback(wd, closure, width, height)
ChimeraGUI wd;
void *closure;
unsigned int width, height;
{
HTMLInline isp = (HTMLInline)closure;
if (isp->box == NULL)
{
isp->width = width;
isp->height = height;
AddInline(isp);
InlineContinue(isp);
}
return;
}
/*
* InlineSelectCallback
*/
static bool
InlineSelectCallback(closure, x, y, action)
void *closure;
int x, y;
char *action;
{
HTMLInline isp = (HTMLInline)closure;
HTMLAnchor a;
GList list;
char *url;
myassert(isp->box != NULL, "MouseCallback: box == NULL");
if (isp->mapurl != NULL)
{
if ((url = HTMLFindMapURL(isp->li, isp->mapurl, x, y)) != NULL)
{
HTMLLoadURL(isp->li, NULL, url, action);
return(true);
}
}
list = isp->li->alist;
for (a = (HTMLAnchor)GListGetHead(list); a != NULL;
a = (HTMLAnchor)GListGetNext(list))
{
if (a->box == isp->box)
{
HTMLLoadAnchor(isp->li, a, x, y, action, isp->ismap);
return(true);
}
}
return(true);
}
static bool
InlineMotionCallback(closure, x, y)
void *closure;
int x, y;
{
HTMLInline isp = (HTMLInline)closure;
HTMLAnchor a;
GList list;
char *url;
myassert(isp->box != NULL, "MotionCallback: box == NULL");
if (isp->mapurl != NULL)
{
if ((url = HTMLFindMapURL(isp->li, isp->mapurl, x, y)) != NULL)
{
HTMLPrintURL(isp->li, url);
return(true);
}
}
isp->li->over = NULL;
list = isp->li->alist;
for (a = (HTMLAnchor)GListGetHead(list); a != NULL;
a = (HTMLAnchor)GListGetNext(list))
{
if (a->box == isp->box)
{
HTMLPrintAnchor(isp->li, a, x, y, isp->ismap);
isp->li->over = a;
return(true);
}
}
return(true);
}
/*
* ImgMessage
*/
static void
ImgMessage(closure, message)
void *closure;
char *message;
{
HTMLInline isp = (HTMLInline)closure;
if (isp->li->wn != NULL) RenderSendMessage(isp->li->wn, message);
return;
}
/*
* ImgEnd
*/
static void
ImgEnd(closure)
void *closure;
{
HTMLInline isp = (HTMLInline)closure;
RenderEnd(isp->wn);
return;
}
/*
* ImgAdd
*/
static void
ImgAdd(closure)
void *closure;
{
HTMLInline isp = (HTMLInline)closure;
RenderAdd(isp->wn);
return;
}
/*
* ImgInit
*/
static int
ImgInit(wp, closure)
ChimeraSink wp;
void *closure;
{
HTMLInline isp = (HTMLInline)closure;
ChimeraRenderHooks *rh;
char *ctype;
ctype = SinkGetInfo(wp, "content-type");
if ((rh = RenderGetHooks(SinkToResources(wp), ctype)) == NULL)
{
SinkCancel(wp);
InlineContinue(isp);
return(-1);
}
isp->wd = GUICreate(isp->li->wc, isp->li->wd, InlineResizeCallback, isp);
if (isp->width > 0 && isp->height > 0)
{
GUISetInitialDimensions(isp->wd, isp->width, isp->height);
}
if (isp->setupcalled)
{
GUIMap(isp->wd, isp->box->x + isp->hspace, isp->box->y + isp->vspace);
}
isp->wn = RenderCreate(isp->li->wc, isp->wd, isp->wp,
rh, &(isp->orh), isp->rc, NULL,
NULL, NULL);
if (isp->wn == NULL)
{
SinkCancel(wp);
return(-1);
}
return(0);
}
/*
*
* Public functions
*
*/
HTMLInline
HTMLCreateInline(li, env, url, ii, orh, rc)
HTMLInfo li;
HTMLEnv env;
char *url;
HTMLInlineInfo *ii;
ChimeraRenderHooks *orh;
void *rc;
{
ChimeraSinkHooks hooks;
HTMLInline isp;
ChimeraRequest *wr;
int width, height, vspace, hspace;
if ((wr = RequestCreate(li->cres, url, li->burl)) == NULL)
{
return(NULL);
}
if (li->reload) HandleInlineReload(li, wr);
/* Select only image content that we can deal with directly */
if (RequestAddRegexContent(li->cres, wr, "image/*") <= 0)
{
RequestDestroy(wr);
return(NULL);
}
isp = (HTMLInline)MPCGet(li->mp, sizeof(struct HTMLInlineP));
memcpy(&(isp->ii), ii, sizeof(HTMLInlineInfo));
isp->li = li;
isp->env = env;
if (orh == NULL)
{
memset(&(isp->orh), 0, sizeof(isp->orh));
isp->orh.select = InlineSelectCallback;
isp->orh.motion = InlineMotionCallback;
isp->rc = isp;
}
else
{
memcpy(&(isp->orh), orh, sizeof(ChimeraRenderHooks));
isp->rc = rc;
}
if ((width = MLAttributeToInt(ii->p, "width")) < 0) isp->width = 0;
else isp->width = width;
if ((height = MLAttributeToInt(ii->p, "height")) < 0) isp->height = 0;
else isp->height = height;
if ((vspace = MLAttributeToInt(ii->p, "vspace")) < 0) isp->vspace = 0;
else isp->vspace = vspace;
if ((hspace = MLAttributeToInt(ii->p, "hspace")) < 0) isp->hspace = 0;
else isp->hspace = hspace;
isp->ismap = MLFindAttribute(ii->p, "ismap") != NULL ? true:false;
isp->mapurl = MLFindAttribute(ii->p, "usemap");
if (isp->width == 0 || isp->height == 0)
{
isp->delayed = true;
HTMLDelayLayout(li);
}
else AddInline(isp);
memset(&hooks, 0, sizeof(hooks));
hooks.init = ImgInit;
hooks.add = ImgAdd;
hooks.end = ImgEnd;
hooks.message = ImgMessage;
if ((isp->wp = SinkCreate(li->cres, wr)) == NULL)
{
InlineContinue(isp);
}
else
{
SinkSetHooks(isp->wp, &hooks, isp);
GListAddHead(li->sinks, isp->wp);
}
return(isp);
}
/*
* HTMLInlineToBox
*/
HTMLBox
HTMLInlineToBox(is)
HTMLInline is;
{
return(is->box);
}
/*
* HTMLInlineToInfo
*/
HTMLInfo
HTMLInlineToInfo(is)
HTMLInline is;
{
return(is->li);
}
/*
* HTMLInlineDestroy
*/
void
HTMLInlineDestroy(is)
HTMLInline is;
{
return;
}
/*
* HTMLImg
*/
void
HTMLImg(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *url;
HTMLInlineInfo ii;
if ((url = MLFindAttribute(p, "src")) == NULL) return;
memset(&ii, 0, sizeof(HTMLInlineInfo));
ii.p = p;
HTMLCreateInline(li, env, url, &ii, NULL, NULL);
return;
}
/*
* HTMLImgInsert
*
* Always OK image insertion for now. I suppose this is where one
* could check for conditional image loading. The idea here is to
* start the download as soon as possible.
*/
HTMLInsertStatus
HTMLImgInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *url;
ChimeraRequest *wr;
ChimeraSink wp;
if ((url = MLFindAttribute(p, "src")) == NULL) return(HTMLInsertOK);
if ((wr = RequestCreate(li->cres, url, li->burl)) == NULL)
{
return(HTMLInsertOK);
}
if (li->reload) HandleInlineReload(li, wr);
/* Select only image content that we can deal with directly */
if (RequestAddRegexContent(li->cres, wr, "image/*") <= 0)
{
RequestDestroy(wr);
return(HTMLInsertOK);
}
if ((wp = SinkCreate(li->cres, wr)) != NULL)
{
SinkSetHooks(wp, NULL, NULL);
GListAddHead(li->sinks, wp);
}
return(HTMLInsertOK);
}
/*
* HandleInlineReload
*/
static void
HandleInlineReload(li, wr)
HTMLInfo li;
ChimeraRequest *wr;
{
char *xurl;
for (xurl = (char *)GListGetHead(li->loads); xurl != NULL;
xurl = (char *)GListGetNext(li->loads))
{
if (strlen(wr->url) == strlen(xurl) && strcmp(wr->url, xurl) == 0)
{
break;
}
}
if (xurl == NULL)
{
RequestReload(wr, true);
GListAddHead(li->loads, MPStrDup(li->mp, wr->url));
}
return;
}

141
html/layout.c Normal file
View File

@ -0,0 +1,141 @@
/*
* layout.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
/*
* HTMLDestroyBox
*/
void
HTMLDestroyBox(li, box)
HTMLInfo li;
HTMLBox box;
{
if (box->destroy != NULL) (box->destroy)(li, box);
return;
}
/*
* HTMLCreateBox
*/
HTMLBox
HTMLCreateBox(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLBox box;
box = (HTMLBox)MPCGet(li->mp, sizeof(struct HTMLBoxP));
box->env = env;
return(box);
}
/*
* HTMLRenderBox
*/
void
HTMLRenderBox(li, r, box)
HTMLInfo li;
Region r;
HTMLBox box;
{
Region xr;
int x, y;
unsigned int width, height;
XRectangle rec;
if (box->render == NULL) return;
if (r == NULL)
{
GUIGetOnScreenDimensions(li->wd, &x, &y, &width, &height);
r = XCreateRegion();
rec.x = (short)x;
rec.y = (short)y;
rec.width = (unsigned short)width;
rec.height = (unsigned short)height;
XUnionRectWithRegion(&rec, r, r);
xr = r;
}
else xr = NULL;
if (XRectInRegion(r, box->x, box->y, box->width, box->height))
{
(box->render)(li, box, r);
}
if (xr != NULL) XDestroyRegion(xr);
return;
}
/*
* HTMLLayoutBox
*/
void
HTMLLayoutBox(li, parent, box)
HTMLInfo li;
HTMLBox parent;
HTMLBox box;
{
myassert(parent->layout != NULL, "Box cannot contain other boxes");
(parent->layout)(li, box, parent);
return;
}
/*
* HTMLSetupBox
*/
void
HTMLSetupBox(li, box)
HTMLInfo li;
HTMLBox box;
{
HTMLEnv env = box->env;
if (env->anchor != NULL) HTMLAddAnchor(li, box, NULL, env->anchor);
if (box->setup != NULL) (box->setup)(li, box);
return;
}
/*
* HTMLGetBoxWidth
*/
unsigned int
HTMLGetBoxWidth(li, box)
HTMLInfo li;
HTMLBox box;
{
myassert(box->maxwidth != NULL, "Box cannot contain other boxes");
return((box->maxwidth)(li, box));
}

633
html/list.c Normal file
View File

@ -0,0 +1,633 @@
/*
* list.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
/*
* Numeric label stuff for <OL> supplied by
* Jake Kesinger <kesinger@math.ttu.edu>
*/
typedef enum
{
OL_NUMERIC,
OL_ALPHA_CAP,
OL_ALPHA_MINISCULE,
OL_ROMAN_CAP,
OL_ROMAN_MINISCULE
} OListType;
typedef struct
{
OListType type; /* type for ol list */
int count; /* count for ol list */
int bullet_diam; /* cached bullet size */
GList klist; /* list of item boxes */
HTMLBox lbox; /* list box */
HTMLBox ibox; /* item box */
HTMLBox tbox; /* text box inside item (dd, li) */
} HList;
/*
*
* Private functions
*
*/
static void RenderLI _ArgProto((HTMLInfo, HTMLBox, Region));
static void SetupList _ArgProto((HTMLInfo, HTMLBox));
static void RenderList _ArgProto((HTMLInfo, HTMLBox, Region));
static void DestroyList _ArgProto((HTMLInfo, HTMLBox));
static HList *CreateList _ArgProto((HTMLInfo, HTMLEnv));
static void OLNext _ArgProto((char *, size_t, int, OListType));
/*
* SetupList
*/
static void
SetupList(li, box)
HTMLInfo li;
HTMLBox box;
{
HList *hl = (HList *)box->closure;
HTMLBox c;
int ty = box->y;
for (c = (HTMLBox)GListGetHead(hl->klist); c != NULL;
c = (HTMLBox)GListGetNext(hl->klist))
{
c->x = box->x;
c->y = ty;
HTMLSetupBox(li, c);
ty += c->height;
}
return;
}
/*
* RenderList
*/
static void
RenderList(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
HList *hl = (HList *)box->closure;
HTMLBox c;
for (c = (HTMLBox)GListGetHead(hl->klist); c != NULL;
c = (HTMLBox)GListGetNext(hl->klist))
{
HTMLRenderBox(li, r, c);
}
return;
}
static void
DestroyList(li, box)
HTMLInfo li;
HTMLBox box;
{
HList *ls = (HList *)box->closure;
HTMLBox c;
for (c = (HTMLBox)GListGetHead(ls->klist); c != NULL;
c = (HTMLBox)GListGetNext(ls->klist))
{
HTMLDestroyBox(li, c);
}
return;
}
/*
* RenderLI
*/
static void
RenderLI(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
unsigned int half = box->width / 2;
XFillArc(li->dpy, li->win, li->gc,
box->x + half, box->y + half, half, half,
0, 360 * 64);
return;
}
/*
* CreateList
*/
static HList *
CreateList(li, env)
HTMLInfo li;
HTMLEnv env;
{
HList *ls;
ls = (HList *)MPCGet(li->mp, sizeof(HList));
ls->lbox = HTMLCreateBox(li, env);
ls->lbox->setup = SetupList;
ls->lbox->render = RenderList;
ls->lbox->destroy = DestroyList;
ls->lbox->closure = ls;
ls->klist = GListCreateX(li->mp);
return(ls);
}
/*
*
* Public functions
*
*/
void
HTMLULBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls;
XFontStruct *font;
font = HTMLGetFont(li, env);
ls = CreateList(li, env);
ls->bullet_diam = font->ascent;
env->closure = ls;
env->ff = FLOW_LEFT_JUSTIFY;
return;
}
void
HTMLListEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls = (HList *)env->closure;
HTMLEnvAddBox(li, env->penv, ls->lbox);
return;
}
void
HTMLOLBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls;
char *startstr;
char *variantstr;
ls = CreateList(li, env);
env->closure = ls;
env->ff = FLOW_LEFT_JUSTIFY;
/*
* If the <ol> specifies a START or SEQNUM attribute, handle that,
* otherwise the default is 1
*/
if((startstr = MLFindAttribute(p, "start"))!= NULL)
{
ls->count = atoi(startstr);
}
else if((startstr = MLFindAttribute(p, "seqnum"))!= NULL)
{
ls->count = atoi(startstr);
}
else
{
ls->count = 1;
}
/*
* Now see if said <ol> has a TYPE attribute.
* Types are:
* 1 ==> std numbering
* aA ==>[aA]lphabetic
* iI ==> [rR]oman
*/
if ((variantstr = MLFindAttribute(p, "type")) != NULL)
{
if (variantstr[0] == 'a') ls->type = OL_ALPHA_MINISCULE;
else if (variantstr[0] == 'A') ls->type = OL_ALPHA_CAP;
else if (variantstr[0] == 'i') ls->type = OL_ROMAN_MINISCULE;
else if (variantstr[0] == 'I') ls->type = OL_ROMAN_CAP;
else ls->type = OL_NUMERIC;
}
else
{
ls->type = OL_NUMERIC;
}
return;
}
void
HTMLLIBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLBox box;
HList *ls;
char buffer[BUFSIZ];
ls = (HList *)env->penv->closure;
ls->ibox = HTMLCreateFlowBox(li, env, HTMLGetMaxWidth(li, env->penv));
GListAddTail(ls->klist, ls->ibox);
env->closure = ls;
if (HTMLTagToID(env->penv->tag) == TAG_OL)
{
OLNext(buffer, sizeof(buffer), ls->count++, ls->type);
box = HTMLCreateTextBox(li, env,
MPStrDup(li->mp, buffer), strlen(buffer));
}
else
{
box = HTMLCreateBox(li, env);
box->width = ls->bullet_diam;
box->height = ls->bullet_diam;
box->render = RenderLI;
}
HTMLSetB(box, BOX_FLOAT_LEFT);
HTMLLayoutBox(li, ls->ibox, box);
ls->tbox = HTMLCreateFlowBox(li, env,
HTMLGetMaxWidth(li, env->penv) - box->width);
return;
}
void
HTMLItemEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls = (HList *)env->closure;
if (ls->tbox != NULL)
{
HTMLFinishFlowBox(li, ls->tbox);
HTMLLayoutBox(li, ls->ibox, ls->tbox);
}
HTMLFinishFlowBox(li, ls->ibox);
HTMLEnvAddBox(li, env->penv, ls->ibox);
return;
}
void
HTMLDDBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls;
HTMLBox indent;
ls = (HList *)env->penv->closure;
ls->ibox = HTMLCreateFlowBox(li, env, HTMLGetMaxWidth(li, env->penv));
GListAddTail(ls->klist, ls->ibox);
env->closure = ls;
indent = HTMLCreateBox(li, env);
if (ResourceGetUInt(li->cres, "html.dlIndent", &(indent->width)) == NULL)
{
indent->width = 20;
}
indent->height = 1;
HTMLSetB(indent, BOX_FLOAT_LEFT);
HTMLLayoutBox(li, ls->ibox, indent);
ls->tbox = HTMLCreateFlowBox(li, env,
HTMLGetMaxWidth(li, env->penv) - indent->width);
return;
}
void
HTMLDTBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls;
ls = (HList *)env->penv->closure;
ls->ibox = HTMLCreateFlowBox(li, env, HTMLGetMaxWidth(li, env->penv));
GListAddTail(ls->klist, ls->ibox);
env->closure = ls;
ls->tbox = NULL; /* this is important */
return;
}
void
HTMLDLBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HList *ls;
ls = CreateList(li, env);
env->closure = ls;
env->ff = FLOW_LEFT_JUSTIFY;
return;
}
/*
* OLNext
*/
static void
OLNext(buffer, bsize, number, oltype)
char *buffer;
size_t bsize;
int number;
OListType oltype;
{
int i;
char *cp;
if (oltype == OL_ALPHA_CAP)
{
number = (number-1) % 26;
number += 65;
snprintf(buffer, bsize, "%c.", (char)number);
}
else if (oltype == OL_ALPHA_MINISCULE)
{
number = (number-1) % 26;
number += 97;
snprintf(buffer, bsize, "%c.", (char)number);
}
else if ((oltype==OL_ROMAN_CAP)||(oltype==OL_ROMAN_MINISCULE))
{
/*Convert an integer to roman*/
i=0;
if (number <0)
{
buffer[i++]='-';
number *= -1;
}
if (number==0)
{
buffer[i++]='0';
}
while ((number > 0) && (i < BUFSIZ - 2))
{
if (number >=1000)
{
number -=1000;
buffer[i++]='M';
}
else if (number >=900)
{
number -=100;
buffer[i++]='C';
buffer[i++]='M';
}
else if (number >= 500)
{
number -= 500;
buffer[i++] ='D';
}
else if (number >= 100)
{
number -= 100;
buffer[i++] ='C';
}
else if (number >= 90)
{
number-= 10;
buffer[i++]='X';
buffer[i++]='C';
}
else if (number >= 50)
{
number -= 50;
buffer[i++] = 'L';
}
else if (number >= 40)
{
number -= 10;
buffer[i++]='X';
buffer[i++]='L';
}
else if (number >= 10)
{
number -= 10;
buffer[i++]='X';
}
else if (number == 9)
{
number = 0;
buffer[i++]='I';
buffer[i++]='X';
}
else if (number >= 5)
{
number -= 5;
buffer[i++]='V';
}
else if (number == 4)
{
number = 0;
buffer[i++]='I';
buffer[i++]='V';
}
else if (number >=1)
{
number--;
buffer[i++]='I';
}
}
buffer[i++] = '.';
buffer[i] = '\0';
/*We've done everything in caps, now convert to lowercase if
necessary*/
if (oltype == OL_ROMAN_MINISCULE)
{
for (cp = buffer; *cp != '\0'; cp++)
{
*cp = tolower(*cp);
}
}
}
else
{
snprintf(buffer, sizeof(buffer), "%d.", number);
}
return;
}
bool
HTMLListAccept(li, obj)
HTMLInfo li;
HTMLObject obj;
{
if (obj->type != HTML_ENV) return(false);
if (HTMLTagToID(obj->o.env->tag) != TAG_LI) return(false);
return(true);
}
bool
HTMLDLAccept(li, obj)
HTMLInfo li;
HTMLObject obj;
{
if (obj->type != HTML_ENV) return(false);
if (HTMLTagToID(obj->o.env->tag) != TAG_DD &&
HTMLTagToID(obj->o.env->tag) != TAG_DT)
{
return(false);
}
return(true);
}
HTMLInsertStatus
HTMLLIInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLEnv tenv;
if ((tenv = HTMLFindEnv(li, TAG_UL)) == NULL &&
(tenv = HTMLFindEnv(li, TAG_OL)) == NULL)
{
return(HTMLInsertReject);
}
if (HTMLTagToID(tenv->tag) == TAG_UL) HTMLPopEnv(li, TAG_UL);
else HTMLPopEnv(li, TAG_OL);
return(HTMLInsertOK);
}
HTMLInsertStatus
HTMLDDInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLEnv tenv;
if ((tenv = HTMLFindEnv(li, TAG_DL)) == NULL)
{
return(HTMLInsertReject);
}
HTMLPopEnv(li, TAG_DL);
return(HTMLInsertOK);
}
HTMLInsertStatus
HTMLDTInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLEnv tenv;
if ((tenv = HTMLFindEnv(li, TAG_DL)) == NULL)
{
return(HTMLInsertReject);
}
HTMLPopEnv(li, TAG_DL);
return(HTMLInsertOK);
}
/*
* HTMLItemAddBox
*/
void
HTMLItemAddBox(li, env, box)
HTMLInfo li;
HTMLEnv env;
HTMLBox box;
{
HList *ls = (HList *)env->closure;
if (ls->tbox != NULL) HTMLLayoutBox(li, ls->tbox, box);
else HTMLLayoutBox(li, ls->ibox, box);
return;
}
/*
* HTMLListAddBox
*/
void
HTMLListAddBox(li, env, box)
HTMLInfo li;
HTMLEnv env;
HTMLBox box;
{
HList *ls = (HList *)env->closure;
HTMLBox parent = ls->lbox;
if (box->width > parent->width) parent->width = box->width;
parent->height += box->height;
return;
}
/*
* HTMLItemWidth
*/
unsigned int
HTMLItemWidth(li, env)
HTMLInfo li;
HTMLEnv env;
{
HList *ls = (HList *)env->closure;
if (ls->tbox != NULL) return(HTMLGetBoxWidth(li, ls->tbox));
else return(HTMLGetBoxWidth(li, ls->ibox));
}

220
html/load.c Normal file
View File

@ -0,0 +1,220 @@
/*
* load.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include "port_after.h"
#include "html.h"
#include "ChimeraStack.h"
int
HTMLLoadURL(li, frame, url, action)
HTMLInfo li;
char *frame;
char *url;
char *action;
{
ChimeraRequest *wr;
if (url == NULL) return(-1);
if (url[0] == '#')
{
HTMLFindName(li, url + 1);
return(0);
}
wr = RequestCreate(li->cres, url, li->burl);
RenderAction(li->wn, wr, action);
return(0);
}
int
HTMLLoadAnchor(li, anchor, x, y, action, ismap)
HTMLInfo li;
HTMLAnchor anchor;
int x, y;
char *action;
bool ismap;
{
char *aurl, *url;
char *target;
MemPool mp;
ChimeraRequest *wr;
ChimeraStack cs;
if ((url = MLFindAttribute(anchor->p, "href")) == NULL) return(-1);
/*
* This could be trouble. What if there is a 'target' attribute?
* I think the solutuion is to prepend the base URL to the fragment
* and submit it so that fragment stuff will end up on the document
* stack.
*/
if (url[0] == '#')
{
HTMLFindName(li, url + 1);
return(0);
}
if (ismap)
{
mp = MPCreate();
aurl = (char *)MPGet(mp, strlen(url) + 200);
snprintf (aurl, strlen(url) + 200, "%s?%d,%d", url, x, y);
url = aurl;
}
else mp = NULL;
wr = RequestCreate(li->cres, url, li->burl);
if (mp != NULL) MPDestroy(mp);
if (wr == NULL) return(-1);
if ((target = MLFindAttribute(anchor->p, "target")) != NULL)
{
HTMLFrameLoad(li, wr, target);
}
else
{
if ((cs = StackGetParent(StackFromGUI(li->wc, li->wd))) == NULL)
{
RenderAction(li->wn, wr, action);
}
else
{
StackAction(cs, wr, action);
}
}
return(0);
}
void
HTMLPrintURL(li, url)
HTMLInfo li;
char *url;
{
ChimeraRequest *wr;
size_t len;
char buffer[BUFSIZ + 100];
const char *msg = "Cannot handle "; /* this is the wrong thing to do! */
if (url == NULL) return;
if ((wr = RequestCreate(li->cres, url, li->burl)) != NULL)
{
url = wr->url;
}
else
{
strcpy(buffer, msg);
len = sizeof(buffer) - strlen(msg) - 1;
strncat(buffer, url, len);
buffer[sizeof(buffer) - 1] = '\0';
url = buffer;
}
RenderSendMessage(li->wn, url);
if (wr != NULL) RequestDestroy(wr);
return;
}
void
HTMLPrintAnchor(li, anchor, x, y, ismap)
HTMLInfo li;
HTMLAnchor anchor;
int x, y;
bool ismap;
{
char *url, *aurl;
MemPool mp;
if ((url = MLFindAttribute(anchor->p, "href")) == NULL) return;
if (ismap)
{
mp = MPCreate();
aurl = (char *)MPGet(mp, strlen(url) + 200);
snprintf (aurl, strlen(url) + 200, "%s?%d,%d", url, x, y);
url = aurl;
HTMLPrintURL(li, url);
MPDestroy(mp);
}
else HTMLPrintURL(li, url);
return;
}
/*
* HTMLAddAnchor
*/
void
HTMLAddAnchor(li, box, name, p)
HTMLInfo li;
HTMLBox box;
char *name;
MLElement p;
{
HTMLAnchor a;
a = (HTMLAnchor)MPCGet(li->mp, sizeof(struct HTMLAnchorP));
a->name = name;
a->p = p;
a->box = box;
GListAddHead(li->alist, a);
return;
}
/*
* HTMLFindName
*/
void
HTMLFindName(li, name)
HTMLInfo li;
char *name;
{
HTMLAnchor a;
GList list;
list = li->alist;
for (a = (HTMLAnchor)GListGetHead(list); a != NULL;
a = (HTMLAnchor)GListGetNext(list))
{
if (a->name != NULL && strlen(name) == strlen(a->name) &&
strcasecmp(name, a->name) == 0)
{
GUISetScrollPosition(li->wd, 0, -(a->box->y));
return;
}
}
return;
}

269
html/map.c Normal file
View File

@ -0,0 +1,269 @@
/*
* map.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
typedef enum
{
HTMLMapShapeRect,
HTMLMapShapeCircle,
HTMLMapShapePoly,
HTMLMapShapeDefault
} HTMLMapShape;
struct HTMLAreaP
{
HTMLMapShape shape;
int *coords;
int count;
char *url;
Region r;
};
struct HTMLMapP
{
char *name;
GList areas;
HTMLArea defarea;
};
static void MakeArea _ArgProto((HTMLInfo, HTMLMap, MLElement));
static void
MakeArea(li, map, p)
HTMLInfo li;
HTMLMap map;
MLElement p;
{
HTMLArea area;
char *shape;
char *href;
char *coords;
int i, j;
char *cp;
XPoint *xp;
area = (HTMLArea)MPCGet(li->mp, sizeof(struct HTMLAreaP));
if ((coords = MLFindAttribute(p, "coords")) != NULL)
{
for (cp = coords, i = 0; *cp != '\0'; cp++)
{
if (*cp == ',') i++;
}
i++;
area->coords = (int *)MPCGet(li->mp, sizeof(int) * i);
area->coords[0] = atoi(coords);
for (cp = coords, i = 1; *cp != '\0'; cp++)
{
if (*cp == ',') area->coords[i++] = atoi(cp + 1);
}
area->count = i;
}
if ((shape = MLFindAttribute(p, "shape")) == NULL) shape = "rect";
if (strcasecmp(shape, "circle") == 0)
{
area->shape = HTMLMapShapeCircle;
GListAddTail(map->areas, area);
}
else if (strcasecmp(shape, "poly") == 0)
{
area->shape = HTMLMapShapePoly;
if (area->count / 2 >= 3)
{
GListAddTail(map->areas, area);
xp = (XPoint *)MPCGet(li->mp, sizeof(XPoint) * area->count / 2);
for (j = 0, i = 0; j < area->count / 2; i += 2, j++)
{
xp[j].x = area->coords[i];
xp[j].y = area->coords[i + 1];
}
area->r = XPolygonRegion(xp, area->count / 2, WindingRule);
}
}
else if (strcasecmp(shape, "default") == 0)
{
area->shape = HTMLMapShapeDefault;
if (map->defarea == NULL) map->defarea = area;
}
else
{
area->shape = HTMLMapShapeRect;
GListAddTail(map->areas, area);
}
if ((href = MLFindAttribute(p, "href")) != NULL) area->url = href;
return;
}
void
HTMLMapBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLMap map;
char *name;
if ((name = MLFindAttribute(p, "name")) == NULL) return;
map = (HTMLMap)MPCGet(li->mp, sizeof(struct HTMLMapP));
map->name = name;
map->areas = GListCreateX(li->mp);
env->closure = map;
return;
}
void
HTMLAreaBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLMap map;
/*
* Area doesn't create an environment so the current environment
* must be the map environment.
*/
map = (HTMLMap)env->closure;
MakeArea(li, map, p);
return;
}
void
HTMLMapEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLMap map;
map = (HTMLMap)env->closure;
GListAddTail(li->maps, map);
return;
}
char *
HTMLFindMapURL(li, url, x, y)
HTMLInfo li;
char *url;
int x, y;
{
HTMLArea area;
HTMLMap map;
GList list;
int dx, dy;
double rd;
URLParts *up;
MemPool mp;
mp = MPCreate();
if ((up = URLParse(mp, url)) == NULL || up->hostname != NULL ||
up->filename != NULL || up->fragment == NULL)
{
MPDestroy(mp);
fprintf (stderr, "Local maps supported only.\n");
return(NULL);
}
list = li->maps;
for (map = (HTMLMap)GListGetHead(list); map != NULL;
map = (HTMLMap)GListGetNext(list))
{
if (strcasecmp(map->name, up->fragment) == 0) break;
}
MPDestroy(mp);
if (map == NULL) return(NULL);
list = map->areas;
for (area = (HTMLArea)GListGetHead(list); area != NULL;
area = (HTMLArea)GListGetNext(list))
{
if (area->shape == HTMLMapShapeRect)
{
if (area->count == 4 &&
area->coords[0] < x && x < area->coords[2] &&
area->coords[1] < y && y < area->coords[3])
{
return(area->url);
}
}
else if (area->shape == HTMLMapShapeCircle)
{
dx = x - area->coords[0];
dy = y - area->coords[1];
rd = sqrt((double)(dx * dx + dy * dy));
if ((int)rd < area->coords[2]) return(area->url);
}
else if (area->shape == HTMLMapShapePoly)
{
if (area->r != NULL && XPointInRegion(area->r, x, y)) return(area->url);
}
}
if (map->defarea != NULL) return(map->defarea->url);
return(NULL);
}
/*
* HTMLMapAccept
*/
bool
HTMLMapAccept(li, obj)
HTMLInfo li;
HTMLObject obj;
{
return(true);
}
/*
* HTMLAreaInsert
*/
HTMLInsertStatus
HTMLAreaInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
if (HTMLTagToID(env->tag) != TAG_MAP) return(HTMLInsertReject);
return(HTMLInsertOK);
}

298
html/misc.c Normal file
View File

@ -0,0 +1,298 @@
/*
* misc.c
*
* libhtml - HTML->X renderer
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
static void RenderAnchor _ArgProto((HTMLInfo, HTMLBox, Region));
/*
* RenderAnchor
*/
static void
RenderAnchor(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
return;
}
void
HTMLAnchorBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *value;
HTMLBox box;
if ((value = MLFindAttribute(p, "name")) != NULL)
{
box = HTMLCreateBox(li, env);
box->width = 2;
box->height = 2;
box->render = RenderAnchor;
HTMLEnvAddBox(li, env, box);
HTMLAddAnchor(li, box, value, NULL);
}
if (MLFindAttribute(p, "href") != NULL) env->anchor = p;
return;
}
HTMLInsertStatus
HTMLAnchorInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
if (MLFindAttribute(p, "href") == NULL)
{
if (MLFindAttribute(p, "name") != NULL) return(HTMLInsertEmpty);
else return(HTMLInsertReject);
}
return(HTMLInsertOK);
}
void
HTMLHxBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAttribID aid;
HTMLTagID tagid;
tagid = HTMLTagToID(env->tag);
if (tagid == TAG_H1) HTMLSetFontScale(env->fi, 5);
else if (tagid == TAG_H2) HTMLSetFontScale(env->fi, 4);
else if (tagid == TAG_H3) HTMLSetFontScale(env->fi, 3);
else if (tagid == TAG_H4) HTMLSetFontScale(env->fi, 2);
else if (tagid == TAG_H5) HTMLSetFontScale(env->fi, 1);
else if (tagid == TAG_H6) HTMLSetFontScale(env->fi, 0);
aid = HTMLAttributeToID(p, "align");
if (aid == ATTRIB_CENTER || aid == ATTRIB_RIGHT)
{
if (aid == ATTRIB_CENTER) env->ff = FLOW_CENTER_JUSTIFY;
else if (aid == ATTRIB_RIGHT) env->ff = FLOW_RIGHT_JUSTIFY;
}
return;
}
void
HTMLHxEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
void
HTMLFontBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLTagID tagid = HTMLTagToID(env->tag);
if (tagid == TAG_EM || tagid == TAG_CITE || tagid == TAG_I)
{
HTMLAddFontSlant(env->fi);
}
else if (tagid == TAG_B || tagid == TAG_STRONG)
{
HTMLAddFontWeight(env->fi);
}
else if (tagid == TAG_TT) HTMLSetFontFixed(env->fi);
return;
}
void
HTMLParaBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAttribID aid;
aid = HTMLAttributeToID(p, "align");
if (aid == ATTRIB_CENTER || aid == ATTRIB_RIGHT)
{
if (aid == ATTRIB_CENTER) env->ff = FLOW_CENTER_JUSTIFY;
else if (aid == ATTRIB_RIGHT) env->ff = FLOW_RIGHT_JUSTIFY;
}
return;
}
void
HTMLParaEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
HTMLInsertStatus
HTMLParaInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
/*
* If the current environment is <p> then terminate the environment
* before starting the new one.
*/
if (HTMLTagToID(env->tag) == TAG_P) HTMLEndEnv(li, TAG_P);
return(HTMLInsertOK);
}
/*
* HTMLBreak
*/
void
HTMLBreak(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAttribID aid;
HTMLBox box;
box = HTMLCreateBox(li, env);
aid = HTMLAttributeToID(p, "clear");
if (aid == ATTRIB_LEFT) HTMLSetB(box, BOX_CLEAR_LEFT);
else if (aid == ATTRIB_RIGHT) HTMLSetB(box, BOX_CLEAR_RIGHT);
else if (aid == ATTRIB_ALL) HTMLSetB(box, BOX_CLEAR_RIGHT | BOX_CLEAR_LEFT);
else HTMLSetB(box, BOX_LINEBREAK);
HTMLEnvAddBox(li, env, box);
return;
}
void
HTMLAddressBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAddFontSlant(env->fi);
HTMLAddBlankLine(li, env);
return;
}
void
HTMLAddressEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAddBlankLine(li, env);
return;
}
void
HTMLBQBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAddLineBreak(li, env);
return;
}
void
HTMLBQEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAddLineBreak(li, env);
return;
}
void
HTMLCenterBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
env->ff = FLOW_CENTER_JUSTIFY;
HTMLAddLineBreak(li, env);
return;
}
void
HTMLCenterEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAddLineBreak(li, env);
return;
}
void
HTMLDivBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAttribID aid;
aid = HTMLAttributeToID(p, "align");
if (aid == ATTRIB_CENTER) env->ff = FLOW_CENTER_JUSTIFY;
else if (aid == ATTRIB_LEFT) env->ff = FLOW_LEFT_JUSTIFY;
else if (aid == ATTRIB_RIGHT) env->ff = FLOW_RIGHT_JUSTIFY;
HTMLAddLineBreak(li, env);
return;
}
void
HTMLDivEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLAddLineBreak(li, env);
return;
}

562
html/module.c Normal file
View File

@ -0,0 +1,562 @@
/*
* module.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "port_after.h"
#include "html.h"
static bool InAnchor _ArgProto((int, int, HTMLBox));
static void HTMLAdd _ArgProto((void *));
static void HTMLEnd _ArgProto((void *));
static bool HTMLExpose _ArgProto((void *, int, int,
unsigned int, unsigned int));
static bool HTMLMotion _ArgProto((void *, int, int));
static bool HTMLMouse _ArgProto((void *, int, int, char *));
static byte *HTMLQuery _ArgProto((void *, char *));
static int HTMLSearch _ArgProto((void *, char *, int));
static void HTMLDestroy _ArgProto((void *));
static void HTMLCancel _ArgProto((void *));
static void *HTMLInit _ArgProto((ChimeraRender, void *, void *));
static void *HTMLGetState _ArgProto((void *));
static void HTMLClassDestroy _ArgProto((void *));
int InitModule_HTML _ArgProto((ChimeraResources));
static void DeselectTimeOut _ArgProto((ChimeraTimeOut, void *));
static void
DeselectTimeOut(wt, closure)
ChimeraTimeOut wt;
void *closure;
{
HTMLAnchor a;
HTMLInfo li = (HTMLInfo)closure;
for (a = (HTMLAnchor)GListGetHead(li->alist); a != NULL;
a = (HTMLAnchor)GListGetNext(li->alist))
{
if (a->p == li->sa->p)
{
HTMLClearB(a->box, BOX_SELECT);
HTMLRenderBox(li, NULL, a->box);
}
}
return;
}
static void
HTMLAdd(closure)
void *closure;
{
HTMLInfo li = (HTMLInfo)closure;
byte *data;
size_t len;
MIMEHeader mh;
if (li->cancel) return;
SinkGetData(li->wp, &data, &len, &mh);
MLAddData(li->hs, (char *)data, len);
return;
}
static void
HTMLEnd(closure)
void *closure;
{
HTMLInfo li = (HTMLInfo)closure;
byte *data;
size_t len;
MIMEHeader mh;
if (li->cancel) return;
SinkGetData(li->wp, &data, &len, &mh);
MLEndData(li->hs, (char *)data, len);
return;
}
static bool
HTMLExpose(closure, x, y, width, height)
void *closure;
int x, y;
unsigned int width, height;
{
HTMLInfo li = (HTMLInfo)closure;
Region r;
XRectangle rec;
r = XCreateRegion();
rec.x = (short)x;
rec.y = (short)y;
rec.width = (unsigned short)width;
rec.height = (unsigned short)height;
XUnionRectWithRegion(&rec, r, r);
HTMLRenderBox(li, r, li->firstbox);
XDestroyRegion(r);
return(true);
}
/*
* InAnchor
*/
static bool
InAnchor(x, y, box)
int x, y;
HTMLBox box;
{
if (x > box->x &&
x < box->x + box->width &&
y > box->y &&
y < box->y + box->height)
{
return(true);
}
return(false);
}
static bool
HTMLMouse(closure, x, y, action)
void *closure;
int x, y;
char *action;
{
HTMLInfo li = (HTMLInfo)closure;
HTMLAnchor a;
GList list;
list = li->alist;
for (a = (HTMLAnchor)GListGetHead(list); a != NULL;
a = (HTMLAnchor)GListGetNext(list))
{
if (InAnchor(x, y, a->box))
{
if (a->p != NULL)
{
li->sa = a;
for (a = (HTMLAnchor)GListGetHead(list); a != NULL;
a = (HTMLAnchor)GListGetNext(list))
{
if (a->p == li->sa->p)
{
HTMLSetB(a->box, BOX_SELECT);
HTMLRenderBox(li, NULL, a->box);
}
}
XFlush(li->dpy);
HTMLLoadAnchor(li, li->sa, x, y, action, false);
if (li->sto != NULL) TimeOutDestroy(li->sto);
li->sto = TimeOutCreate(li->cres, li->selectTimeOut,
DeselectTimeOut, li);
}
break;
}
}
return(true);
}
static bool
HTMLMotion(closure, x, y)
void *closure;
int x, y;
{
HTMLInfo li = (HTMLInfo)closure;
HTMLAnchor a;
GList list;
list = li->alist;
for (a = (HTMLAnchor)GListGetHead(list); a != NULL;
a = (HTMLAnchor)GListGetNext(list))
{
if (InAnchor(x, y, a->box)) break;
}
if (a == NULL || a->p == NULL) RenderSendMessage(li->wn, NULL);
else HTMLPrintAnchor(li, a, x, y, false);
li->over = a;
return(true);
}
/*
* HTMLQuery
*/
static byte *
HTMLQuery(closure, key)
void *closure;
char *key;
{
HTMLInfo li = (HTMLInfo)closure;
if (strcmp(key, "title") == 0)
{
if (li->title != NULL) return(li->title);
}
return(NULL);
}
/*
* HTMLSearch
*
* And here's an interesting development...there is no way to do a
* search for text unless another field is added to HTMLBox. That
* is unsavory. Work on this later.
*/
static int
HTMLSearch(closure, key, mode)
void *closure;
char *key;
int mode;
{
return(-1);
}
/*
* HTMLCancel
*/
static void
HTMLCancel(closure)
void *closure;
{
HTMLInfo li = (HTMLInfo)closure;
ChimeraSink wp;
myassert(li != NULL, "HTMLInfo is NULL!");
for (wp = (ChimeraSink)GListGetHead(li->sinks); wp != NULL;
wp = (ChimeraSink)GListGetNext(li->sinks))
{
SinkCancel(wp);
}
li->cancel = true;
if (li->wt != NULL)
{
TaskRemove(li->cres, li->wt);
li->wt = NULL;
}
return;
}
/*
* HTMLDestroy
*/
static void
HTMLDestroy(closure)
void *closure;
{
HTMLInfo li = (HTMLInfo)closure;
ChimeraSink wp;
GListRemoveItem(li->lc->contexts, li);
HTMLDestroyBox(li, li->firstbox);
while ((wp = (ChimeraSink)GListPop(li->sinks)) != NULL)
{
SinkDestroy(wp);
}
HTMLDestroyFrameSets(li);
if (li->wt != NULL) TaskRemove(li->cres, li->wt);
if (li->sto != NULL) TimeOutDestroy(li->sto);
if (li->hs != NULL) MLDestroy(li->hs);
MPDestroy(li->mp);
return;
}
/*
* HTMLInit
*/
static void *
HTMLInit(wn, closure, state)
ChimeraRender wn;
void *closure;
void *state;
{
HTMLInfo li;
HTMLClass lc = (HTMLClass)closure;
MemPool mp;
char *url;
ChimeraSink wp;
ChimeraGUI wd;
wp = RenderToSink(wn);
wd = RenderToGUI(wn);
url = SinkGetInfo(wp, "x-url");
mp = MPCreate();
li = (HTMLInfo)MPCGet(mp, sizeof(struct HTMLInfoP));
li->mp = mp;
li->wc = RenderToContext(wn);
li->cres = RenderToResources(wn);
li->ps = (HTMLState)state;
li->url = url;
li->burl = url;
li->wd = wd;
li->wp = wp;
li->wn = wn;
li->widget = GUIToWidget(li->wd);
li->hs = MLInit(HTMLHandler, li);
li->lc = lc;
li->css = lc->css;
li->envstack = GListCreateX(mp);
li->selectors = GListCreateX(mp);
li->oldselectors = GListCreateX(mp);
li->endstack = GListCreateX(mp);
li->alist = GListCreateX(mp);
li->maps = GListCreateX(mp);
li->sinks = GListCreateX(mp);
li->loads = GListCreateX(mp);
li->framesets = GListCreateX(mp);
if (SinkWasReloaded(wp)) li->reload = true;
else li->reload = false;
ResourceGetInt(li->cres, "html.leftMargin", &(li->lmargin));
if (li->lmargin <= 0) li->lmargin = 20;
ResourceGetInt(li->cres, "html.rightMargin", &(li->rmargin));
if (li->rmargin <= 0) li->rmargin = 20;
ResourceGetInt(li->cres, "html.bottomMargin", &(li->bmargin));
if (li->bmargin <= 0) li->bmargin = 20;
ResourceGetInt(li->cres, "html.topMargin", &(li->tmargin));
if (li->tmargin <= 0) li->tmargin = 20;
ResourceGetBool(li->cres, "html.printHTMLErrors", &(li->printHTMLErrors));
li->textLineSpace = -1;
ResourceGetInt(li->cres, "html.textLineSpace", &(li->textLineSpace));
if (li->textLineSpace < 0) li->textLineSpace = 3;
li->tableCellInfinity = 0;
ResourceGetUInt(li->cres,
"html.tableCellInfinity", &(li->tableCellInfinity));
ResourceGetUInt(li->cres, "html.inlineTimeOut", &(li->inlineTimeOut));
if (li->inlineTimeOut < 5) li->inlineTimeOut = 5000;
ResourceGetUInt(li->cres, "html.selectTimeOut", &(li->selectTimeOut));
if (li->selectTimeOut < 1000) li->selectTimeOut = 1000;
ResourceGetBool(li->cres, "html.flowDebug", &(li->flowDebug));
ResourceGetBool(li->cres, "html.constraintDebug", &(li->constraintDebug));
ResourceGetBool(li->cres, "html.printTags", &(li->printTags));
/*
* Graphics setup
*/
li->dpy = GUIToDisplay(li->wd);
li->win = GUIToWindow(li->wd);
li->gc = DefaultGC(li->dpy, DefaultScreen(li->dpy));
GUIGetNamedColor(wd, "blue", &(li->anchor_color));
GUIGetNamedColor(wd, "red", &(li->anchor_select_color));
GUIGetNamedColor(wd, "black", &(li->fg));
XSetForeground(li->dpy, li->gc, li->fg);
HTMLSetupFonts(li);
GUISetScrollBar(wd, true);
if (GUIGetDimensions(wd, &(li->maxwidth), &(li->maxheight)) == -1)
{
/* Dimensions of display not set so we'll set them. */
li->maxwidth = 200;
li->maxheight = 200;
GUISetDimensions(wd, li->maxwidth, li->maxheight);
/* Now grab the internal dimensions again */
if (GUIGetDimensions(wd, &(li->maxwidth), &(li->maxheight)) == -1)
{
return(NULL);
}
}
GListAddHead(lc->contexts, li);
HTMLStart(li);
return(li);
}
/*
* HTMLClassDestroy
*/
static void
HTMLClassDestroy(closure)
void *closure;
{
HTMLClass lc = (HTMLClass)closure;
HTMLFreeFonts(lc);
MPDestroy(lc->mp);
return;
}
/*
* HTMLGetState
*/
void *
HTMLGetState(closure)
void *closure;
{
HTMLInfo li = (HTMLInfo)closure;
HTMLState ps;
if ((ps = (HTMLState)GListPop(li->lc->oldstates)) == NULL)
{
ps = (HTMLState)MPCGet(li->lc->mp, sizeof(struct HTMLStateP));
}
GUIGetScrollPosition(li->wd, &(ps->x), &(ps->y));
return(ps);
}
/*
* InitModule_HTML
*/
int
InitModule_HTML(cres)
ChimeraResources cres;
{
ChimeraRenderHooks rh;
HTMLClass lc;
MemPool mp;
FILE *fp;
char *cssfile;
char *b;
struct stat st;
size_t rval, blen;
mp = MPCreate();
lc = (HTMLClass)MPCGet(mp, sizeof(struct HTMLClassP));
lc->mp = mp;
lc->oldstates = GListCreateX(mp);
lc->contexts = GListCreateX(mp);
/*
* Snarf up the default style sheet.
*/
if ((cssfile = ResourceGetFilename(cres, mp, "html.cssFile")) != NULL)
{
if (stat(cssfile, &st) == 0 && (fp = fopen(cssfile, "r")) != NULL)
{
if ((b = (char *)alloc_mem(st.st_size)) == NULL)
{
while ((rval = fread(b + blen, 1, st.st_size - blen, fp)) > 0 &&
!feof(fp))
{
blen += rval;
}
fclose(fp);
if (blen == st.st_size)
{
lc->css = CSSParseBuffer(NULL, b, blen, NULL, NULL);
}
free_mem(b);
}
}
}
memset(&rh, 0, sizeof(rh));
rh.class_context = lc;
rh.class_destroy = HTMLClassDestroy;
rh.content = "text/html";
rh.init = HTMLInit;
rh.add = HTMLAdd;
rh.end = HTMLEnd;
rh.search = HTMLSearch;
rh.destroy = HTMLDestroy;
rh.getstate = HTMLGetState;
rh.query = HTMLQuery;
rh.cancel = HTMLCancel;
rh.expose = HTMLExpose;
rh.select = HTMLMouse;
rh.motion = HTMLMotion;
RenderAddHooks(cres, &rh);
return(0);
}
/*
* HTMLSetFinalPosition
*/
void
HTMLSetFinalPosition(li)
HTMLInfo li;
{
char *cp;
if (li->ps != NULL)
{
GUISetScrollPosition(li->wd, li->ps->x, li->ps->y);
GListAddHead(li->lc->oldstates, li->ps);
li->ps = NULL;
}
else
{
for (cp = li->url; *cp != '\0'; cp++)
{
if (*cp == '#')
{
HTMLFindName(li, cp + 1);
return;
}
}
}
return;
}

900
html/table.c Normal file
View File

@ -0,0 +1,900 @@
/*
* table.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
typedef struct
{
HTMLBox box;
unsigned int width;
int rowspan, colspan;
} HData;
typedef struct
{
bool original;
int rowspan, colspan;
HData *ds;
int rowspan2, colspan2;
HData *ds2;
} HCell;
typedef struct
{
GList datas;
int colcount;
HCell *ca;
} HRow;
typedef struct
{
MemPool mp;
unsigned int border; /* table border width */
HTMLBox box; /* table box */
HTMLBox dbox; /* current data box */
MLElement p; /* table tag element */
GList grid; /* grid of rows and data */
GList klist; /* list of kids */
int rowcount, colcount; /* nearly always greater than real */
int pass;
unsigned int *cwidth, *rheight; /* column widths, row heights */
unsigned int *swidth; /* scaled columns widths */
unsigned int max_width; /* width available for table */
unsigned int inf_width; /* width with unbounded table size */
} HTable;
/*
* Private functions
*/
static void DestroyTable _ArgProto((HTMLInfo, HTMLBox));
static void SetupTable _ArgProto((HTMLInfo, HTMLBox));
static void RenderTable _ArgProto((HTMLInfo, HTMLBox, Region));
static void TablePosition1 _ArgProto((HTable *));
static void TablePosition2 _ArgProto((HTable *));
static void FillSpans _ArgProto((HTable *));
/*
* SetupTable
*
* Called when the position of the table is known. Now set the location
* of the child boxes and arrange to have their setup function called.
*/
static void
SetupTable(li, box)
HTMLInfo li;
HTMLBox box;
{
int i, j;
HRow *rs;
HData *ds;
int bx, by;
HTable *ts = (HTable *)box->closure;
bx = 0;
by = 0;
for (j = 0, rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid), j++)
{
if (rs->ca == NULL) continue;
for (i = 0; i < ts->colcount; i++)
{
if (rs->ca[i].ds != NULL && rs->ca[i].original)
{
ds = rs->ca[i].ds;
ds->box->x = bx + box->x;
ds->box->y = by + box->y;
HTMLSetupBox(li, ds->box);
bx += ts->cwidth[i];
}
else
{
bx += ts->cwidth[i];
}
}
bx = 0;
by += ts->rheight[j];
}
return;
}
/*
* RenderTable
*
* Called when the table has been exposed. Since the child boxes
* will handle their own refresh only need to refresh the border if
* there is one.
*/
static void
RenderTable(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
HTable *ts = (HTable *)box->closure;
HTMLBox c;
for (c = (HTMLBox)GListGetHead(ts->klist); c != NULL;
c = (HTMLBox)GListGetNext(ts->klist))
{
HTMLRenderBox(li, r, c);
}
return;
}
/*
* DestroyTable
*/
static void
DestroyTable(li, box)
HTMLInfo li;
HTMLBox box;
{
HTable *ts = (HTable *)box->closure;
HTMLBox c;
while ((c = (HTMLBox)GListPop(ts->klist)) != NULL)
{
HTMLDestroyBox(li, c);
}
return;
}
/*
* HTMLTableAddBox
*/
void
HTMLTableAddBox(li, env, box)
HTMLInfo li;
HTMLEnv env;
HTMLBox box;
{
return;
}
/*
* HTMLTDAddBox
*/
void
HTMLTDAddBox(li, env, box)
HTMLInfo li;
HTMLEnv env;
HTMLBox box;
{
HTable *ts = (HTable *)env->closure;
HTMLLayoutBox(li, ts->dbox, box);
return;
}
/*
* HTMLTDBegin
*
* Called when a <td> tag is encountered
*/
void
HTMLTDBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTable *ts;
HRow *rs;
HData *ds;
ts = (HTable *)env->penv->closure;
env->closure = ts;
if (ts->pass == 0)
{
rs = (HRow *)GListGetTail(ts->grid);
myassert(rs != NULL, "Could not find row data (1).");
ds = (HData *)MPCGet(ts->mp, sizeof(HData));
if (p == NULL)
{
ds->colspan = 1;
ds->rowspan = 1;
}
else
{
if ((ds->colspan = MLAttributeToInt(p, "colspan")) < 1) ds->colspan = 1;
if ((ds->rowspan = MLAttributeToInt(p, "rowspan")) < 1) ds->rowspan = 1;
}
GListAddTail(rs->datas, ds);
rs->colcount += ds->colspan;
if (rs->colcount > ts->colcount) ts->colcount = rs->colcount;
/* this is more than the real count but that's ok. */
ts->rowcount += ds->rowspan;
ts->dbox = ds->box = HTMLCreateFlowBox(li, env, li->tableCellInfinity);
}
else
{
rs = (HRow *)GListGetCurrent(ts->grid);
myassert(rs != NULL, "Could not find row data (2).");
ds = (HData *)GListGetCurrent(rs->datas);
myassert(ds != NULL, "Could not find cell data (2).");
ts->dbox = ds->box = HTMLCreateFlowBox(li, env, ds->width);
}
GListAddHead(ts->klist, ds->box);
return;
}
/*
* HTMLTDEnd
*
* Called when a <td> tag is encountered
*/
void
HTMLTDEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTable *ts = (HTable *)env->closure;
HRow *rs;
HTMLFinishFlowBox(li, ts->dbox);
if (ts->pass > 0)
{
rs = (HRow *)GListGetCurrent(ts->grid);
GListGetNext(rs->datas);
}
return;
}
/*
* HTMLTRBegin
*/
void
HTMLTRBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTable *ts;
HRow *rs;
ts = (HTable *)env->penv->closure;
env->closure = ts;
if (ts->pass == 0)
{
rs = (HRow *)MPCGet(ts->mp, sizeof(HRow));
GListAddTail(ts->grid, rs);
rs->datas = GListCreateX(ts->mp);
}
else
{
rs = (HRow *)GListGetCurrent(ts->grid);
GListGetHead(rs->datas);
}
return;
}
/*
* HTMLTREnd
*/
void
HTMLTREnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTable *ts;
ts = (HTable *)env->penv->closure;
env->closure = ts;
if (ts->pass > 0) GListGetNext(ts->grid);
return;
}
/*
* HTMLTableBegin
*
* Called when <table> is encountered. Has to deal with two passes.
*/
void
HTMLTableBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLBox box;
HTable *ts;
char *value, *cp;
int x;
int border;
unsigned int width, maxwidth;
maxwidth = width = HTMLGetMaxWidth(li, env->penv);
env->ff = FLOW_LEFT_JUSTIFY;
env->anchor = NULL;
if (env->closure == NULL)
{
ts = (HTable *)MPCGet(li->mp, sizeof(HTable));
ts->mp = li->mp;
ts->p = p;
env->closure = ts;
if ((border = MLAttributeToInt(p, "border")) < 0) border = 0;
ts->border = border;
ts->grid = GListCreateX(ts->mp);
ts->klist = GListCreateX(li->mp);
if ((value = MLFindAttribute(p, "width")) != NULL)
{
if (isdigit(value[0]))
{
x = atoi(value);
for (cp = value; ; cp++)
{
if (!isdigit(*cp)) break;
}
if (*cp != '\0')
{
if (*cp == '%')
{
if (x >= 10) width = width * x / 100;
}
else if (x >= 100) width = x;
}
else if (x >= 100) width = x;
}
}
if (width > 0) ts->max_width = width;
else ts->max_width = 0;
}
else
{
ts = (HTable *)env->closure;
GListGetHead(ts->grid);
GListClear(ts->klist);
}
ts->pass = env->pass;
/*
* Create the table box
*/
ts->box = box = HTMLCreateBox(li, env);
box->setup = SetupTable;
box->render = RenderTable;
box->destroy = DestroyTable;
box->closure = ts;
return;
}
/*
* HTMLTableEnd
*
* Called when </table> is encountered. Has to deal with two passes.
*/
void
HTMLTableEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTable *ts = (HTable *)env->closure;
if (ts->colcount == 0) return;
if (ts->pass == 0)
{
/*
* Do first pass size calculations.
*/
FillSpans(ts);
TablePosition1(ts);
/*
* Now destroy the table box and its children since we need to rebuild
* from scratch.
*/
HTMLDestroyBox(li, ts->box);
ts->box = NULL;
}
else
{
TablePosition2(ts);
HTMLEnvAddBox(li, env->penv, ts->box);
}
return;
}
/*
* FillSpans
*/
static void
FillSpans(ts)
HTable *ts;
{
HRow *rs;
HData *ds;
int i, j, k;
HCell *pca;
ts->colcount *= 2;
/*
* Allocate an array for each row to keep track of the data grid.
*/
for (k = 0, rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid), k++)
{
rs->ca = (HCell *)MPCGet(ts->mp, sizeof(HCell) * ts->colcount);
}
/*
* Its possible rowspan has pushed things down a bit so add rows as
* necessary. Overkill is OK.
*/
for (; k < ts->rowcount; k++)
{
rs = (HRow *)MPCGet(ts->mp, sizeof(HRow));
GListAddTail(ts->grid, rs);
rs->datas = GListCreateX(ts->mp);
rs->ca = (HCell *)MPCGet(ts->mp, sizeof(HCell) * ts->colcount);
}
/*
* Put the data into the grids according to rowspan and colspan.
*/
pca = NULL;
for (rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid))
{
/*
* If there is a previous row then look at the HCell's above and
* see if they need to be extended. We know the HCell above needs to
* be extended down if rowspan > 1. Move rowspan - 1 down to the
* current row. Also, move the colspan
* value down (its not used, though) and the HData pointer.
*/
if (pca != NULL)
{
for (i = 0; i < ts->colcount; i++)
{
if (pca[i].ds != NULL && pca[i].rowspan > 1)
{
myassert(rs->ca[i].ds == NULL, "Cell visitation unexpected!");
rs->ca[i].rowspan = pca[i].rowspan - 1;
rs->ca[i].colspan = pca[i].colspan;
rs->ca[i].ds = pca[i].ds;
}
if (pca[i].ds2 != NULL && pca[i].rowspan2 > 1)
{
myassert(rs->ca[i].ds == NULL, "Cell visitation unexpected! (2)");
rs->ca[i].rowspan = pca[i].rowspan2 - 1;
rs->ca[i].colspan = pca[i].colspan2;
rs->ca[i].ds = pca[i].ds2;
}
}
}
/*
* Now extend HData to the right depending on the colspan.
*/
for (ds = (HData *)GListGetHead(rs->datas); ds != NULL;
ds = (HData *)GListGetNext(rs->datas))
{
/*
* Scan to the right and look for the first empty HCell. This needs
* to be done because an HData above could have spanned down to fill
* in the beginning of the row.
*
* This has to be done for each data section because a row that
* was extended down may have used up space in the middle of the
* row.
*/
for (i = 0; i < ts->colcount; i++)
{
if (rs->ca[i].ds == NULL) break;
}
myassert(ts->colcount != i, "Table column count confused.");
rs->ca[i].original = true;
for (j = 0; j < ds->colspan; j++, i++)
{
if (rs->ca[i].ds == NULL)
{
rs->ca[i].ds = ds;
rs->ca[i].colspan = ds->colspan - j;
rs->ca[i].rowspan = ds->rowspan;
}
else
{
rs->ca[i].ds2 = ds;
rs->ca[i].colspan2 = ds->colspan - j;
rs->ca[i].rowspan2 = ds->rowspan;
}
}
}
pca = rs->ca;
}
/*
* Test code. Print out patterns to see if the internal representation
* looks reasonable.
*/
/*
for (rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid))
{
for (i = 0; i < ts->colcount; i++)
{
if (rs->ca[i].ds2 != NULL) printf ("o");
else if (rs->ca[i].ds != NULL && rs->ca[i].original)
{
printf ("%c", (char )((int)('A') + i));
}
else if (rs->ca[i].ds != NULL) printf ("%c", (char )((int)('a') + i));
else printf ("x");
}
printf("\n");
}
*/
return;
}
/*
* TablePosition1
*/
static void
TablePosition1(ts)
HTable *ts;
{
int i, j;
HRow *rs;
HData *ds;
unsigned int twidth, width;
/*
* Allocate arrays to hold the column widths and row heights.
*
* cwidth = column width
* swidth = scaled column width
* rheight = row height
*/
ts->cwidth = (unsigned int *)MPCGet(ts->mp, sizeof(unsigned int) *
ts->colcount);
ts->swidth = (unsigned int *)MPCGet(ts->mp, sizeof(unsigned int) *
ts->colcount);
ts->rheight = (unsigned int *)MPCGet(ts->mp, sizeof(unsigned int) *
ts->rowcount);
/*
* Figure out the unrestrained widths of the columns. Needed a little
* later to determine the width of the table.
*/
twidth = 0;
for (rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid))
{
for (i = 0; i < ts->colcount; i++)
{
if (rs->ca[i].ds != NULL)
{
ds = rs->ca[i].ds;
width = ds->box->width / ds->colspan;
if (width > ts->cwidth[i]) ts->cwidth[i] = width;
}
if (rs->ca[i].ds2 != NULL)
{
ds = rs->ca[i].ds2;
width = ds->box->width / ds->colspan;
if (width > ts->cwidth[i]) ts->cwidth[i] = width;
}
}
}
/*
* Determine the width of the unrestrained table.
*/
twidth = 0;
for (i = 0; i < ts->colcount; i++)
{
twidth += ts->cwidth[i];
}
if (twidth > 0 && twidth > ts->max_width)
{
/*
* Now scale the columns to fit in the space available attempting to keep
* things in proportion.
*/
for (i = 0; i < ts->colcount; i++)
{
ts->swidth[i] = ts->max_width * ts->cwidth[i] / twidth;
}
}
else
{
/*
* No size problems so just copy the widths as-is.
*/
for (i = 0; i < ts->colcount; i++)
{
ts->swidth[i] = ts->cwidth[i];
}
}
/*
* Finally, figure out the widths of individual cells.
*/
for (rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid))
{
for (i = 0; i < ts->colcount; i++)
{
if (rs->ca[i].ds != NULL && rs->ca[i].original)
{
/*
* Add in the widths of all the columns for a column spanning
* cell.
*/
ds = rs->ca[i].ds;
for (j = 0; j + i < ts->colcount && j < ds->colspan; j++)
{
ds->width += ts->swidth[i + j];
}
}
}
}
return;
}
/*
* TablePosition2
*/
static void
TablePosition2(ts)
HTable *ts;
{
int i, j;
unsigned int width, height;
HRow *rs;
HData *ds;
memset(ts->cwidth, 0, ts->colcount * sizeof(unsigned int));
memset(ts->rheight, 0, ts->rowcount * sizeof(unsigned int));
/*
* Get the columns widths and row heights for the restrained table
* (second pass).
*/
for (j = 0, rs = (HRow *)GListGetHead(ts->grid); rs != NULL;
rs = (HRow *)GListGetNext(ts->grid), j++)
{
for (i = 0; i < ts->colcount; i++)
{
if (rs->ca[i].ds != NULL)
{
ds = rs->ca[i].ds;
width = ds->box->width / ds->colspan;
if (width > ts->cwidth[i]) ts->cwidth[i] = width;
height = ds->box->height / ds->rowspan;
if (height > ts->rheight[j]) ts->rheight[j] = height;
}
if (rs->ca[i].ds2 != NULL)
{
ds = rs->ca[i].ds2;
width = ds->box->width / ds->colspan;
if (width > ts->cwidth[i]) ts->cwidth[i] = width;
height = ds->box->height / ds->rowspan;
if (height > ts->rheight[j]) ts->rheight[j] = height;
}
}
}
/*
* Find the final width and height of the table.
*/
width = 0;
height = 0;
for (i = 0; i < ts->colcount; i++)
{
width += ts->cwidth[i];
}
for (i = 0; i < ts->rowcount; i++)
{
height += ts->rheight[i];
}
ts->box->width = width;
ts->box->height = height;
return;
}
/*
* HTMLTableAccept
*/
bool
HTMLTableAccept(li, obj)
HTMLInfo li;
HTMLObject obj;
{
if (obj->type != HTML_ENV) return(false);
if (HTMLTagToID(obj->o.env->tag) != TAG_TR) return(false);
return(true);
}
/*
* HTMLTRAccept
*/
bool
HTMLTRAccept(li, obj)
HTMLInfo li;
HTMLObject obj;
{
HTMLTagID tagid;
if (obj->type != HTML_ENV) return(false);
tagid = HTMLTagToID(obj->o.env->tag);
if (tagid != TAG_TD && tagid != TAG_TH) return(false);
return(true);
}
/*
* HTMLTDInsert
*/
HTMLInsertStatus
HTMLTDInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLEnv c;
HTMLTagID tid;
for (c = (HTMLEnv)GListGetHead(li->envstack); c != NULL;
c = (HTMLEnv)GListGetNext(li->envstack))
{
tid = HTMLTagToID(c->tag);
if (tid == TAG_TABLE || tid == TAG_TR) break;
}
if (c == NULL) return(HTMLInsertReject);
else if (tid == TAG_TABLE) HTMLStartEnv(li, TAG_TR, NULL);
else HTMLPopEnv(li, TAG_TR);
return(HTMLInsertOK);
}
/*
* HTMLTDClamp
*/
bool
HTMLTDClamp(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLEnv c;
HTMLTagID tid;
for (c = (HTMLEnv)GListGetHead(li->envstack); c != NULL;
c = (HTMLEnv)GListGetNext(li->envstack))
{
tid = HTMLTagToID(c->tag);
if (tid == TAG_TABLE || tid == TAG_TD) break;
}
if (c == NULL) return(false);
else if (tid == TAG_TABLE) return(false);
return(true);
}
/*
* HTMLTRInsert
*/
HTMLInsertStatus
HTMLTRInsert(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLEnv tenv;
if ((tenv = HTMLFindEnv(li, TAG_TABLE)) == NULL) return(HTMLInsertReject);
HTMLPopEnv(li, TAG_TABLE);
return(HTMLInsertOK);
}
/*
* HTMLTRClamp
*/
bool
HTMLTRClamp(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLEnv c;
HTMLTagID tid;
for (c = (HTMLEnv)GListGetHead(li->envstack); c != NULL;
c = (HTMLEnv)GListGetNext(li->envstack))
{
tid = HTMLTagToID(c->tag);
if (tid == TAG_TABLE || tid == TAG_TR) break;
}
if (c == NULL) return(false);
else if (tid == TAG_TABLE) return(false);
return(true);
}
/*
* HTMLTDWidth
*/
unsigned int
HTMLTDWidth(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTable *ts = (HTable *)env->closure;
return(HTMLGetBoxWidth(li, ts->dbox));
}

489
html/text.c Normal file
View File

@ -0,0 +1,489 @@
/*
* text.c
*
* libhtml - HTML->X renderer
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "html.h"
#define TAB_EXPANSION 4
typedef struct TextStateP
{
char *s;
size_t len;
} TextState;
/*
*
* Private functions
*
*/
static void RenderText _ArgProto((HTMLInfo, HTMLBox, Region));
static char *ExpandTabs _ArgProto((HTMLInfo, char *, size_t, size_t));
static void LineMode _ArgProto((HTMLInfo, HTMLEnv, MLElement));
static void HTMLPreformatted _ArgProto((HTMLInfo, HTMLEnv, char *, size_t));
/*
* RenderText
*/
static void
RenderText(li, box, r)
HTMLInfo li;
HTMLBox box;
Region r;
{
TextState *ts = (TextState *)box->closure;
int x, y;
XFontStruct *font = HTMLGetFont(li, box->env);
XSetFont(li->dpy, li->gc, font->fid);
/* y position + ascent to line up correctly + descent for line spacing */
y = box->y + font->ascent;
x = box->x;
if (box->env->anchor != NULL)
{
if (HTMLTestB(box, BOX_SELECT))
{
XSetForeground(li->dpy, li->gc, li->anchor_select_color);
}
else XSetForeground(li->dpy, li->gc, li->anchor_color);
XDrawString(li->dpy, li->win, li->gc, x, y, ts->s, (int)ts->len);
XDrawLine(li->dpy, li->win, li->gc, x, y + font->descent - 1,
x + box->width, y + font->descent - 1);
XSetForeground(li->dpy, li->gc, li->fg);
}
else
{
XDrawString(li->dpy, li->win, li->gc, x, y, ts->s, (int)ts->len);
}
return;
}
/*
* HTMLCreateTextBox
*/
HTMLBox
HTMLCreateTextBox(li, env, s, slen)
HTMLInfo li;
HTMLEnv env;
char *s;
size_t slen;
{
HTMLBox box;
TextState *ts;
HTMLBoxFlags bflags;
XFontStruct *font = HTMLGetFont(li, env);
if (s == NULL)
{
s = " ";
slen = 1;
bflags = BOX_SPACE;
}
else
{
bflags = BOX_NONE;
}
ts = (TextState *)MPCGet(li->mp, sizeof(TextState));
ts->s = s;
ts->len = slen;
box = HTMLCreateBox(li, env);
HTMLSetB(box, bflags);
box->closure = ts;
box->render = RenderText;
box->width = XTextWidth(font, s, slen);
box->height = font->ascent + font->descent + li->textLineSpace;
box->baseline = font->ascent + li->textLineSpace;
return(box);
}
/*
* HTMLPreformatted - basically, the guts of LineMode()
*/
static void
HTMLPreformatted(li, env, text, len)
HTMLInfo li;
HTMLEnv env;
char *text;
size_t len;
{
char *cp, *lastcp, *start;
size_t ptlen;
char *s;
bool tabbed;
lastcp = text + len;
tabbed = false;
for (ptlen = 0, start = cp = text; cp < lastcp; cp++)
{
if (*cp == '\r') continue;
else if (*cp == '\n')
{
if (tabbed)
{
s = ExpandTabs(li, start, cp - start, ptlen);
HTMLEnvAddBox(li, env, HTMLCreateTextBox(li, env, s, ptlen));
}
else
{
HTMLEnvAddBox(li, env, HTMLCreateTextBox(li, env, start, ptlen));
}
HTMLAddLineBreak(li, env);
ptlen = 0;
start = cp + 1;
tabbed = false;
}
else if (*cp == '\t')
{
ptlen += TAB_EXPANSION;
tabbed = true;
}
else ptlen++;
}
if (tabbed)
{
s = ExpandTabs(li, start, cp - start, ptlen);
HTMLEnvAddBox(li, env, HTMLCreateTextBox(li, env, s, ptlen));
}
else
{
HTMLEnvAddBox(li, env, HTMLCreateTextBox(li, env, start, ptlen));
}
return;
}
/*
*
* Public functions
*
*/
/*
* ExpandTabs
*/
static char *
ExpandTabs(li, t, len, tlen)
HTMLInfo li;
char *t;
size_t len;
size_t tlen;
{
char *s, *cp, *lastcp, *xs;
lastcp = t + len;
s = (char *)MPGet(li->mp, tlen);
for (cp = t, xs = s; cp < lastcp; cp++)
{
if (*cp == '\t')
{
memset(xs, ' ', TAB_EXPANSION);
xs += TAB_EXPANSION;
}
else if (*cp != '\r')
{
*xs = *cp;
xs++;
}
}
return(s);
}
/*
* LineMode
*/
static void
LineMode(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *text;
size_t len;
MLGetText(p, &text, &len);
if (text == NULL) return;
HTMLPreformatted(li, env, text, len);
return;
}
/*
* HTMLPlainData
*/
void
HTMLPlainData(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
LineMode(li, env, p);
return;
}
/*
* HTMLPreData
*/
void
HTMLPreData(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
LineMode(li, env, p);
return;
}
/*
* HTMLFillData
*/
void
HTMLFillData(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
char *s, *cp, *lastcp;
bool found_space;
char *text;
size_t len;
MLGetText(p, &text, &len);
if (text == NULL) return;
if (li->formatted) HTMLPreformatted(li, env, text, len);
else
{
for (lastcp = text + len, cp = text; cp < lastcp; )
{
for (found_space = false; cp < lastcp && isspace8(*cp); cp++)
{
found_space = true;
}
if (found_space)
{
HTMLEnvAddBox(li, env, HTMLCreateTextBox(li, env, NULL, 0));
}
if (cp == lastcp) break;
for (s = cp; cp < lastcp && !isspace8(*cp); cp++)
;
HTMLEnvAddBox(li, env, HTMLCreateTextBox(li, env, s, cp - s));
}
}
return;
}
void
HTMLPreBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLSetFontFixed(env->fi);
li->formatted = true; /* would anyone actually nest PREs? - djhjr */
return;
}
void
HTMLPreEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
li->formatted = false; /* nah... - djhjr */
return;
}
void
HTMLPlainEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
void
HTMLPlainBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
HTMLSetFontFixed(env->fi);
return;
}
void
HTMLNoFrameBegin(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
/*
* HTMLNoFrameEnd
*/
void
HTMLNoFrameEnd(li, env, p)
HTMLInfo li;
HTMLEnv env;
MLElement p;
{
return;
}
/*
* HTMLGetText
*/
char *
HTMLGetEnvText(mp, env)
MemPool mp;
HTMLEnv env;
{
HTMLObject c, b, e;
char *text, *str;
size_t tlen = 0;
size_t len;
GList list = env->slist;
if (GListEmpty(list)) return(NULL);
e = (HTMLObject)GListGetTail(list);
for (b = c = (HTMLObject)GListGetHead(list); c != NULL;
c = (HTMLObject)GListGetNext(list))
{
if (c != b && c != e)
{
if (c->type != HTML_ENV)
{
MLGetText(c->o.p, &str, &len);
tlen += len;
}
}
}
text = MPGet(mp, tlen + 1);
tlen = 0;
for (c = (HTMLObject)GListGetHead(list); c != NULL;
c = (HTMLObject)GListGetNext(list))
{
if (c != b && c != e)
{
if (c->type != HTML_ENV)
{
MLGetText(c->o.p, &str, &len);
strncpy(text + tlen, str, len);
tlen += len;
}
}
}
text[tlen] = '\0';
return(text);
}
/*
* HTMLAddLineBreak
*/
void
HTMLAddLineBreak(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLBox box;
box = HTMLCreateBox(li, env);
HTMLSetB(box, BOX_LINEBREAK);
HTMLEnvAddBox(li, env, box);
return;
}
/*
* HTMLAddBlankLine
*/
void
HTMLAddBlankLine(li, env)
HTMLInfo li;
HTMLEnv env;
{
HTMLBox box;
HTMLAddLineBreak(li, env);
box = HTMLCreateBox(li, env);
box->height = 6;
box->width = 0; /* really really want this to be zero */
HTMLEnvAddBox(li, env, box);
HTMLAddLineBreak(li, env);
return;
}
/*
* HTMLStringSpacify
*
* Turns all whitespace to spaces
*/
void
HTMLStringSpacify(s, len)
char *s;
size_t len;
{
char *cp, *lastcp = s + len;
for (cp = s; cp < lastcp; cp++)
{
if (isspace8(*cp)) *cp = ' ';
}
return;
}

28
image/Imakefile Normal file
View File

@ -0,0 +1,28 @@
#include <../Common.tmpl>
#ifdef Use_JPEG
JPEG_INCLUDES = $(JPEGINCLUDE)
JPEG_DEFINES = -DHAVE_JPEG
JPEG_OBJS = jpeg.o
JPEG_SRCS = jpeg.c
#endif
#ifdef Use_PNG
PNG_INCLUDES = $(PNGINCLUDE)
PNG_DEFINES = -DHAVE_PNG
PNG_OBJS = png.o
PNG_SRCS = png.c
#endif
OBJS = gif.o xbm.o pnm.o new.o dispdither.o halftone.o \
colorcube.o xcolorcube.o image.o $(JPEG_OBJS) $(PNG_OBJS)
SRCS = gif.c xbm.c pnm.c new.c dispdither.c halftone.c \
colorcube.c xcolorcube.c image.c $(JPEG_SRCS) $(PNG_SRCS)
EXTRA_INCLUDES = -I../port -I../common -I../chimera $(JPEG_INCLUDES) $(PNG_INCLUDES)
EXTRA_DEFINES = $(XRELEASE) $(CHIMERA_DEFINES) $(JPEG_DEFINES) $(PNG_DEFINES)
NormalLibraryTarget(ximage, $(OBJS))
DependTarget()

562
image/colorcube.c Normal file
View File

@ -0,0 +1,562 @@
/* colorcube.c
*
* (c) 1995 Erik Corry. ehcorry@inet.uni-c.dk erik@kroete2.freinet.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This contains routines which take a general description of which
* colors we have managed to allocate from the device, and produces
* tables that can be used to convert various input formats to use
* these colors. The dither algorithm used (where necessary) is a
* dispersed table dither up to 4x4 in size, from an automatically
* generated table.
*
* The routines here are not necessarily fast (some of them are very
* slow indeed), but they generate tables that can be used in fast code.
*
* Error diffusion dither is not used for three reasons:
*
* o It is somewhat slower than table dither.
* o You cannot dither an interleaved image properly with it.
* o You cannot alter a small part of an image and then just redither that
* without the edges showing.
* o It is harder to program.
* o You shouldn't be trying to view jpegs on a 1-bit screen anyway. :-)
*/
#include "port_before.h"
#include <stdlib.h>
#include "port_after.h"
#include "imagep.h"
#include "colorcube.h"
/*
* Create a matrix of the type:
*
* (1 3)
* (4 2)
*
* but of the required size, for a dispersed dither.
*/
static void
lf_create_dither_matrix(
int matrix[4][4],
int tr,
int tc)
{
int c,r;
bool swapped = false;
/* Make sure the column count is <= row count */
if (tc > tr)
{
int t = tc;
tc = tr;
tr = t;
swapped = true;
}
/* Seed the matrix */
matrix[0][0] = 1;
/* Bring matrix up to size */
for (c = 1, r = 2; r <= tr; r *= 2)
{
int x,y;
int r2 = r/2;
int c2 = c;
for (y = 0; y < r2; y++)
{
for (x = 0; x < c; x++)
{
matrix[y + r2][x] = matrix[y][x] * 2 -1;
matrix[y][x] *= 2;
}
}
c *=2;
if (c > tc) break;
for (y = 0; y < r; y++)
{
for (x= 0; x < c2; x++)
{
matrix[(y + r2) % r][x + c2] = matrix[y][x] * 2 -1;
matrix[y][x] *= 2;
}
}
}
/* Swap matrix width/height if necessary */
if (swapped)
{
for (r = 0; r < tr; r++)
{
for (c = 0; c < r; c++)
{
int t = matrix[r][c];
matrix[r][c] = matrix[c][r];
matrix[c][r] = t;
}
}
}
}
static bool
lf_power_of_2(int t)
{
if (t == (t&1)) return true;
return lf_power_of_2(t >> 1);
}
static void
lf_calculate_dither_table(
unsigned int *brightnesses,
int value_count,
double max,
int total_columns,
int matrix[8],
unsigned int answer_pixel_values[8][256],
unsigned long pixel_values[256])
{
int i, c, j;
double brightness_factor = 255.0 /
(brightnesses[value_count - 1] -
brightnesses[0]);
for (c = 0; c < total_columns; c++)
{
for (i = 1; i < value_count; i++)
{
int l = brightnesses[i-1];
int u = brightnesses[i];
l -= brightnesses[0];
u -= brightnesses[0];
l = (int)((double)l * brightness_factor + 0.001);
u = (int)((double)u * brightness_factor + 0.001);
if(u != l) for (j = l; j <= u; j++)
{
if (((double)(j-l) / (double)(u-l)) <=
((double)(matrix[c]-1) / max))
answer_pixel_values[c][j] = pixel_values[i-1];
else
answer_pixel_values[c][j] = pixel_values[i];
/*
* Special hack to avoid spotty saturated colors
*/
if(u == 255 && j == 255)
answer_pixel_values[c][j] = pixel_values[i];
}
}
}
for (c = total_columns; c < 4; c++)
{
for (i = 0; i < 256; i++)
{
answer_pixel_values[c][i] = answer_pixel_values[c % total_columns][i];
}
}
}
static bool
lf_check_rows_columns(int total_rows, int total_columns)
{
/* Check inputs are reasonable */
if (total_rows > 4 ||
total_columns > 4 ||
total_rows < 1 ||
total_columns < 1 ||
!lf_power_of_2(total_rows) ||
!lf_power_of_2(total_columns))
{
return false;
}
if (total_rows / total_columns > 2) return false;
if (total_columns / total_rows > 2) return false;
return true;
}
cct_true_8_dither_table
ccf_create_true_8_dither_table(
int row,
int total_rows,
int total_columns,
cct_cube cube)
{
cct_true_8_dither_table answer;
int matrix[4][4];
int i;
int rgb;
double max;
if (!lf_check_rows_columns(total_rows, total_columns))
return 0;
for (rgb = 0; rgb < 3; rgb++)
{
/* relies on union fields coinciding */
if (cube->u.mapping.value_count[rgb] < 2) return 0;
}
lf_create_dither_matrix(matrix, total_rows, total_columns);
max = total_rows * total_columns - 1;
answer = (cct_true_8_dither_table)
calloc(1, sizeof(struct ccs_true_8_dither_table));
answer->column_count = total_columns;
answer->mapping_used = (cube->cube_type == cube_mapping);
if (answer->mapping_used)
{
for (i = 0; i < 256; i++)
answer->mapping[i] = cube->u.mapping.mapping[i];
}
for (rgb = 0; rgb < 3; rgb++)
{
lf_calculate_dither_table(
cube->u.mapping.brightnesses[rgb],
cube->u.mapping.value_count[rgb],
max,
total_columns,
matrix[row],
answer->pixel_values[rgb],
cube->u.mapping.pixel_values[rgb]);
}
return answer;
}
/*
* If a color is exactly allocated on the screen, outside of the
* color cube, there is no need to dither that color, it can be
* displayed directly. This routine amends the tables accordingly
*/
void
ccf_set_specially_allocated(
cct_8_8_dither_table table,
unsigned char entry,
unsigned int pixel)
{
int c;
for(c = 0; c < 4; c++)
{
table->pixel_values[c][entry] = pixel;
}
}
cct_8_8_dither_table
ccf_create_gray_dither_table(
int row,
int total_rows,
int total_columns,
cct_cube cube)
{
cct_8_8_dither_table answer;
int matrix[4][4];
double max;
if(!lf_check_rows_columns(total_rows, total_columns)) return 0;
if (cube->u.grayscale.value_count < 2) return 0;
lf_create_dither_matrix(matrix, total_rows, total_columns);
max = total_rows * total_columns - 1;
answer = (cct_8_8_dither_table)
calloc(1, sizeof(struct ccs_8_8_dither_table));
answer->column_count = total_columns;
lf_calculate_dither_table(
cube->u.grayscale.brightnesses,
cube->u.grayscale.value_count,
max,
total_columns,
matrix[row],
answer->pixel_values,
cube->u.grayscale.pixel_values);
return answer;
}
/*
* For 8-bit palette input we do not need to convert to true-color
* before dithering. We simply make a new table that takes palette
* entries as inputs
*/
cct_8_8_dither_table
ccf_true_8_to_8_8_dither_table(
cct_true_8_dither_table true_8,
int map_size,
unsigned char *colormaps[3])
{
cct_8_8_dither_table answer;
int c,i,rgb;
answer =
(cct_8_8_dither_table) calloc(1, sizeof(struct ccs_8_8_dither_table));
answer->column_count = true_8->column_count;
for (c = 0; c < 4; c++)
{
for (i = 0; i < map_size; i++)
{
for (rgb = 0; rgb < 3; rgb++)
{
answer->pixel_values[c][i] +=
true_8->pixel_values[rgb][c][colormaps[rgb][i]];
}
if (true_8->mapping_used)
answer->pixel_values[c][i] =
true_8->mapping[answer->pixel_values[c][i]];
}
}
return answer;
}
/*
* How many 1 bits are there in the longword.
* Low performance, do not call often.
*/
static int
lf_number_of_bits_set(unsigned long a)
{
if (!a) return 0;
if (a & 1) return 1 + lf_number_of_bits_set(a >> 1);
return(lf_number_of_bits_set(a >> 1));
}
/*
* Shift the 0s in the least significant end out of the longword.
* Low performance, do not call often.
*/
static unsigned long
lf_shifted_down(unsigned long a)
{
if (!a) return 0ul;
if (a & 1) return a;
return lf_shifted_down(a >> 1);
}
/*
* How many 0 bits are there at most significant end of longword.
* Low performance, do not call often.
*/
static int
lf_free_bits_at_top(unsigned long a)
{
/* assume char is 8 bits */
if (!a) return sizeof(unsigned long) * 8;
/* assume twos complement */
if (((long)a) < 0l) return 0;
return 1 + lf_free_bits_at_top(a << 1);
}
/*
* How many 0 bits are there at least significant end of longword.
* Low performance, do not call often.
*/
static int
lf_free_bits_at_bottom(unsigned long a)
{
/* assume char is 8 bits */
if (!a) return sizeof(unsigned long) * 8;
if (((long)a) & 1l) return 0;
return 1 + lf_free_bits_at_bottom(a >> 1);
}
cct_true_true_conversion_table
ccf_create_true_true_conversion_table(cct_cube cube)
{
cct_true_true_conversion_table answer;
int i,rgb;
answer = (cct_true_true_conversion_table)
calloc(1, sizeof(struct ccs_true_true_conversion_table));
for (rgb = 0; rgb < 3; rgb++)
{
int bits_set = lf_number_of_bits_set(cube->u.true_color.color_mask[rgb]);
int free_bits_at_bottom =
lf_free_bits_at_bottom(cube->u.true_color.color_mask[rgb]);
for (i = 0; i < 256; i++)
{
answer->pixel_values[rgb][i] = (i >> (8 - bits_set)) << free_bits_at_bottom;
if (rgb == 0)
answer->pixel_values[rgb][i] += cube->u.true_color.color_base;
}
}
return answer;
}
/*
* For 8-bit palette input we do not need to convert to true-color
* one component at a time. We can do it in one lookup. This generates
* the table.
*/
cct_8_true_conversion_table
ccf_true_true_to_8_true_conversion_table(
cct_true_true_conversion_table true_true,
int map_size,
unsigned char *colormaps[3])
{
cct_8_true_conversion_table answer;
int i, rgb;
answer = (cct_8_true_conversion_table)
calloc(1, sizeof(struct ccs_8_true_conversion_table));
for (i = 0; i < map_size; i++)
{
for (rgb = 0; rgb < 3; rgb ++)
{
answer->pixel_values[i] +=
true_true->pixel_values[rgb][colormaps[rgb][i]];
}
}
return answer;
}
/*
* Create gray table. This is assuming we have enough entries in the
* colormap that we do not need to dither, but can simply remap. This
* is about 64 entries, 32 at a push.
*/
cct_8_true_conversion_table
ccf_create_gray_conversion_table(cct_cube cube)
{
cct_8_true_conversion_table answer;
int i;
answer = (cct_8_true_conversion_table)
calloc(1, sizeof(struct ccs_8_true_conversion_table));
for (i = 0; i < 256; i++)
{
int j;
int min_dist = 400000; /* big number ! */
int min_entry;
for (j = 0; j < cube->u.grayscale.value_count; j++)
{
int dist;
dist = i - cube->u.grayscale.brightnesses[j];
if (dist < 0) dist = -dist;
if (dist < min_dist)
{
min_dist = dist;
min_entry = j;
}
}
answer->pixel_values[i] = cube->u.grayscale.pixel_values[min_entry];
}
return answer;
}
/*
* If we are converting 8-bit palette to grayscale, we do not
* need to convert every pixel to gray, we can simply integrate
* the color map into the dither table
*/
cct_8_8_dither_table
ccf_gray_to_gray_dither_convert(
cct_8_8_dither_table table,
int map_size,
unsigned char *colormaps[3])
{
int i;
int c;
cct_8_8_dither_table answer;
answer = (cct_8_8_dither_table)calloc(1, sizeof(struct ccs_8_8_dither_table));
answer->column_count = table->column_count;
for (i = 0; i < map_size; i++)
{
unsigned int bright =
RedIntensity[colormaps[0][i]] +
GreenIntensity[colormaps[1][i]] +
BlueIntensity[colormaps[2][i]];
bright >>= 8;
for (c = 0; c < 4; c++)
{
answer->pixel_values[c][i] = table->pixel_values[c][bright];
}
}
return answer;
}
/*
* If we are converting 8-bit palette to grayscale, we do not
* need to convert every pixel to gray, we can simply integrate
* the color map into the conversion table
*/
cct_8_true_conversion_table
ccf_gray_to_gray_conversion_convert(
cct_8_true_conversion_table table,
int map_size,
unsigned char *colormaps[3])
{
int i;
cct_8_true_conversion_table answer;
answer = (cct_8_true_conversion_table)
calloc(1, sizeof(struct ccs_8_true_conversion_table));
for (i = 0; i < map_size; i++)
{
unsigned int bright =
RedIntensity[colormaps[0][i]] +
GreenIntensity[colormaps[1][i]] +
BlueIntensity[colormaps[2][i]];
bright >>= 8;
answer->pixel_values[i] = table->pixel_values[bright];
}
return answer;
}

218
image/colorcube.h Normal file
View File

@ -0,0 +1,218 @@
/* colorcube.h
*
* (c) 1995 Erik Corry. ehcorry@inet.uni-c.dk erik@kroete2.freinet.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This contains routines which take a general description of which
* colors we have managed to allocate from the device, and produces
* tables that can be used to convert various input formats to use
* these colors. The dither algorithm used (where necessary) is a
* dispersed table dither up to 8x8 in size, from an automatically
* generated table.
*
* The routines here are not necessarily fast (some of them are very
* slow indeed), but they generate tables that can be used in fast code.
*
*/
#ifndef COLORCUBE_H_INCLUDED
#define COLORCUBE_H_INCLUDED 1
typedef struct ccs_cube *cct_cube;
typedef union ccu_dither_table cct_dither_table;
typedef struct ccs_true_8_dither_table *cct_true_8_dither_table;
typedef struct ccs_8_8_dither_table *cct_8_8_dither_table;
typedef struct ccs_8_true_conversion_table *cct_8_true_conversion_table;
typedef struct ccs_true_true_conversion_table *cct_true_true_conversion_table;
union ccu_dither_table
{
void *generic_dither_table;
cct_true_8_dither_table true_8_dither;
cct_8_8_dither_table eight_8_dither;
cct_8_true_conversion_table eight_true_conversion;
cct_true_true_conversion_table true_true_conversion;
};
typedef enum
{
cube_true_color,
cube_mapping,
cube_no_mapping,
cube_grayscale
} cce_cube_type;
/*
* General description of colors that have been allocated on output
* device.
*
* For a small rxbxg cuboid, mapping or no_mapping is used.
* value_count[0] is the number of red planes, etc. Brightness
* is measured 0-255. To get a pixel number, add the pixel
* values together for r, g and b and then use the mapping table if
* necessary.
*
* For true_color (incl. 'hicolor') no dithering is necessary.
* Just shift and mask.
*
* brightnesses should be sorted in ascending order!
*
*/
struct ccs_cube
{
union
{
struct
{
unsigned long pixel_values[3][256];
unsigned int brightnesses[3][256];
int value_count[3];
} no_mapping;
struct
{
unsigned long pixel_values[3][256];
unsigned int brightnesses[3][256];
int value_count[3];
unsigned int mapping[256];
} mapping;
struct
{
unsigned int color_mask[3];
unsigned int color_base;
} true_color;
struct
{
unsigned long pixel_values[256];
unsigned int brightnesses[256];
int value_count;
} grayscale;
} u;
cce_cube_type cube_type;
};
struct ccs_special_color
{
unsigned long pixel;
unsigned char brightnesses[3];
};
typedef struct ccs_special_color *cct_special_color;
/*
* Table for dithering from true-color to a colorcube allocated on
* an 4-16 bit pseudocolor screen. This table is only good for one
* row of a dither table, (which could be 2x2 up to 4x4). If the
* table has less than 4 columns, the first entries are duplicated
* so that 4 can always be assumed when using the table for simplicity.
*
* Since the mapping table has only 256 entries it can only be used on
* screens with 8 bits per pixel or less.
*/
struct ccs_true_8_dither_table
{
unsigned int mapping[256];
unsigned int pixel_values[3][4][256];
int column_count; /* 2-8 */
bool mapping_used;
};
/*
* Table for dithering from an 8-bit palette image to a color image
* based on a fixed allocation of colors on the screen.
*
* Also used as a:
* Table for dithering from gray 8-bit pixels to less gray levels.
* Works right down to only 2 different colors i.e. black and white
* See above wrt. column_count
*/
struct ccs_8_8_dither_table
{
unsigned int pixel_values[4][256];
int column_count; /* 2-8 */
};
/*
* Table for converting 8-bit colormap pixels to true color (or
* hi-color) pixels on screen.
*/
struct ccs_8_true_conversion_table
{
unsigned int pixel_values[256];
};
/*
* Table for converting a true-color 24-bit image to a true-color
* or hi-color screen with a different information layout.
*/
struct ccs_true_true_conversion_table
{
unsigned int pixel_values[3][256];
};
cct_true_8_dither_table
ccf_create_true_8_dither_table(
int row,
int total_rows,
int total_columns,
cct_cube cube);
cct_8_8_dither_table
ccf_create_gray_dither_table(
int row,
int total_rows,
int total_columns,
cct_cube cube);
cct_8_8_dither_table
ccf_true_8_to_8_8_dither_table(
cct_true_8_dither_table true_8,
int map_size,
unsigned char *colormaps[3]);
cct_true_true_conversion_table
ccf_create_true_true_conversion_table(cct_cube cube);
cct_8_true_conversion_table
ccf_true_true_to_8_true_conversion_table(
cct_true_true_conversion_table true_true,
int map_size,
unsigned char *colormaps[3]);
cct_8_true_conversion_table
ccf_create_gray_conversion_table(cct_cube cube);
cct_8_8_dither_table
ccf_gray_to_gray_dither_convert(
cct_8_8_dither_table table,
int map_size,
unsigned char *colormaps[3]);
cct_8_true_conversion_table
ccf_gray_to_gray_conversion_convert(
cct_8_true_conversion_table table,
int map_size,
unsigned char *colormaps[3]);
void
ccf_set_specially_allocated(
cct_8_8_dither_table table,
unsigned char entry,
unsigned int pixel);
#endif /* COLORCUBE_H_INCLUDED */

1040
image/dispdither.c Normal file

File diff suppressed because it is too large Load Diff

101
image/dispdither.h Normal file
View File

@ -0,0 +1,101 @@
/* dispdither.h
*
* (c) 1995 Erik Corry. ehcorry@inet.uni-c.dk erik@kroete2.freinet.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This contains routines which dither or convert image data from 8 or
* 24 bit input data to 1/2/4/8/16/24/32 bit output, possibly dithered.
*/
#ifndef DISPDITHER_H_INCLUDED
#define DISPDITHER_H_INCLUDED
#include "colorcube.h"
/*
* ddt_dither_fn is a pointer to a function returning void
*/
typedef void (*ddt_dither_fn)();
/*
* 4, 8, 16 obpp
*/
void
ddf_color_dither_line_24(
cct_dither_table table,
unsigned char *input,
unsigned char *output,
int output_bits_per_pixel,
int pixel_count);
/*
* 1, 2, 4, 8, 16 obpp
*/
void
ddf_gray_dither_line_24(
cct_dither_table table,
unsigned char *input,
unsigned char *output,
int output_bits_per_pixel,
int pixel_count);
/*
* 4, 8, 16 obpp
*/
void
ddf_gray_convert_line_24(
cct_dither_table table,
unsigned char *input,
unsigned char *output,
int output_bits_per_pixel,
int pixel_count);
/*
* 1, 2, 4, 8, 16 obpp
*/
void
ddf_dither_line_8(
cct_dither_table table,
unsigned char *input,
unsigned char *output,
int output_bits_per_pixel,
int pixel_count);
/*
* 4, 8, 16, 24, 32 obpp
*/
void
ddf_convert_line_8(
cct_dither_table table,
unsigned char *input,
unsigned char *output,
int output_bits_per_pixel,
int pixel_count);
/*
* 16, 24, 32 obpp
*/
void
ddf_convert_line_24(
cct_dither_table table,
unsigned char *input,
unsigned char *output,
int output_bits_per_pixel,
int pixel_count);
#endif /* DISPDITHER_H_INCLUDED */

740
image/gif.c Normal file
View File

@ -0,0 +1,740 @@
/*
* gif.c:
*
* Modified to be called so that GIFs can be decoded "on-the-fly".
* Sort of. Reparses lots of data it doesn't have to.
* John Kilburg <john@cs.unlv.edu>
*
* adapted from code by kirk johnson (tuna@athena.mit.edu). most of this
* code is unchanged. -- jim frost 12.31.89
*
* gifin.c
* kirk johnson
* november 1989
*
* routines for reading GIF files
*
* Copyright 1989 Kirk L. Johnson
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this
* permission notice appear in supporting documentation. The
* author makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
* OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "imagep.h"
#include "image_endian.h"
#include "image_format.h"
#include "gifp.h"
/* start line for interlacing */
static int interlace_start[4] = { 0, 4, 2, 1 };
/* rate at which we accelerate vertically */
static int interlace_rate[4] = { 8, 8, 4, 2 };
/* how often to copy the line */
static int interlace_copy[4] = { 8, 4, 2, 1 };
static int gs_read_image_header _ArgProto((gifState *));
static int gs_read_sig _ArgProto((gifState *));
static int gs_read_data_block _ArgProto((gifState *));
static int gs_read _ArgProto((gifState *, byte **, int));
static int gs_open_file _ArgProto((gifState *));
static int gs_open_image _ArgProto((gifState *));
static int gs_get_pixel _ArgProto((gifState *, int *));
static int gs_init_decoder _ArgProto((gifState *));
/*
* read GIF data
*/
static int
gs_read(gs, b, blen)
gifState *gs;
byte **b;
int blen;
{
if (gs->datalen < blen + gs->pos) return(0);
*b = gs->data + gs->pos;
gs->pos += blen;
return(blen);
}
/*
* gs_read_sig
*
*/
static int
gs_read_sig(gs)
gifState *gs;
{
byte *b;
/* check GIF signature */
if (gs_read(gs, &b, GIF_SIG_LEN) != GIF_SIG_LEN) return(GS_NEED_DATA);
if ((strncmp((char *)b, GIF_SIG, strlen(GIF_SIG)) != 0) &&
(strncmp((char *)b, GIF_SIG_89, strlen(GIF_SIG_89)) != 0))
{
return(GS_ERR_BAD_SIG);
}
gs->state = GS_OPEN_FILE;
return(GS_SUCCESS);
}
/*
* gs_open_file
*
* open a GIF file
*/
static int
gs_open_file(gs)
gifState *gs;
{
byte *b;
/* read screen descriptor */
if (gs_read(gs, &b, GIF_SD_SIZE) != GIF_SD_SIZE) return(GS_NEED_DATA);
/* decode screen descriptor */
gs->rast_width = (b[1] << 8) + b[0];
gs->rast_height = (b[3] << 8) + b[2];
gs->g_cmap_flag = (b[4] & 0x80) ? 1 : 0;
gs->color_bits = ((b[4] & 0x70) >> 4) + 1;
gs->g_pixel_bits = (b[4] & 0x07) + 1;
gs->bg_color = b[5];
/* load global colormap */
if (gs->g_cmap_flag)
{
gs->g_ncolors = (1 << gs->g_pixel_bits);
gs->g_ncolors_pos = 0;
gs->state = GS_LOAD_G_CMAP;
}
else
{
gs->state = GS_OPEN_IMAGE;
gs->g_ncolors_pos = 0;
gs->g_ncolors = 0;
}
gs->have_dimensions = 1;
return(GS_SUCCESS);
}
/*
* gs_init_decoder
*
* This isn't a separate state.
*/
static int
gs_init_decoder(gs)
gifState *gs;
{
int i;
byte *b;
if (gs_read(gs, &b, 1) != 1) return(GS_NEED_DATA);
gs->root_size = (int)(*b);
gs->clr_code = 1 << gs->root_size;
gs->eoi_code = gs->clr_code + 1;
gs->table_size = gs->clr_code + 2;
gs->code_size = gs->root_size + 1;
gs->code_mask = (1 << gs->code_size) - 1;
gs->work_bits = 0;
gs->work_data = 0;
gs->buf_idx = 0;
gs->buf_cnt = 0;
gs->first = 0;
/* initialize string table */
for (i = 0; i < STAB_SIZE; i++)
{
gs->prefix[i] = NULL_CODE;
gs->extnsn[i] = i;
}
/* initialize pixel stack */
gs->pstk_idx = 0;
gs->state = GS_MAKE_IMAGE;
return(GS_SUCCESS);
}
/*
* gs_open_image
*/
static int
gs_open_image(gs)
gifState *gs;
{
int separator;
byte *b;
int rval;
int pos = gs->pos;
if (gs_read(gs, &b, 1) != 1) return(GS_NEED_DATA);
separator = (int)(*b);
if (separator == GIF_EXTENSION)
{
/* get the extension function byte */
if (gs_read(gs, &b, 1) != 1)
{
gs->pos = pos;
return(GS_NEED_DATA);
}
if (*b == 0xf9)
{
if ((rval = gs_read_data_block(gs)) != GS_SUCCESS)
{
gs->pos = pos;
return(rval);
}
if (gs->buf[0] & 0x1) gs->transparent = gs->buf[3];
}
else
{
if ((rval = gs_read_data_block(gs)) != GS_SUCCESS)
{
gs->pos = pos;
return(rval);
}
}
return(GS_SUCCESS);
}
else if (separator == GIF_TERMINATOR) return(GS_DONE);
/*
* If it's a broken GIF, just keep scanning till we meet a
* separator we recognise.
*/
else if (separator != GIF_SEPARATOR) return(GS_SUCCESS);
gs->state = GS_READ_IMAGE_HEADER;
return(GS_SUCCESS);
}
/*
* gs_read_image_header
*/
static int
gs_read_image_header(gs)
gifState *gs;
{
byte *b;
/* read image descriptor */
if (gs_read(gs, &b, GIF_ID_SIZE) != GIF_ID_SIZE) return(GS_NEED_DATA);
/* decode image descriptor */
gs->img_left = (b[1] << 8) + b[0];
gs->img_top = (b[3] << 8) + b[2];
gs->img_width = (b[5] << 8) + b[4];
gs->img_height = (b[7] << 8) + b[6];
gs->l_cmap_flag = (b[8] & 0x80) ? 1 : 0;
gs->interlace_flag = (b[8] & 0x40) ? 1 : 0;
gs->l_pixel_bits = (b[8] & 0x07) + 1;
/* load local colormap */
if (gs->l_cmap_flag)
{
gs->l_ncolors = (1 << gs->l_pixel_bits);
gs->l_ncolors_pos = 0;
gs->state = GS_LOAD_L_CMAP;
}
else
{
gs->l_ncolors = 0;
gs->l_ncolors_pos = 0;
gs->state = GS_INIT_DECODER;
}
return(GS_SUCCESS);
}
/*
* gs_load_l_cmap
*
* load a local colormap from the input stream
*/
static int
gs_load_l_cmap(gs)
gifState *gs;
{
byte *b;
if (gs_read(gs, &b, 3) != 3) return(GS_NEED_DATA);
gs->l_cmap[GIF_RED][gs->l_ncolors_pos] = b[GIF_RED] << 8;
gs->l_cmap[GIF_GRN][gs->l_ncolors_pos] = b[GIF_GRN] << 8;
gs->l_cmap[GIF_BLU][gs->l_ncolors_pos] = b[GIF_BLU] << 8;
gs->l_ncolors_pos++;
if (gs->l_ncolors_pos == gs->l_ncolors) gs->state = GS_INIT_DECODER;
return(GS_SUCCESS);
}
/*
* gs_load_g_cmap
*
* load a global colormap from the input stream
*/
static int
gs_load_g_cmap(gs)
gifState *gs;
{
byte *b;
if (gs_read(gs, &b, 3) != 3) return(GS_NEED_DATA);
gs->g_cmap[GIF_RED][gs->g_ncolors_pos] = b[GIF_RED] << 8;
gs->g_cmap[GIF_GRN][gs->g_ncolors_pos] = b[GIF_GRN] << 8;
gs->g_cmap[GIF_BLU][gs->g_ncolors_pos] = b[GIF_BLU] << 8;
gs->g_ncolors_pos++;
if (gs->g_ncolors_pos == gs->g_ncolors) gs->state = GS_OPEN_IMAGE;
return(GS_SUCCESS);
}
/*
* gs_read_data_block
*
* read a new data block from the input stream
*/
static int
gs_read_data_block(gs)
gifState *gs;
{
byte *b;
int cnt;
int pos = gs->pos;
/* read the data block header */
if (gs_read(gs, &b, 1) != 1) return(GS_NEED_DATA);
cnt = (int)(*b);
/* read the data block body */
if (gs_read(gs, &gs->buf, cnt) != cnt)
{
gs->pos = pos;
return(GS_NEED_DATA);
}
gs->buf_idx = 0;
gs->buf_cnt = cnt;
return(GS_SUCCESS);
}
/*
* gs_make_image
*/
static int
gs_make_image(gs)
gifState *gs;
{
Image *image;
int i;
bool gray = true;
if (gs->l_cmap_flag)
{
image = newRGBImage(gs->img_width, gs->img_height, gs->l_pixel_bits);
if (!image) return(GS_ERR_NOMEM);
image->rgb.red = gs->l_cmap[GIF_RED];
image->rgb.green = gs->l_cmap[GIF_GRN];
image->rgb.blue = gs->l_cmap[GIF_BLU];
image->rgb.used = gs->l_ncolors;
}
else
{
image = newRGBImage(gs->img_width, gs->img_height, gs->g_pixel_bits);
if (!image) return(GS_ERR_NOMEM);
image->rgb.red = gs->g_cmap[GIF_RED];
image->rgb.green = gs->g_cmap[GIF_GRN];
image->rgb.blue = gs->g_cmap[GIF_BLU];
image->rgb.used = gs->g_ncolors;
}
for(i = 0; i < image->rgb.used; i++)
if(image->rgb.red[i] >> 8 != image->rgb.green[i] >> 8 ||
image->rgb.red[i] >> 8 != image->rgb.blue[i] >> 8)
{
gray = false;
break;
}
if(gray) image->type = IGRAY;
image->transparent = gs->transparent;
gs->image = image;
gs->state = GS_DECODE_DATA;
image->x = 0;
image->pass = 0;
if (gs->interlace_flag) image->y = interlace_start[image->pass];
else image->y = 0;
return(GS_SUCCESS);
}
/*
* gs_get_pixel
*
* try to read next pixel from the raster, return result in *pel
*/
static int
gs_get_pixel(gs, pel)
gifState *gs;
int *pel;
{
int code;
int rval;
/* decode until there are some pixels on the pixel stack */
while (gs->pstk_idx == 0)
{
while (gs->work_bits < gs->code_size)
{
int pos = gs->pos;
if (gs->buf_idx == gs->buf_cnt)
{
if ((rval = gs_read_data_block(gs)) != GS_SUCCESS)
{
gs->pos = pos;
return(rval);
}
}
gs->work_data |= ((unsigned) gs->buf[gs->buf_idx++]) << gs->work_bits;
gs->work_bits += 8;
}
/* get the next code */
code = gs->work_data & gs->code_mask;
gs->work_data >>= gs->code_size;
gs->work_bits -= gs->code_size;
/* interpret the code */
if (code > gs->table_size || code == gs->eoi_code)
{
/* Format Error */
return(GS_ERR_EOF);
}
if (code == gs->clr_code)
{
/* reset decoder */
gs->code_size = gs->root_size + 1;
gs->code_mask = (1 << gs->code_size) - 1;
gs->table_size = gs->clr_code + 2;
gs->prev_code = NULL_CODE;
continue;
}
if (gs->prev_code == NULL_CODE)
{
gs->pstk[gs->pstk_idx++] = gs->extnsn[code];
gs->prev_code = code;
gs->first = code;
continue;
}
else
{
int in_code = code;
if (code == gs->table_size)
{
gs->pstk[gs->pstk_idx++] = gs->first;
code = gs->prev_code;
}
while (code > gs->clr_code)
{
gs->pstk[gs->pstk_idx++] = gs->extnsn[code];
code = gs->prefix[code];
}
gs->first = gs->extnsn[code];
/* Add a new string to the string table. */
if (gs->table_size >= PSTK_SIZE)
return(GS_ERR_EOF);
gs->pstk[gs->pstk_idx++] = gs->first;
gs->prefix[gs->table_size] = gs->prev_code;
gs->extnsn[gs->table_size] = gs->first;
gs->table_size ++;
if (((gs->table_size & gs->code_mask)) == 0
&& (gs->table_size < PSTK_SIZE))
{
gs->code_size ++;
gs->code_mask += gs->table_size;
}
gs->prev_code = in_code;
}
}
*pel = (int)gs->pstk[--gs->pstk_idx];
return(GS_SUCCESS);
}
/*
* gs_decode_data
*
* TODO: This routine looks like something of a performance catastrophe
*/
static int
gs_decode_data(gs)
gifState *gs;
{
Image *image = gs->image;
int pixel;
byte *pixptr;
int rval;
int xpix;
if (gs->interlace_flag)
{
if (image->x == image->width)
{
image->y += interlace_rate[image->pass];
while (image->y >= image->height)
{
image->pass++;
if (image->pass == 4) return(GS_DONE);
image->y = interlace_start[image->pass];
}
image->x = 0;
}
}
else
{
if (image->x == image->width)
{
image->y++;
image->x = 0;
}
if (image->y == image->height) return(GS_DONE);
}
xpix = image->y * image->bytes_per_line +
(image->x * image->pixlen) / CHAR_BITS;
if (xpix < image->height * image->bytes_per_line)
{
pixptr = image->data + xpix;
if ((rval = gs_get_pixel(gs, &pixel)) != GS_SUCCESS) return(rval);
if(image->pixlen == 1)
{
int bitpos = image->x & 7;
if (bitpos == 0) *pixptr = 0;
# ifdef CHIMERA_LITTLE_ENDIAN
pixel <<= bitpos;
# else
pixel <<= 7 - bitpos;
# endif
*pixptr |= pixel;
}
else /* pixlen is 8 bits */
{
*pixptr = pixel;
}
}
image->x++;
if (image->x == image->width)
{
if (gs->interlace_flag && interlace_copy[image->pass] > 1)
{
byte *origline = image->data + image->y * image->bytes_per_line;
byte *copyline = origline + image->bytes_per_line;
int i;
for (i = 1;
i < interlace_copy[image->pass] && image->y + i < image->height;
i++, copyline += image->bytes_per_line)
{
memcpy(copyline, origline, image->bytes_per_line);
}
if (gs->lineProc != NULL)
(gs->lineProc)(gs->closure,
image->y,
MIN(image->y + interlace_copy[image->pass] - 1,
image->height - 1));
}
else
{
if (gs->lineProc != NULL)
(gs->lineProc)(gs->closure, image->y, image->y);
}
}
return(GS_SUCCESS);
}
/*
* gifDestroy
*
* This doesn't do the whole job!
*/
static void
gifDestroy(pointer)
void *pointer;
{
gifState *gs = (gifState *)pointer;
if (gs->image)
freeImage(gs->image);
gs->image = 0;
if (gs != NULL) free_mem(gs);
return;
}
/*
* gifAddData
*
* 0 success
* 1 needs more data
* -1 error
*
* Assumes data is the address of the beginning of the GIF data and len
* is the total length.
*/
static int
gifAddData(pointer, data, len, data_ended)
void *pointer;
byte *data;
int len;
bool data_ended;
{
gifState *gs = (gifState *)pointer;
int rval;
int pos;
gs->data = data;
gs->datalen = len;
for ( ; ; )
{
pos = gs->pos; /* save in case we need to rewind */
switch (gs->state)
{
case GS_READ_SIG:
rval = gs_read_sig(gs);
break;
case GS_OPEN_FILE:
rval = gs_open_file(gs);
break;
case GS_OPEN_IMAGE:
if ((rval = gs_open_image(gs)) == GS_DONE) return(0);
break;
case GS_READ_IMAGE_HEADER:
rval = gs_read_image_header(gs);
break;
case GS_LOAD_G_CMAP:
rval = gs_load_g_cmap(gs);
break;
case GS_LOAD_L_CMAP:
rval = gs_load_l_cmap(gs);
break;
case GS_MAKE_IMAGE:
rval = gs_make_image(gs);
break;
case GS_DECODE_DATA:
if ((rval = gs_decode_data(gs)) == GS_DONE) return(0);
break;
case GS_INIT_DECODER:
rval = gs_init_decoder(gs);
break;
default:
rval = GS_ERR_BAD_STATE;
}
if (rval == GS_NEED_DATA)
{
gs->pos = pos;
if(data_ended) return -1;
return(1);
}
else if (rval != GS_SUCCESS) return(-1);
}
return(-1);
}
static Image *
gifGetImage(void *pointer)
{
gifState *gs = (gifState *)pointer;
return gs->image;
}
/*
* gifInit
*
* Initialize GIF reader state
*/
void
gifInit(lineProc, closure, if_vector)
FormatLineProc lineProc;
void *closure;
struct ifs_vector *if_vector;
{
gifState *gs;
gs = (gifState *)alloc_mem(sizeof(gifState));
memset(gs, 0, sizeof(gifState));
gs->state = GS_READ_SIG;
gs->transparent = -1;
gs->lineProc = lineProc;
gs->closure = closure;
if_vector->image_format_closure = (void *)gs;
if_vector->initProc = &gifInit;
if_vector->destroyProc = &gifDestroy;
if_vector->addDataProc = &gifAddData;
if_vector->getImageProc = &gifGetImage;
}

91
image/gif.h Normal file
View File

@ -0,0 +1,91 @@
/*
* gif.h
*
* Copyright (C) 1995, John Kilburg (john@isri.unlv.edu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __GIF_H__
#define __GIF_H__ 1
#define STAB_SIZE 4096 /* string table size */
#define PSTK_SIZE 4096 /* pixel stack size */
/*
* gifState
*/
typedef struct _gif_state
{
int state; /* state of GIF reader */
void (*lineProc)(); /* line callback */
void *closure; /* closure for callback */
Image *image;
int root_size; /* root code size */
int clr_code; /* clear code */
int eoi_code; /* end of information code */
int code_size; /* current code size */
int code_mask; /* current code mask */
int prev_code; /* previous code */
int work_data; /* working bit buffer */
int work_bits; /* working bit count */
byte *buf; /* byte buffer */
int buf_cnt; /* byte count */
int buf_idx; /* buffer index */
int table_size; /* string table size */
int prefix[STAB_SIZE]; /* string table : prefixes */
int extnsn[STAB_SIZE]; /* string table : extensions */
byte pstk[PSTK_SIZE]; /* pixel stack */
int pstk_idx; /* pixel stack pointer */
int pos; /* current read position */
byte *data; /* pointer to data */
int datalen; /* length of data */
int rast_width; /* raster width */
int rast_height; /* raster height */
byte g_cmap_flag; /* global colormap flag */
int g_pixel_bits; /* bits per pixel, global colormap */
int g_ncolors; /* number of colors, global colormap */
int g_ncolors_pos; /* number of colors processed, global colormap */
Intensity g_cmap[3][256]; /* global colormap */
int bg_color; /* background color index */
int color_bits; /* bits of color resolution */
int transparent; /* transparent color index */
int img_left; /* image position on raster */
int img_top; /* image position on raster */
int img_width; /* image width */
int img_height; /* image height */
byte have_dimensions; /* 1 when dimensions known */
byte l_cmap_flag; /* local colormap flag */
int l_pixel_bits; /* bits per pixel, local colormap */
int l_ncolors; /* number of colors, local colormap */
int l_ncolors_pos; /* number of colors processed, local colormap */
Intensity l_cmap[3][256]; /* local colormap */
byte interlace_flag; /* interlace image format flag */
} gifState;
gifState *gifInit _ArgProto((void (*)(), void *));
void gifDestroy _ArgProto((gifState *));
int gifAddData _ArgProto((gifState *, byte *, int));
#endif

145
image/gifp.h Normal file
View File

@ -0,0 +1,145 @@
/*
* gifp.h
*
* Created from parts of old gifin.h
* John Kilburg (john@cs.unlv.edu)
*
* gifin.h
* kirk johnson
* november 1989
* external interface to gifin.c
*
* Copyright 1989 Kirk L. Johnson
* See the file COPYRIGHT for details
*/
/*
* the old gif.h file
*
* Copyright (C) 1995, John Kilburg (john@isri.unlv.edu)
*/
#define STAB_SIZE 4096 /* string table size */
#define PSTK_SIZE 4096 /* pixel stack size */
/*
* gifState
*/
typedef struct _gif_state
{
int state; /* state of GIF reader */
FormatLineProc lineProc; /* line callback */
void *closure; /* closure for callback */
Image *image;
int root_size; /* root code size */
int clr_code; /* clear code */
int eoi_code; /* end of information code */
int code_size; /* current code size */
int code_mask; /* current code mask */
int prev_code; /* previous code */
int first; /* */
unsigned work_data; /* working bit buffer */
int work_bits; /* working bit count */
byte *buf; /* byte buffer */
int buf_cnt; /* byte count */
int buf_idx; /* buffer index */
int table_size; /* string table size */
int prefix[STAB_SIZE]; /* string table : prefixes */
int extnsn[STAB_SIZE]; /* string table : extensions */
byte pstk[PSTK_SIZE]; /* pixel stack */
int pstk_idx; /* pixel stack pointer */
int pos; /* current read position */
byte *data; /* pointer to data */
int datalen; /* length of data */
int rast_width; /* raster width */
int rast_height; /* raster height */
byte g_cmap_flag; /* global colormap flag */
int g_pixel_bits; /* bits per pixel, global colormap */
int g_ncolors; /* number of colors, global colormap */
int g_ncolors_pos; /* number of colors processed, global colormap */
Intensity g_cmap[3][256]; /* global colormap */
int bg_color; /* background color index */
int color_bits; /* bits of color resolution */
int transparent; /* transparent color index */
int img_left; /* image position on raster */
int img_top; /* image position on raster */
int img_width; /* image width */
int img_height; /* image height */
byte have_dimensions; /* 1 when dimensions known */
byte l_cmap_flag; /* local colormap flag */
int l_pixel_bits; /* bits per pixel, local colormap */
int l_ncolors; /* number of colors, local colormap */
int l_ncolors_pos; /* number of colors processed, local colormap */
Intensity l_cmap[3][256]; /* local colormap */
byte interlace_flag; /* interlace image format flag */
} gifState;
/*
* end of old gif.h file
*/
/*
* gifin return codes
*/
#define GS_SUCCESS 0 /* success */
#define GS_DONE 1 /* no more images */
#define GS_NEED_DATA 2 /* needs more data */
#define GS_NEED_DATA_NOR 3 /* needs more data, no rewind */
#define GS_ERR_BAD_SD -1 /* bad screen descriptor */
#define GS_ERR_BAD_SEP -2 /* bad image separator */
#define GS_ERR_BAD_SIG -3 /* bad signature */
#define GS_ERR_EOD -4 /* unexpected end of raster data */
#define GS_ERR_EOF -5 /* unexpected end of input stream */
#define GS_ERR_FAO -6 /* file already open */
#define GS_ERR_IAO -7 /* image already open */
#define GS_ERR_NFO -8 /* no file open */
#define GS_ERR_NIO -9 /* no image open */
#define GS_ERR_BAD_STATE -10 /* bad state */
#define GS_ERR_NOMEM -11 /* allocation failure */
/*
* colormap indices
*/
#define GIF_RED 0
#define GIF_GRN 1
#define GIF_BLU 2
/*
* #defines, typedefs, and such
*/
#define GIF_SIG "GIF87a"
#define GIF_SIG_89 "GIF89a"
#define GIF_SIG_LEN 6 /* GIF signature length */
#define GIF_SD_SIZE 7 /* GIF screen descriptor size */
#define GIF_ID_SIZE 9 /* GIF image descriptor size */
#define GIF_SEPARATOR ',' /* GIF image separator */
#define GIF_EXTENSION '!' /* GIF extension block marker */
#define GIF_TERMINATOR ';' /* GIF terminator */
#define NULL_CODE -1 /* string table null code */
/*
* GIF states
*/
#define GS_OPEN_FILE 0
#define GS_OPEN_IMAGE 1
#define GS_LOAD_G_CMAP 2
#define GS_LOAD_L_CMAP 4
#define GS_DECODE_DATA 5
#define GS_MAKE_IMAGE 6
#define GS_INIT_DECODER 8
#define GS_READ_SIG 9
#define GS_READ_IMAGE_HEADER 10

127
image/halftone.c Normal file
View File

@ -0,0 +1,127 @@
/*
* halftone.c
*
* Copyright (c) 1995 Erik Corry
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* RGB intensity tables.
*/
unsigned short RedIntensity[256]= {
0, 77, 154, 231, 308, 385, 462, 539,
616, 693, 770, 847, 924, 1001, 1078, 1155,
1232, 1309, 1386, 1463, 1540, 1617, 1694, 1771,
1848, 1925, 2002, 2079, 2156, 2233, 2310, 2387,
2464, 2541, 2618, 2695, 2772, 2849, 2926, 3003,
3080, 3157, 3234, 3311, 3388, 3465, 3542, 3619,
3696, 3773, 3850, 3927, 4004, 4081, 4158, 4235,
4312, 4389, 4466, 4543, 4620, 4697, 4774, 4851,
4928, 5005, 5082, 5159, 5236, 5313, 5390, 5467,
5544, 5621, 5698, 5775, 5852, 5929, 6006, 6083,
6160, 6237, 6314, 6391, 6468, 6545, 6622, 6699,
6776, 6853, 6930, 7007, 7084, 7161, 7238, 7315,
7392, 7469, 7546, 7623, 7700, 7777, 7854, 7931,
8008, 8085, 8162, 8239, 8316, 8393, 8470, 8547,
8624, 8701, 8778, 8855, 8932, 9009, 9086, 9163,
9240, 9317, 9394, 9471, 9548, 9625, 9702, 9779,
9856, 9933,10010,10087,10164,10241,10318,10395,
10472,10549,10626,10703,10780,10857,10934,11011,
11088,11165,11242,11319,11396,11473,11550,11627,
11704,11781,11858,11935,12012,12089,12166,12243,
12320,12397,12474,12551,12628,12705,12782,12859,
12936,13013,13090,13167,13244,13321,13398,13475,
13552,13629,13706,13783,13860,13937,14014,14091,
14168,14245,14322,14399,14476,14553,14630,14707,
14784,14861,14938,15015,15092,15169,15246,15323,
15400,15477,15554,15631,15708,15785,15862,15939,
16016,16093,16170,16247,16324,16401,16478,16555,
16632,16709,16786,16863,16940,17017,17094,17171,
17248,17325,17402,17479,17556,17633,17710,17787,
17864,17941,18018,18095,18172,18249,18326,18403,
18480,18557,18634,18711,18788,18865,18942,19019,
19096,19173,19250,19327,19404,19481,19558,19635
};
unsigned short GreenIntensity[256]= {
0, 150, 300, 450, 600, 750, 900, 1050,
1200, 1350, 1500, 1650, 1800, 1950, 2100, 2250,
2400, 2550, 2700, 2850, 3000, 3150, 3300, 3450,
3600, 3750, 3900, 4050, 4200, 4350, 4500, 4650,
4800, 4950, 5100, 5250, 5400, 5550, 5700, 5850,
6000, 6150, 6300, 6450, 6600, 6750, 6900, 7050,
7200, 7350, 7500, 7650, 7800, 7950, 8100, 8250,
8400, 8550, 8700, 8850, 9000, 9150, 9300, 9450,
9600, 9750, 9900,10050,10200,10350,10500,10650,
10800,10950,11100,11250,11400,11550,11700,11850,
12000,12150,12300,12450,12600,12750,12900,13050,
13200,13350,13500,13650,13800,13950,14100,14250,
14400,14550,14700,14850,15000,15150,15300,15450,
15600,15750,15900,16050,16200,16350,16500,16650,
16800,16950,17100,17250,17400,17550,17700,17850,
18000,18150,18300,18450,18600,18750,18900,19050,
19200,19350,19500,19650,19800,19950,20100,20250,
20400,20550,20700,20850,21000,21150,21300,21450,
21600,21750,21900,22050,22200,22350,22500,22650,
22800,22950,23100,23250,23400,23550,23700,23850,
24000,24150,24300,24450,24600,24750,24900,25050,
25200,25350,25500,25650,25800,25950,26100,26250,
26400,26550,26700,26850,27000,27150,27300,27450,
27600,27750,27900,28050,28200,28350,28500,28650,
28800,28950,29100,29250,29400,29550,29700,29850,
30000,30150,30300,30450,30600,30750,30900,31050,
31200,31350,31500,31650,31800,31950,32100,32250,
32400,32550,32700,32850,33000,33150,33300,33450,
33600,33750,33900,34050,34200,34350,34500,34650,
34800,34950,35100,35250,35400,35550,35700,35850,
36000,36150,36300,36450,36600,36750,36900,37050,
37200,37350,37500,37650,37800,37950,38100,38250
};
unsigned short BlueIntensity[256]= {
0, 29, 58, 87, 116, 145, 174, 203,
232, 261, 290, 319, 348, 377, 406, 435,
464, 493, 522, 551, 580, 609, 638, 667,
696, 725, 754, 783, 812, 841, 870, 899,
928, 957, 986, 1015, 1044, 1073, 1102, 1131,
1160, 1189, 1218, 1247, 1276, 1305, 1334, 1363,
1392, 1421, 1450, 1479, 1508, 1537, 1566, 1595,
1624, 1653, 1682, 1711, 1740, 1769, 1798, 1827,
1856, 1885, 1914, 1943, 1972, 2001, 2030, 2059,
2088, 2117, 2146, 2175, 2204, 2233, 2262, 2291,
2320, 2349, 2378, 2407, 2436, 2465, 2494, 2523,
2552, 2581, 2610, 2639, 2668, 2697, 2726, 2755,
2784, 2813, 2842, 2871, 2900, 2929, 2958, 2987,
3016, 3045, 3074, 3103, 3132, 3161, 3190, 3219,
3248, 3277, 3306, 3335, 3364, 3393, 3422, 3451,
3480, 3509, 3538, 3567, 3596, 3625, 3654, 3683,
3712, 3741, 3770, 3799, 3828, 3857, 3886, 3915,
3944, 3973, 4002, 4031, 4060, 4089, 4118, 4147,
4176, 4205, 4234, 4263, 4292, 4321, 4350, 4379,
4408, 4437, 4466, 4495, 4524, 4553, 4582, 4611,
4640, 4669, 4698, 4727, 4756, 4785, 4814, 4843,
4872, 4901, 4930, 4959, 4988, 5017, 5046, 5075,
5104, 5133, 5162, 5191, 5220, 5249, 5278, 5307,
5336, 5365, 5394, 5423, 5452, 5481, 5510, 5539,
5568, 5597, 5626, 5655, 5684, 5713, 5742, 5771,
5800, 5829, 5858, 5887, 5916, 5945, 5974, 6003,
6032, 6061, 6090, 6119, 6148, 6177, 6206, 6235,
6264, 6293, 6322, 6351, 6380, 6409, 6438, 6467,
6496, 6525, 6554, 6583, 6612, 6641, 6670, 6699,
6728, 6757, 6786, 6815, 6844, 6873, 6902, 6931,
6960, 6989, 7018, 7047, 7076, 7105, 7134, 7163,
7192, 7221, 7250, 7279, 7308, 7337, 7366, 7395
};

1254
image/image.c Normal file

File diff suppressed because it is too large Load Diff

82
image/image_endian.h Normal file
View File

@ -0,0 +1,82 @@
/*
* endian.h
*/
#ifndef __ENDIAN_H__
#define __ENDIAN_H__ 1
/*
* Endianism determination by Erik Corry. Please email changes/additions!!!
*/
#if !defined(__MIPSEL__) && (defined(MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(__mipsel) || defined(__mipsel__))
#define __MIPSEL__ 1
#endif
#if !defined(__MIPSEB__) && (defined(MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || defined(__mipseb) || defined(__mipseb__) || defined(_MIPSEB))
#define __MIPSEB__ 1
#endif
#if !defined(__SPARC__) && (defined(SPARC) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc) || defined(__sparc__))
#define __SPARC__ 1
#endif
#if !defined(__alpha__) && (defined(ALPHA) || defined(__ALPHA) || defined(__ALPHA__) || defined(__alpha))
#define __alpha__ 1
#endif
#if !defined(__680x0__) && (defined(__680x0) || defined(__680x0__) || defined(__mc68000__))
#define __680x0__ 1
#endif
#if !defined(__AIX__) && (defined(AIX) || defined(_AIX) || defined(__AIX) || defined(__AIX__))
#define __AIX__ 1
#endif
#if !defined(__RS6000__) && (defined(__AIX__) || defined(RS6000) || defined(_RS6000) || defined(__RS6000) || defined(__RS6000__))
#define __RS6000__ 1
#endif
#if !defined(__HPUX__) && (defined(HPUX) || defined(_HPUX) || defined(__HPUX) || defined(__HPUX__))
#define __HPUX__ 1
#endif
#if !defined(__HPUX__) && (defined(hpux) || defined(_hpux) || defined(__hpux) || defined(__hpux__))
#define __HPUX__ 1
#endif
#if !defined(__VAX__) && (defined(VAX) || defined (__VAX))
#define __VAX__ 1
#endif
#if defined(__i386__) || defined(__VAX__) || defined(__MIPSEL__) || defined(__alpha__) || defined(__QNX__)
#undef CHIMERA_BIG_ENDIAN
#define CHIMERA_LITTLE_ENDIAN
#endif
#if defined(__RS6000__) || defined(__SPARC__) || defined(__680x0__) || defined(__HPUX__) || defined(__MIPSEB__) || defined(__convex__)
#undef CHIMERA_LITTLE_ENDIAN
#define CHIMERA_BIG_ENDIAN
#endif
#if !defined(CHIMERA_LITTLE_ENDIAN) && !defined(CHIMERA_BIG_ENDIAN)
/*
* If you hit this and you don't know what symbols your system defines,
* look in the compiler manual. Try to find a symbol that identifies the
* processor, rather than the OS or compiler. If you have gcc on a Unix
* system, the following will tell you what symbols it defines:
*
* ln -s /dev/null null.c
* gcc -ansi -dM -E null.c
*
* If you have a system that does not have a clear integer endianism you
* are going to have severe portability problems.
*
*/
Error: Unknown endianism of architecture
#endif
#ifdef __alpha__
#define SIXTYFOUR_BIT
#endif
#endif /* __ENDIAN_H__ */

56
image/image_format.h Normal file
View File

@ -0,0 +1,56 @@
/*
* image_format.h
*
* Copyright (c) 1995 Erik Corry ehcorry@inet.uni-c.dk
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef IMAGE_FORMAT_H_INCLUDED
#define IMAGE_FORMAT_H_INCLUDED
typedef struct ifs_vector *ift_vector;
typedef void (*FormatLineProc) _ArgProto((void *, int, int));
typedef void (InitProcDecl) _ArgProto((FormatLineProc line_proc,
void *line_proc_closure,
ift_vector vector));
typedef InitProcDecl *InitProc;
typedef void (*DestroyProc) _ArgProto((void *image_format_closure));
typedef int (*AddDataProc) _ArgProto((void *image_format_closure,
byte *data,
int len,
bool data_ended));
typedef Image *(*GetImageProc) _ArgProto((void *image_format_closure));
InitProcDecl gifInit;
InitProcDecl xbmInit;
InitProcDecl pnmInit;
InitProcDecl jpegInit;
InitProcDecl pngInit;
struct ifs_vector
{
void *image_format_closure;
int image_format;
InitProc initProc;
DestroyProc destroyProc;
AddDataProc addDataProc;
GetImageProc getImageProc;
};
#endif

106
image/imagep.h Normal file
View File

@ -0,0 +1,106 @@
/* image.h:
*
* portable image type declarations
*
* jim frost 10.02.89
*
* Copyright 1989 Jim Frost.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. The author makes no representations
* about the suitability of this software for any purpose. It is
* provided "as is" without express or implied warranty.
*
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Changes (c) Copyright 1995 Erik Corry ehcorry@inet.uni-c.dk
*/
#ifndef __IMAGEP_H__
#define __IMAGEP_H__ 1
#ifndef MAX
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/*
* should be in limits.h
*/
#ifndef CHAR_BITS
#define CHAR_BITS 8
#endif
typedef unsigned short Intensity;
typedef struct rgbcolor
{
Intensity red, green, blue;
} RGBColor;
typedef struct rgbmap
{
unsigned int size; /* size of RGB map (bytes per enty) */
unsigned int used; /* number of colors used in RGB map */
unsigned int compressed; /* image uses colormap fully */
Intensity *red; /* color values in X style */
Intensity *green;
Intensity *blue;
} RGBMap;
/* image structure
*/
typedef struct
{
unsigned int type; /* type of image */
int x, y; /* x, y of decoded image */
int pass; /* interlace pass */
int transparent; /* transparent color index */
RGBMap rgb; /* RGB map of image if IRGB or IGRAY type */
unsigned int width; /* width of image in pixels */
unsigned int height; /* height of image in pixels */
unsigned int depth; /* depth of image in bits */
unsigned int pixlen; /* length of pixel in bits after padding */
unsigned int bytes_per_line; /* After padding */
float gamma; /* gamma of display the image is adjusted for */
byte *data; /* data rounded to full byte for each row */
} Image;
#define IBAD 0 /* invalid image type (used when freeing) */
#define IBITMAP 1 /* image is a bitmap */
#define IRGB 2 /* image is RGB */
#define ITRUE 3 /* image is true color */
#define IGRAY 4 /* image is gray scale */
/* new.c */
Image *newBitImage _ArgProto((unsigned int width, unsigned int height));
Image *newTrueImage _ArgProto((unsigned int width, unsigned int height));
Image *newRGBImage _ArgProto((unsigned int width, unsigned int height,
unsigned int depth));
void freeImage _ArgProto((Image *image));
/*
* this returns the (approximate) intensity of an RGB triple
*/
#define colorIntensity(R,G,B) \
(RedIntensity[(R) >> 8] + GreenIntensity[(G) >> 8] + BlueIntensity[(B) >> 8])
extern unsigned short RedIntensity[];
extern unsigned short GreenIntensity[];
extern unsigned short BlueIntensity[];
#endif /* __IMAGEP_H__ */

570
image/jpeg.c Normal file
View File

@ -0,0 +1,570 @@
/*
* jpeg.c:
*
* (c) 1995 Erik Corry ehcorry@inet.uni-c.dk
*
* modelled on xbm.c.
*
* If you want to understand this read the following files from libjpeg:
*
* libjpeg.doc
* jdatasrc.c
* jpeglib.h
* example.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "port_after.h"
#include "common.h"
#include "imagep.h"
#include "jpegp.h"
static void jpegDestroy _ArgProto((void *));
/*
* jpegGetImage - called through vector
*/
static Image *
jpegGetImage(void *pointer)
{
jpegState *jpeg = (jpegState *)pointer;
return jpeg->image;
}
/*
* jpegDestroy - called through vector
*/
static void
jpegDestroy(pointer)
void *pointer;
{
jpegState *jpeg = (jpegState *)pointer;
if (jpeg) {
if(setjmp(jpeg->error_state.jump_buffer))
{
/*
* Oh shit, an error while clearing up...
*/
fprintf(stderr, "jpegDestroy: failed\n");
return;
}
if (jpeg->image)
freeImage(jpeg->image);
jpeg->image = 0;
if (jpeg->destroy_jpeg)
jpeg_destroy_decompress(&jpeg->cinfo);
jpeg->destroy_jpeg = false;
free_mem(jpeg);
}
}
/*
* these routines form a suspending "data source manager" for libjpeg.
*/
static void
lf_init_source_callback(
struct jpeg_decompress_struct *cinfo)
{
}
static boolean
lf_fill_input_buffer_callback(
struct jpeg_decompress_struct *cinfo)
{
struct jpeg_chimera_input_state *input_state =
(struct jpeg_chimera_input_state *)(cinfo->src);
if (! input_state->at_eof)
return FALSE; /* force suspension until more data arrives */
/* If libjpeg demands more data beyond the EOF,
* pacify it by supplying EOI marker(s).
* This lets us produce some kind of image from a trucated or corrupted file.
*/
WARNMS(cinfo, JWRN_JPEG_EOF);
input_state->fake_eoi[0] = (JOCTET) 0xFF;
input_state->fake_eoi[1] = (JOCTET) JPEG_EOI;
input_state->pub.next_input_byte = input_state->fake_eoi;
input_state->pub.bytes_in_buffer = 2;
input_state->faked_eoi = true;
return TRUE;
}
static void
lf_skip_input_data_callback(
struct jpeg_decompress_struct *cinfo,
long num_bytes)
{
struct jpeg_chimera_input_state *input_state =
(struct jpeg_chimera_input_state *)(cinfo->src);
if (num_bytes <= 0) return;
if (num_bytes > (long) input_state->pub.bytes_in_buffer)
{
/* Tricky code here: we advance next_input_byte beyond the end of the
* buffer. libjpeg will suspend because we set bytes_in_buffer to 0,
* and then jpegAddData's bookkeeping will do the right thing.
* This could fail on sufficiently weird architectures, because
* pointers aren't guaranteed by the C standard to be able to point
* past the end of allocated memory; but in practice it should be fine.
*/
input_state->pub.next_input_byte += num_bytes;
input_state->pub.bytes_in_buffer = 0;
}
else
{
input_state->pub.next_input_byte += num_bytes;
input_state->pub.bytes_in_buffer -= num_bytes;
}
}
static void
lf_term_source_callback(
struct jpeg_decompress_struct *cinfo)
{
}
/*
* this routine overrides libjpeg's default fatal-error handler.
*/
static void
lf_error_exit_callback(
j_common_ptr cinfo)
{
struct jpeg_chimera_error_state *error_state =
(struct jpeg_chimera_error_state *)(cinfo->err);
/*
* Display message. At the moment I use the builtin stderr handler,
* but we could install something smarter, or just keep quiet about it.
* Note that if we did want to keep quiet, we'd have to override
* output_message as well as error_exit, so as to suppress warning msgs.
*/
(error_state->pub.output_message)(cinfo);
/* Return control to the setjmp point */
longjmp(error_state->jump_buffer, 1);
}
/*
* These routines are the elements of a state machine for reading JPEGs.
* We use a distinct state for each point at which we may have to suspend
* processing.
*/
static int
lf_read_header(jpegState *jpeg)
{
int status = jpeg_read_header(&jpeg->cinfo, TRUE);
if (status == JPEG_SUSPENDED) return CH_JPEG_NEED_DATA;
/*
* Done reading header; set decompression parameters.
* Probably ought to have some user-settable preferences here.
*/
/* These are needed for progressive rendering */
if (jpeg_has_multiple_scans(&jpeg->cinfo))
jpeg->cinfo.buffered_image = TRUE;
jpeg->cinfo.do_block_smoothing = TRUE;
/* These are optional tradeoffs of quality for speed */
/* if (force-grayscale) jpeg->cinfo.out_color_space = JCS_GRAYSCALE; */
jpeg->cinfo.dct_method = JDCT_FASTEST;
jpeg->cinfo.do_fancy_upsampling = FALSE;
/* Advance to next state */
jpeg->state = CH_JPEG_START_DECOMPRESS;
return CH_JPEG_SUCCESS;
}
static int
lf_start_decompress(jpegState *jpeg)
{
int status = jpeg_start_decompress(&jpeg->cinfo);
if (status == FALSE) return CH_JPEG_NEED_DATA;
/*
* start_decompress done; get image parameters
*/
if (jpeg->cinfo.out_color_space == JCS_GRAYSCALE &&
jpeg->cinfo.output_components == 1)
{
/* we represent grayscale as RGBI with a gray-ramp palette */
int i;
jpeg->image = newRGBImage(jpeg->cinfo.output_width,
jpeg->cinfo.output_height, 8);
if (!jpeg->image)
return CH_JPEG_ERROR;
jpeg->image->type = IGRAY;
jpeg->image->rgb.red = jpeg->cmap;
jpeg->image->rgb.green = jpeg->cmap;
jpeg->image->rgb.blue = jpeg->cmap;
jpeg->image->rgb.used = 256;
for (i = 0; i < 256; i++)
jpeg->cmap[i] = i | (i << 8);
}
else if (jpeg->cinfo.out_color_space == JCS_RGB &&
jpeg->cinfo.output_components == 3)
{
jpeg->image = newTrueImage(jpeg->cinfo.output_width,
jpeg->cinfo.output_height);
if (!jpeg->image)
return CH_JPEG_ERROR;
}
else
{
fprintf(stderr, "Unsupported JPEG colorspace\n");
return CH_JPEG_ERROR;
}
/* Advance to next state */
jpeg->state = CH_JPEG_START_OUTPUT;
return CH_JPEG_SUCCESS;
}
static int
lf_start_output(jpegState *jpeg)
{
if (jpeg->cinfo.buffered_image)
{
/* Eat all the available data before issuing start_output.
* This ensures we have an up-to-date target scan number
* and prevents executing unnecessary output passes.
* Once we get a SUSPENDED return (or possibly an EOI),
* we can proceed with display.
*/
int status;
for (;;) {
status = jpeg_consume_input(&jpeg->cinfo);
if (status == JPEG_SUSPENDED || status == JPEG_REACHED_EOI)
break;
}
status = jpeg_start_output(&jpeg->cinfo, jpeg->cinfo.input_scan_number);
if (status == FALSE) return CH_JPEG_NEED_DATA;
/* printf("scan %d\n", jpeg->cinfo.input_scan_number); */
}
jpeg->ypos = 0;
/* Advance to next state */
jpeg->state = CH_JPEG_READ_IMAGE;
return CH_JPEG_SUCCESS;
}
static int
lf_read_image(jpegState *jpeg)
{
int scanline_count, max_scanlines;
int i;
unsigned char *scanline_pointers[4];
unsigned char *output_addr;
if (jpeg->cinfo.buffered_image)
{
/* In progressive mode, consume all available input right away.
* NOTE: maybe ought to be less greedy if whole file is available???
*/
for (;;) {
int status = jpeg_consume_input(&jpeg->cinfo);
if (status == JPEG_SUSPENDED || status == JPEG_REACHED_EOI)
break;
}
}
while (jpeg->ypos < jpeg->cinfo.output_height)
{
/* Somewhat optimistically, we assume that libjpeg may be able to
* give us as many as four scanlines per call.
*/
max_scanlines = MIN(4, jpeg->cinfo.output_height - jpeg->ypos);
output_addr =
jpeg->image->data + jpeg->image->bytes_per_line * jpeg->ypos;
for (i = 0; i < max_scanlines; i++)
{
scanline_pointers[i] = output_addr;
output_addr += jpeg->image->bytes_per_line;
}
scanline_count =
jpeg_read_scanlines(&jpeg->cinfo, scanline_pointers, max_scanlines);
if (scanline_count == 0) return CH_JPEG_NEED_DATA;
if (jpeg->lineProc != NULL)
(jpeg->lineProc)(jpeg->lineClosure, jpeg->ypos,
jpeg->ypos + scanline_count - 1);
jpeg->ypos += scanline_count;
}
/* Advance to next state */
jpeg->state = CH_JPEG_FINISH_OUTPUT;
return CH_JPEG_SUCCESS;
}
static int
lf_finish_output(jpegState *jpeg)
{
if (jpeg->cinfo.buffered_image)
{
int status = jpeg_finish_output(&jpeg->cinfo);
if (status == FALSE) return CH_JPEG_NEED_DATA;
/* We need another output scan unless the input file is all read
* and the just-completed output scan was started after the final
* input scan began arriving.
*/
if (! jpeg_input_complete(&jpeg->cinfo) ||
jpeg->cinfo.output_scan_number < jpeg->cinfo.input_scan_number)
{
jpeg->state = CH_JPEG_START_OUTPUT;
return CH_JPEG_SUCCESS;
}
}
/* Advance to next state */
jpeg->state = CH_JPEG_FINISH_DECOMPRESS;
return CH_JPEG_SUCCESS;
}
static int
lf_finish_decompress(jpegState *jpeg)
{
int status = jpeg_finish_decompress(&jpeg->cinfo);
if (status == FALSE) return CH_JPEG_NEED_DATA;
/* Advance to next state */
jpeg->state = CH_JPEG_FINISHED;
return CH_JPEG_SUCCESS;
}
/*
* jpegAddData - called through vector
*
* Returns:
* 0 success
* 1 need more data
* -1 error
*
* Assumes data is the address of the beginning of the jpeg data and len
* is the total length.
*/
static int
jpegAddData(pointer, data, len, data_ended)
void *pointer;
byte *data;
int len;
bool data_ended;
{
jpegState *jpeg = (jpegState *)pointer;
int rval;
/*
fprintf(stderr, "jpegAddData %p: buf %p %d %d\n",
&jpeg->cinfo, data, len, data_ended);
*/
if (setjmp(jpeg->error_state.jump_buffer))
{
/* Failed. Assume we will get a jpegDestroy call */
return -1;
}
/*
* Can't progress unless more data is available (or EOI is reached).
* Note that len < bytes_consumed is entirely valid, if libjpeg has
* commanded a skip beyond the data so far received.
*/
if (len <= jpeg->input_state.bytes_consumed)
{
if (! data_ended) return 1; /* suspend */
/* If reached EOF, terminate any incomplete skip. */
jpeg->input_state.bytes_consumed = len;
}
/* Update libjpeg's input pointers */
jpeg->input_state.pub.next_input_byte =
((JOCTET*) data) + jpeg->input_state.bytes_consumed;
jpeg->input_state.pub.bytes_in_buffer =
len - jpeg->input_state.bytes_consumed;
jpeg->input_state.faked_eoi = false; /* next_input_byte is valid */
if (data_ended)
jpeg->input_state.at_eof = true;
/*
* Don't bother to parse less than a few hundred bytes at a time;
* this prevents excess cycling in libjpeg. (Normal TCP connections
* will deliver a packet at a time, so this test will probably never
* trigger...)
*/
if (!data_ended &&
jpeg->input_state.pub.bytes_in_buffer < 200)
return 1;
/*
* Cycle the state machine until done or forced to suspend by lack of input.
* Note that we are able to progress through multiple states per call
* as long as the input is there.
*/
for ( ; ; )
{
switch (jpeg->state)
{
case CH_JPEG_READ_HEADER:
rval = lf_read_header(jpeg);
break;
case CH_JPEG_START_DECOMPRESS:
rval = lf_start_decompress(jpeg);
break;
case CH_JPEG_START_OUTPUT:
rval = lf_start_output(jpeg);
break;
case CH_JPEG_READ_IMAGE:
rval = lf_read_image(jpeg);
break;
case CH_JPEG_FINISH_OUTPUT:
rval = lf_finish_output(jpeg);
break;
case CH_JPEG_FINISH_DECOMPRESS:
rval = lf_finish_decompress(jpeg);
break;
case CH_JPEG_FINISHED:
rval = CH_JPEG_FINISHED;
break;
default:
fprintf(stderr, "jpegAddData: bogus state %d\n", jpeg->state);
rval = CH_JPEG_ERROR;
break;
}
/* exit loop for FINISHED, NEED_DATA, or ERROR returns */
if (rval != CH_JPEG_SUCCESS)
break;
}
/*
* Record how much data libjpeg consumed.
*/
if (jpeg->input_state.faked_eoi)
{
/* next_input_bytes is invalid, just say we ate it all. */
jpeg->input_state.bytes_consumed = len;
}
else
{
jpeg->input_state.bytes_consumed =
jpeg->input_state.pub.next_input_byte - ((JOCTET*) data);
}
if (rval == CH_JPEG_NEED_DATA)
return 1;
if (rval == CH_JPEG_FINISHED)
return 0;
return(-1);
}
/*
* jpegInit
*
* Initialize JPEG reader state
*/
void
jpegInit(lineProc, lineClosure, if_vector)
void (*lineProc)();
void *lineClosure;
struct ifs_vector *if_vector;
{
jpegState *jpeg;
/*
* Initialise vector for methods Chimera needs
*/
if_vector->initProc = &jpegInit;
if_vector->destroyProc = &jpegDestroy;
if_vector->addDataProc = &jpegAddData;
if_vector->getImageProc = &jpegGetImage;
/* allocate my workspace */
jpeg = (jpegState *)alloc_mem(sizeof(jpegState));
if_vector->image_format_closure = (void *)jpeg;
if (jpeg == NULL)
return;
memset(jpeg, 0, sizeof(jpegState));
jpeg->state = CH_JPEG_READ_HEADER;
jpeg->lineProc = lineProc;
jpeg->lineClosure = lineClosure;
/*
* Initialise error handler.
* We set up the normal JPEG error routines, then override error_exit.
*/
jpeg->cinfo.err = jpeg_std_error(&jpeg->error_state.pub);
jpeg->error_state.pub.error_exit = &lf_error_exit_callback;
if (setjmp(jpeg->error_state.jump_buffer))
{
/*
* We get here after a failure in initialisation. Lets just assume that
* people are careful about the order in which things are done, and that
* a destroy will work here.
*/
jpegDestroy((void *)jpeg);
/*
* It would be nice if init could indicate failure...
*/
return;
}
/*
* Initialise jpeg library
*/
jpeg->destroy_jpeg = true; /* jpeg_destroy is OK even if create fails */
jpeg_create_decompress(&jpeg->cinfo);
/*
* Initialise our input reader.
*/
jpeg->cinfo.src = &jpeg->input_state.pub;
jpeg->input_state.pub.init_source = &lf_init_source_callback;
jpeg->input_state.pub.fill_input_buffer = &lf_fill_input_buffer_callback;
jpeg->input_state.pub.skip_input_data = &lf_skip_input_data_callback;
jpeg->input_state.pub.resync_to_restart = &jpeg_resync_to_restart;
jpeg->input_state.pub.term_source = &lf_term_source_callback;
jpeg->input_state.pub.bytes_in_buffer = 0;
jpeg->input_state.pub.next_input_byte = NULL;
jpeg->input_state.bytes_consumed = 0;
jpeg->input_state.at_eof = false;
}

114
image/jpegp.h Normal file
View File

@ -0,0 +1,114 @@
/*
* jpegp.h
*
* Copyright (C) 1995, Erik Corry (ehcorry@inet.uni-c.dk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This stuff is very fragile wrt. changes in the sizes of the
* jpeg library structures. It's a real good idea to be using libjpeg
* version 6a or later; 6a added some defenses against structure mismatches.
*/
#ifndef JPEG_H_INCLUDED
#define JPEG_H_INCLUDED 1
#include <stdio.h>
#include <sys/types.h> /* in case size_t is not defined by stdio.h */
#include <setjmp.h>
#include "image_format.h"
/*
* Unfortunately libjpeg uses some of the same configuration symbols
* as Chimera. Undef'ing these symbols here is not essential, but it
* prevents macro-redefinition warnings from gcc and like-minded compilers.
*/
#undef HAVE_PROTOTYPES
#undef HAVE_UNSIGNED_CHAR
#undef HAVE_UNSIGNED_SHORT
#undef HAVE_STDDEF_H
#undef HAVE_STDLIB_H
#include "jpeglib.h"
#include "jerror.h"
/*
* Each of these structures begins with a jpeg library struct,
* followed by chimera extension fields. This lets us cast pointers
* back and forth between the structs known to the library and the
* full struct definitions. Poor man's subclassing, if you like.
*/
struct jpeg_chimera_error_state
{
struct jpeg_error_mgr pub; /* - this struct comes from jpeg lib */
jmp_buf jump_buffer; /* usually an array of sorts from setjmp.h */
};
struct jpeg_chimera_input_state
{
struct jpeg_source_mgr pub; /* - this struct comes from jpeg lib */
int bytes_consumed; /* # bytes already consumed by jpeg lib */
bool at_eof; /* indicates we've gotten the whole file */
bool faked_eoi; /* indicates next_input_byte is phony */
JOCTET fake_eoi[2]; /* workspace for making a fake EOI */
};
/*
* jpegState
*/
typedef struct jpeg_state
{
struct jpeg_decompress_struct cinfo; /* - this struct comes from jpeg lib */
struct jpeg_chimera_error_state error_state; /* subsidiary structures */
struct jpeg_chimera_input_state input_state;
bool destroy_jpeg; /* indicates we need to call jpeg_destroy */
int state; /* state of JPEG reader */
JDIMENSION ypos; /* current scanline number */
FormatLineProc lineProc; /* line callback */
void *lineClosure; /* closure for callback */
Image *image;
Intensity cmap[256]; /* room for making a grayscale palette */
} jpegState;
/*
* state of JPEG reader
*/
#define CH_JPEG_READ_HEADER 1
#define CH_JPEG_START_DECOMPRESS 2
#define CH_JPEG_START_OUTPUT 3
#define CH_JPEG_READ_IMAGE 4
#define CH_JPEG_FINISH_OUTPUT 5
#define CH_JPEG_FINISH_DECOMPRESS 6
#define CH_JPEG_FINISHED 0
/*
* return values from jpeg processing fns
* NOTE: CH_JPEG_FINISHED is also used as a return value!
*/
#define CH_JPEG_SUCCESS 1
#define CH_JPEG_NEED_DATA 2
#define CH_JPEG_ERROR 3
#endif

176
image/new.c Normal file
View File

@ -0,0 +1,176 @@
/* new.c:
*
* functions to allocate and deallocate structures and structure data
*
* jim frost 09.29.89
*
* Copyright 1989, 1991 Jim Frost.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. The author makes no representations
* about the suitability of this software for any purpose. It is
* provided "as is" without express or implied warranty.
*
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "port_before.h"
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "imagep.h"
Image *
newBitImage(width, height)
unsigned int width, height;
{
unsigned long datasize;
Image *image;
image = (Image *)alloc_mem(sizeof(Image));
if (!image) return((Image *) 0);
memset(image, 0, sizeof(Image));
image->type = IBITMAP;
image->width = width;
image->height = height;
image->depth = 1;
image->pixlen = 1;
/* round bytes_per_line up to nearest byte */
image->bytes_per_line = ((width - 1) / CHAR_BITS) + 1;
/* round bytes_per_line up to nearest longword */
image->bytes_per_line = ((image->bytes_per_line - 1) / sizeof(long)) + 1;
image->bytes_per_line *= sizeof(long);
/* Allocate a little too much memory, to allow overread */
datasize = image->bytes_per_line * height + 32;
image->data = (byte *)alloc_mem(datasize);
memset(image->data, 0, datasize);
image->transparent = -1;
return(image);
}
Image *
newRGBImage(width, height, depth)
unsigned int width, height, depth;
{
Image *image;
unsigned int pixlen;
unsigned long datasize;
if(depth == 1)
{
image = newBitImage(width, height);
image->type = IRGB;
return image;
}
pixlen = ((depth - 1) / CHAR_BITS) + 1;
pixlen *= CHAR_BITS;
if (pixlen == 0) pixlen = 1;
image = (Image *)alloc_mem(sizeof(Image));
if (!image) return((Image *)0);
memset(image, 0, sizeof(Image));
image->type = IRGB;
image->width = width;
image->height = height;
image->depth = depth;
image->pixlen = pixlen;
/* set bytes_per_line (pixlen is a multiple of CHAR_BITS) */
image->bytes_per_line = (width * pixlen) / CHAR_BITS;
/* round bytes_per_line up to nearest longword */
image->bytes_per_line = ((image->bytes_per_line - 1) / sizeof(long)) + 1;
image->bytes_per_line *= sizeof(long);
/* Allocate a little too much memory, to allow overread */
datasize = image->bytes_per_line * height + 32;
image->data = (byte *)alloc_mem(datasize);
if (!image->data)
{
free_mem((char *)image);
return((Image *)0);
}
memset(image->data, 0, datasize);
image->rgb.used = 0;
image->rgb.compressed = 0;
image->rgb.size = 2;
image->transparent = -1;
return(image);
}
Image *
newTrueImage(width, height)
unsigned int width, height;
{
Image *image;
unsigned long datasize;
image = (Image *)alloc_mem(sizeof(Image));
if (!image) return((Image *) 0);
memset(image, 0, sizeof(Image));
image->type = ITRUE;
image->width = width;
image->height = height;
image->depth = 8;
image->pixlen = 24;
/* set bytes_per_line */
image->bytes_per_line = width * 3;
/* round bytes_per_line up to nearest longword */
image->bytes_per_line = ((image->bytes_per_line - 1) / sizeof(long)) + 1;
image->bytes_per_line *= sizeof(long);
/* Allocate a little too much memory, to allow overread */
datasize = image->bytes_per_line * height + 32;
image->data = (byte *)alloc_mem(datasize);
if (!image->data)
{
free_mem((char *)image);
return ((Image *)0);
}
memset(image->data, 0, datasize);
image->rgb.used = 0;
image->rgb.compressed = 0;
image->rgb.size = 2;
image->transparent = -1;
return(image);
}
void
freeImage(image)
Image *image;
{
if (image->data != NULL) free_mem((char *)image->data);
image->data = NULL;
free_mem((char *)image);
return;
}

310
image/png.c Normal file
View File

@ -0,0 +1,310 @@
/*
* Portable Network Graphics (PNG) image format
*/
#include "port_before.h"
#include <png.h>
#include "port_after.h"
#include "common.h"
#include "imagep.h"
#include "image_format.h"
#include "image_endian.h"
#include <assert.h>
#define PM_SCALE(a, b, c) (long)((a) * (c))/(b)
enum {
image_success = 0, image_need_data = 1, image_error = -1
};
typedef struct {
png_struct *state;
png_info *info;
Image *image;
Intensity cmap[3][256];
void (*lineProc)(void *, int, int);
void *closure;
int lenSoFar;
int done;
} pngState;
static Image *
pngGetImage(void *pointer)
{
return ((pngState *) pointer)->image;
}
static void lc_reverse_byte(byte *row, int n)
{
int i;
byte c;
for (i = 0; i < n; ++i) {
c = row[i];
c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
row[i] = c;
}
}
static void
lf_info_callback(png_struct *state, png_info *info)
{
int orig_depth = 0;
pngState *png = (pngState *) png_get_progressive_ptr(state);
if (info->bit_depth < 8 && (PNG_COLOR_TYPE_RGB == info->color_type ||
PNG_COLOR_TYPE_RGB_ALPHA == info->color_type))
png_set_expand(state);
/* I wish the frame's background colour was available here */
if (info->color_type & PNG_COLOR_MASK_ALPHA) {
png_color_16 bg;
int gflag = PNG_BACKGROUND_GAMMA_SCREEN;
double gval = 1.0;
int expand = 0;
bg.red = bg.green = bg.blue = bg.gray = 0;
if (PNG_COLOR_TYPE_PALETTE == info->color_type)
png_set_expand(state);
png_set_background(state, &bg, gflag, expand, gval);
}
if (info->bit_depth < 8 && (info->bit_depth > 1 ||
PNG_COLOR_TYPE_GRAY != info->color_type)) {
if (PNG_COLOR_TYPE_GRAY == info->color_type)
orig_depth = info->bit_depth;
png_set_packing(state);
}
/* tell libpng to strip 16 bit depth files down to 8 bits */
if (info->bit_depth > 8)
png_set_strip_16(state);
png_set_interlace_handling(state);
/* update palette with transformations, update the info structure */
png_read_update_info(state, info);
/* allocate the memory to hold the image using the fields of png_info. */
if (PNG_COLOR_TYPE_GRAY == info->color_type && 1 == info->bit_depth) {
png->image = newBitImage(info->width, info->height);
if (!png->image) {
png->done = image_error;
return;
}
png_set_invert_mono(state);
} else if (PNG_COLOR_TYPE_PALETTE == info->color_type) {
int i;
png->image = newRGBImage(info->width, info->height, info->bit_depth);
if (!png->image) {
png->done = image_error;
return;
}
png->image->rgb.red = png->cmap[0];
png->image->rgb.green = png->cmap[1];
png->image->rgb.blue = png->cmap[2];
for (i = 0; i < info->num_palette; ++i) {
png->image->rgb.red[i] = info->palette[i].red << 8;
png->image->rgb.green[i] = info->palette[i].green << 8;
png->image->rgb.blue[i] = info->palette[i].blue << 8;
}
png->image->rgb.used = info->num_palette;
if (info->valid & PNG_INFO_tRNS) {
int val, i;
val = 0;
for (i = 0; i < info->num_trans; ++i) {
if (info->trans[i] < info->trans[val])
val = i;
}
png->image->transparent = val;
}
} else if (PNG_COLOR_TYPE_GRAY == info->color_type) {
int i;
int depth = orig_depth ? orig_depth : info->bit_depth;
int maxval = (1 << depth) - 1;
png->image = newRGBImage(info->width, info->height, depth);
if (!png->image) {
png->done = image_error;
return;
}
/* png->image->type = IGRAY; */
png->image->rgb.red = png->cmap[0];
png->image->rgb.green = png->cmap[1];
png->image->rgb.blue = png->cmap[2];
for (i = 0; i <= maxval; i++) {
png->image->rgb.red[i] = PM_SCALE(i, maxval, 0xffff);
png->image->rgb.green[i] = PM_SCALE(i, maxval, 0xffff);
png->image->rgb.blue[i] = PM_SCALE(i, maxval, 0xffff);
}
png->image->rgb.used = maxval + 1;
if (info->valid & PNG_INFO_tRNS)
png->image->transparent = info->trans_values.gray;
} else {
png->image = newTrueImage(info->width, info->height);
if (!png->image) {
png->done = image_error;
return;
}
}
if (info->valid & PNG_INFO_gAMA && png->image->type != IBITMAP)
png->image->gamma = 1.0 / info->gamma;
assert((png->image->width * png->image->pixlen + 7) / 8 == info->rowbytes);
}
static void
lf_row_callback(png_struct *state, png_byte *new_row, png_uint_32 row_num,
int pass)
{
pngState *png;
byte *old_row;
if (!new_row)
return;
png = (pngState *) png_get_progressive_ptr(state);
if (!png->image)
return;
old_row = png->image->data + png->image->bytes_per_line * row_num;
png_progressive_combine_row(state, old_row, new_row);
if (png->lineProc) {
/* I can't say I'm too fond of this endian business. */
#ifdef CHIMERA_LITTLE_ENDIAN
if (IBITMAP == png->image->type)
lc_reverse_byte(old_row, png->info->rowbytes);
#endif
(png->lineProc)(png->closure, row_num, row_num);
#ifdef CHIMERA_LITTLE_ENDIAN
if (IBITMAP == png->image->type)
lc_reverse_byte(old_row,png->info->rowbytes);
#endif
}
}
static void
lf_end_callback(png_struct *state, png_info *info)
{
pngState *png= (pngState *) png_get_progressive_ptr(state);
png->done = image_success;
}
static void
pngDestroy(void *pointer)
{
pngState *png = (pngState *) pointer;
if (!png)
return;
if (setjmp(png->state->jmpbuf))
return;
if (png->state) {
png_read_destroy(png->state, png->info, (png_info *) 0);
free_mem(png->state);
png->state = 0;
}
if (png->info) {
free_mem(png->info);
png->info = 0;
}
if (png->image) {
freeImage(png->image);
png->image = 0;
}
free_mem(png);
}
static int
pngAddData(void *pointer, byte *data, int len, bool data_ended)
{
pngState *png = (pngState *) pointer;
if (setjmp(png->state->jmpbuf))
return image_error;
if (len > png->lenSoFar) {
png_process_data(png->state, png->info, data + png->lenSoFar,
len - png->lenSoFar);
png->lenSoFar = len;
}
if (image_need_data == png->done && data_ended)
return image_error;
return png->done;
}
void
pngInit(void (*lineProc)(void *, int, int), void *closure, struct ifs_vector *ifsv)
{
pngState *png;
ifsv->image_format_closure = 0;
png = (pngState *) alloc_mem(sizeof(pngState));
if (!png)
return;
memset(png, 0, sizeof(pngState));
png->lineProc = lineProc;
png->closure = closure;
png->state = (png_struct *) alloc_mem(sizeof(png_struct));
if (!png->state)
return;
png->info = (png_info *) alloc_mem(sizeof(png_info));
if (!png->info) {
free_mem(png->state);
return;
}
if (setjmp(png->state->jmpbuf)) {
png_read_destroy(png->state, png->info, (png_info *) 0);
free_mem(png->state);
free_mem(png->info);
png->state = 0;
png->info = 0;
return;
}
png_info_init(png->info);
png_read_init(png->state);
png_set_progressive_read_fn(png->state, (void *) png, lf_info_callback,
lf_row_callback, lf_end_callback);
png->done = image_need_data;
png->lenSoFar = 0;
ifsv->initProc = &pngInit;
ifsv->destroyProc = &pngDestroy;
ifsv->addDataProc = &pngAddData;
ifsv->getImageProc = &pngGetImage;
ifsv->image_format_closure = (void *) png;
}

Some files were not shown because too many files have changed in this diff Show More