Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]

Modules

ADT
Database
GTK2
GUI
IP
PiJAX
Public
Sql
Stdio
Subversion
System
Tools
Xosd
lua
v4l2
wx

Recent Changes

Public.Parser.XML2 1.50
Public.ZeroMQ 1.1
Public.Template.Mustache 1.0
Public.Protocols.XMPP 1.4
Sql.Provider.jdbc 1.0

Popular Downloads

Public.Parser.JSON2 1.0
Public.Parser.JSON 0.2
GTK2 2.23
Public.Web.FCGI 1.8
Public.Parser.XML2 1.48


Module Information
Public.Parser.ClearSilver
Viewing contents of Public_Parser_ClearSilver-1.2/ClearSilver.cmod

/*
 * Copyright (c) 2005 Adam Montague 
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND 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, DIRECT, 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 "util.h"
#include 

/* creates a C string containing the text of a NEOERR */
static char *format_error(NEOERR *err)
{
	STRING str;
	char *ret;

	if (err == NULL) {
		return("");
	}

	string_init(&str);
	if (nerr_match(err, NERR_PARSE)) {
		nerr_error_string(err, &str);
	} else {
		nerr_error_traceback(err, &str);
	}
	ret = strdup(str.buf);
	string_clear(&str);
	return (ret);
}

/* used to render templates, since clearsilver uses its own string type */
static NEOERR *output(void *ctx, char *s)
{
	NEOERR *err = string_append((STRING *)ctx, s);
	return (err);
}

/* sort function wrapper to call the pike function supplied by the user */
/* the actual function is at the bottom of the file, because I need OBJ2_HDF */
static int sortme(const void *, const void *);

/*! @module Public
 */

/*! @module Parser
 */

/*! @module ClearSilver
 */

EXTRA
{
	add_string_constant("__version", "1.2", 0);
	add_string_constant("__author", "Adam Montague ", 0);
}

/*! @class HDF
 */
