|
|
| (39 intermediate revisions by 2 users not shown) |
| Line 1: |
Line 1: |
| === Programmer's Guides === | | === Complete list of var, dim and exoprog functions === |
|
| |
|
| ==== [[C++]] ====
| | [[Functions]] |
|
| |
|
| === ICONV/OCONV PATTERNS === | | === ICONV/OCONV PATTERNS === |
|
| |
|
| |
|
| ==== Decimal (MD/MC) ==== | | ==== Decimal (MD/MC) ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !input!!conversion!!output | | !input!!conversion (string)!!output |
| |- | | |- |
| |1234||MD2||12.34 | | |1234||MD2||12.34 |
| Line 33: |
Line 32: |
| |-1234||MD20-||1234.00- | | |-1234||MD20-||1234.00- |
| |} | | |} |
|
| |
|
| |
|
| ==== Date (D) ==== | | ==== Date (D) ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !input!!conversion!!output | | !input!!conversion (string)!!output |
| |- | | |- |
| |12345||D||18 OCT 2001 | | |12345||D||18 OCT 2001 |
| Line 74: |
Line 72: |
| |12345||DL||31 | | |12345||DL||31 |
| |} | | |} |
|
| |
|
| |
|
| ==== Time (MT) ==== | | ==== Time (MT) ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !input!!conversion!!output | | !input!!conversion (string)!!output |
| |- | | |- |
| |234800||MT||17:13 | | |234800||MT||17:13 |
| Line 100: |
Line 97: |
| ==== Hex (HEX/MX) ==== | | ==== Hex (HEX/MX) ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !input!!conversion!!output | | !input!!conversion (string)!!output |
| |- | | |- |
| |ab||HEX||(same as HEX8 or HEX4 depending on platform) | | |ab||HEX||(same as HEX8 or HEX4 depending on platform) |
| Line 124: |
Line 121: |
| ==== Text (L/R/T) ==== | | ==== Text (L/R/T) ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !input!!conversion!!output | | !input!!conversion!! (string)output |
| |- | | |- |
| |abcd||L#3||abc | | |abcd||L#3||abc |
| Line 179: |
Line 176: |
| |- | | |- |
| |10||WIDTH||Column Width on fixed width reports | | |10||WIDTH||Column Width on fixed width reports |
| |}
| |
|
| |
| ==== Exodus Dictionary Subroutines ====
| |
|
| |
| "S" type file dictionary entries define table columns that are derived by calling a subroutine.
| |
|
| |
| Dictionary subroutines can be executed in two cases.
| |
|
| |
| # During a SSELECT command e.g. SELECT USERS WITH AGE_IN_YEARS > 10
| |
| # In any Exodus program using the Exodus's "calculate" function. e.g. calculate("AGE_IN_YEARS")
| |
|
| |
| ===== Dictionary Subroutine Library Format =====
| |
|
| |
| Dictionary subroutines are a simplified type of Exodus external subroutine.
| |
|
| |
| A dictionary subroutine is in the format "dict(xyz){...}" where xyz is the dictionary field key *without* quotes and ... is one or more lines of ordinary Exodus source code.
| |
|
| |
| The source code may contain calculate() statements that obtain the results of other dictionary fields.
| |
|
| |
| The source code must result in the variable ANS being set with the required result.
| |
|
| |
| Return statement(s) may be placed anywhere in the code but are not required.
| |
|
| |
| They are slightly different from ordinary external subroutines and do not have programinit()/programexit() clauses. In OO terms, this means that they are simple global functions and not classes, therefore:
| |
|
| |
| #No global variables
| |
| #Any local subroutines or functions must be defined before (above) the dictionary subroutine.
| |
|
| |
| All the subroutines related to one dictionary file go in one "external subroutine library" which can either be written manually or generated automatically from the source code in field 8 of S type dictionaries using the "compile dict_USERS" command.
| |
|
| |
| The library name must be the same as the dictionary file name unless a "USING dictfilename" clause is included in the SSELECT or LIST command.
| |
|
| |
| edic dict_USERS
| |
|
| |
| <pre>
| |
| #include <exodus/dict.h>
| |
|
| |
| dict(AGE_IN_DAYS) {
| |
| ANS=date()-RECORD(1);
| |
| }
| |
|
| |
| dict(AGE_IN_YEARS) {
| |
| ANS=calculate("AGE_IN_DAYS")/365.25;
| |
| }
| |
|
| |
| </pre>
| |
|
| |
| ===== Dictionary subroutine variables =====
| |
|
| |
| Dictionary subroutines have access to the following variables.
| |
|
| |
| When using "calculate(dictid)" the programmer is responsible for setting all these variables (with the exception of ANS) *before* the calculate() expression.
| |
|
| |
| {|
| |
| !Variable!!Purpose
| |
| |-
| |
| |ID || The database record key.
| |
| |-
| |
| |RECORD || The database record
| |
| |-
| |
| |DICT|| The dictionary file name.
| |
| |-
| |
| |MV || The required multivalue number or 0 for all.
| |
| |-
| |
| |ANS || Dictionary subroutines return their result in ANS.
| |
| |-
| |
| |} | | |} |
|
| |
|
| Line 287: |
Line 218: |
| </pre> | | </pre> |
|
| |
|
| === Traditional Multivalue Functions and Statements (non-OO) === | | === Functions and Commands === |
| | |
| Exodus clones traditional multivalue function and statement behaviour and retains their syntax as far as possible.
| |
| | |
| * Traditional functions are rendered as Exodus functions.
| |
| * Traditional statements are rendered as Exodus subroutines.
| |
| | |
| PRINT OCONV(DATE(),'D')
| |
| | |
| in Exodus becomes:
| |
| | |
| printl(oconv(date(),"D"));
| |
|
| |
|
| ==== String Commands ==== | | ==== String Commands ==== |
|
| |
|
| The use of most of Exodus's functions will be fairly obvious to traditional multivalue programmers.
| | Most string functions like trim() that return a new modified string have a corresponding modify in place command like function like trimmer() that is is usually much faster. |
| | | So we have convert and converter, replace and replacer, insert and inserter and so on. |
| Ηοwever it is not so obvious that all the functions ending in "-er" correspond to the old string commands.
| |
| | |
| For example, the classic multivalue "modify in-place" character conversion command:
| |
| | |
| CONVERT 'ab' TO 'cd' IN ZZ
| |
| | |
| is now represented in Exodus by: | |
| | |
| converter(zz,"ab","cd");
| |
|
| |
|
| Exodus provides a complete set of string modification commands even where there was no specific command in classic mv basic.
| | Therefore by preference use |
|
| |
|
| To guarantee fast performance (regardless of compiler optimisation) you should always use the command instead of the old "self assign" idiom.
| | trimmer(v1); |
| | // or |
| | v1.trimmer() |
|
| |
|
| For example:
| | instead of |
|
| |
|
| ZZ=TRIM(ZZ) | | v1 = trim(v1); |
| | | // or |
| should appear in Exodus as:
| | v1 = v1.trim(); |
| | |
| trimmer(zz); | |
| | |
| and not:
| |
| | |
| zz=trim(zz); | |
|
| |
|
| ==== Function Types ==== | | ==== Function Types ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !TYPE !!FUNCTION TYPE|| | | !TYPE !!FUNCTION TYPE|| |
| |- | | |- |
| Line 341: |
Line 248: |
| |cmd ||traditional commands with no outputs|| | | |cmd ||traditional commands with no outputs|| |
| |- | | |- |
| |cmd2 ||traditional commands that now have outputs and can be used in expressions|| | | |expr ||traditional commands that now have outputs and can be used in expressions|| |
| |} | | |} |
|
| |
|
| ==== Parameters/Argument Types ==== | | ==== Parameters/Argument Types ==== |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| |in|| Parameters that provide data to the function. Can be variables or raw data like 1 or "X"|| | | |in|| Parameters that provide data to the function. Can be variables or raw data like 1 or "X"|| |
| |- | | |- |
| Line 359: |
Line 266: |
| Optional Parameters | | Optional Parameters |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| !Key !!Default|| | | !Key !!Default|| |
| |- | | |- |
| |="" ||""|| | | |= "" ||""|| |
| |-
| |
| |=" " ||" "||
| |
| |-
| |
| |="." ||"."||
| |
| |-
| |
| |=1 ||1 ||
| |
| |-
| |
| |=0 ||0||
| |
| |-
| |
| |=true ||true||
| |
| |-
| |
| |=false ||false||
| |
| |}
| |
| | |
| ==== Complete List of Functions ====
| |
| | |
| | |
| ===== Environment =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |-
| |
| |var= ||osgetenv(envname)||
| |
| |-
| |
| |if ||osgetenv(envname, out value)||
| |
| |-
| |
| |if ||ossetenv(envname, newvalue)||
| |
| |}
| |
| | |
| ===== Time/Date/Sleep =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||date()||
| |
| |-
| |
| |var= ||time()||
| |
| |-
| |
| |var= ||timedate()||
| |
| |-
| |
| |cmd ||ossleep(milliseconds)||
| |
| |-
| |
| |var= ||ostime()||
| |
| |}
| |
| | |
| ===== System File =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |if ||osopen(filename, out filehandle, in locale="")||
| |
| |-
| |
| |cmd ||osclose(filehandle)||
| |
| |-
| |
| |var= ||osbread(filehandle, startoffset, length)||
| |
| |-
| |
| |cmd ||osbread(out data, filehandle, startoffset, length)||
| |
| |-
| |
| |cmd ||osbwrite(data, filehandle, startoffset)||
| |
| |-
| |
| |if ||osread(out data, osfilename, in locale="")||
| |
| |-
| |
| |var= ||osread(osfilename, in locale="")||
| |
| |-
| |
| |if ||oswrite(data, osfilename, in locale="")||
| |
| |-
| |
| |if ||osdelete(osfilename)||
| |
| |-
| |
| |if ||osrename(oldosdir_or_filename, newosdir_or_filename)||
| |
| |-
| |
| |if ||oscopy(fromosdir_or_filename, newosdir_or_filename)||
| |
| |-
| |
| |cmd ||osflush()||
| |
| |}
| |
| | |
| ===== System Directory =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||oslist(path=".", wildcard="", mode=0)||
| |
| |-
| |
| |var= ||oslistf(path=".", wildcard="")||
| |
| |-
| |
| |var= ||oslistd(path=".", wildcard="")||
| |
| |-
| |
| |var= ||osfile(filename)||
| |
| |-
| |
| |var= ||osdir(filename)||
| |
| |-
| |
| |if ||osmkdir(newdirname)||
| |
| |-
| |
| |if ||osrmdir(dirname, evenifnotempty=false)||
| |
| |-
| |
| |var= ||oscwd()||
| |
| |-
| |
| |var= ||oscwd(newdirname)||
| |
| |}
| |
| | |
| ===== Program Control =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||suspend(command)||
| |
| |-
| |
| |var= ||osshell(command)||
| |
| |-
| |
| |var= ||osshellread(command)||
| |
| |-
| |
| |cmd ||osshellread(out commandoutput, command)||
| |
| |-
| |
| |cmd ||osshellwrite(commandinput, command)||
| |
| |-
| |
| |cmd ||stop(text="")||
| |
| |-
| |
| |cmd ||abort(text)||
| |
| |-
| |
| |var= ||perform(command)||
| |
| |-
| |
| |var= ||execute(command)||
| |
| |-
| |
| |var= ||chain(command)||
| |
| |-
| |
| |var= ||logoff()||
| |
| |-
| |
| |cmd ||debug()||
| |
| |}
| |
| | |
| | |
| ===== Variable Control =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |if ||assigned(anyvar)||
| |
| |-
| |
| |if ||unassigned(anyvar)||
| |
| |-
| |
| |cmd2 ||exchange(var1,var2)||
| |
| |-
| |
| |cmd2 ||transfer(fromvar,tovar)||
| |
| |}
| |
| | |
| ===== Console Output =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |cmd ||print(instring)||
| |
| |-
| |
| |cmd ||printl(instring="")||
| |
| |-
| |
| |cmd ||printt(instring="")||
| |
| |}
| |
| | |
| ===== Cursor =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||at(column0orcode)||
| |
| |-
| |
| |var= ||at(column0, row0)||
| |
| |-
| |
| |var= ||getcursor()||
| |
| |-
| |
| |cmd ||setcursor(cursorstr)||
| |
| |-
| |
| |var= ||getprompt()||
| |
| |-
| |
| |cmd ||setprompt(promptchar)||
| |
| |}
| |
| | |
| ===== Console Input =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |-
| |
| |var= ||input()||
| |
| |-
| |
| |var= ||input(out inputstr)||
| |
| |-
| |
| |var= ||input(prompt, out inputstr)||
| |
| |-
| |
| |var= ||inputn(n)||
| |
| |}
| |
| | |
| ===== Math =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||rnd(number)||
| |
| |-
| |
| |cmd ||initrnd(seednumber)||
| |
| |- | | |- |
| |var= ||mod(dividend, divisor)|| | | |= " " ||" "|| |
| |- | | |- |
| |var= ||abs(number)|| | | |= "." ||"."|| |
| |- | | |- |
| |var= ||pwr(base, exponent)|| | | |= 1 ||1 || |
| |- | | |- |
| |var= ||exp(power)|| | | |= 0 ||0|| |
| |- | | |- |
| |var= ||sqrt(number)|| | | |= true ||true|| |
| |- | | |- |
| |var= ||sin(degrees)|| | | |= false ||false|| |
| |-
| |
| |var= ||cos(degrees)||
| |
| |-
| |
| |var= ||tan(degrees)||
| |
| |-
| |
| |var= ||atan(number)||
| |
| |-
| |
| |var= ||loge(number)||
| |
| |-
| |
| |var= ||integer(number)||
| |
| |-
| |
| |var= ||floor(number)||
| |
| |-
| |
| |var= ||round(number, ndecimals=0)||
| |
| |} | | |} |
|
| |
|
| ===== String Creation ===== | | ==== Field mark characters ==== |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||chr(integer)||
| |
| |-
| |
| |var= ||str(instring, number)||
| |
| |-
| |
| |var= ||space(number)||
| |
| |}
| |
|
| |
|
| | Exodus implements a PICK OS data structure called a "dynamic array". This is simply any string which uses six specific unprintable ASCII delimiter characters (\x1A to \x1F) to separate its various parts. The parts are referred to as records, fields, values, subvalues, text, and subtext and fall within each other. |
|
| |
|
| ===== String Info/Search =====
| | Dynamic arrays therefore implement sparse six dimensional arrays. |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0"
| | Typical CPU caching architecture favours similar values being adjacent in memory therefore implementing them as strings of values separated by delimiter characters can have performance advantages over more complex structures. |
| |-
| |
| |var= ||count(instring, substr)||
| |
| |-
| |
| |var= ||dcount(instring, substr)||
| |
| |-
| |
| |var= ||index(instring, substr, occurrenceno=1)||
| |
| |-
| |
| |var= ||index2(instring, substr, startcharno=1)||
| |
| |-
| |
| |var= ||len(instring)||
| |
| |-
| |
| |var= ||length(instring)||
| |
| |-
| |
| |if ||match(instring, matchstr, options="")||
| |
| |-
| |
| |var= ||seq(inchar)||
| |
| |}
| |
| | |
| ===== String Functions =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||convert(instring, oldchars, newchars)||
| |
| |-
| |
| |var= ||crop(instring)||
| |
| |-
| |
| |var= ||field(instring, sepchar, fieldno, nfields=1)||
| |
| |-
| |
| |var= ||field2(instring, sepchar, fieldno, nfields=1)||
| |
| |-
| |
| |var= ||fieldstore(instring, sepchar, fieldno, nfields, replacementstr)||
| |
| |-
| |
| |var= ||lcase(instring)||
| |
| |-
| |
| |var= ||ucase(instring)||
| |
| |-
| |
| |var= ||lower(instring)||
| |
| |-
| |
| |var= ||raise(instring)||
| |
| |-
| |
| |cmd2 ||quote(instring)||
| |
| |-
| |
| |cmd2 ||squote(instring)||
| |
| |-
| |
| |cmd2 ||unquote(instring)||
| |
| |-
| |
| |var= ||splice(instring, fromcharno, nchars, insertionstr)||
| |
| |-
| |
| |var= ||substr(instring, fromcharno)||
| |
| |-
| |
| |var= ||substr(instring, fromcharno, nchars)||
| |
| |-
| |
| |var= ||swap(instring, oldstr, newstr, options="")||
| |
| |-
| |
| |var= ||trim(instring, trimchars=" ")||
| |
| |-
| |
| |var= ||trimb(instring, trimchars=" ")||
| |
| |-
| |
| |var= ||trimf(instring, trimchars=" ")||
| |
| |}
| |
|
| |
|
| ===== String Commands =====
| | In practice the vast majority of dynamic arrays consist of "fields" separated by the FM character (\x1E) but it is very common for fields to have values separated by the VM character (\x1D) and values to have subvalues using SM (\x1D). |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0"
| | Since the six delimiter characters fall in the unprintable character range certain other characters have been designated as usable for coding and printing. For example the FM character is represented as ^ and can be entered in source code appended with _var to indicate that the string must be converted to internal format. |
| |-
| |
| |cmd2 ||converter(io instring, oldchars, newchars)||
| |
| |-
| |
| |var= ||cropper(io instring)||
| |
| |-
| |
| |cmd2 ||fieldstorer(io instring, sepchar, fieldno, nfields, replacementstr)||
| |
| |-
| |
| |cmd2 ||lcaser(io instring)||
| |
| |-
| |
| |var= ||ucaser(io instring)||
| |
| |-
| |
| |cmd2 ||lowerer(io instring)||
| |
| |-
| |
| |cmd2 ||raiser(io instring)||
| |
| |-
| |
| |cmd2 ||quoter(io instring)||
| |
| |-
| |
| |cmd2 ||squoter(io instring)||
| |
| |-
| |
| |cmd2 ||unquoter(io instring)||
| |
| |-
| |
| |cmd2 ||splicer(io instring, fromcharno, nchars, insertion)||
| |
| |-
| |
| |var= ||substrer(io instring, fromcharno)||
| |
| |-
| |
| |var= ||substrer(io instring, fromcharno, nchars)||
| |
| |-
| |
| |cmd2 ||swapper(io instring, oldstr, newstr, options="")||
| |
| |-
| |
| |cmd2 ||trimmer(io instring, trimchars=" ")||
| |
| |-
| |
| |cmd2 ||trimmerb(io instring, trimchars=" ")||
| |
| |-
| |
| |cmd2 ||trimmerf(io instring, trimchars=" ")||
| |
| |}
| |
|
| |
|
| ===== iconv/oconv ===== | | var v1 = "f1^f2^f3"_var; // Three fields |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0"
| | var v2 = "f1^v1]v2]v3^f3"_var; // Three fields, 2nd field has 3 values. It is "multivalued". |
| |var= ||oconv(instring, conversion)||
| |
| |-
| |
| |var= ||iconv(instring, conversion)||
| |
| |}
| |
|
| |
|
| ===== Database =====
| | Anything which contains a collection of fields can be considered as a "record" and records can be stored in files with a unique primary key. The fields might represent different columns of a traditional database table. So anonymous field number 1 might be a contact name, field 2 the contact address, field 3 a multivalued list of contact points. etc. |
|
| |
|
| {|border="1" cellpadding="10" cellspacing="0" | | {|class="wikitable" |
| |if ||connect(connectionstring="")||
| | !Delimiter<br>name!!var||Hex!!Display!!cstr " "||char ' ' |
| |- | | |- |
| |if ||disconnect()|| | | |Record Mark ||RM||\x1F|| ` || _RM || RM_ |
| |- | | |- |
| |if ||createdb(dbname, out errmsg)|| | | |Field Mark ||FM||\x1E|| ^ || _FM || FM_ |
| |- | | |- |
| |if ||deletedb(dbname, out errmsg)|| | | |Value Mark ||VM||\x1D|| ] || _VM || VM_ |
| |- | | |- |
| |if ||createfile(filename, options="")|| | | |Subvalue Mark ||SM||\x1C|| } || _SM || SM_ |
| |- | | |- |
| |if ||deletefile(filename)|| | | |Text Mark||TM ||\x1B|| | || _TM || TM_ |
| |- | | |- |
| |if ||clearfile(filename)|| | | |Subtext Mark ||STM||\x1A|| ~ || _STM || STM_ |
| |- | |
| |var= ||listfiles()|| | |
| |-
| |
| |if ||createindex(filename, fieldname, usingdictfilename="")||
| |
| |-
| |
| |if ||deleteindex(filename, fieldname)||
| |
| |-
| |
| |var= ||listindexes(filename="")||
| |
| |-
| |
| |if ||begintrans()||
| |
| |-
| |
| |if ||rollbacktrans()||
| |
| |-
| |
| |if ||committrans()||
| |
| |} | | |} |
|
| |
|
| ===== Database Files and Records =====
| | {|class="wikitable" style="text-align: center;" |
| | |
| {|border="1" cellpadding="10" cellspacing="0" | |
| |if ||open(filename, out filehandle)||
| |
| |- | | |- |
| |if ||read(out record, filehandle, key)|| | | |align=right|<b> Delimiter Name :</b> ||Record Mark||Field Mark||Value Mark||Subvalue Mark||Text Mark||Subtext Mark |
| |- | | |- |
| |if ||matread(out dimrecord, filehandle, key)|| | | |align=right|<b>var :</b> || RM ||FM ||VM ||SM ||TM ||STM |
| |- | | |- |
| |if ||readv(out record, filehandle, key, fieldnumber)|| | | |align=right|<b>Display :</b>||` ||^ || ] || } || | || ~ |
| |- | | |- |
| |if ||write(record, filehandle, key)|| | | |align=right|<b>Hex :</b> ||\x1F||\x1E||\x1D||\x1C||\x1B||\x1A |
| |- | | |- |
| |if ||matwrite(in dimrecord, filehandle, key)|| | | |align=right|<b>cstr " " :</b> ||_RM ||_FM ||_VM ||_SM ||_TM ||_STM |
| |- | | |- |
| |if ||writev(record, filehandle, key, fieldn)|| | | |align=right|<b>char ' ' :</b> ||RM_ ||FM_ ||VM_ ||SM_ ||TM_ ||STM_ |
| |-
| |
| |if ||deleterecord(filehandle, key)||
| |
| |-
| |
| |if ||updaterecord(record, filehandle, key)||the record key must already exist
| |
| |-
| |
| |if ||insertrecord(record, filehandle, key)||the record key must not already exist
| |
| |-
| |
| |if ||lock(filehandle, key)||
| |
| |-
| |
| |cmd ||unlock(filehandle, key)||
| |
| |-
| |
| |cmd ||unlockall()||
| |
| |}
| |
| | |
| ===== Record Selection =====
| |
| | |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |if ||select(sortselectclause="")||
| |
| |- | |
| |cmd ||clearselect()||
| |
| |-
| |
| |if ||readnext(out key)||
| |
| |-
| |
| |if ||readnext(out key, out valueno)||valueno returns multivalue numbers if your sortselectclause sorted BY-EXP on a multivalued field. Not implemented yet.
| |
| |-
| |
| |if ||selectrecord(sortselectclause="")||
| |
| |- | |
| |if ||readnextrecord(out record, out id)||must be preceded by a selectrecord() not select() | |
| |} | | |} |
|
| |
| ===== Dictionary =====
| |
|
| |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||calculate(fieldname)||
| |
| |-
| |
| |var= ||xlate(filename, key, fieldno, mode)||
| |
| |}
| |
|
| |
|
| |
| ===== Dynamic Array Functions =====
| |
|
| |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |var= ||replace(instring, fieldno, replacement)||
| |
| |-
| |
| |var= ||replace(instring, fieldno, valueno, replacement)||
| |
| |-
| |
| |var= ||replace(instring, fieldno, valueno, subvalueno, replacement)||
| |
| |-
| |
| |var= ||extract(instring, fieldno, valueno=0, subvalueno=0)||
| |
| |-
| |
| |var= ||erase(instring, fieldno, valueno=0, subvalueno=0)||
| |
| |-
| |
| |var= ||insert(instring, fieldno, insertion)||
| |
| |-
| |
| |var= ||insert(instring, fieldno, valueno, insertion)||
| |
| |-
| |
| |var= ||insert(instring, fieldno, valueno, subvalueno, insertion)||
| |
| |-
| |
| |if ||locate(instring, target, out setting, fieldn=0, valuen=0)||
| |
| |-
| |
| |if ||locateby(instring, target, ordercode, out setting, fieldn=0, valuen=0)||
| |
| |-
| |
| |if ||locateusing(instring, target, usingchar, out setting, fieldn=0, valuen=0, subvaluen=0)||
| |
| |-
| |
| |if ||locateusing(instring, target, usingchar)||
| |
| |-
| |
| |var= ||remove(fromstr, io startx, out delimiterno)||
| |
| |-
| |
| |var= ||sum(instring, sepchar=VM_)||
| |
| |}
| |
|
| |
| ===== Dynamic Array Commands =====
| |
|
| |
| {|border="1" cellpadding="10" cellspacing="0"
| |
| |cmd2 ||replacer(io instring, fieldno, replacement)||
| |
| |-
| |
| |cmd2 ||replacer(io instring, fieldno, valueno, replacement)||
| |
| |-
| |
| |cmd2 ||replacer(io instring, fieldno, valueno, subvalueno, replacement)||
| |
| |-
| |
| |cmd2 ||inserter(io instring, fieldno, insertion)||
| |
| |-
| |
| |cmd2 ||inserter(io instring, fieldno, valueno, insertion)||
| |
| |-
| |
| |cmd2 ||inserter(io instring, fieldno, valueno, subvalueno, insertion)||
| |
| |-
| |
| |cmd2 ||eraser(io instring, fieldno, valueno=0, subvalueno=0)||
| |
| |}
| |
|
| |
| === Troubleshooting ===
| |
|
| |
| ==== printl(lcaser("ABC")); //won't compile! ====
| |
|
| |
| Simply use lcase instead of lcaser.
| |
|
| |
| printl(lcase("ABC")); //result is abc
| |
|
| |
| lcaser is designed to modify a variable so lcaser's parameter must be a variable and not raw data like "ABC".
| |
|
| |
| ==== aa(10)=bb; //compiles but doesnt do anything! ====
| |
|
| |
| To replace field 10 of dynamic array aa do one of the following.
| |
|
| |
| replacer(aa,10,bb);
| |
| aa.replacer(10,bb);
| |
|
| |
| Exodus doesnt support "aa(10)=" style syntax to replace dynamic array fields.
| |
|
| |
| ==== if (aa ^ bb > cc) //won't compile! ====
| |
|
| |
| If the intent is to work like classic multivalue basic code then put brackets to clarify that to the compiler.
| |
|
| |
| if ( (aa ^ bb) > cc)
| |
|
| |
| If instead the intent is aa ^ (bb > cc) then you must pre-calculate the result of bb > cc ...
| |
|
| |
| var dd=bb > cc;
| |
| if (aa ^ dd)
| |
|
| |
| ... or just wrap it in var()
| |
|
| |
| if (aa ^ var(bb>cc) )
| |
|
| |
| Exodus will not treat the direct result of a logical operation as a character "1" or "0" for the purposes of string concatenation. This is the only deliberate difference from multivalue Basic in Exodus. For why this is so, read about Exodus's concatenation operator.
| |
|
| |
|
| |
| ==== using asserts ====
| |
|
| |
| Asserts may be used to trap some errors in Exodus code.
| |
| Typical scheme to use asserts:
| |
| // near beginning of .cpp file:
| |
| #include <cassert>
| |
| ...
| |
| // somewhere in the code:
| |
| assert( some_expression_that_should_be_normally_true);
| |
| If <code>some_expression_that_should_be_normally_true</code> happens to be false, the program aborts with message printed to console.
| |
|
| |
| Exodus has 3 additional include files which modify or extend the functionality of standard cassert file.
| |
|
| |
| <code>cassert_warn</code> - redefines all assert()s to display diagnostic message when triggered, but not to abort() the program;
| |
|
| |
| <code>cassert_pause</code> - redefines all assert()s to display diagnostic message when triggered, and then pause the program until user presses a key; macro does not abort() the program;
| |
|
| |
| <code>cassert_exodus</code> - defines assert() macro in the standard way, but adds 2 more macros:
| |
| <code>assert_warn( some_expression_that_should_be_normally_true)</code> - message, no abort();
| |
| <code>assert_pause( some_expression_that_should_be_normally_true)</code> - message, pause until keypress, no abort().
| |
|
| |
| For simple examples - click on [[assert_examples]].
| |
Complete list of var, dim and exoprog functions
Functions
ICONV/OCONV PATTERNS
Decimal (MD/MC)
| input |
conversion (string) |
output
|
| 1234 |
MD2 |
12.34
|
| 1234 |
MD20 |
1234.00
|
| 1234 |
MD20, |
1,234.00
|
| 1234.5678 |
MD2 |
12.35
|
| 1234.5678 |
MD20 |
1234.57
|
| 1234.5678 |
MD20, |
1,234.57
|
| 1234 |
MC2 |
12,34
|
| 1234 |
MC20 |
1234,00
|
| 1234 |
MC20, |
1.234,00
|
| 1234 |
MD20- |
1234.00
|
Date (D)
| input |
conversion (string) |
output
|
| 12345 |
D |
18 OCT 2001
|
| 12345 |
D/ |
10/18/2001
|
| 12345 |
D- |
10-18-2001
|
| 12345 |
D2 |
18 OCT 01
|
| 12345 |
D/E |
18/10/2001
|
| 12345 |
DS |
2001 OCT 18
|
| 12345 |
DS/ |
2001/10/18
|
| 12345 |
DM |
10
|
| 12345 |
DMA |
OCTOBER
|
| 12345 |
DY |
2001
|
| 12345 |
DY2 |
01
|
| 12345 |
DD |
18
|
| 12345 |
DW |
4
|
| 12345 |
DWA |
THURSDAY
|
| 12345 |
DQ |
4
|
| 12345 |
DJ |
291
|
| 12345 |
DL |
31
|
Time (MT)
| input |
conversion (string) |
output
|
| 234800 |
MT |
17:13
|
| 234800 |
MTH |
05:13PM
|
| 234800 |
MTS |
17:13:20
|
| 234800 |
MTHS |
05:13:20PM
|
| 0 |
MT |
00:00
|
| 0 |
MTH |
12:00AM
|
| 0 |
MTS |
00:00:00
|
| 0 |
MTHS |
12:00:00AM
|
Hex (HEX/MX)
| input |
conversion (string) |
output
|
| ab |
HEX |
(same as HEX8 or HEX4 depending on platform)
|
| ab |
HEX8 |
0000006100000062
|
| ab |
HEX4 |
00610062
|
| ab |
HEX2 |
6162
|
| 15 |
MX |
F
|
| 254 |
MX |
FE
|
| 255 |
MX |
FF
|
| 256 |
MX |
100
|
| 27354234 |
MX |
1A1647A
|
Text (L/R/T)
| input |
conversion |
(string)output
|
| abcd |
L#3 |
abc
|
| ab |
L#3 |
ab␣
|
| abcd |
R#3 |
bcd
|
| ab |
R#3 |
␣ab
|
| ab |
T#3 |
ab␣
|
| abcd |
T#3 |
abc™d␣␣
|
| 42 |
L(0)#5 |
42000
|
| 42 |
R(0)#5 |
00042
|
| 42 |
T(0)#5 |
42000
|
Dictionaries
Exodus dictionaries enable classic multivalue database data definition. Dictionaries are just normal Exodus multivalue files that contain one record for each data column definition. You can use Exodus's edir program to manually edit dictionaries.
Dictionary file names must start with the word "dict_". For example, if you have a "books" file, then you will probably have a "dict_books" file.
You can list the contents of a dictionary by typing "list dict_filename".
Exodus Dictionary Format
| 0 |
DICTID |
Field/Column Code
|
| 1 |
DICTTYPE |
"F" or "S" : "F" means use Field No (i.e. raw data) and "S" means use Source Code (i.e. a function).
|
| 2 |
FIELDNO |
Field number (0=key, 1=field 1 etc for "Fields"
|
| 3 |
TITLE |
Title on reports
|
| 4 |
SM |
S or M or Mnn : "Single Value" or "Multivalue" or "Multivalue Group nn"
|
| 5 |
KEYPARTNO |
Multipart keys are separated by * characters.
|
| 6 |
|
| 7 |
CONVERSION |
Conversion (MD/MT/D etc.)
|
| 8 |
SOURCE |
Source Code of a subroutine to calculate the field. Multivalues are lines and the result must be placed in a variable "ANS".
|
| 9 |
JUST |
"L" or "R" or "T" requesting left, right or text justification
|
| 10 |
WIDTH |
Column Width on fixed width reports
|
Sort/Select Command
Exodus provides the classic multivalue sort/select command within any Exodus program followed by readnext().
Classic multivalue select/readnext functions only provide the keys of the selected records. Exodus provides the classic select/readnext and also selectrecords/readnextrecord which provides complete records instead of just keys.
The format of the select/sselect command is as follows:
SELECT|SSELECT
{max_number_of_records}
{using filename}
filename
{datakeyvalue} ...
{BY|BY-DSND fieldname} ...
{
WITH
{NO|ALL|ANY}
dict_field_id
{
CONTAINING|STARTING|ENDING|LIKE|EQ|NE|NOT|GT|LT|GE|LE=|<>|>|<|>=|<= value(s)
|
BETWEEN value AND value
}
{AND|OR}
} ...
Functions and Commands
String Commands
Most string functions like trim() that return a new modified string have a corresponding modify in place command like function like trimmer() that is is usually much faster.
So we have convert and converter, replace and replacer, insert and inserter and so on.
Therefore by preference use
trimmer(v1);
// or
v1.trimmer()
instead of
v1 = trim(v1);
// or
v1 = v1.trim();
Function Types
| TYPE |
FUNCTION TYPE |
|
| var= |
traditional functions that return values and can be used in expressions and be on the right hand side of assignments |
|
| if |
traditional conditional statements that started with "if" or ended with "then/else" (or could have) |
|
| cmd |
traditional commands with no outputs |
|
| expr |
traditional commands that now have outputs and can be used in expressions |
|
Parameters/Argument Types
| in |
Parameters that provide data to the function. Can be variables or raw data like 1 or "X" |
|
| unspecified |
Same as "in". Omission of the most common type de-clutters the documentation. NB When defining your own subroutines and functions "in" cannot be omitted from the source code. |
|
| io |
Parameters that may provide and/or return data. Must be variables. Cannot be raw data like 1 or "X" |
|
| out |
Parameters that return data. Must be variables. Cannot be raw data like 1 or "X" |
|
Optional Parameters
| Key |
Default |
|
| = "" |
"" |
|
| = " " |
" " |
|
| = "." |
"." |
|
| = 1 |
1 |
|
| = 0 |
0 |
|
| = true |
true |
|
| = false |
false |
|
Field mark characters
Exodus implements a PICK OS data structure called a "dynamic array". This is simply any string which uses six specific unprintable ASCII delimiter characters (\x1A to \x1F) to separate its various parts. The parts are referred to as records, fields, values, subvalues, text, and subtext and fall within each other.
Dynamic arrays therefore implement sparse six dimensional arrays.
Typical CPU caching architecture favours similar values being adjacent in memory therefore implementing them as strings of values separated by delimiter characters can have performance advantages over more complex structures.
In practice the vast majority of dynamic arrays consist of "fields" separated by the FM character (\x1E) but it is very common for fields to have values separated by the VM character (\x1D) and values to have subvalues using SM (\x1D).
Since the six delimiter characters fall in the unprintable character range certain other characters have been designated as usable for coding and printing. For example the FM character is represented as ^ and can be entered in source code appended with _var to indicate that the string must be converted to internal format.
var v1 = "f1^f2^f3"_var; // Three fields
var v2 = "f1^v1]v2]v3^f3"_var; // Three fields, 2nd field has 3 values. It is "multivalued".
Anything which contains a collection of fields can be considered as a "record" and records can be stored in files with a unique primary key. The fields might represent different columns of a traditional database table. So anonymous field number 1 might be a contact name, field 2 the contact address, field 3 a multivalued list of contact points. etc.
Delimiter name |
var |
Hex |
Display |
cstr " " |
char ' '
|
| Record Mark |
RM |
\x1F |
` |
_RM |
RM_
|
| Field Mark |
FM |
\x1E |
^ |
_FM |
FM_
|
| Value Mark |
VM |
\x1D |
] |
_VM |
VM_
|
| Subvalue Mark |
SM |
\x1C |
} |
_SM |
SM_
|
| Text Mark |
TM |
\x1B |
| |
_TM |
TM_
|
| Subtext Mark |
STM |
\x1A |
~ |
_STM |
STM_
|
| Delimiter Name : |
Record Mark |
Field Mark |
Value Mark |
Subvalue Mark |
Text Mark |
Subtext Mark
|
| var : |
RM |
FM |
VM |
SM |
TM |
STM
|
| Display : |
` |
^ |
] |
} |
| |
~
|
| Hex : |
\x1F |
\x1E |
\x1D |
\x1C |
\x1B |
\x1A
|
| cstr " " : |
_RM |
_FM |
_VM |
_SM |
_TM |
_STM
|
| char ' ' : |
RM_ |
FM_ |
VM_ |
SM_ |
TM_ |
STM_
|