![]()
For the example given, the MAIN SYSTEM stamps the layouts:
Articles & SuppliersThe layouts show that:
File 1 fa\arc\Articles 1000 rec. Articles 46000 bytes trk 1 ordered by Code
1 1 Code $ 2 7 Description $ 38 end data 39 PF Articles --> Prices 43 PL Articles --> Prices 46 end PTs File 2 fa\arc\Supplier 100 rec. Suppliers 4500 bytes trk 2 ordered by Code 1 1 Code $ 2 6 Description $ 37 end data 38 PF Suppliers --> Prices 42 PL Suppliers --> Prices 45 end PTs File 3 fa\arc\Prices 100000 rec. Prices 5900000 bytes trk 3 1 1 Price S occurs 5 2 21 Starting Date d occurs 5 35 end data 36 PND Articles --> Prices 40 PPD Articles --> Prices 44 POW Articles --> Prices 48 PND Suppliers --> Prices 52 PPD Suppliers --> Prices 56 POW Suppliers --> Prices 59 end PTs space occupied: 5950500 bytes
1. the Articles and suppliers files are equipped with index on their respective fields Code;
2. after the data zone at the beginning, all 3 record types have a Pointers zone, which
highlights the reticular connections:
2.1. every A record and every S record is Owner of a Prices chain, because
they contain the Pointers PF e PL (at the First and Last Price record in
the chain);
2.2. every Price record is Member of 2 chains, hanging respectively from an A
and a S, because each one contains 3 Pointers PND, PPD e POW: at the Next and at the
Prior Detail (that is, at the following Price record and at the previous one) and at the
Owner.
3. in the data zone the fields are numbered progressively, and for each one the physical location is given, as well as the field type and the array dimension ("occurs 5"), present only when it's different from 1; in the example, the prices fixed by a S for a given A are assumed to vary in the course of time and a record is kept of the latest 5 prices, with the relative starting dates. The information relative to the physical location of data and the Pointers does NOT normally concern the user programs of the MAIN-SYSTEM, which refer to data (never to the Pointers) by means of their progressive number in the record. It is useful, though, when the record layout needs changing, to implement the CNVARC program.
The example does not show all types of data managed, which are:
$ alphaliberol string; A Ascii value(1 byte); I short integer (2 bytes); L long integer (4 bytes); S single precision floating (4 bytes); D double precision floating (8 bytes); C currency (8 bytes); d date (yymmdd in 3 bytes); s date (yyyymmdd in 4 bytes).The example also does not contain relational references to other files. If, for example, there existed a fourth file "Brand", containing a Code and a Description for each Brand, and furnished with an index on the Code field, there could appear a third field on the Article record, which would be printed as:
3 39 Brand I Xkey for Brands
![]()
2. MAIN-SYSTEM instructions set
Conventionally, the following variables identify:
f% a file number; tr% a record type number, which normally coincides with f%; i% a field number in a record type; j% an array index when the field is an array with more than 1 element.The instructions in brackets are FUNCTIONs, the others SUBs.
- Basic instructions
iniproc proc$ prepares the environment for files management in the
directory proc$;
openfl f% opens the f% file in the proc$ package;
closfl f% closes the f% file; if f%=0 it closes all the open files;
initr tr% opens the record type tr% (which must be located in a f%
file already open); used only for those files that have
more than 1 record type;
endtr tr% closes tr%;
inibuf tr% initializes all tr% fields, loading spaces/zeros in the
alphaliberol/liberol fields;
getbuf tr%, rec$ loads rec$ with the tr% buffer containing the current
record;
putbuf tr%, rec$ loads the tr% buffer with rec$;
addrec f% adds a new record to the end of the f% file;
rdnrec f%, k reads the record number k in the file f%;
modrec f% rewrites the current file in the f% file;
getfld$ (tr%, i%) value of field i% in tr%;
getfldj$ (tr%, i%, j%) value of occurrence j% of i% in tr%;
putfld tr%, i%, in$ loads in$ in the i% field in tr%;
putfldj tr%, i%, j%, in$ loads in$ in the occurrence j% of i% in tr%;
inffld tr%, i%, dd$, ofs%, tdr%, lun%, occ%, kf%
furnishes for the field i% of tr%, the information:
dd$ name of field;
ofs% position in record tr%;
tdr% data type (alphanumeric, integer, ...);
lun% length (if alphanumeric);
occ% dimension of field i% (maximum value assumable
for array index j%; value at least 1);
kf% if significant, the value of field i% points
to a position in file kf%;
nametrk$ (tr%, sp%) name of tr%, singular or plural, according to whether
sp% = 1 or 2;
namefile$ (f%) string of f%, complete with directories and
subdirectories;
nrec (f%) number of records present in f%, that is, the number of
addrec executed;
maxrf (f%) maximum number of records admitted in f%;
currec (f%) position of current record in f%;
lockf f% executes Lock on f%;
ulockf f% executes Unlock on f%;
vercurr f% checks current record has not been changed by another
work place;
fldrec op%, tr%, i%, j%, in$, ed%, ls%, sws%, n, d
general routine which, varying the operation code op%,
executes all the above-mentioned operations.
openix f% opens the index; to execute after openfl f%;
closix f% closes the index; to execute before closfl;
rdrix f%, k$ reads the record with key k$;
addix f%, knew$ adds the record with knew$ key; does not admit duplicate
key;
adddpix f%, knew$ like addix, but admits duplicates;
modix f%, newk$, oldk$ modifies from oldk$ to newk$ the key of the current
record; does not admit duplicate keys;
moddpix f%, newk$, oldk$ as above, but admits duplicates;
delix f% cancels the current record;
ndel (f%) number of records cancelled, that is, number of delix
executed;
ksort$ (f%) number of fields composing f% key;
minkix f%, k$ reads the first record with a string equal to k$ at
the beginning of the key;
maxkix f%, k$ reads the last record with a string equal to k$ at
the beginning of the key;
grteix f%, k$ like minkix, but if it does not find a key with k$,
it supplies the first key > k$;
nextix f% reads sequentially according to index;
prioix f% as above, but in reverse;
curix% (f%) position of the current key in the index;
strtix f%, k% reads the k-th position in the index;
nuclix op%, f%, knw$, kol$
general routine which, varying the operation code op%,
executes all the above-listed operations;
curkey$ (f%) value of current record key.
- Operations on reticular files
In these operations, you should imagine a chain between a file fo% (containing the owners) and a file fm% (with the members) and that the record of the operation, called "object", is the current one of fm%.
connmm fo%, fm%, ins%, ind connects the object to the current record on fo%;
ins% defines the position on the chain:
1 at the end, 2 at the beginning, 3 or 4 before
or after another member with location ind;
discmm fo%, fm% detaches the object from the chains;
delmm fo%, fm% cancels the object and occupies its position in the file
fm%, moving there the record found at the end of the file;
so doing, nrec(fm%) diminishes by one unit;
nextmm fo%, fm%, strt% reads the chain sequentially; strt% specifies
whether to start from the beginning (if = 0)
or from the next object;
priomm fo%, fm%, strt% as above, but reading in reverse, starting
from the last member;
ownmm fo%, fm% reads the owner;
kowmm (fo%, fm%) location of owner.
- High level operations
FindPos rg%, cl%, f%, x$, in$, swkey%, swalf%, lk%, cf%
dialogue with terminal user to identify a file position
f%, using the index if necessary;
NexPrix f%, lk%, sw%
run down f%, starting from the position identified by
FindPos, to present on video the Next and Prior positions
(according to the f% index), until one is chosen;
FindAlt rg%, cl%, f%, ialt%, jalt%, dd$, lun%, in$, swno%, max%, trov%,
kalt!(), cf%
similar to FindPos, but does not use the index and operates in any
field of f%; can identify up to max% positions, with the locations
loaded in kalt!();
NexPri f%, nel%, kalt(), sw%
similar to NexPrix, it uses the locations in kalt();
UpdSet fo%, fm%, mf$, ret%, cf% elaboration of members in the set fo%-fm%:
running along and up-dating;
Bounds f%, rg%, swkey%, k1$, k2$, psel(), nmax%, nk%, cf%
dialogue with terminal user to identify the positions to be read;
it permits:
- position intervals per number or per index;
- series of typed positions per number or per index;
- all positions except a series as above;
MultiRead f%, swkey%, psel(), recpos%, ntrov%
reads f% in conformity with the request for Bounds;
Kest op%, k$, pt Sort of a file temporarily created within
a program;
CreInd proc$, f% reconstructs the index of f%;
BuildSet fo%, fm% reconstructs the set between fo% and fm%;
UpdArc fz%, f%, oldk$, okdup% inserts/updates record; also changes key.
Forms Management
msk1def x$, ret% form definition with parameters inside user program;
also usable for producing reports (see textgen);
msk2def proc$, cod$ form definition with parameters loaded by appropriate
MAIN-SYSTEM utility; gives more complex and attractive
forms;
mskparm tt$(), w AS wpar, rgd$, rgt$
loading parameters relative to a form already defined;
in particular, tt$() contains the field heading lines;
mskshow x$, w AS wpar, ret%
presents the form on screen with all the fields already loaded;
mskputfld vl$, rg%, k%
loads the string vl$ in the k-th field of line rg%;
mskgen (op%, p$, r$(), w AS wpar, f%, ret%, xin$, xtr%, xi%, xj%)
general routine which, by varying the operation code op%, can carry
out the operations above and, furthermore, can update the form by
interacting with the user program from which it can request any
further checks, having already verified:
- the validity of data of any numeric fields;
- the validity of the dates;
- the presence in the archive of the key codes for other archives.
Managing Reports
textgen par%, w AS wpar, ret%, vs$, r$()
generates the lines to be produced by writext$; this is controlled
using the form defined by msk1def;
writext$ (r$(), tt$(), tst$, sel$, msn$, w AS wpar)
generates reports on screen or to print; it can produce several
lines at every operation, prepared by textgen or built by the
program, with a series of options.
Other Functionscopertin2 tt$, apm$ standard form for entry in a package; tt$ is the title, apm$ the author. The MAIN-SYSTEM manages the multiuser environment; when a terminal user begins a session, Copertin2 asks his name and the password, if any; normally, no other work place using the same name can work at the same time. DefUsr defines recognised names and respective passwords. UpdatClr2 personalises screen colours for every recognised name. EdTxt r$(), maxrg%, nrg%, lrg%, cf% text editor, useful, for example, when presenting on screen a text prepared by a program, allowing the terminal user to check it before printing. NumLet$ (x#, lung%) transforms the numbers into letters, to the length required. VerFisc cod$, ok% checks the fiscal code, indicating which should be the last character. dat.secx (dmy$) dat.secn (d%, m%, y%) converts date into days from 1/1/1900, starting from the date in string format or with 3 separate liberol components; it makes no difference whether the year of the two routines is in 2 or 4 figures. sec.dat$ (days, na%) converts days from 1/1/1900 into the corresponding date; na% specifies whether the year needs to be in 2 or 4 figures.
![]()
3. The "Articles & Suppliers" program
This is an example using the archives defined in Enclosure 1.
To try it, you can freely download file
example.txt (a demo version,
which can manage up to 10 Articles, 10 Suppliers and 100 Prices), then:
Some important general rules:
- wherever you are in the program, the ESC key (or the "*" character typed at the
start of the field) takes you back to the previous level; in the first menu, you exit from
the program;
- use the 4 arrows and the Home key to move from one field to another in the
forms; the right arrow moves you within the field: to move to the next field, press
"Return";
- the down arrow is not for inserting, but only for making changes;
- the function key F10 helps change position without following the route through all
the fields;
- the Ins and Del keys operate on the character where the cursor is positioned;
- the End key cancels the field containing the cursor.
The first menu offers the choice:
1. Articles 2. Suppliers 3. Article Prices 4. Supplier Prices 5. Rebuild ChainsChoice 5 regenerates all the reticular connections; it may be useful if a previous updating has been interrupted wrongly, for example, due to a power cut or by turning off the machine before finishing the program.
Choices 1 and 2 produce the same menu, for the A and S respectively:
1. Insert 2. Change 3. View 4. Print 5. Rebuild Index 6. Deleteand on the same video screen indicate the extent of the archive, that is, the total number of loaded positions and how many are in being and how many cancelled.
In particular, the Change and Cancel functions, which need to identify the intervention
position, can recall it by means of the progressive number or the code. Where the
number is left blank, the code is requested: typing it, even incompletely, the first
position in the archive appears with its appropriate code, and moving up and down the
archive you can reach the desired position.
In addition, the Rebuild Index can regenerate the archive index; this could be useful for
the same cases as the Rebuilding Chains.
The choice of "Article Prices" in the first menu (the "Supplier Prices" operates
identically) requires you to choose the A, as above, then asks whether to update the
Prices or list them (on screen or print). The choice "Update", where there is already a
Prices chain hanging from A, presents the form of the first Price in the chain, and
allows you to:
- run up and down the Prices chain, stating how many members are present in the
chain and where the Price record currently shown is to be found on the chain; if you
reach the end (or, proceeding in the other direction, the start), there appears the
indication "End Prices": by typing "c" (continue) you can insert a series of Price
records;
- cancel the P record.;
- insert a new P record; in this case, it asks whether before or after the current P;
- change the P record; the cursor is positioned on the Supplier code to change it (in
which case the P record will be disconnected from the chain hanging from the previous
S and attached to the new S), then the cursor moves to the 5 prices and starting dates.
On the other hand, if there is no Price hanging yet from A, the "Update" choice will immediately provoke the message "End Prices" and you can proceed as above.
![]()
I think everyone will agree that the source code for program
G03B (less than 9 K) is remarkably short considering
the number and complexity of the functions it carries out.
But this code, with its ease of use, is mostly made up from a general "skeleton", valid
for any program and containing all the crossreferences and interfaces of more complex
routines (see G03BSKEL).
Therefore, the specific code for this example is practically equal to the difference
between the dimensions of the two programs, about 2 K.
This means that an almost insignificant quantity of new code is needed to create the
program GO3B, and very little time.
Please, send your impressions or suggestions to:
[email protected]
![]()