PIKECLASS HDF
{
	CVAR HDF *hdf;

	INIT
	{
		THIS->hdf = NULL;
	}

	EXIT
	{
	}

/*! @decl void create()
 *!   Creates a new, empty HDF object.  HDF objects are used to store
 *!   and manipulate all the data to be rendered by a CS object.
 */
	PIKEFUN void create()
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = hdf_init(&(THIS->hdf));
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error("HDF Initialization failed\n");
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

	PIKEFUN void destroy(void|int a)
	{
		pop_n_elems(args);
		if (THIS->hdf != NULL)
			hdf_destroy(&(THIS->hdf));
	}

/*! @decl void read_file(string filename)
 *!   Reads and parses a file containing an HDF dataset, and adds it
 *!   to the current object.
 *!
 *! @param filename
 *!   The name of the file containing the HDF dataset.
 */
	PIKEFUN void read_file(string filename)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = hdf_read_file(THIS->hdf, filename->str);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl void write_file(string filename)
 *!   Writes the current HDF dataset out to a file.
 *!
 *! @param filename
 *!   The name of the file to write the data to.  If it exists, the file
 *!   will be overwritten.
 */
	PIKEFUN void write_file(string filename)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = hdf_write_file(THIS->hdf, filename->str);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl string get(string hdfpath)
 *!   Returns the value of hdfpath, or 0 if hdfpath does
 *!   not exist.
 *!
 *! @param hdfpath
 *!   The path to look for the value in dotted form "A.B.C".
 */
	PIKEFUN string get(string hdfpath)
	{
		struct pike_string *ret;
		char *string;
		char *undefined = "__UNDEFINED_HDF__";
		
		string = hdf_get_value(THIS->hdf, hdfpath->str, undefined);
		if (string == undefined) {
			pop_n_elems(args);
			return;
		}
		ret = make_shared_string(string);
		free(string);
		RETURN(ret);
	}

/*! @decl void set(string hdfpath, string value)
 *!   Sets hdfpath to be new_value.
 *!
 *! @param hdfpath
 *!   The path to set in dotted form "A.B.C".
 *!
 *! @param value
 *!   The value to set hdfpath to.
 */
	PIKEFUN void set(string hdfpath, string value)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = hdf_set_value(THIS->hdf, hdfpath->str, value->str);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl void sort(function sort_function)
 *!   Sorts an HDF object's data using the supplied function.
 *!
 *! @param sort_function
 *!   The function used to sort the HDF data.  It must accept two strings, and return
 *!   1 if the first argument is greater than the second, 0 if they are equal, or -1
 *!   if the first argument is less than the second.
 */
	PIKEFUN void sort(function sort_function)
	{
		hdf_sort_obj(THIS->hdf, sortme);
		pop_n_elems(args);
	}

/*! @decl string name()
 *!   Returns the name of the current HDF node.  Only the current level
 *!   is returned.  If this node is A.B.C, obj_name will return "C".
 */
	PIKEFUN string name()
	{
		struct pike_string *ret;
		char *string;

		string = hdf_obj_name(THIS->hdf);
		if (string == NULL) {
			RETURN(make_shared_string(""));
		}

		ret = make_shared_string(string);
		RETURN(ret);
	}

/*! @decl string value()
 *!   Returns the value of the current HDF node.
 */
	PIKEFUN string value()
	{
		struct pike_string *ret;
		char *string;
		
		string = hdf_obj_value(THIS->hdf);
		if (string == NULL) {
			RETURN(make_shared_string(""));
		}

		ret = make_shared_string(string);
		RETURN(ret);
	}

/*! @decl Public.Parser.ClearSilver.HDF child()
 *!   Returns an HDF object representing the child of the current HDF object.
 */
	PIKEFUN object child()
	{
		struct object *ret;

		ret = clone_object(HDF_program, 0);
		OBJ2_HDF(ret)->hdf = hdf_obj_child(THIS->hdf);
		if (OBJ2_HDF(ret)->hdf == NULL) {
			free_object(ret);
			pop_n_elems(args);
			return;
		}
		RETURN(ret);
	}

/*! @decl Public.Parser.ClearSilver.HDF next()
 *!   Returns an HDF object representing the next peer of the current
 *!   HDF object.
 */
	PIKEFUN object next()
	{
		struct object *ret;

		ret = clone_object(HDF_program, 0);
		OBJ2_HDF(ret)->hdf = hdf_obj_next(THIS->hdf);
		if (OBJ2_HDF(ret)->hdf == NULL) {
			free_object(ret);
			pop_n_elems(args);
			return;
		}
		RETURN(ret);
	}

/*! @decl Public.Parser.ClearSilver.HDF get_hdf(string hdfpath)
 *!   Returns an HDF object representing the HDF subtree located at
 *!   hdfpath.
 *!
 *! @param hdfpath
 *!   The path to retrieve in dotted form "A.B.C".
 */
	PIKEFUN object get_hdf(string name)
	{
		struct object *ret;

		ret = clone_object(HDF_program, 0);
		OBJ2_HDF(ret)->hdf = hdf_get_obj(THIS->hdf, name->str);
		if (OBJ2_HDF(ret)->hdf == NULL) {
			free_object(ret);
			pop_n_elems(args);
			return;
		}
		RETURN(ret);
	}

/*! @decl Public.Parser.ClearSilver.HDF get_child(string hdfpath)
 *!   Returns an HDF object representing the child of the HDF path
 *!   hdfpath.
 *!
 *! @param hdfpath
 *!   The path to retrieve the child of, in dotted form "A.B.C".
 */
	PIKEFUN object get_child(string name)
	{
		struct object *ret;

		ret = clone_object(HDF_program, 0);
		OBJ2_HDF(ret)->hdf = hdf_get_child(THIS->hdf, name->str);
		if (OBJ2_HDF(ret)->hdf == NULL) {
			free_object(ret);
			pop_n_elems(args);
			return;
		}
		RETURN(ret);
	}

/*! @decl void delete_tree(string hdfpath)
 *!   Recursively delete a node and all its child nodes from the HDF object.
 *!
 *! @param hdfpath
 *!   The path to the hdf node to delete, in dotted form "A.B.C".
 */
	PIKEFUN void delete_tree(string hdfpath)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = hdf_remove_tree(THIS->hdf, hdfpath->str);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl void copy(string hdfpath, Public.Parser.ClearSilver.HDF src)
 *!   Copies an HDF object into the current HDF object's tree.
 *!
 *! @param hdfpath
 *!   The path in the current object's tree to copy the object to, in
 *!   dotted form "A.B.C".
 *!
 *! @param src
 *!   The HDF object to copy into the current objects tree.
 */
	PIKEFUN void copy(string hdfpath, object src)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		if (src->prog != HDF_program)
			Pike_error("Invalid class for src argument\n");

		err = hdf_copy(THIS->hdf, hdfpath->str, OBJ2_HDF(src)->hdf);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl void read(string data)
 *!   Reads and parses a string of HDF data, and adds it to the current
 *!   object's HDF tree.  Returns 1 on success or 0 on failure.
 *!
 *! @param data
 *!   The data to read, in either HDF format.
 */
	PIKEFUN void read(string data)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = hdf_read_string(THIS->hdf, data->str);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl string write(string|void prefix)
 *!   Returns a string containing the current HDF dataset.
 *!
 *! @param prefix
 *!   The optional prefix to prepend to the HDF data returned.
 */
	PIKEFUN string write(string|void prefix)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;
		STRING str;
		struct pike_string *ret;

		string_init(&str);

		if (Pike_sp[-1].type == T_STRING) {
			err = hdf_dump_str(THIS->hdf, Pike_sp[-1].u.string->str, 1, &str);
		} else {
			err = hdf_dump_str(THIS->hdf, "", 1, &str);
		}

		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
		if (str.len == 0) {
			string_clear(&str);
			RETURN(make_shared_string(""));
		}

		ret = make_shared_string(str.buf);
		string_clear(&str);
		RETURN(ret);
	}
}

