Upstream tarball
This commit is contained in:
commit
21863d7241
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
This is chimera version 2. Please look in doc/ for license information,
|
||||
build information, and other bits.
|
||||
|
||||
-john
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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()
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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));
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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!
|
||||
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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::
|
|
@ -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
|
|
@ -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));
|
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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]);
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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()
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -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
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue