/* -*-c-*-
*
- * $Id: rxglue.c,v 1.1 2002/01/25 19:34:45 mdw Exp $
+ * $Id: rxglue.c,v 1.4 2002/02/02 22:43:50 mdw Exp $
*
* REXX glue for C core functionality
*
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: rxglue.c,v $
- * Revision 1.1 2002/01/25 19:34:45 mdw
- * Initial revision
- *
- */
-
/*----- Header files ------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include <rexxsaa.h>
#include <mLib/alloc.h>
+#include <mLib/exc.h>
#include <mLib/dstr.h>
+#include "au.h"
+#include "aunum.h"
#include "err.h"
#include "rxglue.h"
#include "txport.h"
static txport *tx = 0;
+/*----- Memory allocation functions ---------------------------------------*/
+
+static void *rx_alloc(size_t sz)
+{
+ void *p = RexxAllocateMemory(sz);
+ if (!p)
+ THROW(EXC_NOMEM);
+ return (p);
+}
+
+static void rx_free(void *p)
+{
+ RexxFreeMemory(p);
+}
+
/*----- Conversion functions ----------------------------------------------*/
/* --- @rxs_putm@ --- *
const void *_p = (p); \
size_t _sz = (sz); \
if (!_x->strptr || _x->strlength < _sz) \
- _x->strptr = xmalloc(_sz); \
+ _x->strptr = rx_alloc(_sz); \
memcpy(_x->strptr, _p, _sz); \
_x->strlength = _sz; \
} while (0)
/*----- REXX functions ----------------------------------------------------*/
-static APIRET APIENTRY rxfn_test(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_test(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
ULONG i;
else
printf("' (%ld)\n", l);
}
- printf("tx = `%s'; f = `%s'; c = `%s'.", txname, txfile, txconf);
+ printf("tx = `%s'; f = `%s'; c = `%s'.\n", txname, txfile, txconf);
rxs_putf(r, "function `%s' completed ok", fn);
return (0);
}
* Returns: The currently-selected transport name.
*/
-static APIRET APIENTRY rxfn_txname(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txname(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
if (ac)
return (-1);
* Returns: The currently-selected transport filename.
*/
-static APIRET APIENTRY rxfn_txfile(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txfile(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
if (ac)
return (-1);
return (0);
}
-/* --- @txfile()@ ---
+/* --- @txconf([CONFIG])@ ---
*
- * Arguments: ---
+ * Arguments: @CONFIG@ = optional string to set
*
* Returns: The currently-selected transport configuration string.
*/
-static APIRET APIENTRY rxfn_txconf(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txconf(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
- if (ac)
+ if (ac > 1)
return (-1);
+ if (ac > 0 && av[0].strptr) {
+ dstr d = DSTR_INIT;
+ int rc;
+ if (!tx)
+ return (-1);
+ rxs_get(&av[0], &d);
+ rc = tx_configure(tx, d.buf);
+ dstr_destroy(&d);
+ if (rc)
+ return (-1);
+ }
rxs_putf(r, "%s", txconf ? txconf : "");
return (0);
}
* defaults.
*/
-static APIRET APIENTRY rxfn_txinit(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txinit(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
const char *n = txname, *f = txfile, *c = txconf;
dstr dn = DSTR_INIT, df = DSTR_INIT, dc = DSTR_INIT;
f = df.buf;
}
if (ac >= 3 && av[2].strptr) {
- rxs_get(&av[2], &dn);
+ rxs_get(&av[2], &dc);
c = dc.buf;
}
tx = tx_create(n, f, c);
return (0);
}
-/* --- @txsend(STRING)@ --- *
+/* --- @txsend(STRING, [OPTION])@ --- *
*
* Arguments: @STRING@ = string to send
+ * @OPTION@ = `l' or `n' (for `linebreak' or `nolinebreak')
*
* Returns: ---
*
* Use: Sends a string (exactly as written) to the transport.
*/
-static APIRET APIENTRY rxfn_txsend(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txsend(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
- if (ac != 1 || !tx || !av[0].strptr)
+ if ((ac != 1 && ac != 2) || !tx || !av[0].strptr)
return (-1);
tx_write(tx, av[0].strptr, av[0].strlength);
+ if (ac == 1 || !av[1].strptr || !av[1].strlength ||
+ av[1].strptr[0] == 'l' || av[1].strptr[0] == 'L')
+ tx_newline(tx);
return (0);
}
* `f') then don't give up. The default is to wait forever.
*/
-static APIRET APIENTRY rxfn_txrecv(unsigned char *fn, ULONG ac, RXSTRING *av,
- char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txrecv(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
txline *l;
unsigned long t = FOREVER;
* false.
*/
-static APIRET APIENTRY rxfn_txeof(unsigned char *fn, ULONG ac,
- RXSTRING *av, char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txeof(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
if (ac || !tx)
return (-1);
* 0 had been specified).
*/
-static APIRET APIENTRY rxfn_txready(unsigned char *fn, ULONG ac,
- RXSTRING *av, char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_txready(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
unsigned long t = 0;
return (0);
}
+/* --- @AUPLAY(TAG, [FLAG])@ --- *
+ *
+ * Arguments: @TAG@ = audio sample tag to play
+ * @FLAG@ = a string to explain what to do more clearly.
+ *
+ * Returns: True if it succeeded.
+ *
+ * Use: Plays a sample. If @FLAG@ begins with `t', don't report
+ * errors if the sample can't be found.
+ */
+
+static APIRET APIENTRY rxfn_auplay(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
+{
+ dstr d = DSTR_INIT;
+ int rc = 1;
+
+ if (ac < 1 || !av[0].strlength || ac > 2)
+ return (-1);
+ rxs_get(&av[0], &d);
+ if (ac > 1 && av[1].strlength >= 1 &&
+ (av[1].strptr[0] == 't' || av[1].strptr[0] == 'T'))
+ rc = au_tryplay(d.buf);
+ else
+ au_play(d.buf);
+ dstr_destroy(&d);
+ rxs_putf(r, "%d", rc);
+ return (0);
+}
+
+/* --- @AUFETCH(TAG)@ --- *
+ *
+ * Arguments: @TAG@ = audio sample tag to play
+ *
+ * Returns: True if it succeeded.
+ *
+ * Use: Prefetches a sample into the cache.
+ */
+
+static APIRET APIENTRY rxfn_aufetch(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
+{
+ dstr d = DSTR_INIT;
+ int rc = 0;
+ au_sample *s;
+ au_data *a;
+
+ if (ac < 1 || !av[0].strlength || ac > 1)
+ return (-1);
+ rxs_get(&av[0], &d);
+ if ((s = au_find(d.buf)) != 0 &&
+ (a = au_fetch(s)) != 0) {
+ au_free(a);
+ rc = 1;
+ }
+ dstr_destroy(&d);
+ rxs_putf(r, "%d", rc);
+ return (0);
+}
+
+/* --- @AUNUM(TAG)@ --- *
+ *
+ * Arguments: @NUM@ = a number to be read
+ *
+ * Returns: ---
+ *
+ * Use: Reads a number aloud to the audio device.
+ */
+
+static APIRET APIENTRY rxfn_aunum(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
+{
+ dstr d = DSTR_INIT;
+
+ if (ac < 1 || !av[0].strlength || ac > 1)
+ return (-1);
+ rxs_get(&av[0], &d);
+ aunum(d.buf);
+ dstr_destroy(&d);
+ return (0);
+}
+
+/* --- @AUCACHE([FLAG], [VALUE, ...]@ --- *
+ *
+ * Arguments: @FLAG@ = operation to perform
+ *
+ * Returns: Dependent on operation.
+ *
+ * Use: If @FLAG@ is omitted or `Info', returns audio cache usage
+ * information as words in the following order:
+ *
+ * sz_max Maximum allowed cache size
+ * sz_total Total size used by samples
+ * sz_spare Size used by `spare' samples
+ * sz_queue Size used by queued samples
+ * n_total Total number of cached samples
+ * n_spare Number of `spare' samples
+ * n_queue Number of queued samples
+ * hits Number of cache hits
+ * misses Number of cache misses
+ *
+ * If @FLAG@ is `Max', sets the maximum cache size to the first
+ * @VALUE@ (if set), and returns the old maximum on its own.
+ *
+ * If @FLAG@ is `Usage', returns the `sz_*' items, as a list of
+ * words.
+ *
+ * If @FLAGS@ is `Numbers', returns the `n_*' items, as a list
+ * of words.
+ *
+ * If @FLAGS@ is `Hits', returns `hits' and `misses' as a pair
+ * of words.
+ */
+
+static APIRET APIENTRY rxfn_aucache(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
+{
+ int i = 1;
+ au_cacheinfo c;
+
+ au_getcacheinfo(&c);
+ if (ac < 1 || !av[0].strlength)
+ goto info;
+ switch (av[0].strptr[0]) {
+ case 'i': case 'I': info:
+ rxs_putf(r, "%lu %lu %lu %lu %u %u %u %lu %lu",
+ (unsigned long)c.sz_max, (unsigned long)c.sz_total,
+ (unsigned long)c.sz_spare, (unsigned long)c.sz_queue,
+ c.n_total, c.n_spare, c.n_total, c.hits, c.misses);
+ break;
+ case 'm': case 'M':
+ if (ac > i) {
+ long max;
+ if (rxs_tol(&av[i], &max))
+ return (-1);
+ au_setcachelimit(max);
+ i++;
+ }
+ rxs_putf(r, "%lu", (unsigned long)c.sz_max);
+ break;
+ case 'u': case 'U':
+ rxs_putf(r, "%lu %lu %lu %lu",
+ (unsigned long)c.sz_max, (unsigned long)c.sz_total,
+ (unsigned long)c.sz_spare, (unsigned long)c.sz_queue);
+ break;
+ case 'n': case 'N':
+ rxs_putf(r, "%u %u %u", c.n_total, c.n_spare, c.n_total);
+ break;
+ case 'h': case 'H':
+ rxs_putf(r, "%lu %lu", c.hits, c.misses);
+ break;
+ default:
+ return (-1);
+ }
+ if (i > ac)
+ return (-1);
+ return (0);
+}
+
/* --- @MILLIWAIT(MILLIS)@ --- *
*
* Arguments: @MILLIS@ = how long (in milliseconds) to wait
* Use: Waits for @MILLIS@ milliseconds. Always.
*/
-static APIRET APIENTRY rxfn_milliwait(unsigned char *fn, ULONG ac,
- RXSTRING *av, char *sn, RXSTRING *r)
+static APIRET APIENTRY rxfn_milliwait(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
{
long l;
struct timeval tv;
struct rxfntab { char *name; RexxFunctionHandler *fn; };
static const struct rxfntab rxfntab[] = {
- { "test", rxfn_test },
- { "txname", rxfn_txname },
- { "txfile", rxfn_txfile },
- { "txconf", rxfn_txconf },
- { "txinit", rxfn_txinit },
- { "txsend", rxfn_txsend },
- { "txrecv", rxfn_txrecv },
- { "txeof", rxfn_txeof },
- { "txready", rxfn_txready },
- { "milliwait", rxfn_milliwait },
+ { "test", rxfn_test },
+ { "txname", rxfn_txname },
+ { "txfile", rxfn_txfile },
+ { "txconf", rxfn_txconf },
+ { "txinit", rxfn_txinit },
+ { "txsend", rxfn_txsend },
+ { "txrecv", rxfn_txrecv },
+ { "txeof", rxfn_txeof },
+ { "txready", rxfn_txready },
+ { "auplay", rxfn_auplay },
+ { "aufetch", rxfn_aufetch },
+ { "aucache", rxfn_aucache },
+ { "aunum", rxfn_aunum },
+ { "milliwait", rxfn_milliwait },
{ 0, 0 }
};
name = "incore";
MAKERXSTRING(prog[0], (void *)p, sz);
MAKERXSTRING(prog[1], 0, 0);
- argv = xmalloc(ac * sizeof(*argv));
+ argv = rx_alloc(ac * sizeof(*argv));
for (i = 0; i < ac; i++)
MAKERXSTRING(argv[i], (char *)av[i], strlen(av[i]));
/* --- Run the script --- */
MAKERXSTRING(res, 0, 0);
- rc = RexxStart(ac, argv, (char *)name, prog,
- "CMD", RXCOMMAND, 0, &badrc, &res);
+ rc = RexxStart(ac, argv, name, prog,
+ "SYSTEM", RXSUBROUTINE, 0, &badrc, &res);
if (rc) {
- free(RXSTRPTR(res));
+ rx_free(RXSTRPTR(res));
+ rx_free(argv);
if (rc < 0)
err_report(ERR_RXERR, 0, -rc, "rexx error from script `%s'", name);
else
/* --- Pick apart the results --- */
dstr_putm(&d, RXSTRPTR(res), RXSTRLEN(res));
- free(RXSTRPTR(res));
+ rx_free(RXSTRPTR(res));
+ rx_free(argv);
dstr_putz(&d);
rc = atoi(d.buf);
dstr_destroy(&d);