📄 how_to_add
字号:
Guidelines for adding custom functions--------------------------------------Step 0: Determine if is should it be done? The main focus for calc is to provide a portable platform for multi-precision calculations in a C-like environment. You should consider implementing algorithms in the calc language as a first choice. Sometimes an algorithm requires use of special hardware, a non-portable OS or pre-compiled C library. In these cases a custom interface may be needed. The custom function interface is intended to make is easy for programmers to add functionality that would be otherwise un-suitable for general distribution. Functions that are non-portable (machine, hardware or OS dependent) or highly specialized are possible candidates for custom functions. So before you go to step 1, ask yourself: + Can I implement this as a calc resource file or calc shell script? If Yes, write the shell script or resource file and be done with it. If No, continue to the next question ... + Does it require the use of non-portable features, OS specific support or special hardware? If No, write it as a regular builtin function. If Yes, continue to step 1 ...Step 1: Do some background work First ... read this file ALL THE WAY THROUGH before implementing anything in Steps 2 and beyond! If you are not familiar with calc internals, we recommend that you look at some examples of custom functions. Look at the the following source files: custom.c custom.h custom/custtbl.c custom/c_*.[ch] custom/*.cal help/custom (or run: calc help custom) You would be well advised to look at a more recent calc source such as one available in from the calc version archive. See the following for more details: help/archive (or run: calc help archive)Step 2: Name your custom function We suggest that you pick a name that does not conflict with one of the builtin names. It makes it easier to get help via the help interface and avoid confusion down the road. You should avoid picking a name that matches a file or directory name under ${HELPDIR} as well. Not all help files are associated with builtin function names. For purposes of this file, we will use the name 'curds' as our example custom function name.Step 3: Document your custom function No this step is NOT out of order. We recommend that you write the help file associated with your new custom function EARLY. By experience we have found that the small amount of effort made to write "how the custom function will be used" into a help file pays off in a big way when it comes to coding. Often the effort of writing a help file will clarify fuzzy aspects of your design. Besides, unless you write the help file first, it will likely never be written later on. :-( OK ... we will stop preaching now ... [[ From now on we will give filenames relative to the custom directory ]] Take a look at one of the example custom help files: custom/devnull custom/argv custom/help custom/sysinfo You can save time by using one of the custom help files as a template. Copy one of these files to your own help file: cd custom cp sysinfo curds and edit it accordingly.Step 4: Write your test code No this step is NOT out of order either. We recommend that you write a simple calc script that will call your custom function and check the results. This script will be useful while you are debugging your code. In addition, if you wish to submit your code for distribution, this test code will be an import part of your submission. Your test code will also service as additional for your custom function. Oops ... we said we would stop preaching, sorry about that ... You can use one of the following as a template: custom/argv.cal custom/halflen.cal Copy one of these to your own file: cd custom cp halflen.cal curds.cal and exit it accordingly. In particular you will want to: remove our header disclaimer (or put your own on) change the name from halflen() to curds() change the comment from 'halflen - determine the length ...' to 'curds - brief description about ...' change the print statement near the very bottom from: print "halflen(num) defined"; to: print "curds( ... args description here ...) defined";Step 5: Write your custom function By convention, the files we ship that contain custom function interface code in filenames of the form: c_*.c We suggest that you use filenames of the form: u_*.c to avoid filename conflicts. We recommend that you use one of the c_*.c files as a template. Copy an appropriate file to your file: cd custom cp c_argv.c u_curds.c Before you edit it, you should note that there are several important features of this file. a) All of the code in the file is found between #if ... #endif: /* * only comments and blank lines at the top */ #if defined(CUSTOM) ... all code, #includes, #defines etc. #endif /* CUSTOM */ This allows this code to 'go away' when the upper Makefile disables the custom code (because ALLOW_CUSTOM no longer has the -DCUSTOM define). b) The function type must be: /*ARGSUSED*/ VALUE u_curds(char *name, int count, VALUE **vals) The 3 args are passed in by the custom interface and have the following meaning: name The name of the custom function that was called. In particular, this is the first string arg that was given to the custom() builtin. This is the equivalent of argv[0] for main() in C programming. The same code can be used for multiple custom functions by processing off of this value. count This is the number of additional args that was given to the custom() builtin. Note that count does NOT include the name arg. This is similar to argc except that count is one less than the main() argc interface. For example, a call of: custom("curds", a, b, c) would cause count to be passed as 3. vals This is a pointer to an array of VALUEs. This is the equivalent of argv+1 for main() in C programming. The difference here is that vals[0] refers to the 1st parameter AFTER the same. For example, a call of: custom("curds", a, b, c) would cause vals to point to the following array: vals[0] points to a vals[1] points to b vals[2] points to c NOTE: If you do not use any of the 3 function parameters, then you should declare that function parameter to be UNUSED. For example, if the count and vals parameters were not used in your custom function, then your declaraction should be: /*ARGSUSED*/ VALUE u_curds(char *name, int UNUSED count, VALUE UNUSED **vals) c) The return value is the function must be a VALUE. The typical way to form a VALUE to return is by declaring the following local variable: VALUE result; /* what we will return */ d) You will need to include: #if defined(CUSTOM) /* any #include <foobar.h> here */ #include "../have_const.h" #include "../value.h" #include "custom.h" #include "../have_unused.h" Typically these will be included just below any system includes and just below the #if defined(CUSTOM) line. To better understand the VALUE type, read: ../value.h The VALUE is a union of major value types found inside calc. The v_type VALUE element determines which union element is being used. Assume that we have: VALUE *vp; Then the value is determined according to v_type: vp->v_type the value is which is a type defined in ---------- ------------ ---------- --------------- V_NULL (none) n/a n/a V_INT vp->v_int long n/a V_NUM vp->v_num NUMBER * ../qmath.h V_COM vp->v_com COMPLEX * ../cmath.h V_ADDR vp->v_addr VALUE * ../value.h V_STR vp->v_str char * n/a V_MAT vp->v_mat MATRIX * ../value.h V_LIST vp->v_list LIST * ../value.h V_ASSOC vp->v_assoc ASSOC * ../value.h V_OBJ vp->v_obj OBJECT * ../value.h V_FILE vp->v_file FILEID ../value.h V_RAND vp->v_rand RAND * ../zrand.h V_RANDOM vp->v_random RANDOM * ../zrandom.h V_CONFIG vp->v_config CONFIG * ../config.h V_HASH vp->v_hash HASH * ../hash.h V_BLOCK vp->v_block BLOCK * ../block.h The V_OCTET is under review and should not be used at this time. There are a number of macros that may be used to determine information about the numerical values (ZVALUE, NUMBER and COMPLEX). you might also want to read the following to understand some of the numerical types of ZVALUE, NUMBER and COMPLEX: ../zmath.h ../qmath.h ../cmath.h While we cannot go into full detail here are some cookbook code for manipulating VALUEs. For these examples assume that we will manipulate the return value: VALUE result; /* what we will return */ To return NULL: result.v_type = V_NULL; return result; To return a long you need to convert it to a NUMBER: long variable; result.v_type = V_NUM; result.v_num = itoq(variable); /* see ../qmath.c */ return result; To return a FULL you need to convert it to a NUMBER: FULL variable; result.v_type = V_NUM; result.v_num = utoq(variable); /* see ../qmath.c */ return result; To convert a ZVALUE to a NUMBER*: ZVALUE variable; result.v_type = V_NUM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -