Monday, November 08, 2010 at 12:05 AM.

on getUpstreamText (f, adrRelativePath=nil, renderedFileExtension="html") {
		<<7/31/02; 3:34:47 PM by JES
			<<Fixed a bug which would cause image URLs not to be patched correctly when radio.macros.imageUrl is used to generate backgroung image URLs for CSS.
				<<We weresearching for ="url" which will appear in <img> tags and <td background="url"...> tags, but in CSS background images are speficied as background: url(...), without '=' and without the quote characters.
				<<Now image urls are matched, and replaced without the leading =" and trailing ".
		<<5/11/02; 4:47:27 PM by JES
			<<Set pagetable.uri to the same value as pagetable.path. This is needed by (for example)
		<<1/24/02; 8:00:57 PM by JES
			<<If the file being rendered, or a #prefs.txt file in the context of the file defines a #renderedFileExtension directive, use the value of the directive for the file extension.
		<<12/17/01; 7:38:51 PM by DW
			<<Supports callbacks that get the text after it has been rendered.
		<<12/11/01; 3:09:54 PM by JES
			<<Make sure the radioResponder.atts sub-table of the pageTable exists before calling radio.webserver.gatherAttributes, because they're needed in order to process sub-templates.
		<<11/30/01; 9:32:58 PM by JES
			<<Add the path to the pagetable.
		<<11/19/01; 1:40:31 AM by JES
			<<Added callback support, so developers can override the way the contents of an upstreamed is generated, and the path at which it's stored.
			<<Callback scripts are in the table.
			<<They take the following parameters:
				<<f -- the path to the file being rendered (upstreamed)
				<<adrFileText -- the address of a string in which to store the text to be upstreamed
				<<adrRelativePath -- the address of the relative path of the upstreamed file -- the callback should set this if the path or filename changes between the local path and the upstreamed path
			<<Callback scripts return true to override the default behavior, or false to allow this script to render the file.
		<<11/12/01; 2:32:35 PM by JES
			<<Complete rewrite. Radio's upstreaming architecture now supports rendering files as they are upstreamed.
			<<This script is the bottleneck which decides whether to render a file, and returns either rendered text, or the untouched text in the file.
			<<If you write an upstream driver, call through this script to get the text to send to the server.
			<<Pass in the path to the file, the address of a string which contains the relative path to the file in the www folder, and optionally an extension to use in case the file is rendered.
			<<Use the relative path in adrRelativePath^ as the relative path at which to store your file in its upstreamed location.
		<<5/13/01; 5:35:27 PM by DW
			<<Created. Most files will be upstreamed without rendering them, but if there's a #prefs file in the hierarchy that has #flRender true, then we'll catch it, and just before it gets upstreamed we'll render it. It's cute, but somewhat powerful.
	local (filetext);
	bundle { //run user callbacks
		if not defined ( {
			new (tableType,};
		local (nomad);
		for nomad in {
			try {
				while typeOf (nomad^) == addressType {
					nomad = nomad^};
				local (s);
				if nomad^ (f, @s, adrRelativePath) {
					return (s)}}}};
	local (fileMimeType = radio.webserver.getFileMimeType (f));
	local (flRender = false);
	if defined ([fileMimeType]) { //set flRender based on mime-type
		flRender =[fileMimeType]};
	if not { //rendering can be disabled by setting this flag to false
		flRender = false};
	bundle { //exception for directory.opml files which are sibblings of an upstream spec
		if string.lower (file.fileFromPath (f)) == string.lower ( {
			if file.exists (file.folderFromPath (f) + {
				flRender = false}}};
	if flRender { //we do render this mime-type -- check directives in #prefs files, and possibly render the file
		local (pagetable, atts);
		new (tabletype, @pagetable);
		new (tabletype, @pagetable.radioResponder);
		new (tabletype, @pagetable.radioResponder.atts);
		radio.webserver.gatherattributes (f, @atts, @pagetable);
		if html.getPref ("flRender", @pagetable) { //render the file
			new (tabletype, @pagetable.requestHeaders);
			bundle { //set some constants in the pagetable
				pagetable.method = "GET";
				<<pagetable.path = "/" + radio.file.getRelativePath (f) //JES: this would be consistent with mainResponder, but we're too well deployed to change it
				pagetable.path = radio.file.getRelativePath (f);
				pagetable.uri = "/" + pagetable.path};
			bundle { //set some constants in pagetable.radioResponder
				pagetable.radioResponder.flStaticRendering = true;
				pagetable.radioResponder.flHomePage = false;
				pagetable.radioResponder.flSameMachine = false;
				pagetable.radioResponder.flImagePatching = true};
			bundle { //put info about the file in the pageTable
				pagetable.radioResponder.fileMimeType = radio.webserver.getFileMimeType (f);
				radio.file.getFileAttributes (f, @pagetable.radioResponder.adrFileTable)};
			filetext = radio.webserver.buildpage (f, @pagetable);
			bundle { //possibly change the rendered file extension; patch relevant items in the pagetable
				if defined (pagetable.renderedFileExtension) {
					renderedFileExtension = pagetable.renderedFileExtension;
					if renderedFileExtension beginsWith "." { //it's expected not to
						renderedFileExtension = string.delete (renderedFileExtension, 1, 1)}}};
				<<bundle //patch pagetable.path and pagetable.uri -- JES: this would be consistent with mainResponder, but we're too well deployed to change it
					<<if not (pagetable.path endswith "/")
						<<local (lastpathpart = string.nthField (pagetable.path, "/", string.countFields (pagetable.path, "/")))
						<<if lastpathpart contains "."
							<<pagetable.path = string.delete (pagetable.path, sizeOf (pagetable.path) - sizeOf (lastpathpart) + 1, sizeOf (lastpathpart)) + string.popSuffix (lastpathpart) + "." + renderedFileExtension
			bundle { //write out the image files, patch image URLs
				if defined (pagetable.radioResponder.imagefiles) {
					local (pc = file.getPathChar ());
					local (imagefolder);
					bundle { //calculate the images sub-folder of the folder which contains the upstream spec for this file
						local (nomad = file.folderFromPath (f));
						loop { //pop out 'till we find the upstream spec, or get to the top-level of www
							if file.exists (nomad + {
							if string.lower (nomad) == string.lower ( {
							nomad = file.folderFromPath (nomad)};
						imagefolder = nomad + + pc};
					local (imagefolderurl = radio.upstream.getFileUrl (imagefolder));
					local (adrimagefile);
					for adrimagefile in @pagetable.radioResponder.imagefiles {
						local (fsource = + nameof (adrimagefile^));
						local (fdest = imagefolder + file.filefrompath (fsource));
						file.surefilepath (fdest);
						local (flcopy = true);
						if file.exists (fdest) {
							if file.modified (fsource) == file.modified (fdest) {
								flcopy = false}};
						if flcopy {
							file.copy (fsource, fdest);
							file.setmodified (fdest, file.modified (fsource));
							file.setcreated (fdest, file.created (fsource))};
						bundle { //patch the HTML text
							local (searchfor = adrimagefile^); //the url is the value
							local (replacewith = imagefolderurl + file.filefrompath (fsource) );
							filetext = string.replaceall (filetext, searchfor, replacewith, false)}}}};
			if adrRelativePath != nil { //change the file extension to .html
				<<temp.relPath = adrRelativePath^
				adrRelativePath^ = string.popSuffix (adrRelativePath^) + "." + renderedFileExtension}}
		else {
			flRender = false}};
	if not flRender {
		filetext = file.readWholeFile (f)};
	bundle { //call the callbacks
		<<12/17/01; 6:45:21 PM by DW
			<<The callbacks have to know the relative path, with the correct extension if they're going to mirror the content on the upstream server. The problem is that this routine takes adrRelativePath as an optional parameter. Ugh. So if it's not provided, it's nil, and the callbacks will fail when we try to dereference it. However I checked, and in all cases the parameter is provided, and if you think about it, it probably shouldn't have been an optional parameter. Just know if you're trying to figure out why your callbacks aren't getting control, it's probably because the caller isn't specifying adrRelativePath.
		on runCallbacks (adrcallbacktable) {
			local (adrscript);
			if not defined (adrcallbacktable^) {
				new (tabletype, adrcallbacktable)};
			for adrscript in adrcallbacktable {
				while typeOf (adrscript^) == addressType {
					adrscript = adrscript^};
				try {adrscript^ (adrRelativePath^, filetext)}}};
		runCallbacks (@radio.upstream.callbacks.upstreamFileRendered);
		runCallbacks (};
	return (filetext)}
<<bundle //test code
	<<local (relpath = "index.txt")
	<<webbrowser.displaytext (getUpstreamText ( + relpath, adrRelativePath:@relpath))
	<<relpath = "stories/2001/12/15/testingLegacyUrls.opml"
	<<webbrowser.displaytext (getUpstreamText ( + string.replaceall (relpath, "/", "\\"), adrRelativePath:@relpath))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:gems:mySubscriptions.opml"))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:2001:11:07.txt"))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:stories:newStory.txt"))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:stories:2001:11:16:teststory.opml"))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:categories:quotations:index.txt"))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:directory.opml"))
	<<webbrowser.displaytext (getUpstreamText ("PowerBook:Applications:Radio:Radio UserLand:www:categories:quotations:directory.opml"))
	<<webbrowser.bringtofront ()

This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.