conNExions API Library v1.3

Copyright 1999, GreyTrout Software, Inc.
Copyright 1995-97, X Engineering Software Systems Corporation.

Permission is hereby granted to copy this document without modification.

Contents

Introduction to the NExS API

The NExS API library (also called the "NExS Connection" library) is a set of C and Fortran-callable procedures for connecting external, user-written C and Fortran programs to the NExS spreadsheet through the X Window client communication mechanisms. The connection library provides each client program with up to 63 independent, simultaneous connections to NExS spreadsheets running on up to 63 different displays.

An architecture independent messaging protocol is utilized so that client applications may connect to NExS spreadsheets running on any of the supported operating systems and hardware platforms. For example, a client application running on VAX/VMS or CRAY/UNICOS may connect to and exchange data with an NExS spreadsheet running on a SPARCstation under Unix. The only prerequisites for creating a client application which utilizes the NExS connection library are a C or Fortran compiler and the X11 (release 3 or higher) object library.

Fortran Interface

The Fortran interface to the NExS connection library is written to conform to the Fortran 77 standard. One significant aspect of this is that all function and subroutine identifiers are composed entirely of alphanumeric characters, and they all are unique within the first six characters. All NExS Fortran function calls return integer values. In keeping with Fortran tradition, the names of these functions all begin with "i". These restrictions make the Fortran calls somewhat less mnemonic than their C counterparts. (But that never bothered Fortran programmers!)

Another significant aspect of conformance is that the Fortran 77 standard doesn't support structures. Structure references occur at several places in the C interface to the library. The most important place is in passing and returning arguments to and from NExS remote functions. A special set of Fortran calls has been designed to provide this functionality without violating the standard. The only library functions which have no Fortran interface are those few which reference X Window structures directly. However, these calls are only useful if your Fortran program itself is directly calling X. In that case your Fortran compiler must include extensions to support structures and long identifiers, which means you can call the C interface routines from Fortran directly.

Multiple Server Connections

