spec

Software for Diffraction

5.3.5. - Adding Site-Dependent C Code



This step applies only to sophisticated end users of spec who understand the C language and need to customize spec for specific, site-dependent uses. Most readers can skip to the next section. Note also, local code can be accessed using the data-pipe facility explained 2.4.6.2 in the Reference Manual.

spec has provisions for end users to add their own C code to the program. User-added code is accessed using the built-in calc() function. If you wish to incorporate non-standard calculations within the spec program, you can do so by adding hooks for the code in the u_hook.c source file. C code that you add should, in general, be limited to calculations. You should avoid I/O, signal catching, etc. Consult CSS for specific information about what is appropriate for including in user-added C code. The geo_*.c files in the standard spec distribution that contain the X-ray diffractometer geometry code are examples of site-dependent code.


Within u_hook.c there is a routine called init_calc(). This routine is called once when spec starts up. Within init_calc(), calls to the routine
ins_calc(int num, int (*func)())
insert the C routine func in a table of functions. These functions are called when calc(num) or calc(num, arg) is typed as a command to spec. The routine func() should be specified as either
func(int num)
or
func(int num, double arg)
depending on whether calc() is to be invoked with one or two arguments.

Any return value from func() is ignored. However, you can have the calc() routine return a value by assigning a number to the variable
extern  double  calc_return;
in func(). If no explicit assignment is made to calc_return, calc() returns zero.

The argument num can be from 0 to 63, but must be chosen not to conflict with any of the other ins_calc() entries already existing in u_hook.c.

You can also create built-in arrays of double precision, floating point numbers that can be used to communicate values between your C code and the user of the program. The routine
ins_asym(double **x, int n, char *s)
inserts the array x consisting of n elements into the table of built-in symbols. The character pointer s points to a string containing the name used to refer to the array from spec command level. For example,
#define N_PARAM 28
double  *gparam[N_PARAM];
init_calc() {
      ...
      ins_asym(gparam, N_PARAM, "G");
      ...
}
inserts the 28-element array referred to as G[] into the program. Since the array gparam[] is an array of pointers, you must use the indirection operator (*) when referring to the values of the floating point numbers in your C code, as in
      ...
      *gparam[3] = 1.54;
      ...
      if (*gparam[2] == 0)
              ...


If you make any changes to u_hook.c, you must relink and reinstall the spec binary.