diff options
Diffstat (limited to 'nyqsrc/nyx.c')
-rw-r--r-- | nyqsrc/nyx.c | 1294 |
1 files changed, 1294 insertions, 0 deletions
diff --git a/nyqsrc/nyx.c b/nyqsrc/nyx.c new file mode 100644 index 0000000..4cc1fea --- /dev/null +++ b/nyqsrc/nyx.c @@ -0,0 +1,1294 @@ +/********************************************************************** + + nyx.c + + Nyx: A very simple external interface to Nyquist + + Dominic Mazzoni + +**********************************************************************/ + +/* system includes */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <math.h> + +#ifndef WIN32 +#include <unistd.h> +#endif + +/* nyx includes */ +#include "nyx.h" + +/* xlisp includes */ +#include "switches.h" +#include "xlisp.h" +#include "cext.h" + +/* nyquist includes */ +#include "sound.h" +#include "samples.h" +#include "falloc.h" + +/* use full copy */ +#define NYX_FULL_COPY 1 + +/* show memory stats */ +// #define NYX_MEMORY_STATS 1 + +/* show details of obarray copy */ +// #define NYX_DEBUG_COPY 1 + +/* macro to compute the size of a segment (taken from xldmem.h) */ +#define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node)) + +/* xldmem external variables */ +extern long nnodes; +extern long nfree; +extern long total; +extern int nsegs; +extern SEGMENT *segs; +extern SEGMENT *lastseg; +extern LVAL fnodes; + +/* nyquist externs */ +extern LVAL a_sound; +extern snd_list_type zero_snd_list; + +/* globals */ +LOCAL nyx_os_callback nyx_os_cb = NULL; +LOCAL void *nyx_os_ud; +LOCAL nyx_output_callback nyx_output_cb; +LOCAL void *nyx_output_ud; +LOCAL int nyx_expr_pos; +LOCAL int nyx_expr_len; +LOCAL const char *nyx_expr_string; +LOCAL LVAL nyx_result; +LOCAL nyx_rval nyx_result_type = nyx_error; +LOCAL XLCONTEXT nyx_cntxt; +LOCAL int nyx_first_time = 1; +LOCAL LVAL nyx_obarray; +LOCAL FLOTYPE nyx_warp_stretch; + +/* Suspension node */ +typedef struct nyx_susp_struct { + snd_susp_node susp; // Must be first + nyx_audio_callback callback; + void *userdata; + long len; + int channel; +} nyx_susp_node, *nyx_susp_type; + +#if defined(NYX_DEBUG_COPY) && NYX_DEBUG_COPY +static const char *_types_[] = +{ + "FREE_NODE", + "SUBR", + "FSUBR", + "CONS", + "SYMBOL", + "FIXNUM", + "FLONUM", + "STRING", + "OBJECT", + "STREAM", + "VECTOR", + "CLOSURE", + "CHAR", + "USTREAM", + "EXTERN" +}; + +// Dump the contents of the obarray +LOCAL void nyx_show_obarray() +{ + LVAL array = getvalue(obarray); + LVAL sym; + int i; + + for (i = 0; i < HSIZE; i++) { + for (sym = getelement(array, i); sym; sym = cdr(sym)) { + LVAL syma = car(sym); + + printf("_sym_ = "); + xlprint(getvalue(s_stdout), syma, TRUE); + + if (getvalue(syma)) { + printf(" _type_ = %s _val_ = ", _types_[ntype(getvalue(syma))]); + xlprint(getvalue(s_stdout), getvalue(syma), TRUE); + } + + if (getfunction(syma)) { + printf(" _type_ = %s _fun_ = ", _types_[ntype(getfunction(syma))]); + xlprint(getvalue(s_stdout), getfunction(syma), TRUE); + } + + printf("\n"); + } + } +} +#endif + +// +// Free empty segments +// +LOCAL void freesegs() +{ + SEGMENT *seg; + SEGMENT *next; + + // Free up as many nodes as possible + gc(); + + // Reset free node tracking + fnodes = NIL; + nfree = 0L; + + // Reset the last segment pointer + lastseg = NULL; + + // Scan all segments + for (seg = segs; seg != NULL; seg = next) { + int n = seg->sg_size; + int empty = TRUE; + int i; + LVAL p; + + // Check this segment for in-use nodes + p = &seg->sg_nodes[0]; + for (i = n; --i >= 0; ++p) { + if (ntype(p) != FREE_NODE) { + empty = FALSE; + break; + } + } + + // Retain pointer to next segment + next = seg->sg_next; + + // Was the current segment empty? + if (empty) { + // Free the segment; + free((void *) seg); + + // Unlink it from the list. No need to worry about a NULL lastseg + // pointer here since the fixnum and char segments will always exist + // at the head of the list and they will always have nodes. So, lastseg + // will have been set before we find any empty nodes. + lastseg->sg_next = next; + + // Reduce the stats + total -= (long) segsize(n); + nsegs--; + nnodes -= n; + } + else { + // Not empty, so remember this node as the last segment + lastseg = seg; + + // Add all of the free nodes in this segment to the free list + p = &seg->sg_nodes[0]; + for (i = n; --i >= 0; ++p) { + if (ntype(p) == FREE_NODE) { + rplaca(p, NIL); + rplacd(p, fnodes); + fnodes = p; + nfree++; + } + } + } + } +} + +#if defined(NYX_FULL_COPY) && NYX_FULL_COPY + +// Copy a node (recursively if appropriate) +LOCAL LVAL nyx_dup_value(LVAL val) +{ + LVAL nval = val; + + // Protect old and new values + xlprot1(val); + xlprot1(nval); + + // Copy the node + if (val != NIL) { + switch (ntype(val)) + { + case FIXNUM: + nval = cvfixnum(getfixnum(val)); + break; + + case FLONUM: + nval = cvflonum(getflonum(val)); + break; + + case CHAR: + nval = cvchar(getchcode(val)); + break; + + case STRING: + nval = cvstring((char *) getstring(val)); + break; + + case VECTOR: + { + int len = getsize(val); + int i; + + nval = newvector(len); + nval->n_type = ntype(val); + + for (i = 0; i < len; i++) { + if (getelement(val, i) == val) { + setelement(nval, i, val); + } + else { + setelement(nval, i, nyx_dup_value(getelement(val, i))); + } + } + } + break; + + case CONS: + nval = cons(nyx_dup_value(car(val)), nyx_dup_value(cdr(val))); + break; + + case SUBR: + case FSUBR: + nval = cvsubr(getsubr(val), ntype(val), getoffset(val)); + break; + + // Symbols should never be copied since their addresses are cached + // all over the place. + case SYMBOL: + nval = val; + break; + + // Streams are not copied (although USTREAM could be) and reference + // the original value. + case USTREAM: + case STREAM: + nval = val; + break; + + // Externals aren't copied because I'm not entirely certain they can be. + case EXTERN: + nval = val; + break; + + // For all other types, just allow them to reference the original + // value. Probably not the right thing to do, but easier. + case OBJECT: + case CLOSURE: + default: + nval = val; + break; + } + } + + xlpop(); + xlpop(); + + return nval; +} + +// Make a copy of the original obarray, leaving the original in place +LOCAL void nyx_save_obarray() +{ + LVAL newarray; + int i; + + // This provide permanent protection for nyx_obarray as we do not want it + // to be garbage-collected. + xlprot1(nyx_obarray); + nyx_obarray = getvalue(obarray); + + // Create and set the new vector. This allows us to use xlenter() to + // properly add the new symbol. Probably slower than adding directly, + // but guarantees proper hashing. + newarray = newvector(HSIZE); + setvalue(obarray, newarray); + + // Scan all obarray vectors + for (i = 0; i < HSIZE; i++) { + LVAL sym; + + // Scan all elements + for (sym = getelement(nyx_obarray, i); sym; sym = cdr(sym)) { + LVAL syma = car(sym); + char *name = (char *) getstring(getpname(syma)); + LVAL nsym = xlenter(name); + + // Ignore *OBARRAY* since there's no need to copy it + if (strcmp(name, "*OBARRAY*") == 0) { + continue; + } + + // Duplicate the symbol's values + setvalue(nsym, nyx_dup_value(getvalue(syma))); + setplist(nsym, nyx_dup_value(getplist(syma))); + setfunction(nsym, nyx_dup_value(getfunction(syma))); + } + } + + // Swap the obarrays, so that the original is put back into service + setvalue(obarray, nyx_obarray); + nyx_obarray = newarray; +} + +// Restore the symbol values to their original value and remove any added +// symbols. +LOCAL void nyx_restore_obarray() +{ + LVAL obvec = getvalue(obarray); + int i; + + // Scan all obarray vectors + for (i = 0; i < HSIZE; i++) { + LVAL last = NULL; + LVAL dcon; + + for (dcon = getelement(obvec, i); dcon; dcon = cdr(dcon)) { + LVAL dsym = car(dcon); + char *name = (char *)getstring(getpname(dsym)); + LVAL scon; + + // Ignore *OBARRAY* since setting it causes the input array to be + // truncated. + if (strcmp(name, "*OBARRAY*") == 0) { + continue; + } + + // Find the symbol in the original obarray. + for (scon = getelement(nyx_obarray, hash(name, HSIZE)); scon; scon = cdr(scon)) { + LVAL ssym = car(scon); + + // If found, then set the current symbols value to the original. + if (strcmp(name, (char *)getstring(getpname(ssym))) == 0) { + setvalue(dsym, nyx_dup_value(getvalue(ssym))); + setplist(dsym, nyx_dup_value(getplist(ssym))); + setfunction(dsym, nyx_dup_value(getfunction(ssym))); + break; + } + } + + // If we didn't find the symbol in the original obarray, then it must've + // been added since and must be removed from the current obarray. + if (scon == NULL) { + if (last) { + rplacd(last, cdr(dcon)); + } + else { + setelement(obvec, i, cdr(dcon)); + } + } + + // Must track the last dcon for symbol removal + last = dcon; + } + } +} + +#else + +LOCAL LVAL copylist(LVAL from) +{ + LVAL nsym; + if (from == NULL) { + return NULL; + } + + return cons(car(from), copylist(cdr(from))); +} + +/* Make a copy of the obarray so that we can erase any + changes the user makes to global variables */ +LOCAL void nyx_copy_obarray() +{ + LVAL newarray; + int i; + + // Create and set the new vector. + newarray = newvector(HSIZE); + setvalue(obarray, newarray); + + for (i = 0; i < HSIZE; i++) { + LVAL from = getelement(nyx_obarray, i); + if (from) { + setelement(newarray, i, copylist(from)); + } + } +} + +#endif + +void nyx_init() +{ + if (nyx_first_time) { + char *argv[1]; + argv[0] = "nyquist"; + xlisp_main_init(1, argv); + + nyx_os_cb = NULL; + nyx_output_cb = NULL; + + nyx_first_time = 0; + +#if defined(NYX_FULL_COPY) && NYX_FULL_COPY + // Save a copy of the original obarray's contents. + nyx_save_obarray(); +#else + // Permanently protect the original obarray value. This is needed since + // it would be unreferenced in the new obarray and would be garbage + // collected. We want to keep it around so we can make copies of it to + // refresh the execution state. + xlprot1(nyx_obarray); + nyx_obarray = getvalue(obarray); +#endif + } + +#if !defined(NYX_FULL_COPY) || !NYX_FULL_COPY + // Create a copy of the original obarray + nyx_copy_obarray(); +#endif + + // Keep nyx_result from being garbage-collected + xlprot1(nyx_result); + +#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS + printf("\nnyx_init\n"); + xmem(); +#endif +} + +void nyx_cleanup() +{ + // Garbage-collect nyx_result + xlpop(); + +#if defined(NYX_FULL_COPY) && NYX_FULL_COPY + + // Restore the original symbol values + nyx_restore_obarray(); + +#else + + // Restore obarray to original state...but not the values + setvalue(obarray, nyx_obarray); + +#endif + + // Make sure the sound nodes can be garbage-collected. Sounds are EXTERN + // nodes whose value does not get copied during a full copy of the obarray. + setvalue(xlenter("S"), NIL); + + // Free excess memory segments - does a gc() + freesegs(); + + // No longer need the callbacks + nyx_output_cb = NULL; + nyx_os_cb = NULL; + +#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS + printf("\nnyx_cleanup\n"); + xmem(); +#endif +} + +LOCAL void nyx_susp_fetch(register nyx_susp_type susp, snd_list_type snd_list) +{ + sample_block_type out; + sample_block_values_type out_ptr; + long n; + int err; + + falloc_sample_block(out, "nyx_susp_fetch"); + out_ptr = out->samples; + snd_list->block = out; + + n = max_sample_block_len; + if (susp->susp.current + n > susp->len) + n = susp->len - susp->susp.current; + + err = susp->callback(out_ptr, susp->channel, + susp->susp.current, n, 0, susp->userdata); + if (err) { + // The user canceled or some other error occurred, so we use + // xlsignal() to jump back to our error handler. + xlsignal(NULL, NULL); + // never get here. + } + + snd_list->block_len = (short)n; + susp->susp.current += n; + + if (n == 0) { + /* we didn't read anything, but can't return length zero, so + convert snd_list to pointer to zero block */ + snd_list_terminate(snd_list); + } + else if (n < max_sample_block_len) { + /* should free susp */ + snd_list_unref(snd_list->u.next); + /* if something is in buffer, terminate by pointing to zero block */ + snd_list->u.next = zero_snd_list; + } +} + +LOCAL void nyx_susp_free(nyx_susp_type susp) +{ + ffree_generic(susp, sizeof(nyx_susp_node), "nyx_susp_free"); +} + +LOCAL void nyx_susp_print_tree(nyx_susp_type susp, int n) +{ +} + +void nyx_capture_output(nyx_output_callback callback, void *userdata) +{ + nyx_output_cb = callback; + nyx_output_ud = userdata; +} + +void nyx_set_audio_params(double rate, long len) +{ + double stretch_len = (len > 0 ? len / rate : 1.0); + LVAL warp; + + /* Bind the sample rate to the "*sound-srate*" global */ + setvalue(xlenter("*SOUND-SRATE*"), cvflonum(rate)); + + /* Bind selection len to "len" global */ + setvalue(xlenter("LEN"), cvflonum(len)); + + /* Set the "*warp*" global based on the length of the audio */ + xlprot1(warp); + warp = cons(cvflonum(0), /* time offset */ + cons(cvflonum(stretch_len), /* time stretch */ + cons(NULL, /* cont. time warp */ + NULL))); + setvalue(xlenter("*WARP*"), warp); + xlpop(); +} + +void nyx_set_input_audio(nyx_audio_callback callback, + void *userdata, + int num_channels, + long len, double rate) +{ + sample_type scale_factor = 1.0; + time_type t0 = 0.0; + nyx_susp_type *susp; + sound_type *snd; + int ch; + + nyx_set_audio_params(rate, len); + + susp = (nyx_susp_type *)malloc(num_channels * sizeof(nyx_susp_type)); + snd = (sound_type *)malloc(num_channels * sizeof(sound_type)); + + for(ch=0; ch < num_channels; ch++) { + falloc_generic(susp[ch], nyx_susp_node, "nyx_set_input_audio"); + + susp[ch]->callback = callback; + susp[ch]->userdata = userdata; + susp[ch]->len = len; + susp[ch]->channel = ch; + + susp[ch]->susp.fetch = nyx_susp_fetch; + susp[ch]->susp.keep_fetch = NULL; + susp[ch]->susp.free = nyx_susp_free; + susp[ch]->susp.mark = NULL; + susp[ch]->susp.print_tree = nyx_susp_print_tree; + susp[ch]->susp.name = "nyx"; + susp[ch]->susp.toss_cnt = 0; + susp[ch]->susp.current = 0; + susp[ch]->susp.sr = rate; + susp[ch]->susp.t0 = t0; + susp[ch]->susp.log_stop_cnt = 0; + + snd[ch] = sound_create((snd_susp_type)susp[ch], t0, + rate, + scale_factor); + } + + if (num_channels > 1) { + LVAL array = newvector(num_channels); + for(ch=0; ch<num_channels; ch++) + setelement(array, ch, cvsound(snd[ch])); + + setvalue(xlenter("S"), array); + } + else { + LVAL s = cvsound(snd[0]); + + setvalue(xlenter("S"), s); + } +} + +LOCAL int nyx_is_labels(LVAL expr) +{ + /* make sure that we have a list whose first element is a + list of the form (time "label") */ + + LVAL label; + LVAL first; + LVAL second; + LVAL third; + + if (expr == NULL) { + return 0; + } + + while (expr != NULL) { + if (!consp(expr)) + return 0; + + label = car(expr); + + if (!consp(label)) + return 0; + + first = car(label); + if (!(floatp(first) || fixp(first))) + return 0; + + if (!consp(cdr(label))) + return 0; + + second = car(cdr(label)); + + if (floatp(second) || fixp(second)) { + if (!consp(cdr(cdr(label)))) + return 0; + third = car(cdr(cdr(label))); + if (!(stringp(third))) + return 0; + } + else + if (!(stringp(second))) + return 0; + + expr = cdr(expr); + } + + return 1; +} + +nyx_rval nyx_get_type(LVAL expr) +{ + if (nyx_result_type != nyx_error) { + return nyx_result_type; + } + + nyx_result_type = nyx_error; + + if (expr==NULL) { + return nyx_result_type; + } + + switch(ntype(expr)) + { + case FIXNUM: + nyx_result_type = nyx_int; + break; + + case FLONUM: + nyx_result_type = nyx_double; + break; + + case STRING: + nyx_result_type = nyx_string; + break; + + case VECTOR: + { + /* make sure it's a vector of sounds */ + int i; + nyx_result_type = nyx_audio; + for(i=0; i<getsize(expr); i++) { + if (!soundp(getelement(expr, i))) { + nyx_result_type = nyx_error; + break; + } + } + } + break; + + case CONS: + { + /* see if it's a list of time/string pairs representing a + label track */ + if (nyx_is_labels(expr)) + nyx_result_type = nyx_labels; + } + break; + + case EXTERN: + { + if (soundp(expr)) + nyx_result_type = nyx_audio; + } + break; + } /* switch */ + + return nyx_result_type; +} + +nyx_rval nyx_eval_expression(const char *expr_string) +{ + LVAL expr = NULL; + +#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS + printf("\nnyx_eval_expression before\n"); + xmem(); +#endif + + nyx_expr_string = expr_string; + nyx_expr_len = strlen(nyx_expr_string); + nyx_expr_pos = 0; + + nyx_result = NULL; + nyx_result_type = nyx_error; + + xlprot1(expr); + + /* Setup a new context */ + xlbegin(&nyx_cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL|CF_ERROR, s_true); + + /* setup the error return */ + if (setjmp(nyx_cntxt.c_jmpbuf)) { + // If the script is cancelled or some other condition occurs that causes + // the script to exit and return to this level, then we don't need to + // restore the previous context. + goto finish; + } + + while(nyx_expr_pos < nyx_expr_len) { + expr = NULL; + + /* read an expression */ + if (!xlread(getvalue(s_stdin), &expr, FALSE)) + break; + + #if 0 + /* save the input expression (so the user can refer to it + as +, ++, or +++) */ + xlrdsave(expr); + #endif + + /* evaluate the expression */ + nyx_result = xleval(expr); + } + + xlflush(); + + xltoplevel(); + + finish: + + xlpop(); /* unprotect expr */ + +#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS + printf("\nnyx_eval_expression after\n"); + xmem(); +#endif + + return nyx_get_type(nyx_result); +} + +int nyx_get_audio_num_channels() +{ + if (nyx_get_type(nyx_result) != nyx_audio) + return 0; + + if (vectorp(nyx_result)) + return getsize(nyx_result); + else + return 1; +} + +int nyx_get_audio(nyx_audio_callback callback, void *userdata) +{ + sample_block_type block; + sound_type snd; + sound_type *snds = NULL; + float *buffer = NULL; + long bufferlen = 0; + long *totals = NULL; + long *lens = NULL; + long cnt; + int result = 0; + int num_channels; + int ch, i; + int success = FALSE; + + if (nyx_get_type(nyx_result) != nyx_audio) + return success; + +#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS + printf("\nnyx_get_audio before\n"); + xmem(); +#endif + + num_channels = nyx_get_audio_num_channels(); + + snds = (sound_type *)malloc(num_channels * sizeof(sound_type)); + if (snds == NULL) { + goto finish; + } + + totals = (long *)malloc(num_channels * sizeof(long)); + if (totals == NULL) { + goto finish; + } + + lens = (long *)malloc(num_channels * sizeof(long)); + if (lens == NULL) { + goto finish; + } + + /* Setup a new context */ + xlbegin(&nyx_cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL|CF_ERROR, s_true); + + /* setup the error return */ + if (setjmp(nyx_cntxt.c_jmpbuf)) { + // If the script is cancelled or some other condition occurs that causes + // the script to exit and return to this level, then we don't need to + // restore the previous context. + goto finish; + } + + for(ch=0; ch<num_channels; ch++) { + if (num_channels == 1) + snd = getsound(nyx_result); + else + snd = getsound(getelement(nyx_result, ch)); + snds[ch] = snd; + totals[ch] = 0; + lens[ch] = snd_length(snd, snd->stop); + } + + while(result==0) { + for(ch=0; ch<num_channels; ch++) { + snd = snds[ch]; + cnt = 0; + block = snd->get_next(snd, &cnt); + if (block == zero_block || cnt == 0) { + result = -1; + break; + } + + /* copy the data to a temporary buffer and scale it + by the appropriate scale factor */ + + if (cnt > bufferlen) { + if (buffer) + free(buffer); + + buffer = (float *)malloc(cnt * sizeof(float)); + if (buffer == NULL) { + goto finish; + } + + bufferlen = cnt; + } + + memcpy(buffer, block->samples, cnt * sizeof(float)); + + for(i=0; i<cnt; i++) + buffer[i] *= snd->scale; + + result = callback(buffer, ch, + totals[ch], cnt, lens[ch], userdata); + + if (result != 0) { + // The user canceled or some other error occurred, so we use + // xlsignal() to jump back to our error handler. + xlsignal(NULL, NULL); + // never get here. + } + + totals[ch] += cnt; + } + } + + success = TRUE; + + xltoplevel(); + + finish: + + gc(); + + if (buffer) { + free(buffer); + } + + if (lens) { + free(lens); + } + + if (totals) { + free(totals); + } + + if (snds) { + free(snds); + } + +#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS + printf("\nnyx_get_audio after\n"); + xmem(); +#endif + + return success; +} + +int nyx_get_int() +{ + if (nyx_get_type(nyx_result) != nyx_int) + return -1; + + return getfixnum(nyx_result); +} + +double nyx_get_double() +{ + if (nyx_get_type(nyx_result) != nyx_double) + return -1.0; + + return getflonum(nyx_result); +} + +const char *nyx_get_string() +{ + if (nyx_get_type(nyx_result) != nyx_string) + return NULL; + + return (const char *)getstring(nyx_result); +} + +unsigned int nyx_get_num_labels() +{ + LVAL s = nyx_result; + int count = 0; + + if (nyx_get_type(nyx_result) != nyx_labels) + return 0; + + while(s) { + count++; + s = cdr(s); + } + + return count; +} + +void nyx_get_label(unsigned int index, + double *start_time, + double *end_time, + const char **label) +{ + LVAL s = nyx_result; + LVAL label_expr; + LVAL t0_expr; + LVAL t1_expr; + LVAL str_expr; + + if (nyx_get_type(nyx_result) != nyx_labels) + return; + + while(index) { + index--; + s = cdr(s); + if (s == NULL) { + // index was larger than number of labels + return; + } + } + + /* We either have (t0 "label") or (t0 t1 "label") */ + + label_expr = car(s); + t0_expr = car(label_expr); + t1_expr = car(cdr(label_expr)); + if (stringp(t1_expr)) { + str_expr = t1_expr; + t1_expr = t0_expr; + } + else + str_expr = car(cdr(cdr(label_expr))); + + if (floatp(t0_expr)) + *start_time = getflonum(t0_expr); + else if (fixp(t0_expr)) + *start_time = (double)getfixnum(t0_expr); + + if (floatp(t1_expr)) + *end_time = getflonum(t1_expr); + else if (fixp(t1_expr)) + *end_time = (double)getfixnum(t1_expr); + + *label = (const char *)getstring(str_expr); +} + +const char *nyx_get_error_str() +{ + return NULL; +} + +void nyx_set_os_callback(nyx_os_callback callback, void *userdata) +{ + nyx_os_cb = callback; + nyx_os_ud = userdata; +} + +void nyx_stop() +{ + xlflush(); + xltoplevel(); +} + +void nyx_break() +{ + xlflush(); + xlbreak("BREAK", s_unbound); +} + +void nyx_continue() +{ + xlflush(); + xlcontinue(); +} + +int ostgetc() +{ + if (nyx_expr_pos < nyx_expr_len) { + fflush(stdout); + return (nyx_expr_string[nyx_expr_pos++]); + } + else if (nyx_expr_pos == nyx_expr_len) { + /* Add whitespace at the end so that the parser + knows that this is the end of the expression */ + nyx_expr_pos++; + return '\n'; + } + else + return EOF; +} + +/* osinit - initialize */ +void osinit(char *banner) +{ +} + +/* osfinish - clean up before returning to the operating system */ +void osfinish(void) +{ +} + +/* oserror - print an error message */ +void oserror(char *msg) +{ + printf("nyx error: %s\n", msg); +} + +long osrand(long n) +{ + return (((int) rand()) % n); +} + +/* cd .. +open - open an ascii file */ +FILE *osaopen(name,mode) char *name,*mode; +{ + FILE *fp; + fp = fopen(name,mode); + return fp; +} + +/* osbopen - open a binary file */ +FILE *osbopen(char *name, char *mode) +{ + char bmode[10]; + FILE *fp; + + strncpy(bmode, mode, 8); + strcat(bmode,"b"); + fp = fopen(name,bmode); + return fp; +} + +/* osclose - close a file */ +int osclose(FILE *fp) +{ + return (fclose(fp)); +} + +/* osagetc - get a character from an ascii file */ +int osagetc(FILE *fp) +{ + return (getc(fp)); +} + +/* osaputc - put a character to an ascii file */ +int osaputc(int ch, FILE *fp) +{ + return (putc(ch,fp)); +} + +/* osoutflush - flush output to a file */ +void osoutflush(FILE *fp) { fflush(fp); } + +extern int dbgflg; + +/* osbgetc - get a character from a binary file */ +/* int osbgetc(fp) FILE *fp; {return (getc(fp));} */ +#ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 + int osbgetc(FILE *fp) + { + return (getc(fp)); + } +#endif + +/* osbputc - put a character to a binary file */ +int osbputc(int ch, FILE *fp) +{ + return (putc(ch,fp)); +} + +/* ostputc - put a character to the terminal */ +void ostputc(int ch) +{ + oscheck(); /* check for control characters */ + + if (nyx_output_cb) + nyx_output_cb(ch, nyx_output_ud); + else + putchar(((char) ch)); +} + +/* ostoutflush - flush output buffer */ +void ostoutflush() +{ + if (!nyx_output_cb) + fflush(stdout); +} + +/* osflush - flush the terminal input buffer */ +void osflush(void) +{ +} + +/* oscheck - check for control characters during execution */ +void oscheck(void) +{ + if (nyx_os_cb) { + nyx_os_cb(nyx_os_ud); + } + /* if they hit control-c: + xflush(); xltoplevel(); return; + */ +} + +/* xsystem - execute a system command */ +#ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 +LVAL xsystem() +{ + if (moreargs()) { + unsigned char *cmd; + cmd = (unsigned char *)getstring(xlgastring()); + fprintf(stderr, "Will not execute system command: %s\n", cmd); + } + return s_true; +} +#endif + +#ifndef WIN32 +/* xsetdir -- set current directory of the process */ +LVAL xsetdir() +{ + char *dir = (char *)getstring(xlgastring()); + int result; + LVAL cwd = NULL; + xllastarg(); + result = chdir(dir); + if (result) { + perror("SETDIR"); + } + dir = getcwd(NULL, 1000); + if (dir) { + cwd = cvstring(dir); + free(dir); + } + return cwd; +} +#endif + +/* xgetkey - get a key from the keyboard */ +#ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 + LVAL xgetkey() {xllastarg(); return (cvfixnum((FIXTYPE)getchar()));} +#endif + +/* ossymbols - enter os specific symbols */ +#ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 + void ossymbols(void) {} +#endif + +/* xsetupconsole -- used to configure window in Win32 version */ +#ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 + LVAL xsetupconsole() { return NULL; } +#endif + +const char os_pathchar = '/'; +const char os_sepchar = ':'; + +/* control-C handling */ +void ctcinit() {} + +/* xechoenabled -- set/clear echo_enabled flag (unix only) */ +LVAL xechoenabled() { return NULL; } + +/* osdir_list_start -- open a directory listing */ +int osdir_list_start(char *path) { return FALSE; } + +/* osdir_list_next -- read the next entry from a directory */ +char *osdir_list_next() { return NULL; } + +/* osdir_list_finish -- close an open directory */ +void osdir_list_finish() { return; } + +#ifndef WIN32 +/* xget_temp_path -- get a path to create temp files */ +LVAL xget_temp_path() +{ + char *tmp = getenv("TMPDIR"); + if (!tmp || !*tmp) { + tmp = getenv("TMP"); + if (!tmp || !*tmp) { + tmp = "/tmp/"; + } + } + return cvstring(tmp); +} +#endif + +#ifndef WIN32 +/* xget_user -- get a string identifying the user, for use in file names */ +LVAL xget_user() +{ + char *user = getenv("USER"); + if (!user || !*user) { + user = getenv("USERNAME"); + if (!user || !*user) { + errputstr("Warning: could not get user ID, using 'nyquist'\n"); + user = "nyquist"; + } + } + return cvstring(user); +} +#endif |