A significant of the NExS Connection Library is that connections to multiple X servers are supported. The Connection Library maintains an internal table of current server connections that are referenced by their "displayID," which is a small integer identifier. To deal with multiple displays without having to constantly refer to a displayID, the Connection Library supports the notion of a "current active display." To open a connection on a particular display, the program must set the "current active display" using "nexs_set_display()" and then call "nexs_open_connection()." This capability facilitates such things as "hot links" between spreadsheets on different workstations and other forms of data sharing. (The Connection Library's internal tables will support up to 63 independent X Server connections; however, on some systems this number may exceed the allowable number of open file descriptors. Consult your operating system manuals on how to resolve the problem if this is an issue in your application.)

Connection Management

The NExS Connection Library allows connection programs to find out about and communicate with other programs connected to an NExS spreadsheet. Also, one connection program per X server can register itself as "Connection Manager" for the display. The "Connection Manager" has certain special privileges, such as being notified whenever a new instance of NExS is invoked on its display, and being able to connect to NExS through a "back door." Functions which are exclusively accessible to the "Connection Manager" are designated by the prefix "mgr". These connection management and communication features combined make it possible to create cooperative application suites of multiple NExS spreadsheets and connection programs.

API Function Reference

Connection Control

These functions open and close connections between connection client programs and NExS instances running on an X Window display, and provide a callback mechanism for handling of connections which unexpectedly close.
int nexs_connect_init(Display *dp);

Called once at startup to initialize the connection mechanism. The dp parameter is a pointer to the Display structure for the X server on which the connection to NExS is to take place. Simple (non-X) clients usually do not call this procedure directly (see nexs_open_connection).

FORTRAN equivalent:

There is no Fortran equivalent to this function since the Fortran 77 standard does not support structures. Some Fortran compilers include extensions which provide support for structures, in which case a program may call nexs_connect_init directly. Consult the Fortran manual for your workstation to see if this is possible.

int nexs_establish_connection(char *name, int timeout);

Attempts to establish a connection to an NExS spreadsheet opened on the X server defined by the call to nexs_connect_init. The "name" parameter is a mnemonic identifier for the connection. "Name" may be up to 10 characters in length. If NExS is not running, or is not currently accepting connections, the value 0 will be returned after the specified "timeout" period (in seconds). If the connection to NExS is established, a port ID in the range 1 to MAX_PORTS will be returned. (Note: Multiple connections to NExS may be opened from a single connection client, each of which may "talk" to a different instance of NExS running on the same server. Connections across multiple X servers are not currently supported.)

FORTRAN equivalent:

      function ixsestc(name, timeout)
      character *(*) name
      integer timeout

int nexs_open_connection(char *name, int timeout);

A convenience routine which opens a connection to the default X server (defined on UNIX systems by the DISPLAY environment variable), calls nexs_connect_init, and then calls nexs_establish_connection. Returns a port ID in the range 1 to MAX_PORTS if successful; 0 otherwise.

FORTRAN equivalent:

      function ixsopen(name, timeout)
      character *(*) name
      integer timeout

void nexs_set_close_notify(void (*close_fn)());

Establishes a call-back procedure "close_fn" which is invoked in the event that the NExS connection is closed from the other end (i.e., NExS exits unexpectedly). This allows orderly clean-up on the client side if necessary.

FORTRAN equivalent:

      subroutine xssetcn(close_fn)
      external close_fn

void nexs_close_connection(int port);

Closes the specified connection to NExS.

FORTRAN equivalent:

      subroutine xsclose(port)
      integer port

int nexs_test_connection(int port);

Returns 1 if there is a live connection on the specified port; 0 otherwise. Clients which do not continuously listen to the X11 server through nexs_dispatcher or a client supplied event loop should generally call nexs_test connection() before sending data to make sure that NExS has not been closed by the user. For clients which do listen to the X server, setting up a "close notify" callback should be used instead. (See "nexs_set_close_notify().")

Data Retrieval

These functions retrieve data and formulas from a NExS spreadsheet.
int nexs_get_value(int port, int row, int col, double *value, char **string);

Reads the current "value" of the cell in the specified "row" and "col" of the NExS spreadsheet connected to "port". Returns NEXS_NUMBER (1) if a value was read, NEXS_STRING (2) if a string was read, or NEXS_EMPTY (0) if the specified cell is empty or the connection to nexs was lost. At most one of "value" or "string" are affected by this call. If the result is NEXS_STRING, the client is responsible for freeing the string when it is no longer needed. (Note: NExS row indices are 1 through 9999. NExS column indices are 0 through 701; column A is 0, column ZZ is 701.)

FORTRAN equivalent:

      function ixsvget(port, row, col, value, string)
      integer port, row, col
      real*8 value
      character*(*) string

(Fortran programs should not free the "string" argument. The actual string returned to the Fortran caller will be truncated to the declared length of the "string" parameter if necessary.)

int nexs_get_string(int port, int row, int col, char **string);

Reads the string value of the specified cell. The string read is the formatted contents of the cell (even if it contains a number). If the cell is empty, a null string is read and NEXS_EMPTY is returned. Otherwise, NEXS_STRING is returned. The client is responsible for freeing the string when it is no longer needed.

FORTRAN equivalent:

      function ixssget(port, row, col, string)
      integer port, row, col
      character*(*) string

(Fortran programs should not free the "string" argument. The actual string returned to the Fortran caller will be truncated to the declared length of the "string" parameter if necessary.)

int nexs_get_number(int port, int row, int col, double *value);

Reads the numeric value of the specified cell. If the cell contains a numeric formula or constant, it is assigned to "value" and NEXS_NUMBER is returned. Otherwise, "value" is set to zero and NEXS_EMPTY is returned.

FORTRAN equivalent:

      function ixsnget(port, row, col, value)
      integer port, row, col
      real*8 value

int nexs_get_numbers(int port, Range range, int start_row, int start_col, XSValBuf xsvbuf[255], int *count);

Retrieves up to 255 numeric values from the specified "range", starting at the cell specified by "start_row" and "start_col". For each cell containing a numeric value, the cell's row, column and current value will be recorded in "xsvbuf" structure array. (See "nexs.h" for details of the XSValBuf structure.) The number of values retrieved is returned in "count". If count equals 255, the buffer is full and another call to nexs_get_numbers() should be made after adjusting "start_row" and "start_col". The cells are retrieved in column-major order, so the proper adjustment for "start_row" and "start_col" to perform a subsequent scan is:

	start_col = xsvbuf[count-1].col;
	start_row = xsvbuf[count-1].row + 1;

This function is much faster than repeated calls to nexs_get_number for retrieving large blocks of data from the spreadsheet. The function return value is set to 1 if the call is successful; 0 otherwise.

FORTRAN equivalent:

      function ixsnsget(port, rmin, cmin, rmax, cmax, rstart, cstart,
     +                 rbuf, cbuf, vbuf, count)
      integer port, rmin, cmin, rmax, cmax, rstart, cstart, count
      integer rbuf(255), cbuf(255)
      real*8 vbuf(255)

int nexs_get_formula(int port, int row, int col, char **string);

Reads the formula or label stored in the specified cell. Returns NEXS_FORMULA if a numeric or string formula was read, NEXS_LABEL if a label was read, or NEXS_EMPTY if the cell is empty. If NEXS_EMPTY is returned, "string" is not assigned. Otherwise, the client is responsible for freeing the string when it is no longer needed.

FORTRAN equivalent:

      function ixsfget(port, row, col, string)
      integer port, row, col
      character*(*) string

(Fortran programs should not free the "string" argument. The actual string returned to the Fortran caller will be truncated to the declared length of the "string" parameter if necessary.)

Data Storage

These functions store data and formulas in a NExS spreadsheet.
void nexs_store_number(int port, int row, int col, double value);

Stores "value" in the specified "row" and "col" of the NExS spreadsheet connected to "port".

FORTRAN equivalent:

      subroutine xsnstore(port, row, col, value)
      integer port, row, col
      real*8 value

void nexs_store_label(int port, int row, int col, char *s);

Stores the string "s" in the specified "row" and "col" of the NExSs spreadsheet connected to "port". If the first character of "s" is ', ", or ^, the string is left, right, or center justified, respectively. Otherwise it is justified according to the current NExS default.

FORTRAN equivalent:

      subroutine xslstore(port, row, col, label)
      integer port, row, col
      character*(*) label

void nexs_store_formula(int port, int row, int col, char *formula);

Stores the NExS formula contained in the string "formula" in the specified cell. (Note: In beta release 1.0A, "formula" must be syntactically correct or NExS will crash.)

FORTRAN equivalent:

      subroutine xsfstore(port, row, col, formula)
      integer port, row, col
      character*(*) formula

void nexs_store_formatted_number(int port, int row, int col, double value, int fnt_code, int fmt_code, int places);

Like nexs_store_number(), but overrides the default cell format. The font is specified by "fnt_code," the cell format is specified by "fmt_code," and the number of decimal places is specified by "places." Possible values for "fnt_code" and "fmt_code" are found in "nexs.h". "Places" must be in the range 0 to 15.

FORTRAN equivalent:

      subroutine xsnfstore(port, row, col, value, fntcode, fmtcode, places)
      integer port, row, col, fntcode, fmtcode, places
      real*8 value

void nexs_store_tagged_number(int port, int row, int col, double value);

Like nexs_store_number(), but tags the number with a reference to "nexs_row" and "nexs_col" (see Client @-Functions). This function is specifically for use in implementing remote embedded tools.

FORTRAN equivalent:

      subroutine xsntstore(port, row, col, value)
      integer port, row, col
      real*8 value

void nexs_store_tagged_string(int port, int row, int col, char *s);

This function is similar to nexs_store_tagged_number(), except that it stores a tagged string value in the cell specified by "row, col". This function is specifically for use in remote embedded tools which return strings.

Example:

  Operand myfunc(Operand argv[]) /* remote embedded tool which returns string */
    {
    char *s1, *s2;      /* two strings to be returned by the embedded tool */
    Operand op;

    /* Body of function goes here... */

    /* Copy the 1st return string into nexs_sbuf. */

    strcpy(nexs_sbuf, s1);

    /* Store the 2nd return string as a tagged value in the cell immediately
       below the current one. */

    nexs_store_tagged_string(nexs_port, nexs_row+1, nexs_col, s2);

    /* Set the return type and return... */

    op.type = ARG_STRING;
    return op;
    }

Data I/O

NOTE: These functions are not meant for human consumption; they are designed primarily for use with automated conNExion programming tools. They are listed here for the sake of completeness, but the function descriptions are rather incomplete at this time. You would be better served by using the functions for reading and storing sheet values presented in the previous sections. Use these functions at your own risk!
void nexs_io_error(nexs_io_errors err_num);

Prints a NExS I/O error number and then exits the connection function that caused the error.

FORTRAN equivalent:

  NONE.
void nexs_io_error_msg(char *msg);

Prints a NExS I/O error message pointed to by "msg" and then exits the connection function that caused the error.

FORTRAN equivalent:

  NONE.
char* rctotext(int col ,int row);

Converts a NExS row,column pair into a text string like "A5". (Note: NExS row indices are 1 through 9999. NExS column indices are 0 through 701; column A is 0, column ZZ is 701.)

FORTRAN equivalent:

  NONE.
void nexs_io_op_error_msg(Operand* op,char* format,...);

Prints an error message relating to operand "op" that was passed to the connection function. The error message is displayed using a printf-like format.

FORTRAN equivalent:

  NONE.
int nexs_io_get_op_size(Operand *operand,int selector);

Returns the number of cells in operand[selector].

FORTRAN equivalent:

  NONE.
int nexs_io_open_nexs_connection(char *connection_name,int wait_before_failure);

Opens a connection to NExS with the name "connection_name" and waits up to "wait_before_failure" seconds before giving up. If a connection is made, it checks to make sure the connection is made with NExS and not some other spreadsheet.

FORTRAN equivalent:

  NONE.
void nexs_io_operand_slice(Operand *src_op,int r0,int c0,int r1,int c1,Operand *dst_op);

Extracts a submatrix of cells bounded by rows "r0", "r1" and columns "c0", "c1" from the source operand. The cells are stored into the destination operand.

FORTRAN equivalent:

  NONE.
Number nexs_io_get_scalar(Operand *operand);

Gets the single number value of "operand" from the NExS spreadsheet.

FORTRAN equivalent:

  NONE.
void nexs_io_store_scalar(Number s,Operand *range);

Stores the single number s into the operand "range" of the NExS spreadsheet.

FORTRAN equivalent:

  NONE.
char *nexs_io_get_str(Operand *operand);

Gets the single string of the operand from the NExS spreadsheet.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_string(char *s,Operand *range);

Frees the storage used by the string s.

FORTRAN equivalent:

  NONE.
void nexs_io_str_string(char *s,Operand *range);

Stores the single string s into the operand of the NExS spreadsheet.

FORTRAN equivalent:

  NONE.
void nexs_io_free_ivector (int *v,int nl,int nh);

Frees the storage of a vector of integers.

FORTRAN equivalent:

  NONE.
void nexs_io_free_imatrix (int **m,int nrl,int nrh,int ncl,int nch);

Frees the storage of a matrix of integers.

FORTRAN equivalent:

  NONE.
int * nexs_io_ivector (int nl,int nh);

Creates a vector of integers.

FORTRAN equivalent:

  NONE.
int * nexs_io_ivector_realloc (int *v,int nl,int nh,int new_nl,int new_nh);

Resizes a vector of integers.

FORTRAN equivalent:

  NONE.
int ** nexs_io_imatrix (int nrl,int nrh,int ncl,int nch);

Creates a matrix of integers.

FORTRAN equivalent:

  NONE.
int * nexs_io_alo_int_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the integer vector from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
int ** nexs_io_alo_int_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the integer matrix from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
int * nexs_io_get_int_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the integer vector from the NExS spreadsheet pointed to by Operand range and reads the integers from the spreadsheet into the vector.

FORTRAN equivalent:

  NONE.
int ** nexs_io_get_int_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the integer matrix from the NExS spreadsheet pointed to by Operand range and reads the integers from the spreadsheet into the matrix.

FORTRAN equivalent:

  NONE.
void nexs_io_str_int_vector (int *v,Operand *range,int lo,int hi);

Stores the values from a vector of integers into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_str_int_matrix (int **m,Operand *range,int rlo,int rhi,int clo,int chi);

Stores the values from a matrix of integers into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_int_vector (int *v,Operand *range,int lo,int hi);

Frees the storage created when getting the vector of integer values from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_int_matrix (int **m,Operand *range,int rlo,int rhi,int clo,int chi);

Frees the storage created when getting the matrix of integer values from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_free_vector (float *v,int nl,int nh);

Frees the storage of a vector of floats.

FORTRAN equivalent:

  NONE.
void nexs_io_free_matrix (float **m,int nrl,int nrh,int ncl,int nch);

Frees the storage of a matrix of floats.

FORTRAN equivalent:

  NONE.
float * nexs_io_vector (int nl,int nh);

Creates a vector of floats.

FORTRAN equivalent:

  NONE.
float * nexs_io_vector_realloc (float *v,int nl,int nh,int new_nl,int new_nh);

Resizes a vector of floats.

FORTRAN equivalent:

  NONE.
float ** nexs_io_matrix (int nrl,int nrh,int ncl,int nch);

Creates a matrix of floats.

FORTRAN equivalent:

  NONE.
float * nexs_io_alo_float_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the float vector from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
float ** nexs_io_alo_float_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the float matrix from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
float * nexs_io_get_float_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the float vector from the NExS spreadsheet pointed to by Operand range and reads the floats from the spreadsheet into the vector.

FORTRAN equivalent:

  NONE.
float ** nexs_io_get_float_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the float matrix from the NExS spreadsheet pointed to by Operand range and reads the floats from the spreadsheet into the matrix.

FORTRAN equivalent:

  NONE.
void nexs_io_str_float_vector (float *v,Operand *range,int lo,int hi);

Stores the values from a vector of floats into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_str_float_matrix (float **m,Operand *range,int rlo,int rhi,int clo,int chi);

Stores the values from a matrix of floats into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_float_vector (float *v,Operand *range,int lo,int hi);

Frees the storage created when getting the vector of float values from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_float_matrix (float **m,Operand *range,int rlo,int rhi,int clo,int chi);

Frees the storage created when getting the matrix of float values from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_free_dvector (double *v,int nl,int nh);

Frees the storage of a vector of doubles.

FORTRAN equivalent:

  NONE.
void nexs_io_free_dmatrix (double **m,int nrl,int nrh,int ncl,int nch);

Frees the storage of a matrix of doubles.

FORTRAN equivalent:

  NONE.
double * nexs_io_dvector (int nl,int nh);

Creates a vector of doubles.

FORTRAN equivalent:

  NONE.
double * nexs_io_dvector_realloc (double *v,int nl,int nh,int new_nl,int new_nh);

Resizes a vector of doubles.

FORTRAN equivalent:

  NONE.
double ** nexs_io_dmatrix (int nrl,int nrh,int ncl,int nch);

Creates a matrix of doubles.

FORTRAN equivalent:

  NONE.
double * nexs_io_alo_double_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the double vector from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
double ** nexs_io_alo_double_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the double matrix from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
double * nexs_io_get_double_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the double vector from the NExS spreadsheet pointed to by Operand range and reads the doubles from the spreadsheet into the vector.

FORTRAN equivalent:

  NONE.
double ** nexs_io_get_double_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the double matrix from the NExS spreadsheet pointed to by Operand range and reads the doubles from the spreadsheet into the matrix.

FORTRAN equivalent:

  NONE.
void nexs_io_str_double_vector (double *v,Operand *range,int lo,int hi);

Stores the values from a vector of doubles into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_str_double_matrix (double **m,Operand *range,int rlo,int rhi,int clo,int chi);

Stores the values from a matrix of doubles into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_double_vector (double *v,Operand *range,int lo,int hi);

Frees the storage created when getting the vector of double values from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_double_matrix (double **m,Operand *range,int rlo,int rhi,int clo,int chi);

Frees the storage created when getting the matrix of double values from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
char **svector(int nl,int nh);

Creates a vector of string pointers.

FORTRAN equivalent:

  NONE.
char ***smatrix(int nrl,int nrh,int ncl,int nch);

Creates a matrix of string pointers.

FORTRAN equivalent:

  NONE.
void free_svector(char **v,int nl,int nh);

Frees a vector of string pointers.

FORTRAN equivalent:

  NONE.
void free_smatrix(char ***m,int nrl,int nrh,int ncl,int nch);

Frees a matrix of string pointers.

FORTRAN equivalent:

  NONE.
char* * nexs_io_alo_string_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the string vector from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
char* ** nexs_io_alo_string_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the string matrix from the NExS spreadsheet pointed to by Operand range.

FORTRAN equivalent:

  NONE.
char* * nexs_io_get_string_vector (Operand *range,int lo,int hi);

Allocates storage large enough to hold the string vector from the NExS spreadsheet pointed to by Operand range and reads the strings from the spreadsheet into the vector.

FORTRAN equivalent:

  NONE.
char* ** nexs_io_get_string_matrix (Operand *range,int rlo,int rhi,int clo,int chi);

Allocates storage large enough to hold the string matrix from the NExS spreadsheet pointed to by Operand range and reads the strings from the spreadsheet into the matrix.

FORTRAN equivalent:

  NONE.
void nexs_io_str_string_vector (char* *v,Operand *range,int lo,int hi);

Stores the values from a vector of strings into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_str_string_matrix (char* **m,Operand *range,int rlo,int rhi,int clo,int chi);

Stores the values from a matrix of strings into the NExS spreadsheet at a location indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_string_vector (char* *v,Operand *range,int lo,int hi);

Frees the storage created when getting the vector of strings from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.
void nexs_io_fre_string_matrix (char* **m,Operand *range,int rlo,int rhi,int clo,int chi);

Frees the storage created when getting the matrix of strings from the NExS spreadsheet indicated by Operand range.

FORTRAN equivalent:

  NONE.

Client @-Functions

The NExS Connection Library provides the ability to define new functions which are syntactically and semantically identical NExS intrinsic functions. These user-defined functions reside in NExS connection clients and thus are installed at run-time. The connection library routine nexs_install_function() (described above and illustrated below) accomplishes the installation. In the case of remote functions, the role of client and server appears to be reversed: the NExS connection client acts as a "remote function server." That is, during the recalculation of the NExS spreadsheet, NExS will invoke the callback installed for the remote function and pass it the argument list entered in the spreadsheet.

The Argument List

The arguments to the remote function are passed as an array of structures of type "Operand." The details of the Operand structure may be found in the header file "nexs.h" and its use is illustrated in the examples below. The first element of the Operand array contains a count of the actual number of arguments passed. For example, suppose we have a remote function callback declared as follows: "Operand remote_fn( Operand argv[] )." The number of arguments to the function is then given by the integer value "argv[0].val.count." The first argument is stored in argv[1], etc. Each argument in the array has a type (argv[i].type) and value (argv[i].val) field. The format of the value field depends on the type. The possible argument types are ARG_NUMBER, ARG_STRING, ARG_CELL, and ARG_RANGE. The function must return a result with one of these types (although it is rare to return ARG_CELL or ARG_RANGE). A function may also return ARG_ERROR if it wishes to indicate an error condition. When returning a result of type ARG_STRING or ARG_ERROR, the function must first copy the string value or error message to the 512 byte buffer "nexs_sbuf."

Remote Function Rules and Etiquette

When NExS invokes a remote function, it blocks any connection I/O on other ports until the remote function returns. This is to prevent the state of the spreadsheet from changing in some unpredictable way while its contents are being recalculated. Since it is almost always necessary for a remote function to query NExS (e.g., to retrieve the contents of a cell or range passed as an argument to the function), NExS will allow dialog to take place on the port where the remote function was invoked, and ONLY that port. Whenever a remote function (or remote menu callback) is invoked, the global variable "nexs_port" is set to the port ID on which the function (or menu callback) is being invoked. This is necessary when clients are connected to more than one instance of NExS (see "server.c" for an example). A simple rule of thumb is that all dialog with NExS from within a remote function should take place on "nexs_port."

A spreadsheet function is responsible for calculating a result based upon its input arguments (if any). The result thus calculated then becomes the value of the cell which contains the function reference. Other than returning its result, a "normal" spreadsheet function should do nothing to change the state of the spreadsheet. NExS extends the boundaries of what a "normal" function is allowed to do with the concept of embedded tools. In addition to returning a result, an embedded tool is allowed to store "tagged data" elsewhere in the spreadsheet. "Tagged data" are numeric or string formulas which consist of a constant value followed by a backslash ("\"), followed by a reference to cell which generated them. The "tag" following the backslash serves as a means of ensuring proper recalculation order during subsequent calculations.

The advantage of embedded tools is that they provide a means for spreadsheet functions to "return" something other than a scalar. In practice, implementing embedded tools is very simple. In the example presented below, "nexs_fn" demonstrates the proper design of a remote embedded tool. This function effectively returns a vector whose first element is the sum of the arguments of NEXS3, and whose second element is two times the first. The second element is generated by the call to nexs_store_tagged_number, which automatically appends a reference to the cell containing the call to NEXS3. The first element is then returned as the value of the remote function.

Remote functions which deviate from the "normal" behavior described in the preceding paragraph should do so with care and should be very well documented. For example, it would not be considered normal for a remote function to call "nexs_goto" or "nexs_moveto." Such calls would not cause any damage to the contents of the spreadsheet, but they would most likely confuse the user considerably! Remote functions should typically not store data in other cells, except by the rules of embedded tools as described above. Remote functions should never attempt to initiate a recalculation by calling "nexs_recalc," however, they may call "nexs_evaluate_cell" and "nexs_evaluate_expr" (NExS allows one level of recursion). This makes it possible to implement remote functions which require iterative evaluation of spreadsheet formulas, such as with the built-in conditional statistical functions.

void nexs_install_function(int port, char *name, Operand (*callback)(), int tag);

Installs a remote function in the NExS spreadsheet. The function's "name" and entry point ("callback") are specified. Remote functions are syntactically and behaviorally identical to NExS intrinsic functions. Remote function names may contain up to 127 alphanumeric characters and underscore (_) characters. Remote embedded tools may also be implemented with this mechanism. (See Client @-Functions.)

FORTRAN equivalent:

      subroutine xsinsfn(port, name, cb)
      integer port
      character*(*) name
      external cb
      integer tag

Cell Cursor Control

These functions allow a connection program to query the location of the cell cursor, and also to move about the spreadsheet by moving the cell cursor.
int nexs_get_location(int port, int *rowp, int *colp);

Returns the current position of the NExS cursor in "*rowp" and "*colp". The value 1 is always returned, unless the port has closed unexpectedly, in which case 0 is returned.

FORTRAN equivalent:

      function ixslget(port, row, col)
      integer port, row, col

void nexs_goto(int port, int row, int col);

Equivalent to a "Goto" command from the NExS utility menu. Causes the specified "row" and "col" to become the current cursor position and upper left corner of the NExS spreadsheet.

FORTRAN equivalent:

      subroutine xsgoto(port, row, col)
      integer port, row, col

void nexs_moveto(int port, int row, int col);

Like nexs_goto(), but does not cause the new cursor position to become the upper left corner of the spreadsheet. This function is more analogous to ordinary movement with the mouse, scrollbars, or arrow keys.

FORTRAN equivalent:

      subroutine xsmovto(port, row, col)
      integer port, row, col

Menu Control

These functions allow a connection program to establish new menu selections on the NExS menu bar, and to associate buttons on the new menu selections with functions in the connection program. There are also functions to control the sensitivity of menu buttons, add mnemonics and accelerators, change the button labels, and delete the client menus and buttons.
long nexs_create_menu(int port, char *name);

Creates a new menu which is added to the NExS menu bar. The text of the new menu is specified by "name", which may be up to 10 characters in length.

FORTRAN equivalent:

      function ixscmnu(port, name)
      integer port
      character*(*) name

long nexs_create_button(int port, long menuID, char *name, void (*callback)(), int tag);

Creates a new button which is added to the specified menuID (returned by nexs_create_menu). The label for the button is specified by "name", which may be up to 15 characters in length. "Callback" is a client- supplied procedure that is called whenever the button is activated. "Tag" is a client-supplied integer that is passed back to the callback procedure through the connection library global variable "nexs_tag" to allow a single callback procedure to handle multiple buttons.

FORTRAN equivalent:

      function ixscbtn(port, menuid, name, cb)
      integer port, menuid
      character*(*) name
      external cb
      integer tag

int nexs_button_accel(int port, long menuID, long buttonID, KeySym mnemonic, char *accel, char *accel_text);

This function adds Motif mnemonics and/or keyboard accelerators to menu buttons created with nexs_create_button().

The "menuID" and "buttonID" parameters are the values returned by nexs_create_menu() and nexs_create_button(), respectively.

The "mnemonic" parameter sets the Motif mnemonic key for the button. It is normally a single ASCII character. The mnemonic should be chosen to be one of the characters in the name string for the button. The first occurrence of the mnemonic character in the name string will be underlined when the button is displayed. If "mnemonic" is set to 0, no mnemonic will be defined for the button.

The "accel" and "accel_text" parameters set the keyboard accelerator for the button. The "accel" string must contain a valid Motif KeyPress translation. The "accel_text" string contains the actual string that will be displayed on the button to indicate the accelerator. If either "accel" or "accel_text" is zero-length or NULL, no accelerator will be set for the button.

The function returns 1 if successful, 0 otherwise.

Examples:

  /*
   * Create a menu named "My Menu", with a button named "My Button".
   */

    void my_button_cb(int tag)
      {
        /* this function called when "My Button" is activated */
      }

    long menuID, buttonID;

    menuID = nexs_create_menu(port, "My Menu");
    buttonID = nexs_create_button(port, menuID, "My Button", my_button_cb, 0);

  /*
   * Add "B" as the mnemonic for "My Button", and Meta-b as the accelerator.
   */

    nexs_button_accel(port, menuID, buttonID, 'B', "Meta<Key>B", "Meta-b");

void nexs_delete_menu(int port, long menuID);

Deletes the specified menu and all its associated buttons.

FORTRAN equivalent:

      subroutine xsdmnu(port, menuid)
      integer port, menuid

void nexs_delete_button(port, menuID, buttonID);

Deletes the specified button on the specified menu. All other buttons on the menu (if any) remain intact.

FORTRAN equivalent:

      subroutine xsdbtn(port, menuid, btnid)
      integer port, menuid, btnid

void nexs_menu_sensitivity(int port, long menuID, int sensitivity);

Enables (sensitivity = 1) or disables (sensitivity = 0) sensitivity of the specificied client menu. Menus are initially sensitive when created with nexs_create_menu(). A menu which has been set insensitive appears "greyed-out" and does not respond to mouse clicks.

void nexs_button_sensitivity(int port, long menuID, long buttonID, int sensitivity);

Enables (sensitivity = 1) or disables (sensitivity = 0) sensitivity of the specificied button on the specified client menu. Buttons are initially sensitive when created with nexs_create_button(). A button which has been set insensitive appears "greyed-out" on the menu and does not respond to mouse clicks.

void nexs_menu_label(int port, long menuID, char *label);

Changes the label on the specified client menu to the null-terminates string pointed to by "label." The length of the menu label is restricted to 10 characters. If the string passed is longer than 10 characters it will be truncated.

void nexs_button_label(int port, long menuID, long buttonID, char *label);

Changes the label on the specified button of the specified client menu to the null-terminates string pointed to by "label." The length of the button label is restricted to 15 characters. If the string passed is longer than 15 characters it will be truncated.

Sheet Calculation

These functions allow a connection client program to force the spreadsheet to recalculate itself, update the calculated value of individual cells, compute the value of arbitrary spreadsheet formulas, and recalculate spreadsheet constraints.
void nexs_recalc(int port, int force, int n, Range ranges[]);

Causes the NExS spreadsheet connected to "port" to recalculate with respect to cell locations covered by the array "ranges", which is of length "n". This routine would typically be called after the client loads new data into NExS. The "force" parameter can be used to override manual recalculation mode if desired. If "force" is non-zero, recalculation will be performed regardless of the current recalculation mode setting (automatic or manual). If "n" is zero, a full recalculation is performed. (Example: a remote application uses nexs_store_number() to place data in cells A1 and A2. To recalculate only those formulas which depend on cells A1 and A2, the application should set ranges[0].r0 = 1, ranges[0].r1 = 2, ranges[0].c0 = 0, and ranges[0].c1 = 0, and then call "nexs_recalc(port, 0, 1, ranges);")

FORTRAN equivalent:

      subroutine xsrcalc(port, force, n, rmin, cmin, rmax, cmax)
      integer port, force, n, rmin(n), cmin(n), rmax(n), cmax(n)

(Note that xsrcalc accepts four integer arrays (rmin(n), cmin(n), rmax(n), and cmax(n)) corresponding to the single Range array in nexs_recalc. If only one range is needed, arrays need not be used. For example, "call xsrecalc(port, force, 1, 1, 0, 2, 1)" will recalculate all formulas which depend on cells in the range A1..B2.)

int nexs_evaluate_cell(int port, int row, int col, double *value, char **str);

Causes the formula in the specified cell to be evaluated without performing a recalculation of the spreadsheet. The return value is NEXS_NUMBER if evaluation of the cell produced a numeric result, in which case "value" is assigned. The return value is NEXS_STRING if if evaluation of the cell produced a string result, in which case "str" is set to point to the string result, which should be freed when it is no longer needed. The return value is NEXS_EMPTY if the target cell is empty. (Note that nexs_evaluate_cell is identical to to nexs_get_value, except that the latter does not cause the cell to be evaluated before retrieving its contents.)

FORTRAN equivalent:

      function ixscleval(port, row, col, value, string)
      integer port, row, col
      real*8 value
      character*(*) string

(Fortran programs should not free the "string" argument. The actual string returned to the Fortran caller will be truncated to the declared length of the "string" parameter if necessary.)

int nexs_evaluate_expr(int port, char *expr, double *value, char **string);

Evaluates "expr" as an NExS expression. If "expr" contains one or more occurrences of the symbol '#', it will be evaluated as an NExS constraint expression. If the result of the evaluation is a number, it is stored in "value" and NEXS_NUMBER is returned. If the result is a string, it is stored in "*string" and NEXS_STRING is returned. Otherwise, 0 is returned. (If NEXS_STRING is returned, the client is responsible for freeing "*string" when it is no longer needed.)

FORTRAN equivalent:

      function ixsexeval(port, expr, value, string)
      integer port
      character*(*) expr, string
      real*8 value

(Fortran programs should not free the "string" argument. The actual string returned to the Fortran caller will be truncated to the declared length of the "string" parameter if necessary.)

int nexs_evaluate_constraint(int port, int row, int col);

This function causes NEXS to evaluate the constraint formula attached to the specified to cell. If the cell has no constraint attached to it, or if the constraint formula evaluates "True", then 0 is returned. If the constraint formula evaluates "False" (thus indicating a constraint violation) then 1 is returned.

FORTRAN equivalent:

      function ixscteval(port, row, col)
      integer port, row, col

int nexs_recalc_constraints(int port);

This function causes NEXS to evaluate all cell constraint formulas. The return value is the total number of constraint violations which resulted.

FORTRAN equivalent:

      function ixscrcalc(port)
      integer port

Range Selection

These functions allow the connection client to request a range to be selected on the spreadsheet, to retrieve the current selected spreadsheet range, and to query the extent of all cells in the spreadsheet.
int nexs_get_range(int port, int *rminp, int *cminp, int *rmaxp, int *cmaxp);

Blocks until the user selects a range on the spreadsheet. The upper left corner of the selected range is returned in *rminp and *cminp, and the lower right corner in *rmaxp and *cmaxp. The return value of the function is 1 if successful, otherwise 0.

FORTRAN equivalent:

      function ixsgrng(port, rmin, cmin, rmax, cmax)
      integer port, rmin, cmin, rmax, cmax

int nexs_get_selected(int port, int *rminp, int *cminp, int *rmaxp, int *cmaxp);

Retrieves the currently selected range, or the current cell if no range is selected. The return value of the function is 1 if successful, otherwise 0. (Note: nexs_get_selected() together with nexs_get_range() allow a remote application to easily implement the select-operate-store semantics in a manner consistent with NExS intrinsic operations.)

FORTRAN equivalent:

      function ixsgsel(port, rmin, cmin, rmax, cmax)
      integer port, rmin, cmin, rmax, cmax

int nexs_get_extent(int port, int *rminp, int *cminp, int *rmaxp, int *cmaxp);

Finds the range which defines the bounding box of all non-empty cells in the spreadsheet. Returns 0 if the spreadsheet is entirely empty, 1 otherwise.

FORTRAN equivalent:

      function ixsgext(port, rmin, cmin, rmax, cmax)
      integer port, rmin, cmin, rmax, cmax

Searching for Labels

These functions support efficient searching for "labels", which are text strings stored in cells. Labels are often used as mnemonic tags for data in the spreadsheet.
int nexs_find_label(int port, char *label, int *rp, int *cp);

Searches the spreadsheet for an occurrence of the specified "label". If the "label" is found, 1 is returned and *rp and *cp are set to the row and column where the label was found. (Note: only one instance of "label" will be found even if multiple instances are contained in the spreadsheet.)

FORTRAN equivalent:

      function ixsfl(port, label, row, col)
      integer port, row, col
      character*(*) label

int nexs_find_label_in_range(int port, char *label, int rmin, int cmin, int rmax, int cmax, int *rp, int *cp);

Similar to nexs_find_label(), but restricts the search to the range specified by rmin, cmin, rmax, and cmax.

FORTRAN equivalent:

      function ixsflir(port, label, rmin, cmin, rmax, cmax, row, col)
      integer port, rmin, cmin, rmax, cmax, row, col
      character*(*) label

Named Range Functions

These functions allow manipulation of named ranges. Range names can be created, resolved, and deleted.
int nexs_define_name(int port, Range *rangep, char *name);

Creates or redefines a range name. "Name" will be added to the NExS range name list as referring to the range specified by "*rangep". If "name" was previously defined its old definition will be lost. Returns 1 if successful, 0 otherwise.

FORTRAN equivalent:

      function ixsdnam(port, rmin, cmin, rmax, cmax, flags, name)
      integer port, rmin, cmin, rmax, cmax, flags
      character*(*) name

(Note that the "rangep" argument is replaced in the Fortran interface by the arguments "rmin", "cmin", "rmax", "cmax", and "flags".)

int nexs_resolve_name(int port, Range *rangep, char *name);

Retrieves the current definition of "name" from the NExS range name list and stores it in "*rangep". Returns 1 if successful, 0 otherwise.

FORTRAN equivalent:

      function ixsrnam(port, rmin, cmin, rmax, cmax, flags, name)
      integer port, rmin, cmin, rmax, cmax, flags
      character*(*) name

(Note that the "rangep" argument is replaced in the Fortran interface by the arguments "rmin", "cmin", "rmax", "cmax", and "flags".)

void nexs_delete_name(int port, char *name);

Deletes the specified "name" from the NExS range name list.

FORTRAN equivalent:

      subroutine xsdlnam(port, name)
      integer port
      character*(*) name

Input Dialog

These functions control a dialog box that allows a connection client to query the user for textual input.
void nexs_dialog(int port, char *prompt, char *deflt, void (*callback)(int status, char *string));

Instantiates a Motif dialog box with with "prompt" as the prompt string, and "deflt" as the initial contents of the text widget. Only one connection may have an active NExS dialog box at any given point in time. The "callback" function is invoked when user interaction with the dialog box is completed. The "status" argument indicates how the dialog was terminated. A value of NEXS_DIALOG_BUSY (0) indicates that the dialog could not take place (most likely, there was another dialog in progress). A value of NEXS_DIALOG_OK (1) indicates that the dialog completed normally with "OK" status, and a value of NEXS_DIALOG_CANCELED (2) indicates that the dialog completed normally with "Cancel" status. The "string" passed to the callback is the contents of the dialog box if completion status was "OK", or a null string otherwise. It is the callback's responsibility to free the string when it is no longer needed. Note that nexs_dialog() is non-blocking; it does not wait for the dialog with the user to complete before returning. Execution of the callback is the only indication that the user has completed the interaction with the dialog box.

FORTRAN equivalent:

There is no Fortran equivalent to this function, due to the fact that the callback arguments are not compatible with the Fortran calling convention. Fortran connection programs may use the blocking version of this call, ixsginput, described below.

int nexs_dialog_no_echo(int port, char *prompt, char *deflt, void (*callback)(int status, char *string));

This function is identical to nexs_dialog() except that the information entered from the keyboard does not echo on the dialog box's text widget, making this dialog suitable for entering "secret" information, such as a password. Note that while the function accepts a default string, this string is invisible on the text widget.

int nexs_get_input(int port, char *prompt, char *buf, int maxchars);

This function causes NExS to prompt the user for input and waits until the input is returned. A Motif dialog box is instantiated, with "prompt" as the prompt string and the characters in "buf" as the initial contents of the text widget. The contents of "buf" are replaced by the contents of the dialog box's text widget when the function returns. The "maxchars" parameter indicates the maximum number of characters which should be returned, including the null terminator. A return value of NEXS_DIALOG_BUSY (0) indicates that the dialog could not take place (most likely, there was another dialog in progress). A return value of NEXS_DIALOG_OK (1) indicates that the dialog completed normally with "OK" status, and a return value of NEXS_DIALOG_CANCELED (2) indicates that the dialog completed normally with "Cancel" status. Clients which cannot afford to block while waiting for user input (i.e., X Window applications) should use nexs_dialog instead of nexs_get_input.

FORTRAN equivalent:

      function ixsginput(port, prompt, buf)
      integer port
      character*(*) prompt, buf

Note that the Fortran call does not include the "maxchars" argument. Instead, the declared length of the "buf" argument is taken as the limit.

File Read/Write/Import/Export/Print

These functions support all NExS file I/O, including reading, writing, importing, exporting, and printing spreadsheets. A function is also provided to reset the spreadsheet to its initial (unloaded) state.
int nexs_read_file(int port, char *name);

This function causes NExS to attempt to read the named file. The return value is 1 if the file was successfully read; 0 otherwise. The previous contents of the spreadsheet are lost.

FORTRAN equivalent:

      function ixsread(port, name)
      integer port
      character*(*) name

int nexs_write_file(int port, char *name);

This function causes NExS to attempt to write its contents to the file "name." The return value is 1 if the file was successfully written, 0 otherwise. The contents of the spreadsheet are unchanged.

FORTRAN equivalent:

      function ixswrite(port, name)
      integer port
      character*(*) name

int nexs_print(int port, int filetype, Range range, char *filename);

Causes the specified "range" to be printed. "Filetype" must be set to either "PRINT_ASCII" or "PRINT_PS". If "filename" is set to NULL or is zero length the output is sent directly to the printer as specified on the Printer Characteristics dialog. Otherwise the output is sent to the named file. Returns 1 if successful, 0 otherwise.

int nexs_import(int port, int filetype, char *filename, int r, int c);

Causes NExS to attempt to import the named file. "Filetype" must be set to one of WKS_FILE (Lotus Release 1), WK1_FILE (Lotus Release 2), TEXT_FILE (plain old ASCII text), XSC_FILE (NExS Cells format), CSV_FILE (comma separated values), or TSV_FILE (tab separated values). For all file types except WKS_FILE and WK1_FILE, "r" and "c" specify the upper left corner of the import destination. Returns 1 if successful, 0 otherwise.

int nexs_export(int port, int filetype, char *filename, Range range);

Causes NExS to attempt to export the named file. "Filetype" must be set to one of WKS_FILE (Lotus Release 1), WK1_FILE (Lotus Release 2), TEXT_FILE (plain old ASCII text), XSC_FILE (NExS Cells format), CSV_FILE (comma separated values), TSV_FILE (tab separated values), TEX_FILE (LaTeX 2.09 tabular format), TEX2E_FILE (LaTeX 2e tabular format), HTML_FILE (HTML 2.0 table with Netscape (R) extensions), or HTML3_FILE (HTML 3.0 table). For all file types except WKS_FILE and WK1_FILE, "range" specifies the region to be exported. Returns 1 if successful, 0 otherwise.

int nexs_clear_sheet(int port);

Clears the entire spreadsheet and returns all settable parameters to their default values. Returns 1 if successful, 0 otherwise.

Range Editing

These functions allow ranges of cells to be copied, moved, or erased; rows and columns to be inserted or deleted, and pagebreaks to be inserted in the spreadsheet.
int nexs_copy_range(int port, int vflag, Range src, Range dst);

Copies the specified source range "src" to the destination "dst". If "vflag" is set to zero formulas are copied; otherwise, values are copied. Expansion of the destination range and translation of relative cell and range references behave identically to copies performed from the NExS menu. Returns 1 if successful, 0 otherwise.

int nexs_erase_range(int port, Range range);

Erases the specified "range". Returns 1 if successful, 0 otherwise.

int nexs_move_range(int port, Range src, int r_dst, int c_dst);

Moves the range "src" to the destination whose upper left corner is (r_dst, c_dst). Translation of relative cell and range references behave identically to moves performed from the NExS menu. Returns 1 if successful, 0 otherwise.

int nexs_insert_rows(int port, int row, int num_rows);

Inserts the specified number of rows starting at row number "row". Returns 1 if successful, 0 otherwise.

int nexs_insert_cols(int port, int col, int num_cols);

Inserts the specified number of columns starting at column number "col". Returns 1 if successful, 0 otherwise.

int nexs_delete_rows(int port, int start_row, int end_row);

Deletes rows "start_row" through "end_row", inclusive. Returns 1 if successful, 0 otherwise.

int nexs_delete_cols(int port, int start_col, int end_col);

Deletes columns "start_col" through "end_col", inclusive. Returns 1 if successful, 0 otherwise.

int nexs_insert_pagebreak(int port, int row);

This function inserts a pagebreak code in the specified row. Note that this function does not handshake with NExS, and requires a call to nexs_flush() or nexs_flush_port() if used outside of an event loop. The return value is 1 if "port" is valid, 0 otherwise.

Column Width

These functions allow column widths to be queried and set.
int nexs_set_width(int port, int c0, int c1, int width, int dflag);

Sets the widths of columns "c0" through "c1", inclusive, to the value of the "width" argument, which must be in the range 1 to 511. If "dflag" is non-zero, the widths columns "c0" through "c1" are set to the global default value and the "width" argument is ignored. Returns 1 if successful, 0 otherwise.

(Note: NExS column widths are sized according to the currently active font. When using variable width fonts, the width of numeric digits is used for the basis of the column width; i.e., a column with width 10 is wide enough to display 10 numeric digits, but may not be wide enough to display 10 upper case `W's.)

int nexs_get_width(int port, int col, int *width);

Retrieves the current width setting for the column specified by "col". If the call is successful, the retrieved value is stored in location specified by "width". Returns 1 if successful, 0 otherwise.

Cell Format and Protection

These functions allow cell attributes, such as font and format, to be queried and controlled. (NOTE: The nexs_cell_attributes() function provides control of all NExS cell attributes. The other functions are provided for backwards compatibility with earlier spreadsheet products.)
int nexs_set_format(int port, int fmt_code, int places, Range range);

Formats the specified "range". See the include file "nexs.h" for possible settings of "fmt_code". "Places" sets the number of displayed digits (if applicable) and must be in the range 0 to 15. Returns 1 if successful, 0 otherwise.

int nexs_set_font(int port, int fnt_code, Range range);

Sets the font for the specified "range". See the include file "nexs.h" for possible settings of "fnt_code". Returns 1 if successful, 0 otherwise.

int nexs_protect(int port, int flag, Range range);

Sets protection for the specified "range". If "flag" is 0, the range is unprotected; otherwise, the range is protected. Returns 1 if successful, 0 otherwise.

int nexs_cell_attributes(int port, Range range, CellAttributes *attr, int mask, int resolve_defaults);

This function is used to set or get the attributes for a cell or range for NExS version 3.

The "attr" parameter points to a CellAttributes structure which contains attribute values to be set for all cells in "range". The attributes selected from "attr" are defined by "mask". If mask is 0, no attributes are set.

When the function returns, the "attr" structure contains all attributes of the upper left cell in "range". If the upper left cell contains some attributes which are set to default, the actual values returned in "attr" will depend on the setting of the "resolve_defaults" parameter. If "resolve_defaults" is True (i.e., non-zero), the default attributes will be resolved to their actual values.

The cell attributes that can be set or read by this function are font family, font style, font size, foreground and background color, justification, protection level, auto word wrap, underlining, format and precision. (See the header file nexs.h for definitions of all attribute and mask values.)

The function returns 1 if successful, 0 otherwise.

Examples:

  /*
   * Set the foreground of range c3..d100 to color 3 (normally red) and
   * the background to color 4 (normally green).
   */

    CellAttributes attr;
    Range range;

    text_to_range("c3..d100", &range);
    attr.fg = 3;
    attr.bg = 4;
    nexs_cell_attributes(port, range, &attr, NEXS_COLOR_MASK, 0);

  /*
   * Read the attributes of cell a1, resolving all default attributes.
   */

    text_to_range("a1", &range);
    nexs_cell_attributes(port, range, &attr, 0, 1);

  /*
   * Set the font of cell zz1 to helvetica bold, 24 point.
   */

    text_to_range("zz1", &range);
    attr.font_family = NEXS_FONT_FAMILY_HELVETICA;
    attr.font_style = NEXS_FONT_STYLE_BOLD;
    attr.font_size = NEXS_FONT_SIZE_24PT;
    nexs_cell_attributes(port, range, &attr,
          NEXS_FONT_FAMILY_MASK | NEXS_FONT_STYLE_MASK | NEXS_FONT_SIZE_MASK, 0);

Titles Rows and Columns

These functions allow connection clients to query or set row and column title regions on a spreadsheet.
int nexs_set_titles(int port, int r, int c, int mode);

Causes rows above row "r" and/or columns to the left of column "c" to become title fields. "Mode" must be set to TITLE_ROWS, TITLE_COLS, or TITLE_BOTH. Row 1 must be visible if "mode" is TITLE_ROWS or TITLE_BOTH, and column A must be visible if "mode" is TITLE_COLS or TITLE_BOTH. Returns 1 if successful, 0 otherwise.

int nexs_clear_titles(int port, int mode);

Undoes the work of "nexs_set_titles()". "Mode" must be set to TITLE_ROWS, TITLE_COLS, or TITLE_BOTH. Returns 1 if successful, 0 otherwise.

Tools

These functions provide interfaces to the NExS searching, sorting, extraction, and goal seek tools.
int nexs_goal_seek(int port, int vr, int vc, int tr, int tc, double target, double *x1, double *x2, int maxit, double tolerance);

Causes NExS to perform a "Goal Seek" operation. The cell that is to be varied during the goal seek is indicated by (vr, vc). The cell whose value is intended to match the "target" value is indicated by (tr, tc). The NExS goal seek algorithm uses the "regula falsa" (false position) method which requires the target to be bracketed, in this case by the variables "x1" and "x2". The way it works is as follows: If storing some value "x1" in cell (vr, vc) caused the value in cell (tr, tc) to be less than the value "target", and storing some other value "x2" in (vr, vc) caused the value of (tr, tc) to be greater than "target", then we say that "target" is bracketed by "x1" and "x2". Goal seek works by iteratively closing down the gap between "x1" and "x2" in such a way that the target always remains bracketed. As the gap narrows, the algorithm will eventually find a value which when stored in (vr, vc) will cause the value in (tr, tc) to be equal (within the numerical precision of the computer) to "target". Since that degree of precision is seldom required in real applications, a "tolerance" parameter is provided. The goal seek algorithm terminates when the absolute value of the difference between the value in (tr, tc) and "target" is less than or equal to "tolerance".

The NExS goal seek algorithm does not require "x1" and "x2" to bracket "target" initially. If it is determined that the target is not bracketed, the gap between "x1" and "x2" is expanded in an attempt to bracket "target". Once bracketing has been achieved, the gap is narrowed until the solution is found.

There are a few pathological cases for which goal seek can not find a solution:

  1. A bracket does not exist; i.e., for all possible values that can be stored in cell (vr, vc) the value in (tr, tc) will either be always greater than "target" or always less than "target".
  2. A bracket exists, but because the function is not continuous there is no value which can be stored in (vr, vc) that will cause the value in (tr, tc) to be equal to "target".
  3. A solution exists, but the function is not well behaved on the interval between the bracket values "x1" and "x2". This generally means that somewhere between "x1" and "x2" the value of (tr, tc) will go to plus or minus infinity, which causes the algorithm to break down.

To limit the work expended by goal seek in difficult or pathological cases, the parameter "maxit" will cause the algorithm to give up if a bracket can not be found within "maxit" iterations, or once a bracket is found, a solution can not be found within "maxit" iterations. Since the final values of "x1" and "x2" are returned to the calling program, a failed "nexs_goal_seek()" may be continued simply by calling it again. While most functions converge very quickly (linear functions always converge in one or two iterations, some complex functions may simply require more iterations to find a solution. The user (or programmer) must decide what action to take in the event that goal seek fails. To assist in this, "nexs_goal_seek()" provides the following return codes:

        1               - success.
        0               - general failure (e.g., the port has closed).
        less than 0     - goal seek has failed for one of the following
                          reasons (defined in "nexs.h"):

        GS_FORMULA_ERR  - the target cell (tr, tc) does not contain a
                          numeric formula and therefore a solution does
                          not exist.
        GS_VARIABLE_ERR - the variable cell (vr, vc) does not contain
                          a numeric constant.
        GS_FP_ERR       - a machine floating point error has occurred
                          during the goal seek process, most likely
                          indicating pathological case 3 above.
        GS_TARGET_ERR   - the target cell's value could not be obtained,
                          most likely indicating that it contains an
                          "Error!" condition.
        GS_BRACKET_ERR  - a bracket was not be found after "maxit"
                          iterations, possibly indicating pathological
                          case 1 above.
        GS_ITER_ERR     - the target is bracketed, but a solution was not
                          found after "maxit" iterations, possibly
                          indicating pathological case 2 above.
To facilitate continuation, "nexs_goal_seek()" does not restore the original contents of cell (vr, vc) in the event of failure. It is therefore the programmer's responsibility to save this value if desired.

int nexs_sort(int port, int dir, int mode, Range range, int keycol1, int keycol2);

Sorts "range". The "dir" parameter must be set to one of SORT_ASCENDING or SORT_DESCENDING. The "mode" parameter must be set to one of SORT_UPDATE or SORT_NO_UPDATE. "Keycol1" indicates the column containing the primary key for the sort, and "keycol2" indicates the column containing the secondary key. See the documentation on the NExS Sort Tool in Chapter 9 of the NExS Spreadsheet User Guide for an explanation of these parameters. The return code is 1 if successful, 0 otherwise.

int nexs_find(int port, int order, int dir, Range range, char *condition, int type, int *find_r, *find_c);

Searches "range" for cells whose contents match "condition". The "order" parameter indicates the order in which the range is scanned and must be one of FIND_BY_ROW or FIND_BY_COL. The "dir" parameter indicates the direction of the scan and must be one of FIND_NEXT or FIND_PREV. The "condition" may be either a Unix-style regular expression (in which case "type" must be set to FIND_REGEX), or an NExS constraint expression (in which case "type" must be set to FIND_NUMERIC). A return code of 1 indicates that "nexs_find()" was successful and the cell which matched condition is indicated by (find_r, find_c). A return code of 0 indicates that find was unsuccessful (or the connection closed unexpectedly, which may be verified by "nexs_test_connection()"). A negative return code indicates that an error occurred in the evaluation of "condition".

int nexs_extract(int port, Range range, int keycol, char *condition, int type, int r_dst, int c_dst);

Extracts the rows in "range" which match "condition" and stores them in successive rows starting at cell (r_dst, c_dst). The "condition" may be either a Unix-style regular expression (in which case "type" must be set to FIND_REGEX), or an NExS constraint expression (in which case "type" must be set to FIND_NUMERIC). The "keycol" parameter indicates the column that contains the cells to which "condition" is to be applied. A return code of 0 indicates that zero rows were extracted (or the connection closed unexpectedly, which may be verified by "nexs_test_connection()"). A positive return code indicates the number of rows that were extracted, while a negative return code indicates that an error occurred in the evaluation of "condition".

Default Characteristics and Options

These functions control the NExS default characteristics and options.
int nexs_sheet_defaults(int port, SheetDefaults *defaults, int mask);

Gets and/or sets all fields on the NExS "Default Sheet Characteristics" dialog. To set fields on the Default Sheet Characteristics dialog box, the corresponding values should be stored in the "defaults" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the SheetDefaults structure and mask. Upon return, the "defaults" structure will be filled in with all current values of the Default Sheet Characteristics dialog box. Returns 1 if successful, 0 otherwise.

int nexs_cell_defaults(int port, CellDefaults *defaults, int mask);

Gets and/or sets all fields on the NExS "Default Cell Characteristics" dialog. To set fields on the Default Cell Characteristics dialog box, the corresponding values should be stored in the "defaults" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the CellDefaults structure and mask. Upon return, the "defaults" structure will be filled in with all current values of the Default Cell Characteristics dialog box. Returns 1 if successful, 0 otherwise.

int nexs_ps_char(int port, PSDefaults *defaults, int mask);

Gets and/or sets all fields on the NExS "PostScript Output Characteristics" dialog. To set fields on the PostScript Output Characteristics dialog box, the corresponding values should be stored in the "defaults" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the PSDefaults structure and mask. Upon return, the "defaults" structure will be filled in with all current values of the PostScript Output Characteristics dialog box. Returns 1 if successful, 0 otherwise.

int nexs_print_char(int port, PrintDefaults *defaults, int mask);

Gets and/or sets all fields on the NExS "Printer Characteristics" dialog. To set fields on the Printer Characteristics dialog box, the corresponding values should be stored in the "defaults" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the PrintDefaults structure and mask. Upon return, the "defaults" structure will be filled in with all current values of the Printer Characteristics dialog box. Returns 1 if successful, 0 otherwise.

int nexs_import_characteristics(int port, int *one_word_per_col, int *ws_threshold, int mask);

This function sets and gets values in the NExS Import Characteristics dialog. The variable parameter "*one_word_per_col" is a boolean corresponding to the "One word per column" toggle on the Import Characteristics dialog. The variable parameter "*ws_threshold" is a value between 0 and 100 corresponding to the "Whitespace threshold" slider. The parameter "mask" is a bit mask formed from zero or more of the following values defined in nexs.h:

        ONE_WORD_PER_COL
        WHITESPACE_THRESHOLD
        IMPORTCHAR_RESET

If the mask contains IMPORTCHAR_RESET, the import characteristics will be reset to their default values. The other two mask values determine whether their corresponding variables will alter the current settings of the import characteristics. If "mask" is set to zero, then the current import characteristics are not changed. In all cases, the new (current) import characteristics settings are retrieved from the dialog and stored in the corresponding variables. The function returns 1 if successful, 0 otherwise.

Graph Functions

These functions support the creation and manipulation of spreadsheet graphs by a connection client.
int nexs_new_graph(int port, int *new_gid);

Creates a new graph. The gid for the graph is returned in "new_gid". The newly created graph is empty, and it's name is set to "Untitled". The function return value is 1 if successful, 0 otherwise.

int nexs_display_graph(int port, int gid);

Causes the graph specified by "gid" to be displayed. Returns 1 if successful, 0 otherwise.

int nexs_redraw_graph(int port, int gid);

Causes the graph specified by "gid" to be redrawn. This function would typically be called after changing the graph's characteristics or data ranges. A graph must be displayed before it can be redrawn. Returns 1 if successful, 0 otherwise.

int nexs_name_graph(int port, int gid, char *name_buf);

Sets the name of the graph specified by "gid" to the name contained in "namebuf". If "namebuf" is an empty string (length == 0), the existing graph name is unchanged. In either case, the new (or existing graph name is retrieved into "namebuf". Therefore, "namebuf" must point to a character array of sufficient size to hold the graph name. Note that the name does not take effect on the graph window's Motif title bar until the graph is redisplayed using nexs_display_graph(). Returns 1 if successful, 0 otherwise.

int nexs_duplicate_graph(int port, int gid, int *new_gid);

Produces a new graph which is a clone of the graph specified by "gid". The new graph's ID is returned in "new_gid". The new graph will not be automatically displayed, even if the graph it is cloning is currently displayed. Returns 1 if successful, 0 otherwise.

int nexs_delete_graph(int port, int gid);

Deletes the graph specified by "gid". The graph's ID is reclaimed by NExS. Returns 1 if successful, 0 otherwise.

int nexs_print_graph(int port, int gid, int type, char *name);

Prints the graph specified by "gid" in the format specified by "type", which must be one of the following values defined in "nexs.h":

        GR_EPS          - encapsulated PostScript, or
        GR_IDRAW_PS     - idraw-compatible PostScript.

If "name" is a non-empty string, it is taken to be a file name to which the output is to be sent. If "name" is empty or NULL, the output is sent to the printer, as specified by the "Print Command" on the "Printer Characteristics" dialog. Note that the graph must be displayed to be printed, and that the aspect ratio of the printed graph will match the aspect ratio of the graph on the X Window display. Returns 1 if successful, 0 otherwise.

int nexs_cancel_graph(int port, int gid);

The graph specified by "gid" is unmapped from the display. The graph may be subsequently redisplayed by calling nexs_display_graph() or by selecting it from the NExS Graph menu. Returns 1 if successful, 0 otherwise.

int nexs_ggen_char(int port, int gid, GrGenChar *gchar, int mask);

Gets and/or sets all fields on the "General Characteristics" dialog of the graph specified by "gid". To set fields on the graph's General Characteristics dialog, the desired values should be stored in the "gchar" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the GrGenChar structure and mask. Upon return, the "gchar" structure will be filled in with all current values of the graph's General Characteristics dialog. Note that the "title_text" member of "gchar" is dynamically allocated and should be freed when no longer needed by the client. Returns 1 if successful, 0 otherwise.

int nexs_axis_char(int port, int gid, int axis, GrAxisChar axischar, int mask);

Gets and/or sets all fields on the "X|Y|Z Axis Characteristics" dialog of the graph specified by "gid". The axis to be manipulated is specified by the parameter "axis", which must be set to one the following valued defined in "nexs.h": X_AXIS, Y_AXIS, Z_AXIS, AUX_Y_AXIS. To set fields on the graph's X|Y|Z Axis Characteristics dialog, the desired values should be stored in the "axischar" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the GrAxisChar structure and mask. Upon return, the "axischar" structure will be filled in with all current values of the graph's General Characteristics dialog. Note that the "label_text" member of "axischar" is dynamically allocated and should be freed when no longer needed by the client. Returns 1 if successful, 0 otherwise.

int nexs_gdata_char(int port, int gid, int dataset, NEXSGrDataChar *dchar, unsigned long mask);

This function provides access to all of the features on the Graph Data Set Characteristics dialog. It is similar to the NExS v2.1 compatible call xs2_gdata_char(), except that it provides access to all of the version 3 data set features, and it DOES NOT use dynmically allocated strings. DO NOT free strings returned in the NEXSGrDataChar structure.

The structure members and mask values are defined in "nexs.h".

Example:

  /*
   * Set the legend text of dataset 3 on graph 1 to 18pt Helvetica bold italic
   */

  NEXSGrDataChar dchar;
  unsigned long mask;

  dchar.legend_size = NEXS_FONT_SIZE_18PT;
  dchar.legend_family = NEXS_FONT_FAMILY_HELVETICA;
  dchar.legend_style = NEXS_FONT_STYLE_BOLDITALIC;

  mask = NEXS_GDATA_LEGEND_SIZE |
         NEXS_GDATA_LEGEND_FAMILY |
         NEXS_GDATA_LEGEND_STYLE;

  nexs_gdata_char(port, 1, 3, &dchar, mask);

int xs2_gdata_char(int port, int dataset, XS2GrDataChar dchar, int mask);

(This function is included only for backwards compatibility with earlier spreadsheet products. New programs should use nexs_gdata_char().)

Gets and/or sets all fields on the "Data Ranges" dialog for the specified "dataset" the graph specified by "gid". The "dataset" must be an integer in the range 1 to 5. To set fields on the graph's Data Ranges dialog, the desired values should be stored in the "dchar" structure and the corresponding bits in "mask" should be set to 1. See "nexs.h" for details of the XS2GrDataChar structure and mask. Upon return, the "dchar" structure will be filled in with all current values of the graph's Data Ranges dialog for the specified "dataset". Note that the "x_range", "y_range", and "z_range" members of the XS2GrDataChar structure are strings rather than Range structures. This feature allows named ranges to be specified if desired. the "x_range", "y_range", "z_range", and "legend_text" members of "dchar" are dynamically allocated and should be freed when no longer needed by the client. Returns 1 if successful, 0 otherwise.

int nexs_rotate_graph(int port, int gid, GrRotate3D *grotate, int mask);

Gets and/or sets the rotation angles for the 3-D surface graph specified by "gid". See "nexs.h" for details on the GrRotate3D structure. Returns 1 if successful, 0 otherwise.

int nexs_graph_geometry(int port, int gid, GrGeometry ggeom, int mask);

Gets and/or sets the screen coordinates and window size for the graph window specified by "gid". See "nexs.h" for details on the GrGeometry structure. Note that this function does not correspond with any NExS dialog; moving and resizing windows are normally handled by interaction with the Window Manager. Note also that the values set by this function may be overidden by the Window Manager. Returns 1 if successful, 0 otherwise.

Action Notfication

These functions allow a connection client to register callbacks for spreadsheet events, such as when the sheet is reset to its initial state.
void nexs_set_action_callback(void (*callback)(int port, int action));

This function registers a function to be called upon notification of an "action" occurring on an NExS spreadsheet for which action notification has been reqested (see nexs_set_action_notify()). When such an action occurs, the registered function is called with two integer parameters. The first parameter is the port number on which the NExS spreadsheet reporting the action is connected, and the second parameter is an action code specifying the action being reported. These codes are defined in nexs.h. (Note: the only action code currently defined is ACTION_NEW_SHEET, which indicates the loading of a new spreadsheet, or resetting the NExS to its initial state via the "File->New" button.)

Notification of actions is asynchronous; that is, NExS does not block and wait for "callback" to return from processing an action notification. If "callback" is set to NULL (it's initial value), then any incoming action notifications are discarded.

Example: (see nexs_set_action_notify...)

int nexs_set_action_notify(int port, int action, int flag);

This function requests the NExS instanced connected on the specified port to report the occurence of events specified by the "action" parameter. If "flag" is set to 1, notification for the specified action is turned on; if "flag" is 0, notification for the action is turned off. Codes for "action" parameter are defined in nexs.h. (Note: the only action code currently defined is ACTION_NEW_SHEET, which indicates the loading of a new spreadsheet, or resetting the NExS to its initial state via the "File->New" button.)

The call to nexs_set_action_notify() must be accompanied by a call to nexs_set_action_callback() to register a function to be called when action notification events occur. It is recommended (but not required) that nexs_set_action_callback() be called first to avoid the loss of any action notification events.

The function returns 1 if the call was processed successfully, or 0 if the port number or the action code is invalid.

Example:

  /* Here is my function to be called upon action notification... */

  void my_action_callback(int port, int action)
    {
    switch (action)
      {
      case ACTION_NEW_SHEET:
        printf("A \"New Sheet\" action occurred on port %d\n", port);
        break;
      default:
        printf("An unknown action occurred on port %d!!!\n", port);
      }
    }

  /* Here are the calls to request notification of the New Sheet action... */

  nexs_set_action_callback(my_action_callback);
  nexs_set_action_notify(port, ACTION_NEW_SHEET, 1);

Range Utility Functions

These are convenience functions which convert between internal cell and range representations and their external representations.
char *col_to_text(int column);

Returns a pointer to the nul-terminated string containing the one or two character identifier for the specified column number. The column number must be in the range 0 ("A") to 701 ("ZZ"). If the specified column number is out of this range, then NULL is returned. Note that the location of the returned string is statically allocated and will be overwritten with each call to col_to_text().

int text_to_col(char *name);

Returns the column number corresponding to the one or two character alphabetic character sequence pointed at by "name". The first character must be alphabetic. If the second character is alphabetic it is taken to be part of the column identfier, otherwise it is ignored. For example, text_to_col("C") == text_to_col("C100") == 2. If name does not point to a valid column identifier, -1 is returned.

int text_to_rc(char *name, int *row, int *col);

Interprets "name" as a cell reference and returns the row and column numbers in "row" and "col". The function return value is 1 if successful, 0 otherwise.

int out_of_range(int row, int col);

Returns 1 if "row" and "col" do not represent a cell address within the range supported by NExS; 0 otherwise.

int text_to_range(char *name, Range *range);

Parses a cell or range name and stores the result in the structure "range". Returns 1 if successful, 0 otherwise.

char *range_to_text(Range *range);

Returns a pointer to the nul-terminated string representing the name of the cell or range reference specified in the structure "range". If the contents of "range" do not represent a valid cell or range reference, then NULL is returned. Note that the location of the returned string is statically allocated and will be overwritten with each call to range_to_text().

int sort_range(Range *range);

Sorts the row and column references contained in the structure "range" so that they are in "standard" order. In NExS standard order, range->r0 and range->c0 specify the upper left corner of the range and range->r1 and range->c1 specify the lower right corner of the range. The bits in range->flags (which mark absolute row and column references) are transposed appropriately.

Miscellaneous

These functions provide special capabilities that do not belong in the categories previously described.
void nexs_display_message(int port, char *s);

Displays the string "s" on the message line of the NExS status display.

FORTRAN equivalent:

      subroutine xsdmsg(port, msg)
      integer port
      character*(*) msg

void nexs_scroll_range(int port, int rmin, int cmin, int rmax, int cmax, int direction);

Scroll the range defined by rmin, cmin, rmax, and cmax one unit in the specified direction (NEXS_SCROLL_UP, NEXS_SCROLL_DOWN, NEXS_SCROLL_RIGHT, NEXS_SCROLL_LEFT). Cells outside of the scrolled range are unaffected. Typically, the remote application will place new data in the position or positions vacated by the scroll operation.

FORTRAN equivalent:

      subroutine xsscroll(port, rmin, cmin, rmax, cmax, dir)
      integer port, rmin, cmin, rmax, cmax, dir

(The Fortran names for the scrolling directions, defined in "xsparams.f[or]", are nexsup, nexsdown, nexsright, and nexsleft.

void nexs_user_lock(int port, int lockflag);

This function sets or clears the "lock flag" associated with the specified port. Each port has the ability to lock out all mouse and keyboard input (i.e., user input) to NExS. The lock state of NExS is the logical "or" of all of its ports' lock flags. Thus, if any port's lock flag is set, then no user input can occur. To avoid data coherence problems, a port's lock flag is automatically set when any of its remote menu buttons are invoked, and cleared when the remote process completes. The nexs_user_lock function is provided as a means to override this automatic behavior.

FORTRAN equivalent:

      subroutine xsulock(port, lock)
      integer port, lock

Multiple Display Control

The NExS API supports multiple simultaneos X Window display connections for each connection client. These functions manage the list of display identifiers and set the "current active display" through which all functions communicate with a NExS spreadsheet.
int nexs_new_display(Display *dp);

Registers a new server connection with NExS and returns an integer displayID. If the server connection is already registered, the existing displayID value is returned. If the maximum number of displayIDs has been exceeded, 0 is returned. NExS_new_display() will automatically initialize the the connection library if nexs_connect_init() has not been called previously.

int nexs_set_display(int displayID);

Sets the current active display to displayID. Returns 0 if displayID is not valid; returns displayID otherwise.

int nexs_get_display(void);

Returns the displayID of the current active display.

int nexs_remove_display(int displayID);

Removes displayID from the connection libraries internal list of display connections. A displayID may be removed only if there are no active connections on that display. If any of the connection ports are using the specified display, then nexs_remove_display returns 0 and the displayID remains intact. Also, if the displayID is not valid, 0 is returned. Otherwise, the displayID is removed from the connection library's internal list and its value is returned.

X Window Interfacing

These functions facilitate incorporating API library functions in an X Window program by providing access to low level interfaces between the API functions and the X Window system.
int nexs_message_handler(XEvent *event);

This procedure is for the convenience of clients which are themselves X Window applications. The "event" is examined to see if it is an NExS client message. If so, it is handled appropriately by the connection library and a 1 is returned. Otherwise, it is left untouched and a 0 is returned.

FORTRAN equivalent:

There is no Fortran equivalent to this function since the Fortran 77 standard does not support structures. Some Fortran compilers include extensions which provide support for structures, in which case a program may call nexs_message_handler directly. Consult the Fortran manual for your workstation to see if this is possible.

void nexs_dispatcher(void (*callback)());

This procedure waits for X events on the server specified by nexs_connect_init, handles the ones destined for the NExS connection library, and passes all other events to the specified callback for further processing. Simple (non-X) applications should pass NULL (0) as the callback function to indicate that they are not interest in non-NExS library related events.

FORTRAN equivalent:

      subroutine xsdispatch

      subroutine xscbdispatch(callback)
      external callback

The first form of this call is used for connection programs which do not need to respond to X Window events other than those related to NExS. The second form registers a callback subroutine to which all non-NExS related X events are passed.

void nexs_flush_port(int port);

This function flushes the output buffer on the server connection associated with port. It should be called whenever an output-only operation occurs that is not followed by an input operation. This simply replaces nexs_flush() in the multi-server model. The old form, nexs_flush(), flushes the current active display.

void nexs_flush();

Flushes all output to NExS on the current active display. Most applications should use nexs_flush_port() instead of nexs_flush(), which has been included for compatibility with version 1.0 of the NExS Connection Library.

FORTRAN equivalent:

      subroutine xsflush

Window nexs_window(int port);

Returns the X11 window ID of the NExS instance associated with the specified "port". If "port" is 0, returns the client's own window ID.

FORTRAN equivalent:

      function ixswndo(port)
      integer port

Window nexs_top_window(int port);

Returns the top-level X window ID of the NExS instance connected to the specified port. Returns the window ID if successful; "None" otherwise.

Window nexs_graph_window(int port, int gid);

Returns the top-level X window ID of graph number "gid" on the NExS instance connected to the specified port. Returns the window ID if successful; "None" otherwise.

Display *nexs_display(int port);

Returns the X11 display pointer associated with the connection on the specified port. If the port is 0, the display pointer associated with the current active display is returned. Note that this call is incompatible with previous versions of the NExS connection library.

NOTE: In version 1.0 of the NExS connection library nexs_display() Did not take an argument since only one display connection was allowed. Programs written for version 1.0 of the library can be compiled under version 2.0 if they are modified to pass the value 0 to nexs_display().

Display *nexs_display_from_ID(int displayID);

Returns the X11 display pointer associated with the specified displayID. Returns NULL if the displayID is not valid.

FORTRAN equivalent:

There is no Fortran equivalent to this routine since it returns a pointer to a structure, which is not supported by the Fortran 77 standard. Some Fortran compilers include extensions to support structure references, in which case "nexs_display" may be called directly.

Inter-connection Messaging

These functions provide a convenient mechanism for multiple connection clients connected to a single instance of NExS to communicate with each other. This could be useful in sophisticated applications where a NExS instance is connected to several client programs, perhaps running on different computers on a network.
int nexs_inquire_connections(int port, int status_list[MAX_PORTS+1], char name_list[MAX_PORTS+1][11]);

Queries NExS about its current connections. "status_list[n]" is set to 1 if a connection exists on NExS port "n" (n is between 1 and MAX_PORTS+1), or 0 if no connection exists on port "n". "Name_list[n]" is set to the null-terminated name of the connection on port "n". The function returns 1 if the inquiry is successful, 0 otherwise.

int nexs_send_message(int port, int remote_port, char message[15]);

Sends an arbitrary 15-byte message to another NExS connection client. "Remote_port" is the NExS port number obtained from "nexs_inquire_connections()". Returns 1 if the message is sent successfully, 0 otherwise.

void nexs_set_receiver(void (*recv_fn)(int port, char message[15]));

Establishes "recv_fn()" as a callback function to be invoked when a message is received from another NExS connection client. The NExS port number of the sending client and the 15-byte message are passed to "recv_fn()" when a message is received. Interpretation of the 15-byte messages is entirely up to the clients.

int nexs_message_wait(int port, int remote_port, char msg_buf[15]);

Blocks and waits for a message from the specified remote port. When a message from "remote_port" is received, the message is stored in msg_buf and 1 is returned. If the call is unsuccessful (i.e., nothing is connected to "remote_port") 0 is returned. Note that messages received in this way will not trigger the "recv_fn()" callback described above. The combination of "nexs_send_message()", "nexs_set_receiver()" and "nexs_message_wait()" provide a convenient mechanism for cooperating NExS clients to establish their own private dialogs.

Connection Management

The NExS API supports the concept of a "NExS connection manager" running on an X Window display. The "NExS connection manager" is analogous to a window manager, such as "mwm" or "fvwm", in that it has access to all NExS instances running on the display. Only one connection manager may run on the display at any given time. Some connection managment functions have special privileges that allow the connection manager special access to NExS instances that is not allowed for normal connection clients. A NExS connection manager would typically run in the background and automatically connect itself to any NExS instance invoked on the display. It could thus be used to provide custom extensions for sophisticated NExS applications.
int mgr_manage_display(int displayID);

Attempts to register the caller as NExS Connection Manager for the X11 display server indicated by the specified displayID. The request will succeed only if no other process is currently registered as manager for the indicated display. Returns 1 if successful; 0 otherwise.

int mgr_unmanage_display(int displayID);

Unregisters the caller as NExS Connection Manager for the display indicated by "displayID". Returns 1 if successful; 0 if "displayID" is not valid, or if the caller was not registered as manager for the indicated display in the first place.

int mgr_set_nexs_notify(void (*nexs_notify_fn)(int displayID, Window w));

Establishes a callback function to notify the NExS Connection Manager that a new instance of NExS has started. The callback function has two arguments, the first is the integer "displayID" to indicate the display on which the new instance resides; the second is the connection window ID "w" of the new instance. The caller will be notified of new instances of NExS only on displays for which it is registered as NExS Connection Manager. Returns 1 if successful, 0 if the program is not a Connection Manager for any display.

int mgr_set_acceptor(int displayID, Window nexs_window);

Requests the instance of NExS whose connection window ID is "nexs_window" on the display indicated by "displayID" to accept connections. NExS will comply with the request if its connections are not explicitly locked. Returns 1 if the NExS instance complied with the request; 0 otherwise.

int mgr_connect(int displayID, Window nexs_window, char *name);

Provides a "back door" mechanism for the NExS Connection Manager to connect to an instance of NExS. The parameters "displayID" and "nexs_window" specify the NExS instance to which the manager desires to connect. "Name" is the 10-character name of the connection as seen by NExS. The connection port ID is returned if a connection is established; otherwise 0 is returned. Two features distinguish "mgr_connect()" from "nexs_establish_connection()":

  1. NExS need not be in "accepting connections" mode for the connection to be established, and
  2. the connection is silent; i.e., no message appears on the NExS status line when the connection is made.
The request will fail and return 0 if:
  1. NExS connections are locked,
  2. no ports are available, or
  3. the caller is not registered as manager for the display.

Window nexs_get_acceptor(int displayID);

Returns the connection window ID of the NExS instance which is currently accepting connections on the display indicated by "displayID", or None if the displayID is invalid or no NExS instance is accepting connections on the indicated display.

char *nexs_get_name(int displayID, Window nexs_window);

Get the name of the specified NExS instance. The name of an NExS instance is explicitly defined by the command line option "-xsname" when NExS is started. If the name is not explicitly set, it defaults to "NExS v2.0". It is not necessary to be connected to an NExS instance to retrieve its name. The string returned by "nexs_get_name()" is dynamically allocated and should be freed (using "free()") when no longer needed. NULL is returned if the call fails.

int nexs_scan_display(int displayID, Window **nexs_windows, int *num_windows);

The display indicated by "displayID" is scanned for instances of NExS. A dynamically allocated array of connection window IDs for all NExS instances found is returned in "nexs_windows". The length of the array is returned in "num_windows". Returns 1 if the call is successful; 0 otherwise. The array returned by "nexs_scan_display()" should be freed (using "free()") when it is no longer needed.

Global Variables

A few global variables are provided, mostly for historical reasons. They provide access to current state information during NExS connection processing.
int nexs_port

When a message is received from NExS (such as a remote function call) "nexs_port" is set to the port ID of the connection over which the message is received. This is useful for NExS connection programs that open more than one connection to NExS. (See the demo program "server.c" for an example of how this variable can be used.)

int nexs_row, nexs_col

When NExS issues a remote function call, "nexs_row" and "nexs_col" are set to the indices of the cell from which the remote function was invoked.

int nexs_recalc_flags

This variable contains a set of six 1-bit flags which are set during a remote function call to tell the client something about the status of the NExS calculation that caused the invocation of the remote function. The flag bits are defined as follows (bit #0 is the least significant bit):

    Bit #  C name                 Description
           Fortran name

       0   NEXS_RECALC          - set if a recalculation is in progress.
           nexsrecalc

       1   NEXS_FORCE_RECALC    - set if a "forced" recalculation is
           nexsforcerecalc        in progress.  A "forced" recalculation
                                  is one initiated by selecting
                                  "Recalculate" from the Utilities menu,
                                  or by typing "meta R", or by pressing
                                  the "Do" key on some systems.

       2   NEXS_FULL_RECALC     - set if a full recalculation of all
           nexsfullrecalc         cells containing formulas is in
                                  effect.  NExS normally only recalculates
                                  cells whose value may have changed
                                  as a result of the most recent
                                  operation.

       3   NEXS_MANUAL_MODE     - indicates the state of the
           nexsmmanual            "Automatic Recalculation" toggle button
                                  on the "Default Sheet Characteristics"
                                  dialog.  If this bit is set, it means
                                  that "Automatic Recalculation" has
                                  been deselected.

       4   NEXS_CONSTRAINT_MODE - indicates the state of the
           nexsmconstraint        "Constraint Checking Enabled" toggle
                                  button on the "Default Sheet
                                  Characteristics" dialog.  If this
                                  bit is set, it means that "Constraint
                                  Checking" has been deselected.

       5   NEXS_CONSTRAINT      - indicates that the remote function
           nexsconstraint         was invoked from within a constraint
                                  expression.

Connection clients which need to optimize their execution may find these flags useful. For example, a remote function which takes a very long time to compute might be designed to respond only to a forced recalculation to avoid unwanted delays during setup and editing of the spreadsheet.

int nexs_conv_warn

NExS allows connections to operate between machines with different floating point architectures. The floating point architectures currently supported are IEEE double precision and VAX (PDP-11) double precision format (D-float). The VAX format provides about one extra digit of precision at the expense of considerable dynamic range. "nexs_conv_warn" is only meaningful if an NExS client on a VAX is connected to NExS running on an IEEE floating point machine or vice-versa. It is set when a number whose magnitude is too large (> 1.7e+38) or too small (< 2.9e-39) to represent in the VAX D-float format is passed over a connection from an IEEE floating point machine. The numbers themselves are actually converted silently to their most "reasonable" representations - numbers greater than 1.7e+38 are truncated to 1.7e+38, and numbers less than 2.9e-39 are set to zero.

Examples

A Simple Client Application Example


/*
 * This application opens a connection to NExS and establishes a
 * new menu with four buttons.  The application simulates a
 * real-time data monitoring application which loads new information
 * into the spreadsheet every 5 seconds.  The buttons control starting
 * and stopping of the monitor, whether or not recalculation is
 * performed automatically when new data is loaded, and closing of
 * the connection.
 */

/*
 *
 * NExS Connection Library V1.0 (Beta release B, September 10, 1990)
 * Copyright 1990, X Engineering Software Systems Corporation
 * Copyright 1999, GreyTrout Software, Inc.
 * All rights reserved.
 *
 * file: test2.c
 *
 */


#include	<stdio.h>
#include	<signal.h>
#include	<nexs.h>

int portID, mon_row, mon_col, recalc_flag = 0;

void b1_fn(), b2_fn(), b3_fn(), b4_fn();

long menu1ID, button1ID, button2ID, button3ID, button4ID;

void doit()
    {
    static int n = 0;
    double sin();
    int net, disk;
    Range range;	/* defines range affecting partial recalculation */

    /* fake some data to monitor */

    net = 10000.0 * (sin(1.0 * n) + 1.0);
    disk = 1000.0 * (sin(1.5 * n) + 1.0);
    nexs_store_number(portID, mon_row+1, mon_col+1, (double) n++);
    nexs_store_number(portID, mon_row+2, mon_col+1, (double) net);
    nexs_store_number(portID, mon_row+3, mon_col+1, (double) disk);
    if (recalc_flag)
	{
	range.r0 = mon_row + 1;
	range.r1 = mon_row + 3;
	range.c0 = range.c1 = mon_col + 1;
	range.flags = 0;
	nexs_recalc(portID, 0, 1, &range);
	}
    nexs_flush();
    signal(SIGALRM, doit);
    alarm(5);
    }

void close_notify_fn(port)
int port;
    {
    fprintf(stderr, "Port number %d closed; exiting...\n", port);
    exit(0);
    }

void b1_fn()	/* start "monitoring" at current location */
    {
    nexs_get_location(portID, &mon_row, &mon_col);
    nexs_display_message(portID, "Monitoring Enabled");
    nexs_store_label(portID, mon_row, mon_col, "\'System Stats");
    nexs_store_label(portID, mon_row+1, mon_col, "\'Interval #");
    nexs_store_label(portID, mon_row+2, mon_col, "\'Network I/O:");
    nexs_store_label(portID, mon_row+2, mon_col+2, "\'packets");
    nexs_store_label(portID, mon_row+3, mon_col, "\'Disk I/O:");
    nexs_store_label(portID, mon_row+3, mon_col+2, "\'seeks");
    doit();
    }

void b2_fn()	/* stop "monitoring" */
    {
    alarm(0);
    nexs_display_message(portID, "Monitoring Disabled");
    }

void b3_fn()	/* Toggle recalculation flag */
    {
    if (recalc_flag)
	{
	recalc_flag = 0;
	nexs_display_message(portID, "Monitor recalculation set to manual");
	}
    else
	{
	recalc_flag = 1;
	nexs_display_message(portID, "Monitor recalculation set to automatic");
	}
    }

void b4_fn()	/* disconnect and exit */
    {
    nexs_close_connection(portID);
    exit(0);
    }

main()
    {
    nexs_set_close_notify(close_notify_fn);
    portID = nexs_open_connection("SysMon", 10);
    if (portID == 0)
	{
	printf("could not connect to NExS after 10 seconds...\n");
	exit(0);
	}
    menu1ID = nexs_create_menu(portID, "Monitor");
    button1ID = nexs_create_button(portID, menu1ID, "Start Monitor", b1_fn, 0);
    button2ID = nexs_create_button(portID, menu1ID, "Stop Monitor", b2_fn, 0);
    button3ID = nexs_create_button(portID, menu1ID, "Toggle Recalc", b3_fn, 0);
    button4ID = nexs_create_button(portID, menu1ID, "Disconnect", b4_fn, 0);

    nexs_dispatcher(NULL);
    }

Remote Functions Example (test5.c)

The following example program creates three remote functions. The first, @NEXS(...), is essentially a recreation of the built-in function @SUM(...), except that it treats string arguments as errors rather than ignoring them. The second, @NEXS2(...), is similar to the first except that it returns a string result. The third, @NEXS3(...), is an example of an embedded tool which returns a two element vector containing (1) the sum of its arguments and (2) two times the sum.


/*
 *
 * NExS Connection Library V1.0 (Beta release B, September 10, 1990)
 * Copyright 1990, X Engineering Software Systems Corporation
 * Copyright 1999, GreyTrout Software, Inc.
 * All rights reserved.
 *
 * The author hereby grants permission to use, modify, and distribute
 * this program so long as the above copyright message is retained.
 *
 * file: test5.c
 *
 * (This example program has been edited for compactness and clarity.
 *  - TKM 10/15/95)
 *
 */


#include	<stdio.h>
#include	<nexs.h>

int portID;

static int error_flag;	/* set if any function arg is a string */

static Number sum_args(Operand *argv)	/* compute sum of function args */
    {
    Number sum, x;
    int i, n = argv->val.count;
    int r, c;

    sum = 0.;
    error_flag = 0;
    for (i=0; i<n; i++)
        {
	switch ((++argv)->type)
	    {
	    case ARG_NUMBER:	/* add the number to the sum */
		sum += argv->val.number;
		break;
	    case ARG_CELL:	/* add the cell contents to the sum */
		if (nexs_get_number(portID,
			argv->val.range.r0, argv->val.range.c0, &x))
		    sum += x;
		break;
	    case ARG_RANGE:	/* sum the cell values in the range */
		for (r = argv->val.range.r0; r <= argv->val.range.r1; r++)
		  for (c = argv->val.range.c0; c <= argv->val.range.c1; c++)
			if (nexs_get_number(portID, r, c, &x))
			    sum += x;
		break;
	    case ARG_STRING:	/* make it an error message */
		strcpy(nexs_sbuf, argv->val.string);
		error_flag = 1;
		return 0.0;
	    default:
		break;  /* ignore it */
	    }
        }
    }

Operand nexs_fn(Operand *argv)	/* identical to @sum(...) */
    {
    Operand op;

    op.val.number = sum_args(argv);
    if (error_flag)
	op.type = ARG_ERROR;
    else
	op.type = ARG_NUMBER;
    return op;
    }

Operand nexs2_fn(Operand *argv)	/* returns a string */
    {
    Operand op;

    if (error_flag)
	op.type = ARG_ERROR;
    else
	{
	op.type = ARG_STRING;
	sprintf(nexs_sbuf, "The sum is %lg", sum_args(argv));
	}
    return op;
    }

Operand nexs3_fn(Operand *argv)	/* stores a "tagged number" (embedded tool) */
    {
    Operand op;

    if (error_flag)
	op.type = ARG_ERROR;
    else
	{
        op.val.number = sum_args(argv);
        nexs_store_tagged_number(portID, nexs_row+1, nexs_col, op.val.number*2);
	op.type = ARG_NUMBER;
	}
    return op;
    }

void close_notify_fn(port)
int port;
    {
    fprintf(stderr, "Port number %d closed; exiting...\n", port);
    exit(0);
    }

main()
    {
    nexs_set_close_notify(close_notify_fn);
    portID = nexs_open_connection("Functions", 10);
    if (portID == 0)
	{
	printf("could not connect to NExS after 10 seconds...\n");
	exit(0);
	}
    nexs_install_function(portID, "NEXS", nexs_fn, 0);
    nexs_install_function(portID, "NEXS2", nexs2_fn, 0);
    nexs_install_function(portID, "NEXS3", nexs_fn, 0);
    nexs_dispatcher(NULL);
    }

Remote Function "Server" Example (server.c)

The following program illustrates how an NExS connection program can act as a remote function "server" for multiple instances of NExS on a given display. The program establishes an "alarm" which triggers periodic checks for a new copy of NExS to connect to. If this program is run in the background, it will autmatically connect each time NExS is run with connections enabled. Up to 63 instances of NExS may be "served" simultaneously. (Some knowledge of UNIX system calls and X Window programming is necessary to fully understand this example.)


/*
 *
 * NExS Connection Library V1.0 (Beta release B, September 10, 1990)
 * Copyright 1990, X Engineering Software Systems Corporation
 * Copyright 1999, GreyTrout Software, Inc.
 * All rights reserved.
 *
 * file: server.c
 *
 */


#include	<stdio.h>
#include	<signal.h>
#include	<X11/Xlib.h>
#include	<X11/Xatom.h>
#include	<nexs.h>

Atom	xsConnectAtom;
Display	*display;
Window	nexs_window();

double number = 0.0;
char *strptr = NULL;
int status;

Operand fn_demo1(argv)
Operand argv[];
/*
  Function @DEMO1(x).  Returns 2 times its argument, if the argument is a
  number or a cell.  Returns 0 otherwise.
*/
    {
    Operand op;
    double x;

    switch (argv[1].type)
	{
	case ARG_NUMBER:
	    op.val.number = argv[1].val.number * 2.0;
	    break;
	case ARG_CELL:
	    nexs_get_number(nexs_port,
		argv[1].val.range.r0, argv[1].val.range.c0, &x);
	    op.val.number = 2.0 * x;
	    break;
	default:
	    op.val.number = 0.0;
	}
    op.type = ARG_NUMBER;
    return op;
    }

Operand fn_demo2(argv)
Operand argv[];
/*
  Function @DEMO2(x).  Returns 0.5 times its argument, if the argument is a
  number or a cell.  Returns 0 otherwise.
*/
    {
    Operand op;
    double x;

    switch (argv[1].type)
	{
	case ARG_NUMBER:
	    op.val.number = argv[1].val.number * 0.5;
	    break;
	case ARG_CELL:
	    nexs_get_number(nexs_port,
		argv[1].val.range.r0, argv[1].val.range.c0, &x);
	    op.val.number = 0.5 * x;
	    break;
	default:
	    op.val.number = 0.0;
	}
    op.type = ARG_NUMBER;
    return op;
    }

void cut_button()
    {
    int r, c;

    nexs_get_location(nexs_port, &r, &c);
    if (strptr)
	{
	free(strptr);
	strptr = NULL;
	}
    status = nexs_get_value(nexs_port, r, c, &number, &strptr); 
    }

void paste_button()
    {
    int r, c;

    nexs_get_location(nexs_port, &r, &c);
    switch (status)
	{
	case NEXS_NUMBER:
	    nexs_store_number(nexs_port, r, c, number);
	    break;
	case NEXS_STRING:
	    nexs_store_label(nexs_port, r, c, strptr);
	    break;
	}
    }

void check_for_nexs()
/*
  Checks for a new nexs "client".  A new client is identified by the
  fact that it owns the xsConnectAtom and its window ID is different
  from any of the currently active ports.
*/
    {
    Window w;
    int portID, i;
    long menu;

    if ((w = XGetSelectionOwner(display, xsConnectAtom)) != None)
	{
	for (i=1; i<=MAX_PORTS; i++)
	    if (w == nexs_window(i)) return;
	portID = nexs_establish_connection("ServerDemo", 0);
	if (portID)
	    {
	    nexs_install_function(portID, "DEMO1", fn_demo1, 0);
	    nexs_install_function(portID, "DEMO2", fn_demo2, 0);
	    menu = nexs_create_menu(portID, "Server");
	    nexs_create_button(portID, menu, "Cut", cut_button, 0);
	    nexs_create_button(portID, menu, "Paste", paste_button, 0);
	    }
	}
    }

void send_time2check()
/*
  Send a ClientMessage event to this process once every second which
  says its time to look and see if any new copies of nexs have come
  up which need to be served.
*/
   {
   XClientMessageEvent cm_event;

   cm_event.type = ClientMessage;
   cm_event.display = display;
   cm_event.window = nexs_window(0);	/* returns client window */
   cm_event.message_type = xsConnectAtom;	/* irrelevant */
   cm_event.format = 32;
   XSendEvent(display, cm_event.window, False, None, &cm_event);
   XFlush(display);
   signal(SIGALRM, send_time2check);	/* set up to check again */
   alarm(1);				/* in one second */
   }

void check_event(event)
XEvent *event;
   {
   if (event->type == ClientMessage &&
       event->xclient.message_type == xsConnectAtom)
	check_for_nexs();
   }

main()
    {
    if ((display = XOpenDisplay("")) == NULL)
	{
	fprintf(stderr, "Could not open display!\n");
	exit(0);
	}
    nexs_connect_init(display);
    xsConnectAtom = XInternAtom(display, "XS_Connect", False);
    send_time2check();
    nexs_dispatcher(check_event);
    }



copyright 1999 GreyTrout Software, Inc.
Maintained by webmaster@greytrout.com
Last updated Mon Jul 26 22:06:00 EDT 1999.