home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / mslang / isam / isammgr.doc < prev    next >
Encoding:
Text File  |  1994-02-08  |  70.3 KB  |  2,079 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.                    ISAM Manager
  14.  
  15.             B+Tree/ISAM System For C++
  16.  
  17.               Copyright 1993 Nildram Software
  18.  
  19.                 All Rights Reserved
  20.  
  21.  
  22.                ISAM Manager was written by Adrian Mardlin
  23.  
  24.  
  25.  
  26. Address:    Nildram Software
  27.         82 Akeman Street
  28.         Tring
  29.         Herts  HP23 6AF
  30.         United Kingdom
  31.  
  32. Telephone:    +44 (0)442 891331
  33.  
  34. Fax:        +44 (0)442 890303
  35.  
  36. Internet:    sales@nildram.com
  37.         support@nildram.com
  38.         info@nildram.com
  39.  
  40. CIS:        GO UKSHARE, Section 10 or email 76004,3436
  41.  
  42. FidoNet:    2:257/112 (Address messages to ADRIAN MARDLIN)
  43.         Or leave messages in C_PLUSPLUS or SHAREWARE echoes
  44.  
  45. ILink:          Leave messages to ADRIAN MARDLIN in SHAREWARE echo.
  46.  
  47. TheNet:         Leave messages to ADRIAN MARDLIN in C Programming echo.
  48.  
  49. BBS:        +44 (0)442 891109
  50.  
  51. ISAM Manager is a trademark of Nildram Software.
  52.  
  53. All trademarks and registered trademarks mentioned in this
  54. document are acknowledged.
  55.  
  56.                               INTRODUCTION
  57.  
  58. Overview
  59.  
  60. ISAM Manager is a database management library for C++
  61. programmers. It is a full B+Tree/ISAM system, which is extremely
  62. fast and provides a very straightforward interface to the
  63. developer. Features include:
  64.  
  65. Full relational capabilities.
  66.  
  67. Up to 2 billion records per data file with FAST access.
  68.  
  69. Multiple Indexes. up to 10 different indexes, each containing up
  70. to 10 data fields are allowed for each data file.
  71.  
  72. Fast! In a database with 4 million records, ISAM Manager can
  73. locate a specific record with as little as 4 disk accesses! It's
  74. made even quicker by its in-built index caching system which can
  75. reduce the number of accesses required even further.
  76.  
  77. 4GL Features. ISAM Manager can automatically generate a data
  78. entry program from just a database description file, giving you
  79. a framework on which you can build a more powerful  application,
  80. or just a quick and easy data entry screen. Just like a 4th
  81. Generation Language (4GL)!
  82.  
  83. Portable. ISAM Manager is provided for both DOS and Windows, and
  84. is easily ported to other operating systems also.
  85.  
  86. ISAM Manager is currently a single-user system. That is, only
  87. one user may access a database at any one time. A multi-user
  88. version is planned, and will have full record-locking
  89. capabilities for fast, multi-user access.
  90.  
  91.  
  92. System Requirements
  93.  
  94. ISAM Manager ships with libraries for the following compilers:
  95.  
  96. Borland C++ v 4.0 or later
  97. Symantec C++ v 6.0 or later
  98. Microsoft Visual C++ v 1.0 or later
  99. Borland C++ for OS/2 v 1.0 or later
  100.  
  101. Other compilers should work fine, as should earlier versions of
  102. the above compilers, but are untested, and will require you to
  103. compile your own libraries. Both DOS and Windows versions of the
  104. libraries are provided, in the large memory model. Source code
  105. is provided to allow you to modify or port it to other
  106. platforms. Approx 500k of disk space is required to install ISAM
  107. Manager.
  108.  
  109.  
  110. Support
  111.  
  112. Full lifetime support is provided to all registered users of
  113. ISAM Manager direct from Nildram Software. Check the front of
  114. this manual for contact details. You will also be notified of
  115. all major upgrades, and offered them at a special reduced price.
  116. Make sure you return your registration card if you didn't 
  117. purchase ISAM Manager direct from Nildram Software, or you won't
  118. be eligible for support, and we won't be able to tell you about
  119. any upgrades.
  120.  
  121. In addition to the normal support, we provide a service
  122. available to anyone who has an Internet address, called the ISAM
  123. Manager Information Service. Simply send an email message to
  124. imis@nildram.com, and we will add you to our mailing list and
  125. email you details of bugs and how to fix them, new releases etc.
  126.  
  127.  
  128. What Is Shareware?
  129.  
  130. Shareware is a distribution method (not a type of software) which lets
  131. users evaluate software before buying. If you try a shareware program
  132. and continue using it, you must register and pay for it. (If you paid
  133. a small duplication and handling fee to receive a trial copy of a
  134. shareware product from a vendor, you have not paid for the product
  135. itself or the right to continue using it after a reasonable trial
  136. period. A separate fee to the program's owner and developer is
  137. required to continue to use the product after evaluation.) Copyright
  138. laws apply to both shareware and commercial software.
  139.  
  140. Shareware authors are accomplished programmers just like commercial
  141. authors and the programs are of comparable quality. In both cases,
  142. there are good and bad programs. The main difference is in the method
  143. of distribution.
  144.  
  145. The shareware system makes fitting your needs easier because you can
  146. try before you buy. Because overheads are low, prices are low also.
  147. Shareware has the ultimate money-back guarantee -- if you don't use
  148. the product, you don't pay for it.
  149.  
  150.  
  151. Terms And Conditions
  152.  
  153. ISAM Manager is shareware program and is provided by Nildram Software
  154. at no charge for evaluation. Feel free to share it with friends and
  155. colleagues for evaluation, but please do not give it away altered or
  156. as part of another system.  The essence of user-supported software is
  157. to provide personal computer users with quality software without high
  158. prices, yet to provide incentive for programmers to continue to
  159. develop new products.
  160.  
  161. Please encourage others to register their copies if they find it
  162. useful.  All registered users receive a copy of the latest version of
  163. the ISAM Manager system.
  164.  
  165. If you continue to use ISAM Manager after a reasonable trial period,
  166. you must make a registration payment of #39.00+VAT to Nildram Software.
  167. This registration fee licenses one copy for use on any one computer at
  168. any one time.  You must treat this software just like a book.  This
  169. software may be used by any number of people and may be freely moved
  170. from one computer location to another provided there is no possibility
  171. of it being used at one location while being used at another, just as
  172. a book cannot be read by two different persons at the same time.
  173.  
  174. Commercial users of ISAM Manager must register and pay for their
  175. copies of ISAM Manager within 30 days of first use or their license
  176. is withdrawn.  Site License arrangements may be made by contacting
  177. Nildram Software.
  178.  
  179.  
  180. Registration
  181.  
  182. If you continue using ISAM Manager, you must register. To do this,
  183. either print and fill in the registration form provided (type "COPY
  184. REGISTER.DOC PRN" at the DOS prompt), or send a cheque for #39.00
  185. (thirty-nine pounds) + VAT (currently 17.5%, so #45.83 total) or
  186. your credit card details to the following address:
  187.  
  188.         Nildram Software
  189.         82 Akeman Street
  190.         Tring
  191.         Herts
  192.         HP23 6AF
  193.                 UK
  194.  
  195.                 Tel: +44 (0)442 891331
  196.                 Fax: +44 (0)442 890303
  197.         Compuserve: 76004,3436
  198.                 Internet: sales@nildram.com
  199.  
  200. Further registration details for overseas customers are contained
  201. in the REGISTER.DOC file. You will receive the latest version of
  202. ISAM Manager without the registration encouragement screens, full
  203. source code, a printed manual, free support and cheap upgrades as
  204. they become available.
  205.  
  206.  
  207. Disclaimer
  208.  
  209. Users of ISAM Manager must accept this disclaimer of warranty:
  210.  
  211. "ISAM Manager is supplied as is. The author disclaims all
  212. warranties, expressed or implied, including, without limitation,
  213. the warranties of merchantability and of fitness for any
  214. purpose. The author assumes no liability for damages, direct or
  215. consequential, which may result from the use of ISAM Manager."
  216.  
  217.  
  218. The ASP
  219.  
  220. This program is produced by a member of the Association of
  221. Shareware Professionals (ASP). ASP wants to make sure that the
  222. shareware principle works for you. If you are unable to resolve
  223. a shareware-related problem with an ASP member by contacting the
  224. member directly, ASP may be able to help. The ASP Ombudsman can
  225. help you resolve a dispute or problem with an ASP member, but
  226. does not provide technical support for members' products. Please
  227. write to the ASP Ombudsman at 545 Grover Road, Muskegon, MI
  228. 49442, USA or send a Compuserve message via Compuserve mail to
  229. ASP Ombudsman 70007,3536.
  230.  
  231.                               INSTALLATION
  232.  
  233.  
  234. Introduction
  235.  
  236. To Install ISAM Manager, simply insert disk 1 into drive A (or
  237. whatever floppy drive letter you are using), and type the
  238. following:
  239.  
  240. A:INSTALL
  241.  
  242. INSTALL will ask you for a drive and directory name to install
  243. ISAM Manager into, which will default to "C:\ISAMMGR". The
  244. following subdirectories off C:\ISAMMGR will also be created:
  245.  
  246. INCLUDE         -       Include files
  247. LIB        -    Library files
  248. TUT1        -    Tutorial 1 files
  249. TUT2        -    Tutorial 2 files
  250. TUT3        -    Tutorial 3 files
  251. SOURCE          -       ISAM Manager source code
  252. FSCREEN         -       FScreen Library source code
  253. KEYSRCH         -       KEYSRCH & ADDFILE Example program files
  254.  
  255. You should now add "C:\ISAMMGR" to your DOS PATH statement, as
  256. this directory will contain some important executable files, and
  257. "C:\ISAMMGR\INCLUDE" should be added to your compiler's include
  258. file search path. "C:\ISAMMGR\LIB" contains the lib files which
  259. should be included. They are named as follows:
  260.  
  261. imbl.lib   - Borland C++ v 4.00 library for DOS
  262. imbwl.lib  - Borland C++ v 4.00 library for Windows
  263. imml.lib   - Microsoft Visual C++ v 1.00 library for DOS
  264. immwl.lib  - Microsoft Visual C++ v 1.00 library for Windows
  265. imsl.lib   - Symantec C++ v 6.10 library for DOS
  266. imswl.lib  - Symantec C++ v 6.10 library for Windows
  267. imbos2.lib - Borland C++ for OS/2 v 1.00 library
  268.  
  269. All DOS and Windows libraries are compiled for the large memory
  270. model. ISAM Manager will also work in compact memory model, but
  271. these libraries have been left out to save space - you will need
  272. to compile your own libraries if you wish to use the compact
  273. memory model. Remember to include a .lib file in each of your
  274. projects or make files. You may want to delete any .lib files
  275. that you know you won't be using.
  276.  
  277.  
  278. Building Libraries
  279.  
  280. There are many reasons why you may want to build your own
  281. libraries - maybe you want to use the compact memory model, or
  282. you need to add a bug fix, or an enhancement of your own. The
  283. process is fairly straightforward, particularly for those
  284. compilers that allow you to create .lib files from within the
  285. integrated environment.
  286.  
  287. To create a DOS library, simply compile all the files in the
  288. ISAM Manager source directory, except for WISAMMSG.CPP, and all
  289. the files in the ISAM Manager fscreen directory, and make a
  290. library from them. To create a Windows library, you simply need
  291. all the files in the ISAM Manager source directory, except for
  292. ISAMMSG.CPP.
  293.  
  294.                                USER GUIDE
  295.  
  296.  
  297. Introduction
  298.  
  299. In this USER GUIDE, we will be concentrating on the DDF file,
  300. its format and its use when programming with ISAM Manager.
  301.  
  302.  
  303. Introduction To DDF
  304.  
  305. DDF stands for "Database Description File". The .DDF file is
  306. where you define the format of your data files, including the
  307. indexes. The format of the file is designed such that it will be
  308. easily extensible in the future to carry additional information.
  309. This is achieved by splitting the file up into sections which
  310. have their own begin and end commands. They are currently as
  311. follows:
  312.  
  313. {BEGDATA}
  314. {ENDDATA}
  315. {BEGIDX}
  316. {ENDIDX}
  317.  
  318. {BEGDATA} and {ENDDATA} specify the beginning and end of the
  319. Data Field definitions, and {BEGIDX} and {ENDIDX} specify the
  320. beginning and end of the Index definitions. All of these
  321. definitions MUST exist in a .DDF file in the order above. They
  322. must also each be placed on a line of their own, at the
  323. beginning of the line. The file may contain any comments you
  324. wish to place in it, so long as they are placed outside of these
  325. groups.
  326.  
  327.  
  328. Data Field Definitions
  329.  
  330. These are defined in between the {BEGDATA} and {ENDDATA}
  331. commands. The first line after {BEGDATA} is a special line, and
  332. should contain the filename to be used for the data file,
  333. including the extension. The filename may also include directory
  334. path information, but must be less than 65 characters long in
  335. total.
  336.  
  337. The subsequent lines, up to the {ENDDATA} statement, should
  338. contain the name and type information for all the data fields
  339. within each record. They will be stored in the data file in the
  340. order in which they are defined (though this does not alter the
  341. functional behaviour of the database). To simplify matters and
  342. shorten the learning curve, these definitions follow the normal
  343. C/C++ syntax, with 1 limitation - no pointers may be defined
  344. (they wouldn't make a great deal of sense in a database context
  345. anyway).
  346.  
  347. The following data types are supported:
  348.  
  349. char
  350. unsigned char
  351. short
  352. unsigned short
  353. int
  354. unsigned int
  355. long
  356. unsigned long
  357. float
  358. double
  359.  
  360. Standard C or C++ comments are allowed after each definition
  361. (which is terminated with a semi-colon, as in C/C++), but each
  362. line MUST contain a definition. Please note that these lines are
  363. picked up and placed in the .H file generated by the DDF program
  364. without any changes being made. DDF will not check whether any
  365. comments placed after the data field definitions are in a
  366. correct format, and thus you will get a syntax error at compile
  367. time if you don't use the proper comment syntax on these lines.
  368.  
  369. Here is an example of an incorrectly formatted Data Field
  370. definition section:
  371.  
  372. {BEGDATA}
  373. DATA.DTA          // You cannot place a comment on this line!
  374. char field1[20]; This will give a compile error
  375. int *field2; // Pointers are not allowed!!!
  376.  
  377. // ^^^ Neither are blank lines (nor this line!)
  378. {ENDDATA}
  379.  
  380. And here's a correct version:
  381.  
  382. {BEGDATA}
  383. DATA.DTA
  384. char field1[20]; // This comment is perfectly OK
  385. int field2; /* So is this one */
  386. float a[23]; // Pretty silly, but it works!
  387. {ENDDATA}
  388.  
  389. Index Definitions
  390.  
  391. As with the Data Field Definitions, the line following the
  392. {BEGIDX} statement should contain the name of the file to be
  393. used to store the indexes. This MUST be a different name to the
  394. data file, or it won't work.
  395.  
  396. The subsequent lines, up to the {ENDIDX} statement, should each
  397. contain an index definition. Comments are allowed after the
  398. definitions, but blank lines are not. The format you should use
  399. is as follows:
  400.  
  401. *Index Name: field1, field2, field3; // Comment
  402.  
  403. The asterisk at the beginning of the line is optional and
  404. denotes whether the index  is 'unique' or not. A unique index
  405. will not allow two records with identical index values to be
  406. inserted, causing the insert() function to fail. Be careful when
  407. choosing to use a unique index - they should only really be used
  408. for indexes that contain values such as customer numbers,
  409. employee numbers etc, which should only occur once in the
  410. database.
  411.  
  412. Following the asterisk (if there is one), is the index name.
  413. This name can contain whitespace characters (as shown above),
  414. and is used to select indexes within your program (though you
  415. can also switch between indexes by number, where the first index
  416. defined is number 0, and so on). The index name is terminated by
  417. a colon.
  418.  
  419. What follows now is a list of up to 10 data field names,
  420. delimited by commas and terminated with a semi-colon. These are
  421. the fields that are contained within the index, in the order in
  422. which they are to be indexed.
  423.  
  424. Here's an example of a complete .DDF file:
  425.  
  426. {BEGDATA}
  427. EMPLOYEE.DTA
  428. int emp_no;
  429. char initials[6];
  430. char surname[21];
  431. char dept[2];
  432. long salary;
  433. {ENDDATA}
  434.  
  435. {BEGIDX}
  436. EMPLOYEE.DTX
  437. Name: surname, initials;
  438. *Employee Number: emp_no;
  439. {ENDIDX}
  440.  
  441.  
  442. Indexing Peculiarities
  443.  
  444. There are certain peculiarities with the way the indexing works
  445. that you should be aware of. They are as follows:
  446.  
  447. With arrays of type char, a zero byte is considered to be the
  448. end of the array, and the rest of the array is padded out with
  449. zeros before being indexed. This is because char arrays are most
  450. commonly used to represent null-terminated strings, which this
  451. approach is ideally suited to. Just be very careful if you are
  452. using a char array to store anything else.
  453.  
  454. When int or long types (both signed and unsigned) are stored in
  455. the index, their byte order is swapped due to the peculiarities
  456. of the Intel architecture, so that they are sorted correctly. If
  457. an array of type int or long is used within an index, the byte
  458. order will NOT be swapped, and so using the next() or prev()
  459. functions may give the impression that the index has not sorted
  460. them correctly.
  461.  
  462. Floating point types will not be sorted properly in order. As
  463. there are very few cases where there is any merit in indexing
  464. using floating point types, this shouldn't cause a major
  465. problem, and can be worked around in any case.
  466.  
  467.  
  468. Using DDF.EXE
  469.  
  470. The program DDF.EXE (for OS/2, you should run DDFOS2.EXE
  471. instead) is provided to convert the contents of a .DDF file into
  472. code that your compiler can understand. Simply specify the name
  473. of the .DDF file or files (wildcards and multiple arguments are
  474. allowed) to be processed on the command line. You do not need to
  475. specify the extension ".DDF". For example:
  476.  
  477. DDF QWERTY
  478.  
  479. In this example, DDF will create two new files -- QWERTY.CPP and
  480. QWERTY.H. If you then wish to use the QWERTY data file within
  481. your application, you simply need to #include "qwerty.h" in your
  482. source code, and compile and link QWERTY.CPP with the rest of
  483. your application. It's as simple as that!
  484.  
  485. Because DDF creates these files, and overwrites any existing
  486. files of the same name, you should be careful that you don't use
  487. the same name for one of your source code files as you do for
  488. any of your .DDF files! Also, do not alter the code in either
  489. the .H file or the .CPP file. If you need to change anything, do
  490. it in the .DDF file.
  491.  
  492.  
  493. Using MAKSCR.EXE
  494.  
  495. The program MAKSCR.EXE is provided to enable you to produce a
  496. 'quick-and-dirty' file maintenance program. This program can
  497. then be used as-is, or as the basis for a more complex and
  498. powerful data entry screen. The code produced by MAKSCR uses the
  499. FScreen Library for all of its screen I/O, though support for
  500. other screen libraries may appear in future releases. It will
  501. also #include the header file, "ATTRDEFS.H", which defines the
  502. colour schemes used within the display. You should alter
  503. ATTRDEFS.H to suit your tastes.
  504.  
  505. MAKSCR sends its output to stdout. This allows you to redirect
  506. it to the file of your choice, or just view it on the screen.
  507. Here's an example:
  508.  
  509. MAKSCR QWERTY.DDF > QWERMNT.CPP
  510.  
  511. Then all you would need to do to create a basic file maintenance
  512. program for the QWERTY data file is to compile and link both
  513. QWERTY.CPP and QWERMNT.CPP (remembering, of course, to also link
  514. in the correct ISAM Manager library file for the memory model
  515. and compiler that you are using).
  516.  
  517. MAKSCR has its limitations. Firstly, it will not successfully
  518. display more than about 20 fields. However the code will be
  519. there, so you can change the screen positions of any fields that
  520. have slipped off the screen. Secondly, it can't handle floating
  521. point numbers, and will ignore any that appear in the .DDF file.
  522.  
  523. What follows is the output of MAKSCR when processing the example
  524. file, EMPLOYEE.DDF used earlier in this chapter. EMPLOYEE.DDF is
  525. also used in  TUTORIAL 1. It may be helpful at this stage to
  526. examine the code below in conjunction with the function
  527. reference chapters and see if you can figure out how it is
  528. working.
  529.  
  530. #include <fscreen.h>
  531. #include <attrdefs.h>
  532.  
  533. #include "EMPLOYEE.H"
  534.  
  535. dfEMPLOYEE employee;
  536.  
  537. void draw_screen(void)
  538.         {
  539.         FSputs("emp_no", attrLEGEND, 3, 3);
  540.         FSputs("initials", attrLEGEND, 4, 1);
  541.         FSputs("surname", attrLEGEND, 5, 2);
  542.         FSputs("dept", attrLEGEND, 6, 5);
  543.         FSputs("salary", attrLEGEND, 7, 3);
  544.         }
  545.  
  546. void display_all(void)
  547.         {
  548.         FSclrbox(3, 10, 7, 79, attrSCREEN);
  549.         FSputi(employee.emp_no, attrINPUT, 3, 10);
  550.         FSputs(employee.initials, attrINPUT, 4, 10);
  551.         FSputs(employee.surname, attrINPUT, 5, 10);
  552.         FSputs(employee.dept, attrINPUT, 6, 10);
  553.         FSputl(employee.salary, attrINPUT, 7, 10);
  554.         }
  555.  
  556. int input_data(int is_index = 0)
  557.         {
  558.         for (int x = 0; x < 5 && x >= 0;)
  559.                 {
  560.                 int FSerror = 0;
  561.                 switch(x)
  562.                         {
  563.                         case 0:
  564.                                 if (is_index)
  565.                                         {
  566.                                         x++;
  567.                                         break;
  568.                                         }
  569.                                 FSerror = FSinputi(employee.emp_no,
  570.                                                 attrINPUT, 3, 10);
  571.                                 break;
  572.  
  573.             case 1:
  574.                                 FSerror = FSinputs(employee.initials,
  575.                                                 attrINPUT, 4, 10, 5);
  576.                                 break;
  577.  
  578.             case 2:
  579.                                 FSerror = FSinputs(employee.surname,
  580.                                                 attrINPUT, 5, 10, 20);
  581.                                 break;
  582.  
  583.             case 3:
  584.                                 if (is_index)
  585.                                         {
  586.                                         x++;
  587.                                         break;
  588.                                         }
  589.                                 FSerror = FSinputs(employee.dept,
  590.                                                 attrINPUT, 6, 10, 1);
  591.                                 break;
  592.  
  593.             case 4:
  594.                                 if (is_index)
  595.                                         {
  596.                                         x++;
  597.                                         break;
  598.                                         }
  599.                                 FSerror = FSinputl(employee.salary,
  600.                                                 attrINPUT, 7, 10);
  601.                                 break;
  602.                         }
  603.  
  604.         switch (FSerror)
  605.                         {
  606.                         case FS_ENTER:
  607.                         case FS_CURSORDOWN:
  608.                                 x++;
  609.                                 break;
  610.  
  611.             case FS_CURSORUP:
  612.                         case FS_BACKSPACE:
  613.                                 x--;
  614.                                 break;
  615.  
  616.             case FS_PGDN:
  617.                                 x = 999;
  618.                                 break;
  619.  
  620.             case FS_ESCAPE:
  621.                         case FS_PGUP:
  622.                                 x = -1;
  623.                                 break;
  624.                         }
  625.                 }
  626.         if (x < 0)
  627.                 return IM_ERROR;
  628.         return IM_OK;
  629.         }
  630.  
  631. int main(void)
  632.         {
  633.         static char *menopts[] = { "^Insert", "^Amend",
  634.         "^Delete", "^Find",     "^Next", "^Prev", "E^xit", NULL };
  635.         FSinit();
  636.         FSclrscr(attrSCREEN);
  637.         draw_screen();
  638.         employee.rew();
  639.         employee.clear_buf();
  640.         display_all();
  641.         FStitle("EMPLOYEE FILE MAINTENANCE", attrTITLE, 0);
  642.  
  643.     for (;;)
  644.                 {
  645.                 switch (FSbarmenu(22, FS_CENTRE, 2, menopts,
  646.                                 attrBMNORM, attrBMHIGH, attrBMHOTK))
  647.                         {
  648.                         case 0: // Insert
  649.                                 employee.clear_buf();
  650.                                 display_all();
  651.                                 if (input_data() == IM_OK)
  652.                                         employee.insert();
  653.                                 else
  654.                                         employee.rew();
  655.                                 break;
  656.  
  657.             case 1: // Amend
  658.                                 if (employee.retrieve() == IM_ERROR)
  659.                                         break;
  660.                                 display_all();
  661.                                 if (input_data() == IM_OK)
  662.                                         employee.amend();
  663.                                 break;
  664.  
  665.                         case 2: // Delete
  666.                                 employee.erase();
  667.                                 employee.clear_buf();
  668.                                 display_all();
  669.                                 break;
  670.  
  671.             case 3: // Find
  672.                                 employee.clear_buf();
  673.                                 display_all();
  674.                                 if (input_data(1) == IM_OK)
  675.                                         {
  676.                                         if (employee.find() == IM_ERROR)
  677.                                             if (employee.retrieve() ==
  678.                                                 IM_ERROR)
  679.                                                 if (employee.prev() ==
  680.                                                         IM_ERROR)
  681.                                                         employee.clear_buf();
  682.                                         display_all();
  683.                                         }
  684.                                 else
  685.                                         {
  686.                                         employee.clear_buf();
  687.                                         display_all();
  688.                                         }
  689.                                 break;
  690.  
  691.                 case 4: // Next
  692.                                 if (employee.next() == IM_ERROR)
  693.                                         employee.prev();
  694.                                 display_all();
  695.                                 break;
  696.  
  697.             case 5: // Prev
  698.                                 if (employee.prev() == IM_ERROR)
  699.                                         employee.next();
  700.                                 display_all();
  701.                                 break;
  702.  
  703.             case  6: // Exit
  704.                         case -1: // <ESCAPE> Pressed
  705.                                 return 0;
  706.                         }
  707.                 }
  708.         return 0;
  709.         }
  710.  
  711.  
  712. Limitations
  713.  
  714. Maximum records per file:        2 billion (approx)
  715. Maximum data fields per record:         1000 (arrays count as 1 field)
  716. Maximum record size:                    32,767 bytes
  717. Maximum index size:                     500 bytes
  718. Maximum indexes per data file:          30
  719. Maximum data fields per index:          10 (arrays count as 1 field)
  720.  
  721.  
  722.                            PROGRAMMING GUIDE
  723.  
  724.  
  725. Introduction
  726.  
  727. Programming in ISAM Manager is designed to be as simple and
  728. straightforward as possible. By using the powerful features
  729. available within the C++ programming language, such as
  730. inheritance and virtual functions, ISAM Manager is able to
  731. completely hide its complexity from you, the programmer. This
  732. means that you only need a rudimentary knowledge of C++ (in
  733. fact, a C programmer should be able to learn ISAM Manager just
  734. as quickly as an experienced C++ programmer), though obviously
  735. the more proficient you are at C or C++, the easier you will
  736. find things.
  737.  
  738. One of the quickest ways to learn the system is to have a look
  739. through some of the example code provided, and also by using the
  740. MAKSCR program (see USER GUIDE for more details) and examining
  741. the code produced by it.
  742.  
  743.  
  744. Including Data Files
  745.  
  746. To include a data file in your project is a very straightforward
  747. process. Once you have created a .DDF file and processed it with
  748. DDF.EXE (see USER GUIDE for more details), you will be left with
  749. a .H and a .CPP file of the same name. Simply #include the .H
  750. file in your code, then declare an instance of the file object
  751. like so:
  752.  
  753. #include "qwerty.h"
  754.  
  755. dfQWERTY qwerty;
  756.  
  757. Notice that the class name is the name of the file in caps and
  758. preceded by 'df'. In this example, the data and index files will
  759. be opened or created, and ready for access within your program.
  760. Only one instance of each file object should be created in a
  761. program, and this should either be a global declaration, or the
  762. space should be allocated and removed by using new and delete
  763. (i.e. Don't create an instance of a file object on the stack as
  764. it will probably cause a stack overflow error).
  765.  
  766. You can declare a data file as being closed by using the
  767. following syntax:
  768.  
  769. dfQWERTY qwerty(moClosed);
  770.  
  771. This can be useful if you are using lots of data files within a
  772. program, and DOS is running out of file handles. Just declare
  773. some of the least used files as closed, and open them when you
  774. need them, and close them when you've finished with them. Please
  775. be aware that if you declare a file as closed, it will still be
  776. opened when your program is initially run, and then closed
  777. again. This is so ISAM Manager can check the existence and
  778. validity of the index and data files before any processing is
  779. done on them.
  780.  
  781. You can also specify your own names for the data and index files
  782. and paths, which will override any name specified in the .DDF
  783. file. For example:
  784.  
  785. dfQWERTY qwerty("C:\ASDFG.DAT", "D:\ASDFG.IDX");
  786.  
  787. This would specify a data file in the root directory of drive C,
  788. and an index file in the root directory of drive D, with the
  789. above names. With this alternative constructor, you can also
  790. specify a closed file - just put moClosed as the third argument,
  791. like so:
  792.  
  793. dfQWERTY qwerty("C:\ASDFG.DAT", "D:\ASDFG.IDX", moClosed);
  794.  
  795.  
  796. Accessing A Data File
  797.  
  798. In the above example, once you have included the QWERTY data
  799. file in your code, you can now access the records and fields
  800. within the file in a very straightforward way. The DDF FUNCTION
  801. REFERENCE chapter documents all the functions that you have at
  802. your disposal for accessing records by using an index, and we
  803. will cover some of them in more detail in this chapter. The
  804. fields that you declared in the .DDF file will now be available
  805. to your code. For example, if you declared a field in QWERTY.DDF
  806. like so:
  807.  
  808. int test;
  809.  
  810. You will now find that this field is a public member of the
  811. dfQWERTY class, and you can access it as a normal integer
  812. variable using the following syntax:
  813.  
  814. qwerty.test
  815.  
  816. It's as simple as that. When you read in a record from the file,
  817. the field variables will be updated with the values in the
  818. record, and when you amend or insert a new record into the file,
  819. the record will be made up from the contents of the field
  820. variables, and then added to the file. If you are searching for
  821. a particular record, you just need to set the field variables
  822. that are members of the currently selected index, call the
  823. find() function, and if a record is found, all the other field
  824. variables will be set accordingly. The find() function will only
  825. succeed if it finds an EXACT match. However, if it fails, the
  826. index cursor will be placed on the next record after the
  827. position where the matching record would have been, if there was
  828. one. You can then retrieve this record from the file, and into
  829. the field variables by calling the retrieve() function.
  830.  
  831. If you haven't done so already, please read through the USER
  832. GUIDE chapter, and study the code example at the end of the
  833. chapter. Make sure you understand roughly how it works before
  834. you proceed any further. If you have trouble understanding it,
  835. you may want to work through the TUTORIAL chapters provided.
  836.  
  837.  
  838. Using Indexes
  839.  
  840. Each data file has between 1 and 10 indexes associated with it.
  841. You can switch between these indexes by use of the set_idx()
  842. function provided. When you call functions such as find(),
  843. next() or prev(), they use the currently set index. You may also
  844. find the get_cur_idx(), get_idx_name() and get_no_idxs()
  845. functions helpful when dealing with indexes.
  846.  
  847.  
  848. Rebuilding Indexes
  849.  
  850. If at any time the indexes of a data file become corrupted, they
  851. will need to be rebuilt. To do this, simply delete the index
  852. file, and the next time you run a program that uses that index,
  853. it will automatically be rebuilt.
  854.  
  855.  
  856. ISAMMSG.CPP
  857.  
  858. ISAMMSG.CPP contains some functions which are called by
  859. ISAMMGR.CPP in the event of an error, or when the indexes are
  860. rebuilt. By default, ISAMMSG.CPP uses fprintf(stderr, ...) for
  861. its output. You can override this to suit the screen library you
  862. are using by writing your own version of ISAMMSG.CPP, or just
  863. rewriting the functions in one of your existing program modules.
  864. This will cause the version contained within the library file
  865. not to be linked. The functions defined within ISAMMSG.CPP are
  866. as follows:
  867.  
  868. void IsamError(const char *errmsg);
  869. void IsamInitProgress(const char *fname, const char *idx);
  870. void IsamProgress(long recno);
  871. void IsamEndProgress(void);
  872.  
  873. IsamError is called if an error occurs. errmsg contains the
  874. error message. ISAM Manager will call the abort() function as
  875. soon as IsamError returns, as any error reported by IsamError is
  876. critical. If you need to do any cleaning up of the screen, for
  877. example, before the program terminates, you should put the
  878. necessary code in your version of IsamError, and perhaps
  879. terminate the program yourself before ISAM Manager gets a chance
  880. to call abort(). IsamInitProgress, IsamProgress and
  881. IsamEndProgress are all used if the indexes need to be rebuilt
  882. at the start of a program. IsamInitProgress is first called with
  883. the name of the data file and the name of the index being
  884. processed. Then IsamProgress is called as the index is being
  885. rebuilt with the number of records processed. And finally,
  886. IsamEndProgress is called when the rebuild is complete.
  887.  
  888. One word of warning however. If an index needs rebuilding, it is
  889. done by the class constructor, and will therefore happen before
  890. main() is called. So watch out  and make sure you initialise
  891. your screen library (if you are using one) before any data files
  892. are declared.
  893.  
  894. Here is the default ISAMMSG.CPP file which will be used if you
  895. don't re-define the functions:
  896.  
  897. #include "isammsg.h"
  898.  
  899. #include <stdio.h>
  900.  
  901. void IsamProgress(long recno)
  902.         {
  903.         char bs[9] = { 8, 8, 8, 8, 8, 8, 8, 8, 0 };
  904.         fprintf(stderr, "%s%8ld", bs, recno);
  905.         }
  906.  
  907. void IsamError(const char *errmsg)
  908.         {
  909.         fprintf(stderr, "%s\n", errmsg);
  910.         }
  911.  
  912. void IsamInitProgress(const char *fname, const char *idx)
  913.         {
  914.         fprintf(stderr, "Rebuilding Index File: \"%s\", Name:"
  915.                 " \"%s\"\nRecords Processed:         ", fname, idx);
  916.         }
  917.  
  918. void IsamEndProgress(void)
  919.         {
  920.         fprintf(stderr, "\n");
  921.         }
  922.  
  923.  
  924. Buffers
  925.  
  926. ISAM Manager makes use of buffers to speed up its access to the
  927. indexes. By default, the number of buffers used is set to 16. To
  928. override this value, simply include the following line in one of
  929. your source files:
  930.  
  931. int DMCacheSize = x;
  932.  
  933. Replace 'x' with the number of buffers you wish to use.
  934.  
  935.  
  936. The ADDFILE & KEYSRCH Programs
  937.  
  938. The ADDFILE and KEYSRCH programs are provided as an example of a
  939. real application that demonstrates the use of multiple data
  940. files, and their inter-relations. You will find them in the
  941. KEYSRCH subdirectory.
  942.  
  943. ADDFILE is a program that will process through any number of
  944. files, extracting any text strings, and adding them to a KEYWORD
  945. data file. KEYSRCH can then locate all the files that contain a
  946. number of keywords very quickly. ADDFILE is quite slow. KEYSRCH
  947. is blindingly fast. With a Btree/ISAM system such as ISAM
  948. Manager, inserting records is relatively slow, but finding them
  949. is exceptionally fast, even when there are literally millions of
  950. records in a file.
  951.  
  952. The syntax for calling these programs is as follows:
  953.  
  954. ADDFILE <filename> ...
  955. KEYSRCH <keyword> ...
  956.  
  957. You may give ADDFILE a list of filenames to process, and you can
  958. give KEYSRCH a list of keywords to process. KEYSRCH will find
  959. all the files that contain all the keywords specified.
  960.  
  961. See if you can figure out how ADDFILE and KEYSRCH work. By
  962. understanding these two programs, you will go a long way towards
  963. understanding the ISAM Manager system as a whole.
  964.  
  965.                                TUTORIAL 1
  966.  
  967.  
  968. Introduction
  969.  
  970. This series of tutorials is designed to introduce you to the
  971. various concepts involved in database programming and, more
  972. particularly, programming using ISAM Manager. Example code is
  973. provided in the subdirectories TUT1, TUT2 and TUT3. You will be
  974. taken through various stages in the development of a simple
  975. employee database starting from the very simplest of screen form
  976. input programs and leading on to such things as batch
  977. processing, switching indexes and so on. This chapter, however,
  978. will cover basic screen form programming.
  979.  
  980.  
  981. DDF File
  982.  
  983. The first and perhaps most important phase in the development of
  984. a database is the design of the .DDF file. For our example, we
  985. are going to use the following design (call the file
  986. EMPLOYEE.DDF):
  987.  
  988. {BEGDATA}
  989. EMPLOYEE.DTA
  990. int emp_no;
  991. char initials[6];
  992. char surname[21];
  993. char dept[2];
  994. long salary;
  995. {ENDDATA}
  996.  
  997. {BEGIDX}
  998. EMPLOYEE.DTX
  999. Name: surname, initials;
  1000. *Employee Number: emp_no;
  1001. {ENDIDX}
  1002.  
  1003. Use your text editor to enter the above into a file called
  1004. EMPLOYEE.DDF". Once you have done this, type "DDF EMPLOYEE",
  1005. and, assuming you have entered everything correctly, DDF will
  1006. exit with no errors and will have created the two files,
  1007. "EMPLOYEE.CPP" and "EMPLOYEE.H".
  1008.  
  1009.  
  1010. Automatic Program Generation
  1011.  
  1012. We are now going to use the MAKSCR command provided with ISAM
  1013. Manager to automatically generate a basic data entry program,
  1014. with which we will be able to enter or search for data in the
  1015. EMPLOYEE data file. To do this, type the following command:
  1016.  
  1017. MAKSCR EMPLOYEE > EMPMAINT.CPP
  1018.  
  1019. You will now have a second .CPP file -- EMPMAINT.CPP. This,
  1020. combined with EMPLOYEE.CPP and EMPLOYEE.H, is all you need to
  1021. create a basic data entry program -- ISAM Manager has
  1022. effectively written all your code for you! To create a working
  1023. .EXE program, simply compile both EMPLOYEE.CPP and EMPMAINT.CPP,
  1024. and link them with the correct ISAM Manager library for your
  1025. compiler and memory model.
  1026.  
  1027.  
  1028. Altering The Source
  1029.  
  1030. Now is probably a good time to familiarise yourself with some of
  1031. the characteristics of the FScreen library, and the way MAKSCR
  1032. writes its code. Try, for example, to edit EMPMAINT.CPP to force
  1033. the input of dept to be upper case. You will find a copy of
  1034. EMPMAINT.CPP listed in the USER GUIDE chapter as an example
  1035. program.
  1036.  
  1037.                                TUTORIAL 2
  1038.  
  1039.  
  1040. Introduction
  1041.  
  1042. In this chapter, we will be introducing another data file and
  1043. seeing how we can link the two files together. The file we are
  1044. going to create will hold information about the various
  1045. departments within our hypothetical company and you should
  1046. create a DDF file as follows called DEPT.DDF:
  1047.  
  1048. {BEGDATA}
  1049. DEPT.DTA
  1050. char dept_code[2];
  1051. char dept_name[41];
  1052. int payrise;
  1053. {ENDDATA}
  1054.  
  1055. {BEGIDX}
  1056. DEPT.DTX
  1057. *Department Code: dept_code;
  1058. {ENDIDX}
  1059.  
  1060. Now follow the steps as in chapter 1 to create a screen form
  1061. input program and enter a few departments.
  1062.  
  1063.  
  1064. Data Validation
  1065.  
  1066. The next thing we are going to do is to introduce some data
  1067. validation. We now have a file containing all the departments in
  1068. our company and it would be nice if, when entering an employee's
  1069. department, the program was to check if that department was
  1070. valid and if not, then give an appropriate error message.
  1071.  
  1072. So edit the employee maintenance program (EMPMAINT.CPP) once
  1073. again and add the department file to it. Now you will need to
  1074. add the code to check the department file when the user inserts
  1075. or amends and employee's record. The following function will do
  1076. the trick:
  1077.  
  1078. int dept_ok(void)          // Validate that the dept of the currently
  1079.         {                  // selected employee record is correct
  1080.         strcpy(dept.dept_code, employee.dept);
  1081.         if (dept.find() == IM_OK)
  1082.                 return 1;  // Record found, so must be OK
  1083.         return 0;          // Record not found, so return FALSE (0)
  1084.         }
  1085.  
  1086. The rest I leave to you.
  1087.  
  1088.  
  1089. Altering The Screen Display
  1090.  
  1091. It would be nice if, upon entering a valid department code, the
  1092. full name of the department is shown on the screen. As we
  1093. already have the code for checking the department code, the
  1094. field dept.dept_name will be automatically set whenever the
  1095. dept_ok function is called AND succeeds in finding a record. So
  1096. you merely have to create another function that also displays
  1097. the contents of dept.dept_name, and then call it at all
  1098. appropriate times. Here's an example of a function that will do
  1099. this:
  1100.  
  1101. void display_dept_name(void)
  1102.         {
  1103.         FSclrbox(6, 13, 6, 53, attrSCREEN);
  1104.         if (dept_ok())
  1105.                 FSputs(dept.dept_name, attrINPUT, 6, 13);
  1106.         else
  1107.                 FSputs("**INVALID DEPARTMENT**", attrINPUT, 6, 13);
  1108.         }
  1109.  
  1110. The tricky bit is making sure that this function gets called at
  1111. all the right times! Once again, I'll leave that to you.
  1112.  
  1113.                                TUTORIAL 3
  1114.  
  1115.  
  1116. Introduction
  1117.  
  1118. In this chapter we will deal with the issue of batch processing.
  1119. First we will write a function to produce a report and then
  1120. adapt it to give each employee a pay rise according to the
  1121. department he or she is in.
  1122.  
  1123.  
  1124. Batch Processing
  1125.  
  1126. Batch processing in the context of database programming is when
  1127. a program processes a sequential batch of records in a file,
  1128. possibly performing an operation on each or selected records. In
  1129. this case, we want to award a pay rise to each employee in
  1130. accordance with which department an employee is in, so the
  1131. program will need to process the whole of the employee file.
  1132. Here is an example function to process every record in the file:
  1133.  
  1134. void process_file(void)
  1135.         {
  1136.         employee.rew(); // Rewind Employee File
  1137.  
  1138.     while (employee.next() == IM_OK) // Step through file
  1139.                 {
  1140.                 .       // Processing for each record here
  1141.                 .
  1142.                 .
  1143.                 }
  1144.  
  1145.     }
  1146.  
  1147. As you can see from this example, all that is needed to do the
  1148. job is a very simple loop. Now write a function that will step
  1149. through the employee file and print (using fprintf(stdprn, ...))
  1150. the Employee Number, Initials, Surname, Salary Department Code
  1151. and Department Name (which you will need to read each time from
  1152. the Department File) in that order. One thing to watch out for
  1153. is that some compilers (Borland, at least) open stdprn in binary
  1154. mode, not text mode. This means that at the end of each line,
  1155. you will need a "\r\n" combination rather than just "\n". Add
  1156. this function to the main bar menu of the Employee Maintenance,
  1157. and then test it to make sure it works OK.
  1158.  
  1159. You should now be able to confirm that your function is
  1160. correctly processing the Employee File, so now write another
  1161. function to increase each Employee's salary by the correct
  1162. percentage according to Department and add this function to the
  1163. main bar menu as well. To help you, here is the piece of code
  1164. that will give each employee a payrise:
  1165.  
  1166.     while (employee.next() == IM_OK)
  1167.                 {
  1168.                 if (dept_ok()) // Function from Tutorial 2
  1169.                         {
  1170.                         employee.salary += (employee.salary *
  1171.                                 dept.payrise) / 100;
  1172.                         employee.amend();
  1173.                         }
  1174.                 }
  1175.  
  1176. One thing to watch out for when sequentially processing a file
  1177. is that if you alter any fields in the current index of the file
  1178. being processed and use amend() to amend the record, your
  1179. position in the index will be altered and you may end up
  1180. processing some records twice and missing others altogether. To
  1181. avoid this, you should switch to an index whose fields are not
  1182. going to be altered in any way by the routine. In this case we
  1183. are OK as only the salary field is being altered, and that isn't
  1184. in the index.
  1185.  
  1186.  
  1187. Switching Indexes
  1188.  
  1189. Back in TUTORIAL 1, we created the EMPLOYEE.DDF file, and
  1190. defined two indexes. Until now, we have been using just the
  1191. default "Name" index. It's now time to make use of the "Employee
  1192. Number" index. What we want to do is change the report function
  1193. that we've just written to list the employees in employee number
  1194. order. To do this, all you need to do is switch index at the
  1195. beginning of the function, and then switch back to the original
  1196. index at the end. The commands to do this are as follows:
  1197.  
  1198. employee.set_idx("Employee Number"); // Switch to Employee
  1199.                                      // Number index
  1200. employee.set_idx("Name"); // And switch back again
  1201.  
  1202. So put these commands in the code, re-compile and make sure all
  1203. works well.
  1204.  
  1205.                     ISAM MANAGER FUNCTION REFERENCE
  1206.  
  1207.  
  1208. Introduction
  1209.  
  1210. This is a guide to all the functions provided by the IsamMgr
  1211. system which come under the broad category of 'file related'
  1212. functions. Their prototypes and return value constants are all
  1213. defined in the header file isammgr.h with the exception of
  1214. clear_buf which is defined in a header file created by DDF. The
  1215. functions are public members of the class IsamMgr, from which
  1216. your file classes are derived.
  1217.  
  1218.  
  1219.  
  1220. --------------------------------------------------------------
  1221.  
  1222. amend
  1223.  
  1224. Function        Amends current record.
  1225.  
  1226. Prototype        int IsamMgr::amend(void)
  1227.  
  1228. Explanation    This function updates the currently selected record
  1229. with the value of its field variables. The effect is similar to
  1230. an erase followed by an insert except that the index cursor
  1231. still points to the same record.
  1232.  
  1233. Return value    IM_OK or IM_ERROR if no record selected or index
  1234. conflict.
  1235.  
  1236. See also        insert and erase.
  1237.  
  1238. --------------------------------------------------------------
  1239.  
  1240. clear_buf
  1241.  
  1242. Function        Clears the contents of the field variables.
  1243.  
  1244. Prototype        void IsamMgr::clear_buf(void)
  1245.  
  1246. Explanation    Clears the contents of the field variables to enable
  1247. data to be entered for use by find or insert. Can also be used
  1248. to clear the data displayed after erasing the current record.
  1249.  
  1250. Return value    None.
  1251.  
  1252. --------------------------------------------------------------
  1253.  
  1254. close
  1255.  
  1256. Function        Closes current file.
  1257.  
  1258. Prototype        void IsamMgr::close(void)
  1259.  
  1260. Explanation    Closes the current data and index files. This should
  1261. be done before running another program to safeguard the files.
  1262. There is also a limit of 20 open files imposed by DOS that may
  1263. require the use of this function.
  1264.  
  1265. Return value    None.
  1266.  
  1267. See also        open
  1268.  
  1269. --------------------------------------------------------------
  1270.  
  1271. erase
  1272.  
  1273. Function        Erases current record.
  1274.  
  1275. Prototype        int IsamMgr::erase(void)
  1276.  
  1277. Explanation    The currently selected record is erased. The field
  1278. variables will remain unchanged, and the index cursor position
  1279. will be undefined, except that the next() function is guaranteed
  1280. to take you onto the next record.
  1281.  
  1282. Return value    IM_OK or IM_ERROR if no record selected.
  1283.  
  1284. See also        amend, clear_buf and insert.
  1285.  
  1286. --------------------------------------------------------------
  1287.  
  1288. find
  1289.  
  1290. Function        Finds record.
  1291.  
  1292. Prototype        int IsamMgr::find(void)
  1293.  
  1294. Explanation    Attempts to find a record whose index exactly
  1295. matches that of the field variables for the currently selected
  1296. index. If the find is successful, the record data is retrieved
  1297. into the field variables. If the find fails, then the cursor is
  1298. placed on the next closest record in the index, which is not
  1299. retrieved.
  1300.  
  1301. Return value    IM_OK or IM_ERROR if no exact match found.
  1302.  
  1303. --------------------------------------------------------------
  1304.  
  1305. get_cur_idx
  1306.  
  1307. Function        Get currently selected index number.
  1308.  
  1309. Prototype        int IsamMgr::get_cur_idx(void)
  1310.  
  1311. Explanation    Returns the number of the index currently in use.
  1312.  
  1313. Return value    Index number.
  1314.  
  1315. --------------------------------------------------------------
  1316.  
  1317. get_idx_name
  1318.  
  1319. Function        Get name of index number.
  1320.  
  1321. Prototype        char *IsamMgr::get_idx_name(int idxno)
  1322.  
  1323. Explanation    Returns a pointer to the name of the index number
  1324. idxno.
  1325.  
  1326. Return value    The name of the currently selected index.
  1327.  
  1328. --------------------------------------------------------------
  1329.  
  1330. get_no_idxs
  1331.  
  1332. Function        Get number of indexes for file.
  1333.  
  1334. Prototype        int IsamMgr::get_no_idxs(void)
  1335.  
  1336. Explanation    Returns the number of indexes for the current file.
  1337.  
  1338. Return value    No of indexes.
  1339.  
  1340. --------------------------------------------------------------
  1341.  
  1342. insert
  1343.  
  1344. Function        Inserts new record.
  1345.  
  1346. Prototype        int IsamMgr::insert(void)
  1347.  
  1348. Explanation    Inserts new record into file and updates all indexes
  1349. on that file.
  1350.  
  1351. Return value    IM_OK or IM_ERROR if index duplicated.
  1352.  
  1353. See also        amend and erase.
  1354.  
  1355. --------------------------------------------------------------
  1356.  
  1357. next
  1358.  
  1359. Function        Moves file cursor to next record in index.
  1360.  
  1361. Prototype        int IsamMgr::next(int no_recs = 1)
  1362.  
  1363. Explanation    Moves index cursor for the current index no_recs
  1364. forward in that index and retrieves the record. If no value is
  1365. given for no_recs,  it will default to 1. no_recs must be
  1366. positive.
  1367.  
  1368. Return value    IM_OK or IM_ERROR if end of file reached.
  1369.  
  1370. See also        prev and rew.
  1371.  
  1372. --------------------------------------------------------------
  1373.  
  1374. open
  1375.  
  1376. Function        Opens a file.
  1377.  
  1378. Prototype        void IsamMgr::open(void)
  1379.  
  1380. Explanation    Opens the data and index files if they are not
  1381. already open.
  1382.  
  1383. Return value    None
  1384.  
  1385. See also        close.
  1386.  
  1387. --------------------------------------------------------------
  1388.  
  1389. prev
  1390.  
  1391. Function        Moves file cursor to previous record in index.
  1392.  
  1393. Prototype        int IsamMgr::prev(void)
  1394.  
  1395. Explanation    Moves index cursor for the current index no_recs
  1396. backwards in that index and retrieves the record. If no value is
  1397. given for no_recs,  it will default to 1. no_recs must be
  1398. positive.
  1399.  
  1400. Return value    IM_OK or IM_ERROR if beginning of file reached.
  1401.  
  1402. See also        next and rew.
  1403.  
  1404. --------------------------------------------------------------
  1405.  
  1406. retrieve
  1407.  
  1408. Function        Retrieves information from current record.
  1409.  
  1410. Prototype        int IsamMgr::retrieve(void)
  1411.  
  1412. Explanation    Retrieves the data contained in the currently
  1413. selected record and places it in the field variables. 
  1414.  
  1415. Return value    IM_OK or IM_ERROR if no record currently selected.
  1416.  
  1417. --------------------------------------------------------------
  1418.  
  1419. rew
  1420.  
  1421. Function        Moves file cursor to first record in index.
  1422.  
  1423. Prototype        void IsamMgr::rew(void)
  1424.  
  1425. Explanation    Positions the index cursor for the current index to
  1426. the beginning of the index. Use next to move on to the first
  1427. record.
  1428.  
  1429. Return value    None.
  1430.  
  1431. --------------------------------------------------------------
  1432.  
  1433. set_idx
  1434.  
  1435. Function        Sets index to use.
  1436.  
  1437. Prototype        void IsamMgr::set_idx(const char *name)
  1438.  
  1439.             void IsamMgr::set_idx(int idxno)
  1440.  
  1441. Explanation    Sets the index to use to the index named in the
  1442. string name or the index number idxno.
  1443.  
  1444.                        FSCREEN FUNCTION REFERENCE
  1445.  
  1446.  
  1447. Introduction
  1448.  
  1449. The FScreen Library is a collection of powerful C++ functions
  1450. that allow you to read and write directly to the screen. This
  1451. gives the functions a very large speed advantage over other
  1452. functions that use DOS or BIOS to access the screen. In the
  1453. FScreen Library are functions to allow you to create menus, open
  1454. windows, move the cursor around the screen and other important
  1455. functions all of which help your program to be presented as
  1456. professionally as possible.
  1457.  
  1458. The FScreen library is primarily provided for use by MAKSCR when
  1459. creating quick-and-dirty data entry screens. It is not the most
  1460. powerful screen library around, and we assume that you probably
  1461. have your own preferred screen library already. For this reason,
  1462. FScreen is considered as a free extra for ISAM Manager rather
  1463. than an integral part of the system, and will not be ported to
  1464. other platforms. For example, you will find the libraries for
  1465. Windows 3 do not contain the FScreen functions.
  1466.  
  1467.  
  1468. Monitor Types
  1469.  
  1470. All monitors are supported but in 80x25 character mode only. The
  1471. function FSinit must be called at the start of any program that
  1472. uses FScreen functions. This detects the monitor type so that
  1473. the direct screen access functions can make allowances for
  1474. different screen memory locations and cater for possible 'snow'
  1475. effects on old CGA monitors.
  1476.  
  1477.  
  1478. Header File
  1479.  
  1480. All function prototypes are contained in the header file
  1481. FSCREEN.H which should be included in the relevant C++ files
  1482. with the line:
  1483.  
  1484. #include <fscreen.h>
  1485.  
  1486.  
  1487. --------------------------------------------------------------
  1488.  
  1489. FSbarmenu
  1490.  
  1491. Function    Allows selection of options via a bar menu.
  1492.  
  1493. Prototype    int FSbarmenu(int row, int col, int spaces,
  1494.                               char *option[], int normcol,
  1495.                               int highcol, int hotkeycol)
  1496.  
  1497. Explanation    FSbarmenu presents the user with a bar style menu
  1498. from which options may be selected using the cursor keys or hot
  1499. keys. The menu will be displayed on row row with spaces spaces
  1500. between each option. The starting column will be col unless col
  1501. is given a value of FS_CENTRE or FS_CENTER in which case the
  1502. menu will be located centrally. The option array is a NULL
  1503. terminated array of options of the following format: "^Option".
  1504. The '^' character MUST be present in each option string and
  1505. denotes the hot key letter for that option. normcol, highcol and
  1506. hotkeycol are the colours for the main menu, the currently
  1507. selected item and hot keys respectively.
  1508.  
  1509. Return value    IM_ERROR if an error has occurred or <ESCAPE> is
  1510. pressed. Otherwise the option number where 0 denotes the first
  1511. option and so on.
  1512.  
  1513. See also    FSmenu.
  1514.  
  1515. Example         #include <fscreen.h>
  1516.                 
  1517.         main()
  1518.                        {
  1519.                         char *menopts[] = {"^Insert", "^Amend",
  1520.                                            "^Delete", "^Find",
  1521.                                            "^Next", "^Prev",
  1522.                                            "E^xit", NULL };
  1523.                         FSinit();
  1524.                         for (;;)
  1525.                                 {
  1526.                                 switch (FSbarmenu(22, FS_CENTRE, 2,
  1527.                                         menopts, attrBMNORM, attrBMHIGH,
  1528.                                         attrBMHOTK))
  1529.                                         {
  1530.                                         case 0:
  1531.                                         .
  1532.                                         .
  1533.                                         .
  1534.                                         }
  1535.                                  }
  1536.                          }
  1537.  
  1538. --------------------------------------------------------------
  1539.  
  1540. FSbox
  1541.  
  1542. Function    Draws a box on the screen.
  1543.  
  1544. Prototype    void FSbox(int toprow, int topcol, int botrow,
  1545.                            int botcol,int style, int attr)
  1546.  
  1547. Explanation    FSbox draws a box where the top left hand corner is
  1548. at row toprow and column topcol and the bottom right hand corner
  1549. is at row botrow and column botcol. The box can be any one of
  1550. four styles dictated by the parameter style.Style  HSVS is a
  1551. single line box, HDVD is a double line box, HDVS has single
  1552. vertical lines and double horizontal lines and HSVD has single
  1553. horizontal lines and double vertical lines. The colour of the
  1554. box lines is dictated by attr.
  1555.  
  1556. Return value    None.
  1557.  
  1558. See also    FSopwin and FSmenu.
  1559.  
  1560. --------------------------------------------------------------
  1561.  
  1562. FSclrbox
  1563.  
  1564. Function    Clears an area of the screen.
  1565.  
  1566. Prototype       void FSclrbox(int toprow, int topcol,
  1567.                               int botrow, int botcol, int attr)
  1568.  
  1569. Explanation    FSclrbox clears a rectangular area of the screen
  1570. where toprow is the row of the top left hand corner of the area,
  1571. topcol is the column and botrow and botcol are the row and
  1572. column respectively of the bottom right hand corner of the area.
  1573.  
  1574. Return value    None.
  1575.  
  1576. See also    FSclrscr and FSscroll.
  1577.  
  1578. Example         #include <fscreen.h>
  1579.  
  1580.         main()
  1581.                         {
  1582.                         int row, col, z;
  1583.                         FSinit();
  1584.                         for (row = 0, col = 0;row< 25 && col < 80;
  1585.                              row++, col +=2)
  1586.                                 {
  1587.                                 FSclrbox(0, 0, row, col);
  1588.                                 for (z = 0; z < 32000; z++);
  1589.                                 }
  1590.                         }
  1591.  
  1592. --------------------------------------------------------------
  1593.  
  1594. FSclrline
  1595.  
  1596. Function    Clears a row.
  1597.  
  1598. Prototype    void FSclrline(int row, int attr)
  1599.  
  1600. Explanation    FSclrline clears the line specified by row, setting
  1601. the attribute to attr.
  1602.  
  1603. Return value    None.
  1604.  
  1605. See also    FSclrbox, FSclrscr and FSscroll.
  1606.  
  1607. --------------------------------------------------------------
  1608.  
  1609. FSclrscr
  1610.  
  1611. Function    Clears the screen.
  1612.  
  1613. Prototype    void FSclrscr(int attr)
  1614.  
  1615. Explanation    FSclrscr simply clears the screen, setting the
  1616. attribute to attr. Like FSclrbox, it is a macro which translates
  1617. into a call to FSscroll and is contained in the header file
  1618. FSCREEN.H.
  1619.  
  1620. Return value    None.
  1621.  
  1622. See also    FSclrbox and FSscroll.
  1623.  
  1624. --------------------------------------------------------------
  1625.  
  1626. FSclwin
  1627.  
  1628. Function    Closes a window previously opened by FSopwin.
  1629.  
  1630. Prototype    int FSclwin(void)
  1631.  
  1632. Explanation    FSclwin closes the last window to be opened with
  1633. FSopwin and restores the contents of the screen underneath the
  1634. window area.
  1635.  
  1636. Please note that FSopwin and FSclwin call FSreadscr and
  1637. FSwritescr respectively. Therefore these functions should be
  1638. used with great care if they are to be used in the same program.
  1639. The basic rule is that is you use FSreadscr after opening a
  1640. window, then you must use FSwritescr before closing that window.
  1641.  
  1642. Return value    IM_OK on success, IM_ERROR if you try to close a
  1643. window when there are none open.
  1644.  
  1645. See also    FSopwin.
  1646.  
  1647. --------------------------------------------------------------
  1648.  
  1649. FSgetch
  1650.  
  1651. Function    Get a character from the keyboard.
  1652.  
  1653. Prototype    int FSgetch(void)
  1654.  
  1655. Explanation    This function calls the DOS interrupt service (int
  1656. 21h) function 07h to receive unfiltered character input from the
  1657. keyboard. This has the advantage over the standard getch()
  1658. routine of not being responsive to <CTRL-C> being pressed.
  1659.  
  1660. Return value    The character read from the keyboard.
  1661.  
  1662. --------------------------------------------------------------
  1663.  
  1664. FSgetmode
  1665.  
  1666. Function    Obtains the current screen display mode.
  1667.  
  1668. Prototype    int FSgetmode(void)
  1669.  
  1670. Explanation    FSgetmode uses the BIOS interrupt service (int 10h)
  1671. function 0Fh to obtain and return the current video mode. The
  1672. main reason for the inclusion of this function is that it is
  1673. used by FSinit to determine the video board in use.
  1674.  
  1675. Return value    The current video mode.
  1676.  
  1677. --------------------------------------------------------------
  1678.  
  1679. FSgetpos
  1680.  
  1681. Function    Obtains the current cursor position.
  1682.  
  1683. Prototype    void FSgetpos(int *row, int *col)
  1684.  
  1685. Explanation    FSgetpos uses the BIOS interrupt service (int 10h)
  1686. function 03h to obtain the current location of the cursor. The
  1687. row and column locations are then placed in row and col.
  1688.  
  1689. Return value    None.
  1690.  
  1691. See also    FSgotopos.
  1692.  
  1693. Example         #include <stdio.h>
  1694.                 #include <fscreen.h>
  1695.  
  1696.         main()
  1697.                         {
  1698.                         int row, col;
  1699.                         FSgetpos(&row, &col);
  1700.                         printf("Cursor was located at (%d, %d)\n",
  1701.                                row, col);
  1702.                         }
  1703.  
  1704. --------------------------------------------------------------
  1705.  
  1706. FSgetstyle
  1707.  
  1708. Function    Obtain the current cursor style.
  1709.  
  1710. Prototype    void FSgetstyle(int *start, int *stop)
  1711.  
  1712. Explanation    FSgetstyle uses the BIOS interrupt service (int 10h)
  1713. function 03h to obtain the current cursor style. The cursor
  1714. style is described by a start and a stop value which dictate at
  1715. which pixel line the cursor block starts and stops. For example,
  1716. the standard start and stop values for a CGA display are 6 and 7
  1717. respectively. FSgetstyle places these values in the variables
  1718. start and stop.
  1719.  
  1720. Return value    None.
  1721.  
  1722. See also    FSsetstyle.
  1723.  
  1724. Example        #include <stdio.h>
  1725.                 #include <fscreen.h>
  1726.  
  1727.                 main()
  1728.                         {
  1729.                         int start, stop;
  1730.                         FSgetstyle(&start, &stop);
  1731.                         printf("Cursor style is (%d, %d)\n",
  1732.                                start, stop);
  1733.                         }
  1734.  
  1735. --------------------------------------------------------------
  1736.  
  1737. FSgetxy
  1738.  
  1739. Function    Returns the contents of a given screen coordinate.
  1740.  
  1741. Prototype    unsigned FSgetxy(int row, int col)
  1742.  
  1743. Explanation    FSgetxy finds the character and attribute at the
  1744. screen location given by row and col. It is used by the
  1745. windowing functions in order to save portions of the screen into
  1746. memory for later recall.
  1747.  
  1748. Return value    FSgetxy returns the attribute and character at the
  1749. specified screen location. The attribute is returned in the high
  1750. byte and the character in the low byte.
  1751.  
  1752. See also    FSputa.
  1753.  
  1754. --------------------------------------------------------------
  1755.  
  1756. FSgotopos
  1757.  
  1758. Function    Sends the cursor to the specified screen location.
  1759.  
  1760. Prototype    void FSgotopos(int row, int col)
  1761.  
  1762. Explanation    FSgotopos uses the BIOS interrupt service (int 10h)
  1763. function 02h to send the cursor to the screen location set by
  1764. row and col which are the row and column of the cursor position
  1765. respectively.
  1766.  
  1767. Return value    None.
  1768.  
  1769. See also    FSgetpos.
  1770.  
  1771. --------------------------------------------------------------
  1772.  
  1773. FSinit
  1774.  
  1775. Function    Initialises the FScreen system.
  1776.  
  1777. Prototype    void FSinit(void)
  1778.  
  1779. Explanation    FSinit determines what screen display adapter is
  1780. present, and sets the global variable FSdisplaymode accordingly.
  1781. The possible values are:
  1782.  
  1783.                 0 - EGA, VGA or other adapter.
  1784.                                 1 - CGA adapter.
  1785.                                 7 - Hercules / Mono adapter.
  1786.  
  1787. Return value    None.
  1788.  
  1789. --------------------------------------------------------------
  1790.  
  1791. FSinput
  1792.  
  1793. Function    Allow input and/or editing of character strings,
  1794. characters, integers and long integers at a given point on the
  1795. screen.
  1796.  
  1797. Prototype       int FSinputs(char *string, int attr, int startrow,
  1798.                              int startcol, int length, int forceflag,
  1799.                              const char *contents)
  1800.  
  1801.                 int FSinputl(long &value, int attr, int startrow,
  1802.                              int startcol, int length, long minval,
  1803.                              long maxval)
  1804.  
  1805.                 int FSinputul(unsigned long &value, int attr,
  1806.                               int startrow, int startcol, int length,
  1807.                               unsigned long minval,
  1808.                               unsigned long maxval)
  1809.  
  1810.                 int FSinputi(int &value, int attr, int startrow,
  1811.                              int startcol, int length, int minval,
  1812.                              int maxval)
  1813.  
  1814.                 int FSinputui(unsigned int &value, int attr,
  1815.                               int startrow,int startcol, int length,
  1816.                               unsigned int minval, unsigned int maxval)
  1817.  
  1818.                 int FSinputc(char &value, int attr, int startrow,
  1819.                              int startcol, int length, int minval,
  1820.                              int maxval)
  1821.  
  1822.                 int FSinputuc(unsigned char &value, int attr,
  1823.                               int startrow, int startcol, int length,
  1824.                               unsigned char minval,
  1825.                               unsigned char maxval)
  1826.  
  1827. Explanation    These functions provide a user input facility for
  1828. character strings and numbers in various forms. Common to each
  1829. function are the variables startrow, startcol, attr and length
  1830. which specify the starting position of the editing area, colour
  1831. and length of input respectively. The variable length has no
  1832. default for character strings and must be specified. When using
  1833. FSinputs, if forceflag is set to TOUPPER or TOLOWER then the
  1834. input is forced to upper case or lower case respectively. The
  1835. variable contents should point to a string containing values
  1836. which are acceptable input. If the string begins with the
  1837. character "^" then those characters listed will be those that
  1838. are not allowed to be input. The numerical input functions can
  1839. be used for single byte numbers (FSinputc & FSinputuc), two byte
  1840. numbers (FSinputi & FSinputui) and four byte numbers (FSinputl &
  1841. FSinputul). In each case the variables length, minval and maxval
  1842. default to appropriate figures but can be set as required.
  1843.  
  1844. Return value    FS_CURSORUP, FS_CURSORDOWN, FS_BACKSPACE, FS_ENTER,
  1845. FS_ESCAPE, FS_PGUP or FS_PGDN depending on the key pressed to
  1846. exit the input field.
  1847.  
  1848. --------------------------------------------------------------
  1849.  
  1850. FSmenu
  1851.  
  1852. Function    Presents user with a scroll bar menu.
  1853.  
  1854. Prototype       int FSmenu(int toprow, int topcol, int style,
  1855.                            char *options[], int normcol, int highcol)
  1856.  
  1857. Explanation    FSmenu pops up a menu for the user to make a
  1858. selection from. The row and column of the top left-hand corner
  1859. of the menu are toprow and topcol respectively. The function
  1860. FSbox is called to draw the box using a line style of style.
  1861. options is a NULL terminated array of char pointers which point
  1862. to the option lines. normcol and highcol are the colours for the
  1863. menu and the currently selected item respectively.
  1864.  
  1865. Return value    Either the number of the option selected where the
  1866. first option is number 0, or IM_ERROR if <ESCAPE> pressed.
  1867.  
  1868. See also    FSbarmenu.
  1869.  
  1870. --------------------------------------------------------------
  1871.  
  1872. FSopwin
  1873.  
  1874. Function    Opens a window on the screen.
  1875.  
  1876. Prototype       int FSopwin(int toprow, int topcol, int botrow,
  1877.                             int botcol, int style, int attr)
  1878.  
  1879. Explanation    A window is opened on the screen where the
  1880. coordinates of the top left-hand corner are toprow and topcol
  1881. and the coordinates of the bottom right- hand corner are botrow
  1882. and botcol. A box is drawn on the perimeter of the window of
  1883. style style and colour attr. The window may subsequently be
  1884. closed by using the FSclwin function. A maximum of 50 windows
  1885. may be opened at any given time.
  1886.  
  1887.     Please note that FSopwin and FSclwin call FSreadscr and
  1888. FSwritescr respectively. Therefore these functions should be
  1889. used with great care if they are to be used in the same program.
  1890. The basic rule is that, if you use FSreadscr after opening a
  1891. window, then you must use FSwritescr before closing that window.
  1892.  
  1893. Return value    IM_ERROR if an error occurs, otherwise IM_OK.
  1894.  
  1895. See also    FSclwin, FSbox, FSreadscr and FSmenu.
  1896.  
  1897. --------------------------------------------------------------
  1898.  
  1899. FSprompt
  1900.  
  1901. Function    Asks a Yes/No type question.
  1902.  
  1903. Prototype    int FSprompt(char *question, int attr, int row)
  1904.  
  1905. Explanation    The string "(Yes/No)? " is appended to question
  1906. which is then echoed to the screen using the attribute attr
  1907. centralised on row row. The function FSyesno is then called and
  1908. its value returned.
  1909.  
  1910. Return value    1 if "Yes" answered or 0 if "No" answered.
  1911.  
  1912. See also    FSyesno.
  1913.  
  1914. --------------------------------------------------------------
  1915.  
  1916. FSputa
  1917.  
  1918. Function    Sets a screen area to a given attribute value.
  1919.  
  1920. Prototype       void FSputa(int attr, int row, int col, int length)
  1921.  
  1922. Explanation    The screen area starting at the coordinates row, col
  1923. for length characters has its attributes set to attr.
  1924.  
  1925. Return value    None.
  1926.  
  1927. See also    FSputs, FSgetxy.
  1928.  
  1929. --------------------------------------------------------------
  1930.  
  1931. FSput
  1932.  
  1933. Function    Write a string or number to the screen.
  1934.  
  1935. Prototype       void FSputs(char *string, int attr, int row, int col)
  1936.  
  1937.                 void FSputl(long value, int attr, int row, int col)
  1938.  
  1939.                 void FSputul(unsigned long value, int attr, int row,
  1940.                              int col)
  1941.  
  1942.                 void FSputi(int value, int attr, int row, int col)
  1943.  
  1944.                 void FSputui(unsigned int value, int attr, int row,
  1945.                              int col)
  1946.  
  1947.                 void FSputc(char value, int attr, int row, int col)
  1948.  
  1949.                 void FSputuc(unsigned char value, int attr, int row,
  1950.                              int col)
  1951.  
  1952. Explanation    These functions put a number or string on the screen
  1953. in the colour attr starting at the coordinates row, col. Use
  1954. FSputs for a string, FSputc or FSputuc for single byte numbers,
  1955. FSputi or FSputui for two byte numbers and FSputl or FSputul for
  1956. four byte numbers.
  1957.  
  1958. Return value    None.
  1959.  
  1960. See also    FSputa.
  1961.  
  1962. --------------------------------------------------------------
  1963.  
  1964. FSreadscr
  1965.  
  1966. Function    Save the contents of an area of the screen.
  1967.  
  1968. Prototype       int FSreadscr(int toprow, int topcol, int botrow,
  1969.                               int botcol)
  1970.  
  1971. Explanation    The contents of a rectangular area of the screen
  1972. where the coordinates for the top left-hand corner are toprow
  1973. and topcol and those for the bottom right-hand corner are botrow
  1974. and botcol are read into an internal buffer which is malloc'ed
  1975. by the function.
  1976.  
  1977.     Please bear in mind that this function is called by FSopwin and
  1978. so extreme care needs to be taken when mixing calls to both
  1979. functions.
  1980.  
  1981. Return value    IM_ERROR if the maximum no of windows have been
  1982. opened (see FSopwin) or there is no available memory. Otherwise
  1983. IM_OK.
  1984.  
  1985. See also    FSwritescr, FSopwin and FSmenu.
  1986.  
  1987. --------------------------------------------------------------
  1988.  
  1989. FSscroll
  1990.  
  1991. Function    Scrolls area of screen.
  1992.  
  1993. Prototype       void FSscroll(int toprow, int topcol, int botrow,
  1994.                               int botcol, int rows)
  1995.  
  1996. Explanation    FSscroll calls the BIOS interrupt service (int 10h)
  1997. functions 06h or 07h to scroll the area of the screen specified
  1998. by toprow, topcol, botrow and botcol rows amount of rows. If
  1999. rows is zero, the screen area is cleared.
  2000.  
  2001. Return value    None.
  2002.  
  2003. See also    FSclrbox and FSclrscr.
  2004.  
  2005. --------------------------------------------------------------
  2006.  
  2007. FSsetstyle
  2008.  
  2009. Function    Sets the cursor style.
  2010.  
  2011. Prototype    void FSsetstyle(int start, int stop)
  2012.  
  2013. Explanation    FSsetstyle use the BIOS interrupt service (int 10h)
  2014. function 01h to set the current cursor style to start at
  2015. position start and end at position stop.
  2016.  
  2017. Return value    None.
  2018.  
  2019. See also    FSgetstyle.
  2020.  
  2021. --------------------------------------------------------------
  2022.  
  2023. FStitle
  2024.  
  2025. Function    Puts a string centrally on the screen.
  2026.  
  2027. Prototype    void FStitle(char *string, int attr, int row)
  2028.  
  2029. Explanation    FStitle is a pre-processor macro which translates
  2030. into a call to FSputs to put the string string centrally located
  2031. on row row with a colour attribute of attr.
  2032.  
  2033. Return value    None.
  2034.  
  2035. See also    FSputs.
  2036.  
  2037. --------------------------------------------------------------
  2038.  
  2039. FSwritescr
  2040.  
  2041. Function    Restores screen contents saved by FSreadscr.
  2042.  
  2043. Prototype       int FSwritescr(int toprow, int topcol, int botrow,
  2044.                                int botcol)
  2045.  
  2046. Explanation    The contents of the buffer saved by the last call to
  2047. FSreadscr are restored to the screen within the area specified
  2048. by toprow, topcol, botrow and botcol. Note that calls to
  2049. FSreadscr and FSwritescr can be stacked. That is, a call to
  2050. FSwritescr removes the last buffer created by FSreadscr and so
  2051. the next call to FSwritescr will restore the contents saved by
  2052. the previous call to FSreadscr.
  2053.  
  2054.     Please bear in mind that this function is called by FSclwin and
  2055. so extreme care needs to be taken when mixing calls to both
  2056. functions.
  2057.  
  2058. Return value    IM_ERROR if no buffers on the stack. Otherwise
  2059. IM_OK.
  2060.  
  2061. See also    FSreadscr, FSopwin, FSclwin and FSmenu.
  2062.  
  2063. --------------------------------------------------------------
  2064.  
  2065. FSyesno
  2066.  
  2067. Function    Asks Yes/No question.
  2068.  
  2069. Prototype    int FSyesno(int attr, int row, int col)
  2070.  
  2071. Explanation    FSyesno waits for the user to press 'Y' or 'N' and
  2072. echoes the response in full to the screen at position row, col
  2073. using attribute attr.
  2074.  
  2075. Return value    1 if answer is "Yes". 0 if answer is "No".
  2076.  
  2077. See also        FSprompt.
  2078.  
  2079.