/*! @endclass
 */

/*! @class CS
 */
PIKECLASS CS
{
	CVAR CSPARSE *cs;

	INIT
	{
		THIS->cs = NULL;
	}

	EXIT
	{
	}

/*! @decl void create(Public.Parser.ClearSilver.HDF hdf)
 *!   Creates a new CS object.  CS objects take HDF data, and clearsilver
 *!   templates, and are used to parse and render the output.
 *!
 *! @param hdf
 *!   The HDF dataset to supply to templates parsed by this object.
 */
	PIKEFUN void create(object hdf)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		if (hdf->prog != HDF_program)
			Pike_error("Invalid class for hdf argument\n");

		err = cs_init(&(THIS->cs), OBJ2_HDF(hdf)->hdf);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}

		err = cgi_register_strfuncs(THIS->cs);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
		
		pop_n_elems(args);
	}

	PIKEFUN void destroy(void|int a)
	{
		pop_n_elems(args);
		if (THIS->cs != NULL) {
			cs_destroy(&(THIS->cs));
		}
	}

/*! @decl void parse_string(string template)
 *!   Parses a string containing a ClearSilver template and adds it
 *!   to the current parse tree.
 *!
 *! @param template
 *!   The string containing the ClearSilver template to be parsed.
 */
	PIKEFUN void parse_string(string template)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		/* ClearSilver modifies the string, so we can't use template->str
		 * directly.  It will free str for us though */
		char *str = strdup(template->str);
		if (str == NULL)
			Pike_error("Memory allocation failed!\n");

		err = cs_parse_string(THIS->cs, str, strlen(str));
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

/*! @decl void parse_file(string filename)
 *!   Parses a file containing a ClearSilver template and adds it
 *!   to the current parse tree.
 *!
 *! @param filename
 *!   The filename containing the ClearSilver template to be parsed.
 */
	PIKEFUN void parse_file(string filename)
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;

		err = cs_parse_file(THIS->cs, filename->str);
		if (err != STATUS_OK) {
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
	}

	PIKEFUN int register_handler()
	{
		//FIXME: make this function
		// ClearSilver does not allow you to do this yet
		RETURN(0);
	}

/*! @decl string render()
 *!   Does the final parsing of the internal parse tree and returns a
 *!   string containing the rendered output.
 */
	PIKEFUN string render()
	{
		NEOERR *err;
		char *err_msg;
		ONERROR tmp;
		struct pike_string *ret;
		STRING str;

		string_init(&str);
		err = cs_render(THIS->cs, &str, output);
		if (err != STATUS_OK) {
			string_clear(&str);
			err_msg = format_error(err);
			SET_ONERROR(tmp, free, err_msg);
			Pike_error(err_msg);
			CALL_AND_UNSET_ONERROR(tmp);
		}
		if (str.len == 0) {
			string_clear(&str);
			RETURN(make_shared_string(""));
		}

		ret = make_shared_string(str.buf);
		string_clear(&str);
		RETURN(ret);
	}
}

/*! @endclass
 */

/*! @endmodule
 */

/*! @endmodule
 */

/*! @endmodule
 */

static int sortme(const void *a, const void *b)
{
	int func, ret, i;
	HDF **ha = (HDF **)a;
	HDF **hb = (HDF **)b;

	for (i = 0; i < 2; i++) {
		push_text("Public.Parser.ClearSilver.HDF");
		SAFE_APPLY_MASTER("resolv", 1);
		apply_svalue(Pike_sp - 1, 0);

		/* we still need to remove the ClearSilver.HDF() function from the stack */
		stack_swap();
		pop_stack();
	}

	OBJ2_HDF(Pike_sp[-2].u.object)->hdf = *ha;
	OBJ2_HDF(Pike_sp[-1].u.object)->hdf = *hb;
	
	apply_svalue(Pike_sp - 3, 2);
	ret = Pike_sp[-1].u.integer;
	pop_n_elems(3);
	return (ret);
}


gotpike.org | Copyright © 2004 - 2019 | Pike is a trademark of Department of Computer and Information Science, Linköping University