modified: SpatialOmicsCoord.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / custom / HOW_TO_ADD
blobdb08382b925da70e8f0579e422e49e829782b143
1 Guidelines for adding custom functions
2 --------------------------------------
4 Step 0: Determine if is should it be done?
6     The main focus for calc is to provide a portable platform for
7     multi-precision calculations in a C-like environment.  You should
8     consider implementing algorithms in the calc language as a first
9     choice.  Sometimes an algorithm requires use of special hardware, a
10     non-portable OS or pre-compiled C library.  In these cases a custom
11     interface may be needed.
13     The custom function interface is intended to make is easy for
14     programmers to add functionality that would be otherwise
15     un-suitable for general distribution.  Functions that are
16     non-portable (machine, hardware or OS dependent) or highly
17     specialized are possible candidates for custom functions.
19     So before you go to step 1, ask yourself:
21         + Can I implement this as a calc resource file or calc shell script?
23             If Yes, write the shell script or resource file and be done with it.
24             If No, continue to the next question ...
26         + Does it require the use of non-portable features,
27           OS specific support or special hardware?
29             If No, write it as a regular builtin function.
30             If Yes, continue to step 1 ...
33 Step 1: Do some background work
35     First ... read this file ALL THE WAY THROUGH before implementing
36     anything in Steps 2 and beyond!
38     If you are not familiar with calc internals, we recommend that
39     you look at some examples of custom functions.  Look at the
40     the following source files:
42         custom.c
43         custom.h
44         custom/custtbl.c
45         custom/c_*.[ch]
46         custom/*.cal
47         help/custom             (or run:  calc help custom)
49     You would be well advised to look at a more recent calc source
50     such as one available in from the calc version archive.
51     See the following for more details:
53         help/archive            (or run:  calc help archive)
56 Step 2: Name your custom function
58     We suggest that you pick a name that does not conflict with
59     one of the builtin names.  It makes it easier to get help
60     via the help interface and avoid confusion down the road.
62     You should avoid picking a name that matches a file or
63     directory name under ${HELPDIR} as well.  Not all help
64     files are associated with builtin function names.
66     For purposes of this file, we will use the name 'curds'
67     as our example custom function name.
70 Step 3: Document your custom function
72     No this step is NOT out of order.  We recommend that you write the
73     help file associated with your new custom function EARLY.  By
74     experience we have found that the small amount of effort made to
75     write "how the custom function will be used" into a help file pays
76     off in a big way when it comes to coding.  Often the effort of
77     writing a help file will clarify fuzzy aspects of your design.
78     Besides, unless you write the help file first, it will likely never
79     be written later on.  :-(
81     OK ... we will stop preaching now ...
83     [[ From now on we will give filenames relative to the custom directory ]]
85     Take a look at one of the example custom help files:
87         custom/devnull
88         custom/argv
89         custom/help
90         custom/sysinfo
92     You can save time by using one of the custom help files
93     as a template.  Copy one of these files to your own help file:
95         cd custom
96         cp sysinfo curds
98     and edit it accordingly.
101 Step 4: Write your test code
103     No this step is NOT out of order either.  We recommend that you
104     write a simple calc script that will call your custom function and
105     check the results.
107     This script will be useful while you are debugging your code.  In
108     addition, if you wish to submit your code for distribution, this
109     test code will be an import part of your submission.  Your test
110     code will also service as additional for your custom function.
112     Oops ... we said we would stop preaching, sorry about that ...
114     You can use one of the following as a template:
116         custom/argv.cal
117         custom/halflen.cal
119     Copy one of these to your own file:
121         cd custom
122         cp halflen.cal curds.cal
124     and exit it accordingly.  In particular you will want to:
126         remove our header disclaimer (or put your own on)
128         change the name from halflen() to curds()
130         change the comment from 'halflen - determine the length ...' to
131         'curds - brief description about ...'
133         change other code as needed.
136 Step 5: Write your custom function
138     By convention, the files we ship that contain custom function
139     interface code in filenames of the form:
141         c_*.c
143     We suggest that you use filenames of the form:
145         u_*.c
147     to avoid filename conflicts.
149     We recommend that you use one of the c_*.c files as a template.
150     Copy an appropriate file to your file:
152         cd custom
153         cp c_argv.c u_curds.c
155     Before you edit it, you should note that there are several important
156     features of this file.
158         a) All of the code in the file is found between #if ... #endif:
160                 /*
161                  * only comments and blank lines at the top
162                  */
164                 #if defined(CUSTOM)
166                 ... all code, #includes, #defines etc.
168                 #endif /* CUSTOM */
170            This allows this code to 'go away' when the upper Makefile
171            disables the custom code (because ALLOW_CUSTOM no longer
172            has the -DCUSTOM define).
174         b) The function type must be:
176                 /*ARGSUSED*/
177                 VALUE
178                 u_curds(char *name, int count, VALUE **vals)
180            The 3 args are passed in by the custom interface
181            and have the following meaning:
183                 name    The name of the custom function that
184                         was called.  In particular, this is the first
185                         string arg that was given to the custom()
186                         builtin.  This is the equivalent of argv[0] for
187                         main() in C programming.
189                         The same code can be used for multiple custom
190                         functions by processing off of this value.
192                 count   This is the number of additional args that
193                         was given to the custom() builtin.  Note
194                         that count does NOT include the name arg.
195                         This is similar to argc except that count
196                         is one less than the main() argc interface.
198                         For example, a call of:
200                             custom("curds", a, b, c)
202                         would cause count to be passed as 3.
204                 vals    This is a pointer to an array of VALUEs.
205                         This is the equivalent of argv+1 for
206                         main() in C programming.  The difference
207                         here is that vals[0] refers to the 1st
208                         parameter AFTER the same.
210                         For example, a call of:
212                             custom("curds", a, b, c)
214                         would cause vals to point to the following array:
216                             vals[0]  points to  a
217                             vals[1]  points to  b
218                             vals[2]  points to  c
220            NOTE: If you do not use any of the 3 function parameters,
221            then you should declare that function parameter to be UNUSED.
222            For example, if the count and vals parameters were not used
223            in your custom function, then your declaraction should be:
225                 /*ARGSUSED*/
226                 VALUE
227                 u_curds(char *name, int UNUSED count, VALUE UNUSED **vals)
229         c) The return value is the function must be a VALUE.
231            The typical way to form a VALUE to return is by declaring
232            the following local variable:
234                 VALUE result;   /* what we will return */
236         d) You will need to include:
238                 #if defined(CUSTOM)
240                 /* any #include <foobar.h> here */
242                 #include "../have_const.h"
243                 #include "../value.h"
244                 #include "custom.h"
246                 #include "../have_unused.h"
248             Typically these will be included just below any system
249             includes and just below the #if defined(CUSTOM) line.
251     To better understand the VALUE type, read:
253         ../value.h
255     The VALUE is a union of major value types found inside calc.
256     The v_type VALUE element determines which union element is
257     being used.   Assume that we have:
259         VALUE *vp;
261     Then the value is determined according to v_type:
263         vp->v_type      the value is    which is a      type defined in
264         ----------      ------------    ----------      ---------------
265         V_NULL          (none)          n/a             n/a
266         V_INT           vp->v_int       long            n/a
267         V_NUM           vp->v_num       NUMBER *        ../qmath.h
268         V_COM           vp->v_com       COMPLEX *       ../cmath.h
269         V_ADDR          vp->v_addr      VALUE *         ../value.h
270         V_STR           vp->v_str       char *          n/a
271         V_MAT           vp->v_mat       MATRIX *        ../value.h
272         V_LIST          vp->v_list      LIST *          ../value.h
273         V_ASSOC         vp->v_assoc     ASSOC *         ../value.h
274         V_OBJ           vp->v_obj       OBJECT *        ../value.h
275         V_FILE          vp->v_file      FILEID          ../value.h
276         V_RAND          vp->v_rand      RAND *          ../zrand.h
277         V_RANDOM        vp->v_random    RANDOM *        ../zrandom.h
278         V_CONFIG        vp->v_config    CONFIG *        ../config.h
279         V_HASH          vp->v_hash      HASH *          ../hash.h
280         V_BLOCK         vp->v_block     BLOCK *         ../block.h
282     The V_OCTET is under review and should not be used at this time.
284     There are a number of macros that may be used to determine
285     information about the numerical values (ZVALUE, NUMBER and COMPLEX).
286     you might also want to read the following to understand
287     some of the numerical types of ZVALUE, NUMBER and COMPLEX:
289         ../zmath.h
290         ../qmath.h
291         ../cmath.h
293     While we cannot go into full detail here are some cookbook
294     code for manipulating VALUEs.  For these examples assume
295     that we will manipulate the return value:
297         VALUE result;   /* what we will return */
299     To return NULL:
301         result.v_type = V_NULL;
302         return result;
304     To return a long you need to convert it to a NUMBER:
306         long variable;
308         result.v_type = V_NUM;
309         result.v_num = itoq(variable);          /* see ../qmath.c */
310         return result;
312     To return a FULL you need to convert it to a NUMBER:
314         FULL variable;
316         result.v_type = V_NUM;
317         result.v_num = utoq(variable);          /* see ../qmath.c */
318         return result;
320     To convert a ZVALUE to a NUMBER*:
322         ZVALUE variable;
324         result.v_type = V_NUM;
325         result.v_num = qalloc();                /* see ../qmath.c */
326         result.v_num->num = variable;
327         return result;
329     To convert a small NUMBER* into a long:
331         NUMBER *num;
332         long variable;
334         variable = qtoi(num);
336     To obtain a ZVALUE from a NUMBER*, extract the numerator:
338         NUMBER *num;
339         ZVALUE z_variable;
341         if (qisint(num)) {
342                 z_variable = num->num;
343         }
345     To be sure that the value will fit, use the ZVALUE test macros:
347         ZVALUE z_num;
348         long variable;
349         unsigned long u_variable;
350         FULL f_variable;
351         short very_tiny_variable;
353         if (zgtmaxlong(z_num)) {                        /* see ../zmath.h */
354                 variable = ztolong(z_num);
355         }
356         if (zgtmaxulong(z_num)) {
357                 u_variable = ztoulong(z_num);
358         }
359         if (zgtmaxufull(z_num)) {
360                 f_variable = ztofull(z_num);
361         }
362         if (zistiny(z_num)) {
363                 very_tiny_variable = z1tol(z_num);
364         }
366     You can (and should) add debugging statements to your custom code
367     by examining bit 8 of the calc_debug config flag:
369         if (conf->calc_debug & CALCDBG_CUSTOM) {
370             fprintf(stderr, "%ssome custom debug note: msg\n",
371                 (conf->tab_ok ? "\t" : ""),
372                 ((msg == NULL) ? "((NULL))" : msg));
373         }
375     One is able to set bit 8 by way of the calc command line:
377         calc -D 128
379     See the calc man page for details.  One may also set that bit
380     while running calc by way of the config() builtin function:
382         config("calc_debug", 128);
384     See the help/config file for details on calc_debug.
386 Step 6: Register the function in the custom interface table
388     To allow the custom() builtin to transfer control to your function,
389     you need to add an entry into the CONST struct custom cust table
390     found in custom/custtbl.c:
392         /*
393          * custom interface table
394          *
395          * The order of the elements in struct custom are:
396          *
397          *      { "xyz", "brief description of the xyz custom function",
398          *         minimum_args, maximum_args, c_xyz },
399          *
400          * where:
401          *
402          *      minimum_args    an int >= 0
403          *      maximum_args    an int >= minimum_args and <= MAX_CUSTOM_ARGS
404          *
405          * Use MAX_CUSTOM_ARGS for maximum_args is the maximum number of args
406          * is potentially 'unlimited'.
407          *
408          * If the brief description cannot fit on the same line as the name
409          * without wrapping on a 80 col window, the description is probably
410          * too long and will not look nice in the show custom output.
411          */
412         CONST struct custom cust[] = {
414         #if defined(CUSTOM)
417                 /*
418                  * add your own custom functions here
419                  *
420                  * We suggest that you sort the entries below by name
421                  * so that show custom will produce a nice sorted list.
422                  */
424                 { "argv", "information about its args, returns arg count",
425                  0, MAX_CUSTOM_ARGS, c_argv },
427                 { "devnull", "does nothing",
428                  0, MAX_CUSTOM_ARGS, c_devnull },
430                 { "help", "help for custom functions",
431                  1, 1, c_help },
433                 { "sysinfo", "return a calc #define value",
434                  0, 1, c_sysinfo },
437         #endif /* CUSTOM */
439                 /*
440                  * This must be at the end of this table!!!
441                  */
442                 {NULL, NULL,
443                  0, 0, NULL}
444         };
446     The definition of struct custom may be found in custom.h.
448     It is important that your entry be placed inside the:
450         #if defined(CUSTOM) ... #endif /* CUSTOM */
452     lines so that when the custom interface is disabled by the upper
453     level Makefile, one does not have unsatisfied symbols.
455     The brief description should be brief so that 'show custom' looks well
456     formatted.  If the brief description cannot fit on the same line as
457     the name without wrapping on a 80 col window, the description is
458     probably too long and will not look nice in the show custom output.
460     The minargs places a lower bound on the number of args that
461     must be supplied to the interface.  This does NOT count
462     the name argument given to custom().  So if minargs is 2:
464         custom("curds")         /* call blocked at high level interface */
465         custom("curds", a)      /* call blocked at high level interface */
466         custom("curds", a, b)   /* call passed down to "curds" interface */
468     The maxargs sets a limit on the number of args that may be passed.
469     If minargs == maxargs, then the call requires a fixed number of
470     argument.  There is a upper limit on the number of args.  If
471     one wants an effectively unlimited upper bound, use MAX_CUSTOM_ARGS.
473     Note that one must have:
475                 0 <= minargs <= maxargs <= MAX_CUSTOM_ARGS
477     To allow the curds function to take at least 2 args and up
478     to 5 args, one would add the following entry to cust[]:
480                 { "curds", "brief description about curds interface",
481                  2, 5, u_curds },
483     It is recommended that the cust[] remain in alphabetical order,
484     so one would place it before the "devnull" and after "argv".
486     Last, you must forward declare the u_curds near the top of the file:
488         #if defined(CUSTOM)
491         /*
492          * add your forward custom function declarations here
493          *
494          * Declare custom functions as follows:
495          *
496          *      E_FUNC VALUE c_xyz(char*, int, VALUE**);
497          *
498          * We suggest that you sort the entries below by name.
499          */
500         E_FUNC VALUE c_argv(char*, int, VALUE**);
501         E_FUNC VALUE c_devnull(char*, int, VALUE**);
502         E_FUNC VALUE c_help(char*, int, VALUE**);
503         E_FUNC VALUE c_sysinfo(char*, int, VALUE**);
505     For u_curds we would add the line:
507         E_FUNC VALUE u_curds(char*, int, VALUE**);
510 Step 7: Add the required information to the custom/Makefile.head
512     The calc test script, curds.cal, should be added to the
513     CUSTOM_CALC_FILES Makefile variable found in custom/Makefile.head:
515         CUSTOM_CALC_FILES= argv.cal halflen.cal curds.cal
517     The help file, curds, should be added to the CUSTOM_HELP
518     custom/Makefile.head variable:
520         CUSTOM_HELP= argv devnull help sysinfo curds
522     If you needed to create any .h files to support u_curds.c, these
523     files should be added to the CUSTOM_H_SRC custom/Makefile.head variable:
525         CUSTOM_H_SRC= u_curds.h otherfile.h
527     Your u_curds.c file MUST be added to the CUSTOM_SRC custom/Makefile.head
528     variable:
530         CUSTOM_SRC= c_argv.c c_devnull.c c_help.c c_sysinfo.c u_curds.c
532     and so must the associated .o file:
534         CUSTOM_OBJ= c_argv.o c_devnull.o c_help.o c_sysinfo.o u_curds.o
537 Step 8: Compile and link in your code
539     If your calc was not previously setup to compile custom code,
540     you should set it up now.  The upper level Makefile (and
541     the custom Makefile) should have the following Makefile
542     variable defined:
544         ALLOW_CUSTOM= -DCUSTOM
546     It is recommended that you build your code from the top level
547     Makefile.  It saves having to sync the other Makefile values.
548     To try and build the new libcustcalc.a that contains u_curds.c:
550         (cd ..; make custom/libcustcalc.a)
552     Fix any compile and syntax errors as needed.  :-)
554     Once libcustcalc.a successfully builds, compile calc:
556         cd ..
557         make calc
559     And check to be sure that the regression test suite still
560     works without errors:
562         make check
565 Step 9: Add the Make dependency tools
567     You should probably add the dependency lines to the bottom of
568     the Makefile.  Given the required include files, you will at least
569     have the following entries placed at the bottom of the Makefile:
571         u_curds.o: ../alloc.h
572         u_curds.o: ../block.h
573         u_curds.o: ../byteswap.h
574         u_curds.o: ../calcerr.h
575         u_curds.o: ../cmath.h
576         u_curds.o: ../config.h
577         u_curds.o: ../endian_calc.h
578         u_curds.o: ../hash.h
579         u_curds.o: ../have_const.h
580         u_curds.o: ../have_malloc.h
581         u_curds.o: ../have_newstr.h
582         u_curds.o: ../have_stdlib.h
583         u_curds.o: ../have_string.h
584         u_curds.o: ../longbits.h
585         u_curds.o: ../nametype.h
586         u_curds.o: ../qmath.h
587         u_curds.o: ../shs.h
588         u_curds.o: ../value.h
589         u_curds.o: ../zmath.h
590         u_curds.o: u_curds.c
591         u_curds.o: ../custom.h
593     If you have the makedepend tool from the X11 development environment
594     (by Todd Brunhoff, Tektronix, Inc. and MIT Project Athena), you can
595     use the following to update your dependencies:
597         # cd to the top level calc directory if you are not there already
599         rm -f Makefile.bak custom/Makefile.bak
600         make depend
602         diff -c Makefile.bak Makefile                   # look at the changes
603         diff -c custom/Makefile.bak custom/Makefile     # look at the changes
605         rm -f Makefile.bak custom/Makefile.bak          # cleanup
607 Step 10: Test
609     Now that you have built calc with your new custom function, test it:
611         ./calc -C               # run the new calc with the -C arg
613     And then try out our test suite:
615         C-style arbitrary precision calculator (version 2.10.3t5.1)
616         [Type "exit" to exit, or "help" for help.]
618         > read custom/curds.cal
619         curds(a, b, [c, d, e]) defined
621         > custom("curds", 2, 3, 4)
624 Step 11: Install
626     Once you are satisfied that everything works, install the new code:
628         # cd to the top level calc directory if you are not there already
630         make install
632     Although calc does not run setuid, you may need to be root to install
633     the directories into which calc installs may be write protected.
636 Step 12: Contribute
638     Your custom function may be of interest to some people and/or
639     serve as an example of what one can do with custom functions.
641     Read the file:
643         help/contrib            (or run:  calc help contrib)
645     and consider submitting your custom function for possible
646     inclusion in later versions of calc.
648 ## Copyright (C) 1999-2007  Landon Curt Noll
650 ## Calc is open software; you can redistribute it and/or modify it under
651 ## the terms of the version 2.1 of the GNU Lesser General Public License
652 ## as published by the Free Software Foundation.
654 ## Calc is distributed in the hope that it will be useful, but WITHOUT
655 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
656 ## or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
657 ## Public License for more details.
659 ## A copy of version 2.1 of the GNU Lesser General Public License is
660 ## distributed with calc under the filename COPYING-LGPL.  You should have
661 ## received a copy with calc; if not, write to Free Software Foundation, Inc.
662 ## 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
664 ## @(#) $Revision: 30.4 $
665 ## @(#) $Id: HOW_TO_ADD,v 30.4 2007/09/21 01:27:27 chongo Exp $
666 ## @(#) $Source: /usr/local/src/bin/calc/custom/RCS/HOW_TO_ADD,v $
668 ## Under source code control:   1997/03/10 03:03:21
669 ## File existed as early as:    1997
671 ## chongo <was here> /\oo/\     http://www.isthe.com/chongo/
672 ## Share and enjoy!  :-)        http://www.isthe.com/chongo/tech/comp/calc/