/* $Id: qint.h,v 1.17 2006/06/23 19:45:14 agraef Exp $
   qint.h: access the Q interpreter in a C/C++ application */

/*  Q eQuational Programming System
    Copyright (c) 1991-2004 by Albert Graef
    <ag@muwiinfa.geschichte.uni-mainz.de, Dr.Graef@t-online.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 1, 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 LIBQ_H
#define LIBQ_H 1

#include <stdlib.h>
#include <stdio.h>

/* __declspec magic required to make Windows DLLs work */
#ifndef __DLL_BUILD
#if defined _WIN32
#define __DLLIMPORT __declspec(dllimport)
#define __DLLEXPORT __declspec(dllexport)
#else
#define __DLLIMPORT extern
#define __DLLEXPORT
#endif
#endif

/* support C++ */
#ifdef __cplusplus
extern "C" {
#endif

/* Please note that in the following, all char* parameters flagged as const
   belong to the caller and are not modified by the libqint functions in any
   way. The same holds for the char* vectors passed to the qexecv* functions.
   Strings returned by the API calls are generally allocated dynamically and
   must be freed by the caller, unless explicitly mentioned otherwise. */

/***************************************************************************/

/* Error handling. Some of the functions below return a status code, which can
   be decoded to an error message with the following function. The returned
   string is owned by the interpreter and must not be modified by the caller.
   Note that some error strings contain a %s placeholder for the source file
   name; this can only happen for status codes returned by the qexecv() and
   qexecl() functions. */

__DLLIMPORT char *qstrerror(int status);

/***************************************************************************/

/* Load a script into the interpreter. Only a single script can be loaded at
   any one time; when loading a new script it replaces an existing one. Also
   note that these operations *must* always be executed in the same thread of
   your application (usually the main thread of the application) which becomes
   the main thread of the interpreter. (For applications which evaluate
   expressions in multiple threads please also see the multithreading support
   operations discussed below.) */

/* The following operations are used to load a script or byte code file into
   the interpreter.

   The relative or absolute path to the script file is given in the path
   parameter. If the pathname is a relative one, the script will be searched
   on the Q library path as usual. The argc parameter specifies the number of
   parameters to pass to the script, including the script name (which is
   parameter 0) itself; the actual parameters are specified as a vector of
   zero-terminated strings with qexecv(), and as a list of string parameters
   with qexecl(). The given parameters determine the contents of the
   interpreter's ARGS variable. If you specify a zero argc count then the
   remaining parameters will be ignored, and the script name (ARGS!0) will be
   set from the path parameter. If path is NULL as well then an empty script
   will be assumed.

   Both functions return a status value indicating whether the operation
   succeeded. The return value will be 0 iff the script was loaded
   successfully. */

__DLLIMPORT int qexecv(const char *path, int argc, char *const argv[]);
__DLLIMPORT int qexecl(const char *path, int argc, ...);

/* The following operations work like qexecv()/qexecl() above, but let you
   pass the script or byte code directly in a buffer which is of the given
   size in bytes. */

__DLLIMPORT int qexecvx(const void *buf, size_t size, int argc,
			char *const argv[]);
__DLLIMPORT int qexeclx(const void *buf, size_t size, int argc, ...);

/***************************************************************************/

/* Evaluate an expression in the interpreter. This is a convenience function
   which takes its input from a string, parses the expression, evaluates it,
   unparses the result, and returns the result as a malloc'd string. It is the
   responsibility of the caller to free the result string when appropriate.
   The returned status is zero iff the evaluation completed successfully.
   Otherwise the return value will be NULL, unless an exception occurred in
   which case the exception value is returned as the result. Note that both
   the input and the result string use the system encoding, the necessary
   conversions to/from the UTF-8 encoding used internally by the Q interpreter
   are done automatically. */

__DLLIMPORT char *qeval(const char *s, int *status);

/* Q expression type (opaque). */

typedef void *qexpr;

/* The following operation works like qeval() above, but evaluates an
   expression given as a qexpr object and returns the result as another qexpr
   object. It is the responsibility of the caller to free the returned
   result. If the expression argument is a temporary (see below), it is
   collected automatically. */

__DLLIMPORT qexpr qevalx(qexpr x, int *status);

/* Operations to parse and unparse expressions. It is the responsibility of
   the caller to free the result expression returned by qparse() and the
   malloc'd string returned by qprint() when appropriate. If the expression
   argument of qprint() is a temporary (see below), it is collected
   automatically. Both operations return NULL and leave an appropriate
   non-zero error code in the status parameter if some error condition
   arises. */

__DLLIMPORT qexpr qparse(const char *s, int *status);
__DLLIMPORT char *qprint(qexpr x, int *status);

/* Define and undefine variables. The given name must either denote an
   existing (possibly qualified) variable symbol, or a new (unqualified)
   variable symbol which will be created in the global namespace of the
   interpreter. Note that the given expression is assumed to be in normal
   form, so it is the caller's responsibility to evaluate it first. To
   undefine a variable, pass NULL as the value of the expression. The returned
   value is zero iff the operation succeeded and an appropriate error code
   otherwise. */

__DLLIMPORT int qdef(const char *name, qexpr x);

/***************************************************************************/

/* Management of expression objects. When a new toplevel expression is first
   created, either explicitly with one of the expression construction
   operations (see below) or implicitly by a call to qevalx() or qparse(), its
   reference count is initialized to zero, indicating a temporary value. Such
   values are collected with the qdispose() function (this is also done
   automatically for the arguments to qevalx() and qprint(), see above). You
   can safely apply this to any expression, since only top level temporaries
   will actually be destroyed.

   Applying qnewref() to an expression increments its reference count and
   returns the expression itself. This also turns a temporary toplevel
   expression into a persistent object. This operation should be invoked
   whenever an expression object is assigned to a variable. Conversely,
   applying qfreeref() decrements the reference count and causes the
   expression to be garbage-collected when the count drops to zero. This
   operation should be invoked when an expression value stored in a variable
   is no longer needed. The number of calls to qfreeref() must match the
   number of previous qnewref() calls on the same expression before it is
   garbage-collected. The qfreeref() function can also be applied to a
   temporary in which case qfreeref() behaves in the same way as qdispose().

   Moreover, all three functions can also be applied to a NULL expression
   argument, in which case no action is performed. */

__DLLIMPORT void qdispose(qexpr x);
__DLLIMPORT qexpr qnewref(qexpr x);
__DLLIMPORT void qfreeref(qexpr x);

/***************************************************************************/

/* Create and inspect Q expression objects. These operations are analogous to
   the routines provided by libq, see libq.h for details. */

/* IMPORTANT: For efficiency reasons, the expression vectors or external
   objects behind pointers passed to the construction operations or returned
   by the inspection operations are *not* copied, but are owned by the
   interpreter. Applications should not attempt to free such pointers. */

/* Macros to access the symbol table. */

#define qsym(name) qgetsym( #name )
#define qtype(name) qgettype( #name )

__DLLIMPORT int qgetsym(const char *name);
__DLLIMPORT int qgettype(const char *name);

/* Determine the precedence of an operator symbol. Returns -1 for ordinary
   function symbols, and the precedence level in the range 0..9 otherwise. */
__DLLIMPORT int qsymprec(int sym);

/* Predefined function and type symbols. */

#if defined(_WIN32) && defined(__cplusplus)
/* Apparently __DLLIMPORT+const gives troubles with Mingw, so we just drop the
   const here. Thanks to Brian Wilfley <drclearly@gmail.com>. */
__DLLIMPORT int qtruesym, qfalsesym, qnilsym, qvoidsym;
__DLLIMPORT int qinttype, qfloattype, qbooltype, qstrtype, qfiletype,
  qlisttype, qtupletype;
#else
__DLLIMPORT const int qtruesym, qfalsesym, qnilsym, qvoidsym;
__DLLIMPORT const int qinttype, qfloattype, qbooltype, qstrtype, qfiletype,
  qlisttype, qtupletype;
#endif

/* Expression construction. If any of these operations fails, the result will
   be NULL and temporary argument expressions are collected automatically.
   This also happens if any of the argument expressions is NULL. Otherwise the
   argument expressions become part of the constructed expression and their
   reference counts are updated accordingly. */

/* Atomic objects: integers, real values, strings, files, and pipes created
   with popen(3). */

__DLLIMPORT qexpr qmkint(long i);
__DLLIMPORT qexpr qmkuint(unsigned long i);
__DLLIMPORT qexpr qmkmpz(void *z /* mpz_t z */);
__DLLIMPORT qexpr qmkmpz_float(double f);
__DLLIMPORT qexpr qmkfloat(double f);
__DLLIMPORT qexpr qmkstr(char *s);
__DLLIMPORT qexpr qmkfile(FILE *fp);
__DLLIMPORT qexpr qmkpipe(FILE *fp);

/* Function (and variable) symbols and external objects. */

__DLLIMPORT qexpr qmksym(int sym);
__DLLIMPORT qexpr qmkbool(int flag);
__DLLIMPORT qexpr qmkobj(int type, void *ptr);

/* Applications, list and tuple construction ([|] resp. (|)). */

__DLLIMPORT qexpr qmkapp(qexpr fun, qexpr arg);
__DLLIMPORT qexpr qmkcons(qexpr hd, qexpr tl);
__DLLIMPORT qexpr qmkcont(qexpr hd, qexpr tl);

/* Create a list or tuple from a given element list. */

__DLLIMPORT qexpr qmklistl(int nelems, ...);
__DLLIMPORT qexpr qmklistv(int nelems, qexpr *elems);

__DLLIMPORT qexpr qmktuplel(int nelems, ...);
__DLLIMPORT qexpr qmktuplev(int nelems, qexpr *elems);

/* Common types of constants defined as parameterless macros. */

#define qmktrue qmksym(qtruesym)
#define qmkfalse qmksym(qfalsesym)
#define qmknil qmksym(qnilsym)
#define qmkvoid qmksym(qvoidsym)

/* Type checking and unboxing. */

__DLLIMPORT int qexprsym(const qexpr x);
__DLLIMPORT int qexprtype(const qexpr x);

__DLLIMPORT int qisint(const qexpr x, long *i);
__DLLIMPORT int qisuint(const qexpr x, unsigned long *i);
__DLLIMPORT int qismpz(const qexpr x, void *z /*mpz_t z*/);
__DLLIMPORT int qismpz_float(const qexpr x, double *f);
__DLLIMPORT int qisfloat(const qexpr x, double *f);
__DLLIMPORT int qisstr(const qexpr x, char **s);
__DLLIMPORT int qisfile(const qexpr x, FILE **fp);

__DLLIMPORT int qissym(const qexpr x, int sym);
__DLLIMPORT int qisbool(const qexpr x, int *flag);
__DLLIMPORT int qisobj(const qexpr x, int type, void **ptr);

__DLLIMPORT int qisapp(const qexpr x, qexpr *fun, qexpr *arg);
__DLLIMPORT int qiscons(const qexpr x, qexpr *hd, qexpr *tl);
__DLLIMPORT int qiscont(const qexpr x, qexpr *hd, qexpr *tl);

__DLLIMPORT int qistuple(const qexpr x, int *nelems, qexpr **elems);

/* Check for the predefined constants. */

#define qistrue(x) qissym(x, qtruesym)
#define qisfalse(x) qissym(x, qfalsesym)
#define qisnil(x) qissym(x, qnilsym)
#define qisvoid(x) qissym(x, qvoidsym)

/* Unicode helpers. These are only needed when encoding UTF-8 string data for
   qmkstr, decoding UTF-8 string data obtained with qisstr, or when encoding
   or decoding string data in connection with Q file objects (which have their
   own builtin iconv conversion handles). The given source/target encoding may
   also be NULL, in which case the system encoding is assumed. */

__DLLIMPORT char *qfrom_utf8(const char *s, const char *encoding);
__DLLIMPORT char *qto_utf8(const char *s, const char *encoding);

__DLLIMPORT char *qfile_from_utf8(const char *s, qexpr file);
__DLLIMPORT char *qfile_to_utf8(const char *s, qexpr file);
__DLLIMPORT int qfile_encoding(qexpr file, const char *encoding);

/***************************************************************************/

/* Multithreading support. The Q interpreter itself is thread-safe, but it
   must know about those "secondary" threads of your application (i.e., all
   threads other than the "main thread" in which qexecv()/qexecl() was
   executed) which want to evaluate expressions or manipulate them in any
   other way. The following operations register and unregister such threads
   with the interpreter, so that the thread-local resources of the interpreter
   (such as the evaluation stack) are properly initialized and finalized.

   The qinit_thread() function returns an integer id to be used with the
   qfini_thread() function when the thread is no longer needed. Note that
   after calling qfini_thread() any attempt to call one of the other
   operations of this library in the finalized thread is a sure way to make
   the interpreter segfault all over the place. ;-) */

__DLLIMPORT int qinit_thread(void);
__DLLIMPORT void qfini_thread(int id);

/* Usually the main thread (in which qexecv()/qexecl() was executed) holds the
   interpreter's lock, which will keep other background threads created in
   your Q script from running, unless an evaluation is in progress. Therefore
   you should explicitly release the lock with qrelease() if your application
   does not need the interpreter. The qacquire() function is then used to
   reacquire the lock before doing an evaluation. */

__DLLIMPORT void qacquire(void);
__DLLIMPORT void qrelease(void);

/***************************************************************************/

/* WIN32 KLUDGE ALERT: We redefine the memory management routines here to use
   wrappers provided by libqint, which use the same malloc() and friends as
   the Q interpreter, namely those from the Mingw compiler. These replacements
   *must* be used when allocating or freeing a pointer passed to or from the
   interpreter in MSVC-based applications on Windows, because the MSVC memory
   allocation routines are *not* compatible with those of Mingw. This would
   lead to memory corruption when MSVC-allocated pointers are passed to the
   interpreter or pointers allocated and returned by the interpreter are freed
   by the MSVC application. */

#ifndef __DLL_BUILD
#ifdef _WIN32
#include <malloc.h>
#define malloc qmalloc
#define realloc qrealloc
#define calloc qcalloc
#define free qfree
#endif
#endif

__DLLIMPORT void *qmalloc(size_t size);
__DLLIMPORT void *qrealloc(void *p, size_t size);
__DLLIMPORT void *qcalloc(size_t num, size_t size);
__DLLIMPORT void qfree(void *p);

#ifdef __cplusplus
}
#endif

#endif
