Files
sibo-playground/docs/1-06 Additional System Information 2.10_djvu.txt
T

10936 lines
359 KiB
Plaintext
Raw Normal View History

2026-07-06 17:27:17 +01:00
ADDITIONAL SYSTEM INFORMATION
Version 2.10
February 3, 1995
(C) Copyright Psion PLC 1990-95
All rights reserved. This manual and the programs referred to herein are copyrighted works of Psion
PLC, London, England. Reproduction in whole or in part, including utilization in machines capable of
reproduction or retrieval, without express written permission of Psion PLC, is prohibited. Reverse
engineering is also prohibited.
The information in this document is subject to change without notice.
Psion and the Psion logo are registered trademarks, and Psion, Psion MC, Psion HC, Psion Series 3,
Psion Series 3a and Psion Workabout are trademarks of Psion PLC.
TopSpeed is a registered trademark of Clarion Software Corporation. IBM, IBM XT and IBM AT are
registered trademarks of International Business Machines Corp. Microsoft and MS-DOS are registered
trademarks of Microsoft Corporation. Apple and Macintosh are registered trademarks of Apple Computer
Inc. VAX and VMS are registered trademarks of Digital Equipment Corporation. Brief is a registered
trademark of Underware Inc. Psion PLC acknowledges that some other names referred to are registered
trademarks.
Contents
1. Melink, (Moeprint:and Sink 2. :00..<550..hccsie belive kiileseccoccecccceetasabecsaseteasseccecitverss 1
MIGIINK OX6 iis fe Serie oles tieaencoweaereensdovesasee cuettes Sea eete deemed oma cea eee ee Tee vers 1
Commands provided in MCLINK............:sscsecscsesccscscecenscceceveceseseentceceses 1
MCLINK and single floppy disk drive PCS ..............cccsccececcuscecscscuceeesens 2
Exiting the MCLINK Program .......csscscscsscsscccecscsececnsssesccerscuteccssonesencees 2
Display the version Of MCLINK ..............ccceccsesenercoscecetecanseeceaevsesacenense 2
MCLINK file-handling COMMAMAS ..............cecrerecsececscsesecsccecsseesscecscscvesvevecs 2
Rules: On TEMaMES iid occce tes cecdacsecnceadecceackeeet neat he ettees aut eeia 2
DIR feos cnc cedvevsevesvacese dete ci seaccade ide tacisesnde hstereee ete ee Bac sa ees ee eens 3
CON sc owctsciecevesictaen ste ceeds cove cu dvccedh ceca teas scale ccc Bh ce eee oe eed eens 3
RENAME cite crave vesta odes chon te sttecaccedcusstea cee ceeattvet tu ovteareie tee aaes wives mceeied ale 4
DEC ETE cc ctaccescccettsntcccit ee hcteteatoctea ts meere tee Merete te satin Marta eer oriaee 4
IMIR DIR iirc cette eteeearccccccc tere fed eens cae Ee ne Pa ee ee a 4,
Changing MCLINK communications SettingS.............:eseccsscesssscseececeucsesessees 4
Options for the SET COMMANGA ...........ccecsccscscsscecscsecncosensaccseesseencuceeeecs 4
Serial port and Baud rate Options ..........ccscsesscecscoececsrseseveesucecesscucceseees 5
Modem ptions oo. sicossisvicsecccrcsavcbes Saecnaseg oe dteas elles viele siuee es ote seeviaas sues ieee: 5
Examples of the SET command
Advanced use of MCLINK wis. . eccccncsas St teeeee Mevacor oi ia ee eiea bs ade buedbecesess 5
Running programs remotely on the MC, HC or Series 3.............cscsseeeees 5
MCLINK batch: files .......scs00c00ePhdeeee cee eet Meee tia nd De eiee sect ehate la ceses ness 6
MCLINK command line processing.............cscecscsescscececsccsceccuteescnerscueess 6
Invoking MCLINK inside an MS-DOS batch file...............c.csceseceeeecevessess 6
MCLINK and «modems oiei.s cocci ivcesssrcen Petra ire cach eet oe eeees sdogecetes ade cdewtbeces Wickes 6
MCLINK as a PC file server via the phone SySteM.........cccsssccscesceeceseecees 7
MCLINK and modem Baud rates..............cscscscsescscecscsscveesececraseceusaceves 7
Link on the MC/HC as a requestor Via MOCEM...........csccccsceresrssucecencncece 7
Link and Modem Baud rates............cececscecscnessncacscecsvssceeseeseenssscucennsrves 8
Link/MCEINK: with! MNP. s s0020c0.00c00.aceteeescteds oe PRUE tovdalivecediocsss 8
Examples With :MOdGEMS: «...0<ccsevesevtarsdl code vevtueneadsvedevsedcaddcadadeaecaveveedaccsaceas 8
Using a Dacom QuadPlus MNP 5 compressing modem...........cessseerseeeees 8
Using an Amstrad SM2400 modem. ............cecscscssscocsecececeeescatececeucseves 8
Using a Dowty Quattro SB2422 000. eccccscscscecsccveeeecsceeseveecensecees 9
Using a WorldPort 1200 pocket Modem. ........sscecscrssstssscsevenccccasececeesens 9
An HC with a Psion Quad modem ..............cscecscscececsvevescsceceesevensaversens 9
An HC with the Amstrad SM2400 modem ............cccssscnscetscescesscccscsenes 9
MCBLIRT CXC 28 ieee ccs ccaee Dt viene tins cues desides eve dswaieeea tev Ueactne than sec voeseepeses@ betes velebecesns 9
Using: MCPRINT sscssccsiccsoeeeeptac cievtecbeves hes the cise do Sieb ave cedecasas deccw ys: 9
Exiting: MGRRINT csi. .ccslsevesssceececcnaeecs sect eeeestecee Sei vciesbseter atta 9
Printer configuration ON the MC ...........cccecesscesceescsceceestsceceecensesessenees 10
Printer configuration on the SerieS 3...........scecscesescececscsstereceeceneesceeceens 10
Parameters. ivccs.scasavdtciSes wanes 2akeckcks eeeeee fae05 Jeni y wseee Fema tea Sea aee ete ose tae tee 10
THe. < prdev->: ParaMeters...cc.scicccescacesstensveesonsssaudievandedenaveskscesdoeecedeees 10
The: -C< POrt > PALAMECtEH,...ccceccccssceccecceeveveeasevesdsceevvenscoeedeuse vovevdauvecss 10
The -t<tiMeOut> Parametel...........cccescecscescescencesccccereccesescensecesesssaues 11
TGQ" Parameter. siiccecvicasscuestetuis csana tienes oe vadee does Gen le cane sas boscuenseeemeesete 11
SINK LOX is sisesseeceds canes esis tice wus sre ccewesvaeauees vend as daly cae''ss swaaddarev cateue Lvaue ooeoeobeeane 11
2 “Resource Fil@s ciciacsssccsccvceses canes ce cede serctvcloseensccencsiclescSuscusevee cadet calaeenesgeioes oactee 13
IMEROGUCTION SG vite A tecicic crews ies Ae ec ec po a danse eae seh ed edean ope aad eos sae gsree eee eenels 13
ADDITIONAL SYSTEM INFORMATION
Format of Sibo resource fileS............csesceccecescescecscescccseseecescsesnentseressseceens 15
WhestormatOLAsCwtilOS sc. cece ccset cores roses cbcece x coinc covuiateruscus dead ca ute tos eecsae 15
Some strategies for reading .rsc fil€S.............csccecscseecscececetsceccusesvenceece 15
Example of reading resource files directly..............csccsssececscscevesesscvsscecs 16
Using the rscfile class im OliD...........cccccccecececsscececetcecsecscnsoecteecaccecessececenes 16
Basic services of the rscfile ClaSS.............cscscsccsteeceececscsssccecceusceteancaves 16
Reading compressed resource files with the rscfile class ...........cecssesecees 17
InitialiSing: aN rSCTIIC OD/SCT... cicc2s. cs cess cen dtecsis sae seoceunu Vadencstecgees baaGeessee ee 17
Which header files are ME@dEd...............ceccesecscnscnccececscecscersucscaseeaseures 18
Run-time errors with the rscfile ClasS.............ccccscscscsesescesececevecseecarecess 18
Possible errors during initialisation ..............ccccscesecesecseovevscacersnseseseenees 18
Eprorssduring tS readcOrgs ReAGNDUP <3, foci sicnesset eerie rene ctoststtaey aeacdesscss 18
How rscfile errors are reported ..............cccscecsecscneceeesescececscecscseucssecese 19
Dealing with errors in rs_read or rS_read_DUF........ccssceeeeeceesensceesceecescees 19
Advice on where to locate resource files ............csccsseeceececsescsscnccccsacceseeces 21
Mono-lingual applications ........sccsssscscscsvssctsscscascsrencetssaccsescsececsccerecss 21
Multi-lingual applications ..............cccececscecececenecscecatcuceccetevscacererseueecuss 21
Copying! Of applications + sicielisccaccis vies disascacaveciaeacs oe dedasdacvazathasstee evens 22
General comments on multi-lingual applications............ccececesesvercecseccesvcscens 22
The basic principle of independence of code from resource file .............. 22
Careful design of screen layout ...........cccecscececcscsecsceecscecsteveseaventsatececs 23
Codesizeproblemsitisv.... 203.00 ne a Ee Re ee 23
MAPYINGRKCYDOSrdS sic sieisevescdscdeccestca consee cere ot oa tee a soascieteleel ber ee tecct ease 23
CONCIUSIONS 2: cccacedectsssccadeccutaciscaseehestet tase atte ec estoe rte conten merit rene cake 23
Creating .rsc files USING FCOMP.EXE..........scscececscecececscneersccceescseveseseetensesses 23
Generated s1SG- TIES « «cisco. sive necdendocseeiescccecssanedsostacesucesaceeseouessvevessdenes 24
The syntax of the rcoMp COMMANGA............sscscscecseeeceasccovarcvevscesccssseses 24
Include files within a reSOUFCe SCIIPt ........ccccccecsecseecncscecceascoeeecscesessees 25
Conditional compilation in resource fileS ............csscsececseecssevcesssensesoeenes 25
Contents Of <(SS: TICS 5. oc ccsacie.cosvcdaccvtedest vee es cane sceeecedcus vans ise sagcesasieaadassaves 25
Declaring STRUCT wciccccvesdecessccccvecsenseuscivevescscevs secs cevavivesdecsevencseveds. 26
Possible member types in STRUCTS..............ccececscsecscecentsecrcessecncaseeeees 26
Declaring?RESOURGES 7h 5s. PRA rete its wnyetacevedes sescets cenecd eves 27
Declaring the values Of SUD-STRUCTS...........cccsscescetsescteseeseecsenssecnscees 27
Leading byte and word length values...............:scecsececesesterevescsceecseasaces 28
Arrays within resource files ..............ccccsacsceceserecsececensctccscescssececsasavecs 29
Creating SYSTEM resource files ..............sccccecsccecsscsceseeascnccececesuscseeees 30
SaeWV DR BMINtinG) .22ci00c60 cs 5 cancccsecctossceccscviceasseeteacsscechotaberduscscuscadeevaccesoeteesraetaes es 31
INTRODUCTION oi. vols edeis oa cases sodceun casts au tene trams taal oue tes aonon tet en ees based wets aseees cs 31
Creating: . WO TIES 65s catccucces i orek cond ss eee cree oe eed Saag OE eae et oats 31
The WDR printing environment variables.............scceccscscscseescesssenceeesenns 32
A note on reading environment variables ...........cscscececcevcecscsesceureceeeeees 32
Overview of the contents of a .wdr file...........cccccsccsceececescsenceetecscsscseeses 32
Deciphering general. wr ...........cscscscscsvesccececencsesceesceecseterssensscessaseceucs 33
The: Header PeSOUrCe co .sc5is cust eecve covcews Does MRT Weve vote da bee ce valved Mielvcacsoess 33
ThE COMMANAS FESOUICE........ccccsessscccnccestncenvecsossacecesceseecececeesssussensese 34
Model resources v2: 2s; sscctteess secs cecuaseadsecte ates sswsveceusets vas ceaedgittieeadevtas scees 34
TY¥PCTACEsFESOULCES so: else ci ssc vedcceseetucescascatnast certeee holeeiebes Tema acti helacns 35
TRANSISTES [ESOULCES 2505. <cscesicecevazencvcadacn olecntenseskecuaued tec ctacdwcesteaetensbes 35
Summary of resource types in a .wdr fil€..............cecceecececscececeeesecssesees 35
More details on the contents of .wdr fileS .............ccscscecscscncececececscscnesceeees 36
Possible: Wdr=flaQs .22..cccsetc.ccce coi leceactededacesvsrecstevancaesasvandenusnbi ceed vedvets 36
The notion of "printer models” ...............ceeeceecseneceeeeecerecesersseeseeceasesaes 36
Overview of the different CoOMMANA SHIriNGS...........cecscecerecscerscecvessvescess 36
Special characters in ComMMand StringS .............cccecsececsecesscnsscsceeererecens 37
The MOVE RIGHT Commands............ccccsscscsssseesssereccersvcseeesesecesenees 37
PRiMterURitSis. <a. esSeescend ic cvessse bites iacesb vee sdadesdsteaegeeeedseteadaueswerss ablecusos 37
Possible; moOdel=tlags yi ic. cis c.cciecccacs coaticaec cnc sts esenvees weores spaitgaestonctenscicess 38
Typefaces ANd TOMS os. eas ececcecve ce tacden¥escesesss4esws bee bl bedesd cesuw es caaseesoayers 38
Ty petaceiMuUmbers c.etiv..iscadss swacen se oesdees coeds ceatwertalSveves lewcvvegscasdensoness 38
CONTENTS
Possible typeface-flags ...........ccceressonscersescssecetsecscecesereceversessssencarsacs 39
Heights. Of fonts ss sre occ iccsheoccadowyn acces canes seeteateucs oateec beuodinee ek tkedalvaane 39
Widths of characters in fonts............ccccscsccecsscecscccuecescuesscceseveseusassenees 39
Creating .wdr files Using WdtraNn.exe .........ceccsecsscoersceecesaececccescesevsscsssesees 40
Contents Of. Wd sfiles ic ciccses.ctockeocecsscss cs ath eae eae SP, 40
Acceptable syntax within a COMMANDS resource definition.................. 41
Acceptable commands within a TRANSLATES resource definition........... 41
Acceptable commands within a WIDTHS resource definition .................. 42
Acceptable commands within a TYPEFACE resource definition ............... 42
Acceptable commands within a MODEL resource definition.................0.. 42
Allowed typeface NUMDETS .............ccsccsecsccestseceseecesuccececaveeccesssaesonseess 43
4. (DBR eS oic sie sc citisc ci conn ceed sedi cesecatcsics coy oddeceda ve vedas seateneatseate seteee tae e ee cca ee Rein beke 45
IMTFOGUGTION ccs cat sccossvcrdesgenedsvetscn cecetercneagetvetessed csiansecusesecisuambecasecurisncases 45
Basic structure of DBF fileS....c..05.cccesedccvascesvevsvecsabsd css ees bettie Peres ccawee 45
The: standard: header sc.....sssscie secswewe clic egessacen tacchtes paeeETs Mac et code mt ese Veeees 46
The, extended headericcsschisccccssstecevvagiveasacact ewes veceveetttbeweel thee esuvdecesan 46
The field information reCOrd...........ccscscsscetecsscuseesscvcscecseasssoesessesenscncnss 46
Thesformat- ofvall reCords si: csecsccuscnesevdbecesedv ovectveeeseeous coleman sso lineven 47
Deletedirecords:osicc. ans. oscis ecco eeecunn coaccu dv acee seh sevesttee seh ctecn Ae at vedas 47
Descriptive reCOrdS «05... ssieccecacuesdueeviseanetsseatesssoocsoseescieccceciececesueeeeans 48
MoresOn: type: 1 *feCOrdS). iii. ists icvecssecsewicecesvsesvececersicseisusadadvevesisasctoces 48
The Series 3 Database .............cccccecsscscaccscsseueccetncessccsesceccessecseneesensercens 48
Field information (type 2) reCOrd ........cccecessscevscecsceesececessesecacecscesrceences 48
Extended Meader oi. ceic.sccesevsssccesavevescscasdeuciiades oda vavcdesbexeeinensevduscvasvedws 49
Descriptive: (type+3): record scccsvecsteceestacetereveeie os eee eeeete Tee 49
Flags options for the Series 3 Database ...............cecscscssevstcecececscceeeceees 50
Flags options for the Series 3a Database...............ccccecsccesccecscecesavcecsecs 50
TYPO AV TSCOPdS i 2.30556 odsisesietvaveve vcr ocestiocvedyvevedeesteseueesss Si0s ces uiwdivewesscdes 50
Continuation SUD-fieldS ..........ccccsssscnscecsccecstencsssscecesscscecvcessestscesseeeeses 51
The: Series: S!Agenda.c..c.0cb seven cte cA etek clots essen Chav aes bea tn au bhetuoees 51
Field information: records: Sete. ce ne ST siactics ab koesues castes tisccceavescvevecs 51
Extended iNeaGer i csc.insccatevetectn eeter rete caches ctecasee cuss sianca Pe asteet erates cvasens 51
DOSCMIPTIVE FECOMG (oi sco. ea chil heeee aad tes cvceve cote coacue od eed a beeas ck oen eb tei uae 51
TYPO PTA ECOLdS 5 cs az. cece dan Seesaw svocd vcs ccte Rete a eee See ee aks ee EE an eed 52
Calculating with AlarmTime...........:.:sccsscescescoscercnesscesscsuseccssncessessesacs 52
The text Of AN APPOINTMENL ...........cscecececcausceeccrensctscuceuccscecceseccecensaees 53
TODO ATEMS 2 65.0.05650 cP MEA, etic eee el sk Bed satan inedouss 53
REPEAL ITEMS, ciiecescensvssenees evades scscsuasdesesdcsesaaarencessvuucacauasegaceen abe monneatede 53
5 Series 3a Agenda File Format .............:cscssscocssccecestontceceessscesecnssescccescecescussecees 55
Basic structure of Agenda files ............cscsccecsccecsscecesacccescacsavecevessercetscsensss 55
Phe sStandard: NEAdSr osc ccs.co.csccenncseoteetesseaescacwacseracdouvestiecacnceesseacene 55
The extended header ........csssccscscsscstescscerssenecscatacceecessanceeossccsacesesenace 55
EMG! Gata reCOrds si. 3 iccscsvoil cabataveseyevoneas eicouss dacs ediewe Concnsas sane bowstncdesets 55
RECOrd TY PSiss.cc sacs casusnieodencugeudads sven sueuedencnededesdvea cue cdstaucdies dened Mewscotteedys 56
Type 0.= deleted reCord 2. vccccesnciccecsccsceck ccossctecacdestsvecesedevccessesedicssisseenivdes 56
Types. 1 to:4 entry records ccccicissccseesceacists SEA ed ed sia eas as vevtentecsouend 57
Entry.detailS: tleldsscse..< ca, dona s Bere Mises dee S een oe sos ete tias eco ee falls ER SRERE awe 57
Aheztitle Field A seceececcscaewesietoteecussateuroed anes easbaaes cbeenaee vaniaehub ein redness 59
Phe alert Hel? asc. se cieeces ceecacrvuetavs cove ence cabeeede s¥eWw cossvcec sass devbececsacs 60
THE MEMO TED: Mess cect seas cseascieeccvasstaran. voseceteres dbececeetese ee toesc ten robes aes 60
ADDITIONAL SYSTEM INFORMATION
TY PO.5 EPCOS s vie Soa ca sevens veVecacemeecedesdetedieesleasaewetoe fetta ettlad oo Taaeoten, 61
Type 6 - ANONYMOUS ata ........ cc ccecscccscetceresecseaccscececeteceseseceseseseteeaeaeneeees 62
Types: 7 and:8 ~ reserved. evs. isivsece cede ci tideens vocnts cis olsclenstets ciiesedsvenssescstes ns 62
Type 9 - to-do list information ............cccscscsccccsscectscsstcesesceceesesssaseescssenens 62
Types 10 to 14 - descriptive records .........cccccscessccecececscecssecnssseeeeatotesaeneas 64
Type 10 - styles descriptive reCOrd.............ececsseececscececerecneeetetescsseceserevecs 64
Type 11 - to-do manager descriptive reCOrd..........ccccccscecscesecscececeeeeateseeuees 64
Type 12 - frequently changing data descriptive record ...........ccccsescsceeterecees 65
Type 13 - general descriptive reCord ...........cscscesccerscserececsececeseecssonesseersenss 65
Diamondélistssetup*field sss 2c ie tieess otis eteis csi a eedeaeede tever set MA Aste 65
Day entry defaults field ...........ccccersessenecccccerersretecececseecacessceteatetessseses 66
Anniversary entry defaults field ............cccccscorscsccscecvcrsssetatssssecsacscessees 67
Generaltdefaultsifield ters nec Pn aR cae Seis ccde ceadahaoteeatatetecess 67
Day ViGW:-SCtHNGS TIGIG Si ics. cs cesccesecheeedsccensvassedeeeee Tie stuavcaie tees Js ota 67
Week view settings field. .........c.csccscecscscscecseqscnesedevdsescortcdedeeseterseatcers 68
Year view: Settings Field ins... sidess cesses seat ss stvonds cceesteGssceevader Tier basceerosdese 68
TOzdO. VIEW SCTHINGS, TICIG soi csicn tsa cacedenedacsttesiatiesaess cokasasestecesdattsteetesses 68
Anniversary View Settings field .............cecccenesscssccnscecnesccessesestecetcceaners 68
List VIEW SETTINGS TIEIG.s... ic. .ccntscsassteessecscsticeesccncas cecsdssesueuneseesreveceestars 68
Type 14 - print setup descriptive reCOrd .........ccccceceseecesenerececececcseterssseeeeees 69
TY Pe 152M Gal cs vec ckieiseteae decade vdeetSansedsacetvssessvaecyetioeosnseascasseavselesebces 69
6 Word Processor File: Format 2... 3.0cc ccc. vcscccescsdescccnscelscsevcisccsVorevetedvcrecesesessssactecas 71
The-document- head e@tssvssvscissececrevesrrsaereraveseverestyreveeeeitec ae eerste eer eT 71
RECOLA TYPOS: conc cc cccccdssorscsteve cs dveseecanesstedarevesseteegisrseeeberteeeeuasseaesureseceetyey 72
The options data record (type 1, length 10) .............c..cesesceseeceseeseseesces 72
Printer-related data record (type 2, length 58) .............cecssevcscsessseccscees 72
Printer model data record (type 3, variable length).................csscsceceeeeees 75
Page header record (type 4, variable length) .............cecessseseseecscscscsseeees 75
Page footer record (type 5, variable length) ..........-....-cesssecesseeseveseeereces 75
Style data record (type 6, length 80)...........cccccecscscececscevevsseseseseeceencnen 75
Emphasis data record (type 7, length 28).............:cccesensorsssoterecsceseataces 76
Document text record (type 8, variable length) ..........c.ccecsesceceeeeneeesenees 77
Document index record (type 9, variable length) ...........cscsecssesscseesseneees 77
TEMplatetil€Stitrcrscctecsesavcistsiscresscceesttcctertotertsrttterstistsenseetesscrcstvorniesion cs 78
Printer Criver fONt MAPPING.........ccceccccssecscsescueseesessecscesnesssecteseseaeacecerectoss 78
7 Series 3/3a and MC Spreadsheet File Format .................cscecscecscncscncscscssossccnvens 81
FUG MOS OR cee: sews enstiiesveneevnsetesbiveesalsecaaters caseueettecdccddacedehevt coseousecvevedoctoaxe 81
RECOPGS west ves scvcccccdvenccuesceeevedswcccsctcswed secs vets sua Miuadsssebncsrdeucececdscededeleud 81
Range reTerenCeS.. ioisc.cnevcsactneesaveisececccesevassesececactsesacscecaceeeveasinaseedees 82
Formula record (type 1, variable length) ............cccsesescsescseeeserererecseeesees 82
Cell record (type 2, variable length)..............cccscecscscecscecscecscnessessceserens 85
Column width (type 3, length 2) .............cccccscscsesecececeeteeencececssensseceeees 86
Default column width (type 4, length 2)................ccececeeceesreeseesseseesees 86
Status information (type 5, length 4).........ccsescsesensreecerserenseseevseceeseenes 86
Display information (type 6, length 26)...........c.cccscecsescseseeescsrersetsoeeeees 87
Named range (type 7, length 26) ...........cccscscsessecsscceseseserscteesetseataeerens 87
Print range (type 8, length 8) ..........ccscsccesecscececsersesstcescessceseeeseeseseeeees 87
Database, criterion settings (type 9, length 16)..........ccccccsssecsceceseeeeetees 87
Table information (type 10, length 16) ................ceceeecececeeececeeeseeneeeaeas 87
Print setup (type 1:1, length 2): ciceccccesscaacchesecsctessbadhen cdedeesteasegeseevdeaace 88
Eont:(typest:2 length. 8) oes ter ctecds cee cane deteatasescsagiastasadantecstvn.verersess 88
Graph (type 13, variable length) ............cccccsseccseerseeeseescessceterssseesteeaees 89
Current graph index (type 14, length 2)..........cccccscecscseescsceecscensnesceeeoes 89
iv
CONTENTS
Font palette (type 15, length 24)..............cccsccesssscerercececavensecsscusesesceees 90
Print data (type 16, length 58)..............ssccsssscsscusnscvcovevesscssseeceveserceans 90
Printer model (type 17, variable length)............cccscececssscccevesesececeaceeevess 90
Header text (type 18, variable length) .............ccscscecscscsccscscevsscecsasecesees 90
Footer text (type 19, variable length) ...............cscccscsuscscscvesnscesesecseceuces 90
Display extras (type 20, length 2) ............c.cecseceecscecsrencecvecessevsceneaueeess 91
3a Display extras (type 21, length 4) ..............csecscoreceseseeeenscunsescececesees 91
Password (type 22, length 18).............cscscssssescessevencessesececusucsecceeecesens 91
8. Writing) Device Drivers iii .25. ins sbi oso Sooe ck Site saci css cacsnseadeccasscticces eitets ctvs sweetie 93
INTRODUCTIONS. 0255. ccecardicaececedvore red eaeavedesue eet be Tore loth eo tee score tes Per oh not Sveti 93
The location of device Arivers ...........cccscsccecsecceseccasscecescsceccscecersenceeses 94
Device Driver Names. .........cccccssscssonsncssccscsseuecsceccecencecceccucesensatesseseenes 94
Device Driver*Ghannels:stesvrecetn eens oe ade eo ons ea asd eee ea nae 94
SearchingiforRDDs ici. vccvsesatevs cevaceecavesesaveten see vase eee eee a eal! 95
Device Driver Hierarchies And Attached Drivers ............ccccccscscsescsensecees 95
Interrupts and Interrupt Service ROUTINES ..............c.sescocossenscereseceeccsevceensses 96
Device Driver I/O Semaphore Waithandlers ..............scccscscsoscecscesecscsacees 96
Loadable Logical Device Driver Structure ..............sccsessevcscecececsssvcnscecesscescs 97
SINGICT COGS SEGMENT. .is..cc2escsvencace siete seetervecepascnecssdeenonreionseoetantetMestssee 97
MHeEsMIDENt: SrUCtUies 525 ii. ceva s cscs cdeadseeweehecascecdanceedlissicnccdendacieessceuteess 97
Mandatory EDD: FUNCtIONS «6.060.005. sscecsnarecescscdeseanctasedontorceesstonsveeaecseoeve 98
DEVEUNCINStall meres cce. i cccn ovensssl<cencrceas soeescescesos soedensesvact tasesestsaneanwadaeeeds 98
DEVEUNCREMOVE ai.52.ccscccs ssa ce cvocsteeedaedescstacGennuedases ees wdiweceue sees dae cekvens 99
DeVEUNCHOlde in. ciccceccrcscncs yeh actebatesenceecevesssccees seeaees vas csaestuenadisaulennbadee 99
D@VEUNCRESUME oi. cvcsicccesncsecscbescssceascscssieccccsccdcaddeasccccloeceecddcceatwetacsive 101
De@VEUNCRESCE avis. scucssecetascecves srassieds cae 3ss0cnehveedssdleadcccgeesavavinwedesiexvers 101
DEVEUNCU RIS weve se cuis svenevasscavensvcdtedgeeseeuded nace cagece dec entdacau lee teeasenue cues 102
DEVEUNCOPEN sis cisceeccce ta caevocadaasisaessccuasasuavieoecceedteeten snot caetaet oufeatieateass 103
DOVEUNCSEATEGY: ss cence ececcssetacasseveids Ptecectescuetetass foes daseeceteleseens MetNeauaats 105
Loadable Physical Device Driver Structure...........ccccccccccccsceccccscsccccececesacsecs 106
Single Code SEQGMent ..........ccssesecscecscaceceususcuccsescecccccesancetecusececeeecesess 106
The BIDENt StrUCture: s vscccccesacsceccesscctetcs. caus ccoctresasuscvactsvstecectstas de wcecs vs 106
Mandatory PDD functions ...............cccesecsesecececsceceescscccseterecseecsasanscecs 107
DevFEunclnstallPDD on5 55 scccccacccscvecccuccvevnevecevescncelswoesedescsessechcoscdsesnsceess 107
DevFUNCREMOVEPDD ..........cccceseccsenescercccceavscscscsceseucesssacscesscsersceesesere 108
DeVEUNCOpenPDD ii... ceseccedsccesssseses see pensesvicscgedsintadersbicvaseusrtisansn eee 109
DéevFuneStrategyRDD. esses oeeccacestssicseeseveasanesa cOSveedd a doeaas sdesee ohavero eee se 109
9 Example: Device: Drivers ci. ceccccsecccxcevcscscosdevoscasuesodcatasudaccascdenuacteoeciaedvevedeSeusees 111
An Attached Device Driver Example ...........cccesecesccecsscececcenscesccssecssesscceeuses 111
Thesde vice: table iis.5.2 cise i te code eciwiscacececctceves cocacecosccstiteucacteudesdelecns cas 111
TheslnstallsFUNCUON we vevesvecssssicesasvavavesesesesese sees covasnce cos sessesceesdieteereeacted 111
THe Remove Function ay..ecccicssciescucetecscescedsccdscecess nave lgsWeevdcticiedssst ones: 111
WHE HOMD FUN CMON wes sees Scccsvscuveeccesvebeuwessipecevscansasecersregeedes Meee socehe bees 111
The ReSume Function ...........ccccscsesessceavccceecccsreceseucescaccccseeceaceseueecuers 411
he RESCH FUTICTION s sewssvissestececcsceedofedeotels ieee asuon sete sia eee ee 111
THEAUMITS FUN CHONG ese Scceeccn ceed scccavavccecedabcecasevcdeoses tec sctlccnisezdefecescants 112
THE OPEN FUNCTION vice. csiesaseevesavcevesneccececcuscesbevetacanechuasaececedscbasieaccceenss 112
The Strategy FUNCHON .iicccseciecicccceeeeccdsuchwasievccsedecenestsdessdussevasasdwededecs 112
The Wait Handler Function ............:cccscscesecsccscscscscecssececcvcesscesaeausoucenes 112
Non Interrupt Based Sound Driver ..............scsccosscsecsestecsrscnsececsesceeveseeensens 113
Phesdevice table ses. scscsdscsnecaaveteea vesecereseasevewnesddecdesacveceediaodseecced cdsceued 113
Ehe: Install PUNCUON . 3.005660 scacevecesad chee cedewancedscteeschssadevssabiascscecdsandecsans 113
The Remove Function............ccccecscscvecsccccvansccsesccusesceseceeasvesanevesensecuens 113
THE HOIGIFUNGTION. « ficiedset ees tis cos ee ne tencc eee veadeeekencades sea dciexdeedaatheteexsesoweos 113
The Resume Function ..............ccccsccecsescscecccccssscsceccccencesnccsssnseesseessaces 114
THEXRESCE- FUNCTION oic5co3c20 sacks bo celeb ode ductecdieseceuesedavestinuxieweusewanedesmeendeas 114
Tes WMitssPUNCION Sc. oeaste scene sec te ee See cece aca cates tease dobdbcasenadtcssesesstaundsots 114
THE OPC MIEUNCUON srececccvecssporesscrsauecnceweutegecdutesesisiced @ocdeetess iaaces tune axe 114
The: Strategys¢ RUA CON co5 res. fhe sax. cescecevecsvesdhccstececieok sleds etotaes ves onies ooaene ds 114
ADDITIONAL SYSTEM INFORMATION
The: Wait: Handler: Functions... s.seio..otee et eed Stee SPE ST eee ees 114
EXERCISING: the: VECIOIS Feces ener sseetiessccsscetterectacseteoncecsieeesene cette sete wieter ats 115
Interrupt Driven Sound Driver ..........ccsceccecsarsccsccecccececsnensseerscenssseesesseesons 115
Thecdevice table sie co criscoccccccccnceca cesses ccoke cuveeces Suuzte lens cess ev cstetoaseteeds 115
TheslnstallFFuncton Aik ove, cee eeaw as cevarsocceeees ec ecsees vecuatensctsnceceuece ccs 115
TERREMOVE FUNCTION ci nese icteet nes ccce ch ease ccna fe ceecmeesevesceuddcsineetaetsedecuecats 115
GHEHHOIGKFUNETIONG.. .ccctevcessnecoctessexercewsataceces tears ssissadecouse ocesineu dec cet te cs 116
THEIRESUMELBUNCH OM Mec.ccs sca cescesancectcccccecvasetestsecodacnmsitetcanestscisecasesees 116
TRENRESCTEUNCHON aii e.c3 si lesceccecdssdestesescaes caacesenceves feser core sista se duentecever 116
THELWNAITSTRUN CHONG Soe5 5 2oiceadadiieedeneveecs et -ntianen tagcat gabe tee steers tested) sa 116
THEOL ODEMLEUNCHON F ooveccaeistcocae tees aceuceusladdaei ils ones oaeeace cetaceans sees cnn suneeceees 116
The StrategyitFunCtOn). co sccccediwesescusceesecssce sche saswendnenensdeestisveeesnatsteueres 116
The Wait: Handler Function. cs... ..scieccciccscccctcadescdadevctescstecssteteesesttetcedes 117
10 Word File Format Conversion DYLS.............:sccscescscsssceccccccsceccsessnsccnssascassnesesens 119
SAVE\INTEPTACE: SEPVICES sic iicdeessccsscccesessccearseecsvccvsdseseestecesosvetenceverssdeesesedes 119
Present file OVErwrite GialOG .........cscccscscsscccesccestcsscsaescesceascoesesassesessses 119
COUNT INDEXAAGS vases cc cc Seccea Sect cote n ac cee aee nea cas Pee eee Mca b ec oebeseneeecewes 120
SONSE AN IMGEX CAG re: oiases ce ceie inca cecashosnaedevsncconsesdavasevedscucerertscgawenseeees 120
COUNT Paragraph-StyleS \<. 0c... cccasccssecdessscsesavecrecsctaneccteedsvecettonesrctoces woes 120
Count EMPNASIS*SIVIES: F...cceveseccs chs edsesescaete wceeeracesgensietecereiseausescsetees 120
Sense a paragraph style by index..............cscceceecencecseeecneesunecesesceseceners 120
Sense an emphasis style by INde@x........ccccscsccsscsacsscscecssoescsseesscveaneeeees 120
Sense a paragraph style by short Code ..........cccecececseecscseseereessoreeetonsees 120
Sense an emphasis style by Short Code ...........cccececscerecereeseeerecsoneeaeaees 120
Copy document text to DUPPEr ....... cece ee ee scene eee eceeencnceeteeeenseeneeceeesens 121
Set afileverrOns: eescecizs foes oswi avs tack vase tabs saewtadeaededsaccadsucnstverce rector esate cass 121
Load jinterface:ServViGeS:.....c.0c ccs iswctesseddecacadscsdscdederenaderntesacreeesat esse beceseees ed 121
CIOSECUIreNntly: OPEN TICs secessccdees cose iene clbeterbacstvecnccadenssebeteodscendedees sei 121
Record name of file ANd redraw ..........cecesecceceecssceceeseesceescecreceessecceseess 121
Append a paragraph Style ...........cccccecscsecsccscscnesccsceessenseccescseesesteesesens 121
Append an emphasis style ...........ccssscsecrscenrscescscrscesseescececeeseeeseetecemens 121
Apply a paragraph Style..........cccccccscccsenscesescecneserseensessssnessoncnseseseeeoess 121
Apply ansOMPHaSisSs si ceiieis seoccdes isa eacacesdedeccnes cocesieteactcvesatsceedocesvened 122
Create: default Styles .....c.cccssssccctesececsaasscdeccccsevecdacentetesteleasdacdusnscsoeees 122
ISOPT TEX Gace scccteecrcevossccsnecacecevensccactieinscaeucospiwecetecdersteitessccsonesseuans 123
Delete: Text nce. coleceSesvatecsvanaessaeedeiiacesndcueceedessssesdaceecssseaetaierssseeacesst es 123
COMMON interface SELVICES ........cscecsececscsscctsceceecessseserecossscesenteneescensensenes 123
Start active object file CONVErSION .........ccccscsececenceeteceesececsetenoeeeeesosaeees 123
Stop active object file CONVErSION ............. ceca ececessenceeeencssteneecseeeeerenes 123
Set/clear Busy Status vsecscctive visiaievawedea cases cube ss Se teacceeeslndteuts Peiweeedecahe 123
Senserprinter data yc... cece c cosas ves cevisedsivesvssaecsvedeusescudetevensereceeenceranwebes 123
Sense printer model data .................ccceeeeecececeeceeecereceeneeseeenueteceeeeeoeaes 124
SENSO PINTER CIVEN ss cec se vcscssteccentetevetesenssaevescsascnes da cdcacsussesvasisesesegee 124
Example Code isis. icdisc iced Mitten cities deten a iedsiaa cs secwavagebecevewedecesisaneetssietess otletes 124
SAVE DIAINtOXtiai ce cliees ces ceeesiacdeekosn casnsccecevescacetecdescetancertenteree sowssanset 124
LQ ad PIAIN, TEX ccs ictc cave sais cs caaic bY ea scien ve ete wc siaw's cule sines Seecetedsdledvcets Shan vee Petes 126
Debugging a Conversion DYL............:cccenseeecsc recent eeecesencetscesnesesscetneesereees 129
CHAPTER 1
IMICLINK, MICPRINT AND SLINK
The directory \sibosdk\sys contains (amongst others) the following programs, all of which can be run on
a PC connected to a SIBO computer:
mclink. exe a program allowing file transfer and remote file access between the PC and the
SIBO computer
slink, exe a “no frills” server-only version of mclink.exe, which may run on PCs or PC-
lookalikes that cannot run mclink
meprint. exe a program for printing "through" a PC to an attached printer.
Basic information on connecting a PC with either an MC computer, a Series 3 computer (see note
below), or an HC computer, is given in, respectively, the MC Operating Manual, the Series 3 User
Guide (see note below), and the Introduction chapter of the HC Programming Guide (part of this SDK).
The information in this chapter gives some more advanced details on the above three programs.
Note: throughout this chapter a reference to the Series 3 machine is taken to include both the Series 3 and
Series 3a machines unless explicitly stated otherwise.
(a a eee a ee
Miclink.exe
MCLINK requires MS-DOS version 3.2 or above. MCLINK is unlikely to run inside "DOS emulations"
provided by other operating systems (though it happily runs inside MS-DOS tasks inside MicroSoft
Windows).
If you experience any problems running MCLINK on your PC, you should experiment with reduced
contents of autoexec.bat and config.sys files. Serial mouse cards may be particularly prone to interfere
with the operation of MCLINK.
If all else fails, you may wish to use the alternative SLINK program, also supplied on the PC MCLINK
disks.
Note that, by default the HC and Series 3 run at 9600 Baud, the MC and Series 3a at 19200 Baud. When
a PC running MCLINK is connected to an MC, either the PC or MC end will in general have to be
changed to enable a link to be established.
Commands provided in MCLINK
When you start up the MCLINK program, the lower window contains a$ prompt. At this prompt you
can enter various commands. These commands cover:
= file-handling
= changing the communications settings
= exiting the MCLINK program
« displaying the version of MCLINK
= running programs on the remote computer.
ADDITIONAL SYSTEM INFORMATION
For all these commands:
= the command can be abbreviated, to a minimum of the first two letters, eg DE for DELETE, RE for
RENAME, CO for copy, and se for SET
=" CTRL-C stops the command (though in multiple file operations, some files may already have been
copied, deleted etc, before the command is stopped).
MCLINK and single floppy disk drive PCs
If your PC has only one floppy disk drive (currently referenced as "A:"), and you mistakenly enter DIR B:
while in the MCLINK program, the program will be halted by MS-DOS, requesting you to insert a disk
into B:.
To avoid this, use the MS-DOS assiaN command before running the MCLINK program, like this:
ASSIGN B=A
Then DIR 8: will be read as DIR A: and the program will not be halted. See your MS-DOS manual for
further details of the ASsiIGn command.
Exiting the MCLINK program
Type EXIT to return to MS-DOS.
Display the version of MCLINK
Type VER to display the version number.
Le ce Se ee ae ae eT
MCLINK file-handling commands
For file transfer operations between a PC and a SIBO computer, you would normally use the File
Manager on the MC or various file options on the Series 3. For certain purposes, however, you might
choose to use the file-handling commands within MCLINK on the PC instead.
Rules on filenames
In order to make full use of the file-handling commands of MCLINK, various rules about filenames need
to be appreciated.
In MCLINK the syntax of full filenames on the PC, MC, HC or Series 3 is:
filing system: :device:\directory\sub-directory\file.extension
This is very similar to MS-DOS, except for the <filing system> prefix.
If you do not specify a filing system in a file specification, Loc:: is presupposed.
In MCLINK on the PC, <filing system is
= oc:: for files on the PC (local)
= remM:: for files on the MC, HC, Series 3 or Series 3a (remote).
On the MC, HC or Series 3 the situation is reversed, with Loc:: for files on the MC, HC, Series 3 or
Series 3a, and rem:: for files on the PC.
Note that for all MCLINK file management commands:
= if no directory is specified, the current directory is assumed
= if no device is specified, the current device is assumed
s if no filing system is specified, the PC is assumed.
When specifying a directory or sub-directory in the file-handling commands, make sure to add a \ onto
the end of the directory name. Otherwise the directory name will be taken as a filename. So:
COPY A:\*.* REM::\LETTERS is wrong - it would try to copy the files in the root directory of a:
to the file LETTERS
1 MCLINK, MCPRINT, AND SLINK
COPY A:\*.* REM::\LETTERS\ is right - it would copy the files on A: to the directory LETTERS.
Syntax: DIR filespec
The directory specified may be on the remote or local filing system - eg DIR A:\LETTERS\ looks in
directory LETTERS on the disk in drive A: of the PC, DIR REM::A:\NOTES\ looks in the notes directory on
the SSD in drive A: of the remote machine.
Use wildcards to list only certain files - eg DIR *.TxT to list just the .TxT files in the current directory.
When you get a directory listing with the o1r command, the following file information is given:
« file name and extension
= date and time when the file was last modified
= size of file in bytes
and a combination of these indicators as appropriate:
Mod file has been modified since last backed up
Rdo read-only file
Sys system file
Hid hidden file
Example: CLIENTS .DBF 14/01/90 09:54:23 544 Mod RdO
Syntax: COPY filespec1 filespec2
Optional flags:
<i include sub-directories: If there are any files copied from subdirectories they are placed in
directories below the current directory, to reflect the source directory structure
-m modified files only, eg COPY REM::A:\*.* -i -m copies all modified files in all directories
of the SSD in drive A: on the remote machine to the PC.
Examples:
COPY REM::M:\*.TXT \BACKUP\ would copy all the .txtT files from the internal disk of the remote
machine to the Backup directory on the PC
COPY \SMITH\*.DOC REM: :A:\LS\ would copy all the .poc files from the sm1tu directory on the PC
to directory Ls on the SSD in drive a: of the remote machine.
If you do not supply a complete destination name, the root directory and/or default disk on the remote
machine is assumed, and the source filename is used as the destination filename. Eg
COPY \HOME\SECURE.TXT REM: :M:
would copy SECURE.TXT to the M:\ directory on the remote machine, giving the file the name SECURE.TXT.
If you do not supply a complete source name, the current device/directory is assumed. Eg
COPY *.TXT REM::Mz\
copies files from the current directory on the PC to the root directory of the remote machine's internal
disk.
Note: if you are transferring a lot of small files to the Series 3, it is a good idea not to stay in the Series 3
System Screen. This could take longer than usual because the System Screen would continually update its
file lists as files arrived. In extreme cases, with lots of very small files, the file transfer could even fail.
So press an application button, such as the TIME button.
ADDITIONAL SYSTEM INFORMATION
Syntax: RENAME filespec1 filespec2
You can rename a file in any directory on any drive on the PC, MC, HC or Series 3. For example
RENAME DETAILS,DOC DETAILS2.DOC
RENAME REM::M:\CLIENTS.DBF REM: :M:\BUSINESS.DBF
You can rename more than one file at a time. For example
RENAME REM: :M:\*.TXT REM: :M:\*.DOC
You cannot rename a file across directories or devices. Thus
RENAME REM: :M:\LETTER1.TXT REMs:B:\LETTER2. TXT
would give an error. Instead, copy the file to the new name and destination then delete the old file.
Syntax: DELETE filespec
Optional flag:
-j delete files of the same name in sub-directories, eg DEL *.TxT -i would delete all .TxT files
in the current directory and in any sub-directories of the current directory.
You can delete files from any directory on the PC, MC, HC or Series 3.
You can delete more than one file at a time by using wildcards.
You cannot delete directories with this command.
Syntax: MKDIR directory
Makes a subdirectory of the current directory.
You can make directories on any drive of the PC, MC, HC or Series 3.
You can make more than one subdirectory at a time - eg MKDIR \HOME\LETTERS makes the subdirectory
\HOME\LETTERS and also the intermediate subdirectory \Home (if it does not exist).
SSS SSS SS ee ee
Changing MCLINK communications settings
The set command in MCLINK allows you to:
= use either of the PC's serial ports
= change the Baud rate which the PC uses
= use a modem (see later in this chapter for more details of using MCLINK over a modem)
The set command creates a new MCLINK.TRM in the current directory to hold the new settings. The
next time you run MCLINK from this directory, these settings will be loaded again.
Options for the SET command
Following the seT command you can specify a variety of options. For example:
SET -pi -b9600 selects com1, 9600 Baud
SET -p2 -b9600 selects com2, 9600 Baud
The full range of options for the set command includes -p, -b, -m, -n, and -c.
These options are also available as parameters to the command line for MCLINK (see later), but in this
case, no permanent record of the options are made in any .7RM file.
4
1 MCLINK, MCPRINT, AND SLINK.
Serial port and Baud rate options
The SET options -p1 or -p2 select com1 or COM2.
The option -b followed by a number sets the Baud rate. You will need to set the Baud rate on the MC,
HC or Series 3 to match that on the PC.
IMPORTANT: In general you should specify both -p and -b, or neither. If you specify just one, the other
is reset to MCLINK's internal default value. The internal default for the Baud rate is 19200. (By default
MCLINK runs at 9600 Baud since when starting up it looks for a file called MCLINK.TRM which is built
in to MCLINK.EXE. This file sets the PC to COM1 at 9600 Baud.)
Modem options
The set options -m or -n specify that you are using a modem (as described in more detail later in this
chapter).
The option -m means wait for a call; MCLINK will establish the speed to use to the modem.
The option -n followed by a number causes MCLINK to dial the number. The modem is assumed to
conform to the Hayes command set. Here you can if you wish specify the speed for MCLINK to use,
with -b. For example: -b2400 -n314159 dials 314159 at 2400 Baud.
The option -c<string> will cause <string> to be transmitted to the modem to configure it before
waiting/dialling:
SET -cATMO turns off the modem speaker
SET -cAT\N3 sets a Dacom modem to MNP fallback mode.
Note that the at is optional in these commands. Multiple strings can be transmitted. For example,
SET -cMO -c\N3
Examples of the SET command:
SET -b1200 1200 Baud
SET -p2 -m waits for a call using the modem in port 2 (com2)
SET -pi -b2400 -n314159 modem connected to port 1 dials the phone number 314159
SET -cm0 turns off the modem speaker.
SSS eS Sa ee
Advanced use of MCLINK
Running programs remotely on the MC, HC or Series 3
The syntax
RUN <program name>, <program command line>
causes the named program to be nm on the remote computer, with the specified command line.
The program is assumed to exist in the default directory of the remote machine or the root directory of
any drive on the remote machine. Otherwise the ROM of the remote machine will be searched for the
program.
The program command line is as required by the program being invoked.
For example,
RUN CLOCK. IMG
will run a copy of CLocK.1mMG on the remote machine.
As an accelerator for running a copy of the remote shell program on HC machines the '!' command is
equivalent to typing RUN SYSSSHLL.
For example:
! DIR
ADDITIONAL SYSTEM INFORMATION
————$ $e
will run a copy of the sys$sHLL program passing an initial command line of DIR. See the HC
Programming Guide for further information on commands available to the sYs$sHLL program.
MCLINK batch files
MCLINK can read a text file containing multiple commands:
= Any line in the file containing a '!' is assumed to be a comment line and is ignored.
# Any blank line is ignored.
= You may specify almost any MCLINK command, although some may be meaningless in this
environment - DIR, for example.
= §=©The sET command should not be used.
To invoke, a batch file, type the 'a' character immediately followed by the name of the text file
containing the commands. For example, if the file SEND_ALL.TXT contains the following lines:
! Sends all text files to the remote machine after
! creating the correct directory, then exits
MKDIR REM: :M:\NOTES\
COPY *.TXT REM: :M:\NOTES\
COPY *.DOC REM::M:\NOTES\
EXIT
then entering @SEND_ALL.TXT at the '$' prompt will cause the \NoTEs\ directory to be created in the internal
memory of the remote machine, all the .1xT and .poc files in the current directory to be copied to this
directory, then MCLINK to exit.
MCLINK command line processing
MCLINK understands a command line entered when running MCLINK from the MS-DOS prompt. The
command line may take the form of the parameters to the sET command, a filename assumed to be a
configuration file, or the @ command to run a sequence of commands.
Examples:
MCLINK -p2 -b9600 will run MCLINK using port 2 at 9600 Baud. No .TRM file will
be created, unlike using the set command, and any future running
of the MCLINK program will not use these parameters.
MCLINK S3SETUP will run MCLINK forcing it to use the file S3SETUP.TRM as the
initial configuration file. This file would typically have been
created by a previous use of the sET command within MCLINK.
MCLINK @SEND_ALL.TXT will run MCLINK and cause the initial commands to be read
from the file SEND_ALL.TXT. MCLINK will wait until a
connection to the MC, HC or Series 3 has been established before
running any of the commands.
Invoking MCLINK inside an MS-DOS batch file
Perhaps the most convenient way to automate a regular MCLINK task is via an MS-DOS batch file.
For example, a batch file SEND_ALL.BAT could contain the single line
MCLINK @SEND_ALL.TXT
in which case the contents of SEND_ALL.TXT would be performed simply by typing
SEND_ALL
from the MS-DOS command line.
ESS ES eee eee ee a oe eee ea
MICLINK and modems
A PC running MCLINK can use one modem at one end of a telephone line to connect to an HC or MC
computer attached to another modem at the other end of the telephone line.
1 MCLINK, MCPRINT, AND SLINK.
Modem communication of this sort is possible only for MC and HC computers. The 3 Link software for
the Series 3 does not have any built-in modem support for communicating over a telephone line to a PC
running MCLINK. (The xp: device driver is not present in the ROM of the Series 3.) To communicate
over a modem using a Series 3, use the Script language instead (which is included with the 3 Link
software for the Series 3).
MCLINK as a PC file server via the phone system
When used as a PC file server via the phone system, MCLINK assumes that your modem follows CCITT
tules and regulations concerning the RS232 signals - ie
=" The modem drives DSR when powered up, never drops DSR and does not use DSR for any sort
of handshaking. If the modem is physically removed, MCLINK detects this as the DSR signal
disappears. If DSR is not driven MCLINK will not talk to the modem as it does not think it is
there.
« The modem responds to the DTR signal in the following manner - when MCLINK drives DTR
low, (off, inactive) the modem should reset itself - ie disconnect if online etc and eventually
enter its command mode. When MCLINK is exited, it drives DTR low to disconnect any calls
currently connected. When MCLINK is started up it drives DTR low for 2 seconds to try to
force the modem into its command mode, at its default settings.
= The modem only drives DCD when it is on line to a remote modem, and drops DCD when the
connection with the remote modem is lost.
When MCLINK is asked to communicate with a modem it sends the 'aT' command string to the modem
at the following Baud rates: 300, 600, 1200, 2400, 4800 and 9600. It monitors the response to sending this
command, and sets itself to the highest speed at which an "ox" reply was received.
MCLINK then sends the following command stream to the modem to configure it:
"ATX4E0SO=1" if the modem's maximum Baud rate was 2400 Baud or above
“ATX1EOSO=1" otherwise.
MCLINK then reads the user command configuration strings passed to it and sends them to the modem.
All commands sent to the modem are checked for validity by waiting for the modem to respond to the
command sent. If the 'ok' response is received the command worked, otherwise an error is reported. This
will result in MCLINK re-starting.
NOTE: If the user command stream contains any form of reset, then the auto answering of calls should
be re-enabled explicitly.
MCLINK and modem Baud rates
When MCLINK displays the status message Waiting for an Incoming Call the Baud rate displayed will be
the fastest Baud rate that MCLINK found the modem supported. Setting the Baud rate is really a
meaningless exercise since the Baud rate at which the modem connection is made is determined by the
Baud rate of the dialling modem (originator) and not the modem accepting the call.
If MCLINK detects the fastest Baud rate its modem can handle is 2400 Baud or above, it assumes that the
modem has the ability to provide a constant speed interface - ie the modem does not change to the
originator's Baud rate as soon as a connection is established. All modems that can handle Baud rates of
2400 and above must have the constant speed interface since this is the way in which MNP throughput is
normally achieved.
If the fastest Baud rate is below 2400 Baud then MCLINK will set the connection Baud rate to that
reported by the modem when it connects - ie the modem is assumed to change to the originators Baud
rate and MCLINK will follow it. Modems in this class will not support any form of data
compression/correction since a higher Baud rate than the connection Baud rate is required to achieve data
compression.
Link on the MC/HC as a requestor via modem
(This section closely matches the corresponding section above for MCLINK.)
When used on the HC or MC as a requestor via the phone system, Link software on the HC/MC assumes
the modem follows CCITT rules and regulations concerning the RS232 signals - ie
= The modem drives DSR when powered up, never drops DSR and does not use DSR for any sort
of handshaking. If the modem is physically removed, Link detects this as the DSR signal
disappears. If DSR is not driven Link will not talk to the modem as it does not think it is there.
ADDITIONAL SYSTEM INFORMATION
# The modem responds to the DTR signal in the following manner - when Link drives DTR low,
(off, inactive) the modem should reset itself - ie disconnect if online etc and eventually enter its
command mode. When Link is exited, it drives DTR low to disconnect any calls currently
connected. When Link is started up it drives DTR low for 2 seconds to try to force the modem
into its command mode, at its default settings.
= The modem only drives DCD when it is on line to a remote modem, and drops DCD when the
connection with the remote modem is lost.
When Link is run it sends the 'at' command string to the modem at the following Baud rates: 300, 600,
1200, 2400, 4800, and 9600. It monitors the response to sending this command, if it sees an 'oK' it assumes
the modem can be driven at that Baud rate.
Link then sends the following command stream to the modem to configure it:
"ATX4E0SO=1" if the modem's maximum Baud rate was 2400 Baud or above
"ATX 1E0SO=1" otherwise.
Link then reads the user command configuration strings and sends them to the modem. All commands
sent to the modem are checked for validity by waiting for the modem to respond to the command sent. If
the ox' response is received the command worked, otherwise an error is reported. This will result in
Link re-starting.
Link and modem Baud rates
Link will send the dial string to the modem at the Baud rate specified from the Link dialog, or in the case
of the HC at the Baud rate specified in the command line. If no Baud rate is specified, the fastest Baud
rate that the modem responded to (see above) is used. By sending the dial string at the specified Baud rate
the particular type of Vxx connection will be established - eg at 2400 a V22bis, at 1200 a V22, and at
300 a V21 connection. Note that a V23 (1200/75) connection cannot be used.
Note: if you want to use your HC as the file server and the PC as the requestor, swap the above
instructions for 'MCLINK and 'Link'.
Link/MCLINK with MNP
If you have MNP modems do not be surprised if the data transfer rate between your PC and MC/HC is
lower. This is because of the way MNP works.
Typically it is not worth having MNP enabled. The protocol used by Link and MCLINK is based
heavily on the MNP protocol, ie it provides an error free connection between the PC and HC.
EES eee SS SS ee ee ee)
Examples with modems
The first four examples below focus on a PC with MCLINK as a file server. The last two examples focus
on an HC with Link software.
For more information on any of the configuration strings see the appropriate modem manuals.
Using a Dacom QuadPlus MNP 5 compressing modem
Run MCLINK with the following command line:
MCLINK -C&F&C1&D3\N3\J1S0=1
Alternatively, you could set up a .TRM file, eg QUADPLUS.TRM and type
MCLINK @QUADPLUS.TRM
or call the .TRM file MCLINK.TRM and just type
MCLINK
Using an Amstrad SM2400 modem
Run MCLINK with the following command line:
MCLINK -m
1 MCLINK, MCPRINT, AND SLINK.
a ee ee ee
Using a Dowty Quattro SB2422
Run MCLINK with the following command line:
MCLINK -m
Using a WorldPort 1200 pocket modem
Run MCLINK with the following command line:
MCLINK -m
An HC with a Psion Quad modem
Run Link with the following command line:
LINK -n<the phone number> -c\n0
This talks to all of the above PC file server configurations.
An HC with the Amstrad SM2400 modem
Run Link with the following command line:
LINK -n<the phone number>
Ee ee a ae ee a er eee
Mecprint.exe
MCPRINT allows an MC, HC, or Series 3 (or any other serial-printing device) to print to a printer
which is connected to an IBM PC/XT/AT or compatible. The PC must have a free serial port which is
used to connect to the MC/HC/Series 3. The printer may be connected to a parallel or serial port on the
PC.
Even if you can link the MC/HC/Series 3 directly to the printer, there may be reasons why it is more
convenient to use MCPRINT:
= The printer is shared by other PCs - either using a multi-port printer buffer or a local area
network - and it would be unreasonable to connect it directly to the MC/HC/Series 3.
= You do not wish to disturb the connection between the PC and the printer.
= You have already set up the serial connection to use MCLINK for file transfer to the PC.
= When your PC is connected to more than one printer, you can select which one the
MC/HC/Series 3 will use.
Note: it is also possible to print via MCLINK to a printer attached to your PC. To do this, set your
MC/HC/Series 3 to print to a file, and give the printer device on REM:: (such as REM::LPT1) as the "file" to
use. This method may be slower than using MCPRINT - especially when printing "justified" text from
the Word Processor on either computer - and will only work reliably on version 3.0 or above of
MCLINK. However, MCLINK can correct transmission errors, whereas MCPRINT can only report
them. Such errors may occasionally be caused by PC add-ons, such as some network card drivers.
Using MCPRINT
Physically connect the MC/HC/Series 3 to the PC exactly as for MCLINK. If the printer is connected to
LPT1, and MC/HC/Series 3 is connected to comi, you can now run MCPRINT on the PC by typing:
MCPRINT
If LpT1 and com! are not the ports used, parameters are required, as described below.
Exiting MCPRINT
To exit MCPRINT, press CONTROL-C.
ADDITIONAL SYSTEM INFORMATION
Printer configuration on the MC
On the MC, select Print Setup from the Options menu in the System application to display the Printer
dialog. Set one of the configurations to output to Serial. You don't normally have to click on the SET
SERIAL... button to change any of the Serial options because MCPRINT uses the default settings.
Once the current configuration has been set to Serial, you print as if the printer was directly connected to
the MC - by selecting the Print menu item in any application which can print. As far as the MC software
is concerned, it is printing to a Serial printer.
Printer configuration on the Series 3
On the Series 3, select the Printer setup option from the Special menu in the System screen. In this
dialog, set the Printer device line to Serial. You don't normally have to change the Serial characteristics
(it displays a subdialog when you press TAB) because MCPRINT uses the default settings.
You can now print as if the printer was directly connected to the Series 3 - by selecting the Print option
in any application which can print - including the built-in Word Processor, Agenda, Database, and
Program editor. (Remember first to use the Print setup options in these applications, to tell the Series 3
about the type of printer and the page layout desired.) As far as the Series 3 software is concerned, it is
printing to a serial printer.
Parameters
MCPRINT takes the following parameters:
<prdev> -c<port> -t<timeout> -q
all of which are optional. To be reminded of these parameters, type:
MCPRINT ?
The <prdev> parameter
<prdev> is the print device name, as for the MS-DOS print command. If omitted, the default is Lpt1 (the
MS-DOS name for the first parallel port).
For example, to print to LPT2, type:
MCPRINT LPT2
If the PC is a station on a local area network, LPT2, LPT3 etc may be used to redirect output to remote
printers attached to the network server.
The <prdev> parameter may specify any suitable output device. If you have a printer connected to a
second serial port on the PC, you can use:
MCPRINT COM2
In this case, you should have previously used the MS-DOS mope command to set the serial parameters to
be used between the PC and the printer.
You can also print to a file on the PC using, for example:
MCPRINT PRINT.LIS
Note that PRINT.LIS will be overwritten each time you print.
To test the connection without wasting paper, type:
MCPRINT CON
con is the MS-DOS name for the console (screen). When you then print from the MC/HC/Series 3, you
should see the output appear on the screen of the PC.
The -c<port> parameter
<-c> is the serial port on the PC to which the MC/HC/Series 3 is connected. If omitted, the default is
port 1, which corresponds to com1. If the MC/HC/Series 3 is connected to the PC's second serial port,
type:
MCPRINT -C2
10
1 MCLINK, MCPRINT, AND SLINK
The -t<timeout> parameter
<timeout> is a number of seconds. This parameter is provided for use on local area networks where it is
necessary to close and open the print device between each print job. It is used to specify an inactivity
time-out in seconds. If there is no printing for this period, the print device is automatically closed. For
example:
MCPRINT LPT2 -T5
will close the print device after 5 seconds of inactivity.
If the parameter is omitted, the print device is not automatically closed. You don't have to specify a time-
out, as you can close the print device manually by pressing any key on the PC keyboard. Exiting
MCPRINT will also close the print device.
The MC/HC/Series 3 are multi-tasking - while one application is printing, you can carry on with
something else. However, the background printing can be held up at times, depending on the processing
requirements of the work you are doing. This can fool MCPRINT's inactivity time-out into thinking that
the printing has finished, causing it to prematurely close the print device. If you experience this problem,
consider increasing the time-out, or convert to closing the printer device manually by pressing a key on
the PC keyboard.
The -q parameter
This parameter suppresses status messages (the 'q' stands for quiet").
SS SSS SS > ee ee, A)
Slink.exe
SLINK is a "no-frills" server-only version of MCLINK.EXE. However, it may run on “"PC"s which are
less than 100% PC-compatible and cannot run MCLINK, and it may run in combination with other
software which conflicts with MCLINK.
By default, SLINK uses the com1 port, at 9600 Baud. You can specify on the command line the Baud rate
and the serial port to use. These are in the same format as in the set command in MCLINK. For
example:
SLINK -p2 -b9600
This sets SLINK to use com2. Note that, as with the sET command in MCLINK, -b9600 is used in this
example to keep the Baud rate at 9600.
If you just type SLINK -p2 this will reset the Baud rate to the internal default of 19200.
Press Q to quit SLINK.
SLINK has no support for modems.
11
CHAPTER 2
RESOURCE FILES
This chapter covers a range of related topics:
= reasons programmers might consider using resource files
= the format of Sibo .rsc resource files
= the Olib rscfile class that can be used to read resource files
# the Sibo resource compiler tool, rcomp.exe, that can be used to create resource files
= general considerations about multi-lingual applications.
Although the topics are all related, it is by no means necessary to read and understand all the sections in
this chapter, just in order to understand one of these sections.
aS Sa a en Sea ee EE Te
Introduction
There are two main reasons why a programmer may wish to use resource files:
= Having data in a resource file, rather than as part of the program itself, cuts down on the size of
the data segment required by the program, and thus makes more efficient use of RAM.
= Resource files make it easier to write applications that can run in more than one language (eg
English, French, German...).
Text strings are a simple but important example of data that can be stored in a resource file. Suppose a
program contains lines of code such as
winfoMsg("Starting calculation");
and
wSetBusyMsg("Scanning");
or even
p_printf("%d items found",num);
The dataspace of this program, when compiled and linked, would contain the three strings "starting
calculation", "Scanning", and "%d items found" - a grand total of some 45 bytes (note that a terminating
zero is stored for each string). A larger program may have many times this number of data strings; up to
2k would not be uncommon. Now this data would be permanently loaded into RAM all the time the
program is running. As a result, 2k less space would be available to the ordinary data of the program -
such as cells in a spreadsheet, or text in a word processor - thus reducing the amount of such data that the
program can accept before giving an “out of memory" error. Moreover, the operating system would be
more likely to refuse to load and run the program, on account of insufficient memory being available to
Start it.
Next consider how the problem worsens for a program that is to be translated into more than one
language. Either the program has to carry the data for all the different target languages, with a choice
being made at run time between the various different possibilities:
13
ADDITIONAL SYSTEM INFORMATION
if (language==LANG_ENGLISH)
wSetBusyMsg("Scanning");
else if (language==LANG_FRENCH)
wSetBusyMsg("'Parcourt");
else if (language==LANG_GERMAN)
wSetBusyMsg("Suche") >:
or else the code will have to be recompiled each time for a new language. But this latter approach makes
the problem of maintaining code much harder; each different change made to the code, such as a bug fix,
will have to be propagated to all the different language versions. At the same time, the job of the
translator is not helped by the text to translate being all mixed up with the rest of the code, whilst if the
translator works on a separate list of text strings, there is the risk of transcription errors when the
separate lists are merged back into the code.
For reasons such as these, serious programming in any system (Sibosdk or otherwise) frequently adopts
one or other resource file approach for text strings and other data items. The strings "starting
calculation", "Scanning", "%d items found", and so on, are kept in a separate file, not as part of the
dataspace of the program, and are loaded into RAM only when they are needed.
Thus the above call
winfoMsg("Scanning");
would be replaced by a call such as
InfoMsg(RESOURCE_SCANNING);
where RESOURCE_SCANNING is a symbolic constant (#define) giving the index of the text string "Scanning" in
the resource file. (The exact meaning of the index varies between different resource file schemes. See
below for the meaning in Sibo resource files.)
The contents of the routine InfoMsg would be something like
LOCAL_C VOID InfoMsg(INT index)
{
TEXT buf [60];
LoadResourceString(&buf [0] , index);
wiInfoMsg(&buf [0] );
}
and in turn LoadResourceString would read data from the appropriate resource file.
At the initialisation of the program, the name of the appropriate resource file would be determined, once
and for all, by reference to the current language (as obtained by a call to p_getlanguage).
Some uses of resource files on Sibo computers
Each of the built-in or bundled applications on the MC and Series3 ranges has its own resource file, in
which are kept menu and dialog data, as well as more basic text strings. The dialog data can contain
numerical layout information and numerical flags customising individual items within dialogs.
Since the text strings and dialogs used by these different applications often overlap, there is also a so-
called system resource file, where common items are kept. Thus an application loads data at various
times from each of two different resource files - its own application resource file, and the system one.
The .wdr printer driver files used by the printer subsystem in form.dyl (as on the Series3 - see the WDR
Printing chapter in this manual for more details) are also resource files, with the data items consisting of
escape sequences, font width tables, and other printer data.
Finally, low-level error messages are defined in another file in the ROM, sys$ctry.cfo. This file also
contains the keyboard layout tables, the fold tables, and other standard text such as the names of the days
of the week. See the Config Files chapter for more details.
14
2 RESOURCE FILES
(Se a ee a a ee ee i ee eer |
Format of Sibo resource files
There are in fact three kinds of Sibo resource files:
a .cfo files, which are language configuration files (sometimes just called config files), with
sys$ctry.cfo being the principle example
® .rsc files, which are standard resource files
= .rzc files, which are Huffman compressed versions of .rsc files.
Access to the data in .cfo files is via Plib functions such as p_errs, p_gettext, and p_nmmon, as described
in the Plib Reference manual.
Data in .rs¢ and .rzc files can be accessed using the functionality of the rscfile class in olib.dyl, as
described later in this chapter.
The Sibo resource compiler, rcomp.exe, can be used to create instances of .rsc files from plain text input
known as resource scripts, which typically have extension .rss. This process is also described later in
this chapter. However, the format of .rsc files (described immediately below) is so straightforward that
programmers could easily create their own tools for producing customised .rsc files.
Unless explicitly stated to the contrary below, the remainder of this chapter focuses exclusively on the
.rsc type of resource files.
The format of .rsc files
A standard resource file just containing the three strings "starting calculation", "Scanning", and "%d
items found", has the following contents (when dumped):
O: 31 00 08 00 53 74 61 72 74 69 6e 67 20 63 61 &c 1...Star ting cal
10: 63 75 6c 61 74 69 6f 6e 00 53 63 61 6e Ge 69 Ge culation .Scannin
20: 67 00 25 64 20 69 74 65 6d 73 20 66 6f 75 be 64 g.%4d ite ms found
30: 00 04 00 1900 220031 00 — ~— Jeeee ws 1s
This conforms to the pattern:
<header><resources><index table>
where:
<header> is always four bytes long, with the first word giving the file offset of the start
of the index table, and the second word giving the length (in bytes) of the
index table
<index table> is a sequence of words, the first giving the file offset of the start of the first
resource, the second giving the file offset of the start of the second resource,
and so on, up to the last word, which gives the file offset of the end of the last
resource (which is also the beginning of the index)
<resources> are a series of variable length data items, whose contents can have any form.
Some strategies for reading .rsc files
Clearly, one way to implement a routine such as LoacResource is essentially as follows:
GLDEF_C VOID LoadResource(UBYTE *pb,INT index)
ULONG fpos; /* file offset */
UWORD tmp[2]; /* section of index table */
fpos=ixpos+(( index-1)*2);/* position into the index table */
p_seek(fcb,P_FA8S,&fpos);
p_read(fcb, &tmp[0] ,4); /* read two words from index table */
fpos=tmp [0] ;
p_seek(fcb,P_FABS,&fpos);
p_read(fcb, pb, tmp[1]-tmp[0] );
>
where:
« feb is the file control block of the open resource file
15
ADDITIONAL SYSTEM INFORMATION
= ~ixpos is the value of the first word in the resource file (ie the file offset of the beginning of the
index table), and has been read into memory during program initialisation, for the sake of
efficiency
® the passed value of index in this case would be 1 for the first resource, 2 for the second resource,
and so on
# the code would need modifications to cope with possible error values returned by the p_seek or
p_read calls (further discussed below).
This strategy relies on a value of ixpos being stored in program memory. Another strategy would be to
store the entire index table in memory - and this is the reason why the length of the index table is
recorded as the second word in the resource file. However, in practice there is no observable speed
degradation on account of reading index table data from the file every time a resource has to be loaded,
and so the earlier scheme is generally to be preferred - in view of the lesser demand it places on RAM
usage.
Example of reading resource files directly
See the file readrsc.c in \sibosdk\demo for an example of how to read the contents of a resource file
directly (i.e. without using the services of the rscfile class).
This example code assumes that the resource file is embedded in the application's program (.app) file.
Thus, when used in an application, the name of the resource file should be specified on the second line of
the application's .afl file.
To use the example code, you must create a resource file with its first two resources both being short text
strings. Any additional resources are not read by the supplied code.
bn |
Using the rscfile class in Olib
Although it is possible, along the lines discussed above, to read .rsc resource files using ordinary Plib
function calls, there are various reasons for instead using the functionality of the rscfite class in
olib.dyl:
= Using the rscfile class avoids needing to remember any details of the format of .rsc files
= The rscfile class also contains considerable logic, hidden from the casual user, to decode .7zc
Huffman compressed resource files - so that a decision can be taken at a later stage, to use .7zc
format files instead of .rsc format, without any need to alter or recompile existing code
= The rscfile class automatically takes care of locating resource files suitably embedded in a .img
file - see below for more details
= The interface to the rscfitle class clarifies and documents all the possible error conditions that
need to be catered for
= Learning about the rscfile class is a useful step along the route to learning about Psion's
proprietary object-oriented programming system - since this system makes heavy use of the
rscfile class.
Basic services of the rscfile class
Before the functionality of the rscfile class can be used in a program, an instance of this class needs to
be created and initialised. This is dealt with below.
The outcome of the initialisation is a handle, rather like a handle to a file control block or to other i/o
device control blocks. Subsequent rscfite services are directed via this handle.
The most primitive rscfile service is to load a resource, specified by index number (starting at 1 for the
first resource), into a supplied buffer. This is the rs_read_buf service. In this case, it is assumed that the
caller has supplied a sufficiently long buffer.
Sometimes, however, it is more appropriate for the rscfile class to allocate a cell of sufficient length, for
the resource to be loaded into. This typically applies when a resource can have variable length, and
when the resultant alloc cell will have some permanence. The rs_read service fulfils this requirement.
16
2 RESOURCE FILES
As an example of the rs_read_buf service, consider the following routine InfoMss:
LOCAL_C VOID InfoMsg(INT index)
{
TEXT buf £60] ;
p_send4(rcb,0_RS_READ_BUF, index, &buf [0] );
wInfoMsg(&buf [0] );
>
with reb being the handle of a suitably initialised rscfile object.
As an example of the rs_read service, consider loading some menubar data in from a resource file. For
Hwif programs, this data is (in part) in the form of an H_MENU_DATA struct. The address of this struct has
to be written to the static _mdata (of type H_MENU_DATA*) whose existence the Hwif library presupposes. In
that case, the following call might be made during the initialisation of an Hwif application:
p_send4(reb,O_RS_READ,MENU_DATA_INDEX,& mdata);
where MENU_DATA_INDEX is a symbolic constant giving the index of the appropriate resource.
Note that although the calling interface to rs_read_buf and rs_read may look similar, they require
different types for the penultimate parameter:
= rs_read_buf requires a parameter such as a TEXT* or a UBYTE*, ie with one level of indirection
from the actual loaded data
= rs_read requires a parameter such as a TEXT** or a UBYTE**, ie with two levels of indirection from
the actual loaded data.
Barring run-time errors (discussed below), the calls rs_read_buf and rs_read both return the length of the
resource read. Note that in the case of a (zero-terminated) string, this length includes the length of the
terminating zero, since that is part of the resource too.
Reading compressed resource files with the rscfile class
If a Huffman compressed resource file, typically with extension .rzc, is substituted for a standard
resource file (typically having extension .7sc), there is no need to alter or recompile in any way
application code making use of the rscfile class. The interface remains exactly the same.
The only point possibly worth mentioning is that the lengths returned by rs_read and rs_read_buf are the
length of the resources once decompressed, and not the length of the compressed resources on file.
Initialising an rscfile object
The following code can be used to create and initialise an rscfile object providing access to a resource
file with name rscname (assumed to be a full path name):
VOID *InitReb(TEXT *rscname)
{
HANDLE OlibCat;
VOID *reb;
INT ret;
p_findtib("OLI8.DYL",&0libCat);
rcb=p_newlibh(Ol ibCat,C_RSCFILE);
if (reb)
{
ret=p_entersend3(rcb,O_RS_INIT,rscname);
if Cret<0)
p_exit(ret);
D
return(rcb);
>
For overtly object oriented programs, the lines
p_findlib¢"OLIB.DYL",&0libCat);
reb=p_newlibh(OlibCat,C_RSCFILE);
17
ADDITIONAL SYSTEM INFORMATION
can be replaced by a line such as
reb=p_new(CAT_HWIF_OLIB,C_RSCFILE);
with the category number CAT_HWIF_OLIB being replaced by the suitable reference to olib.dyl from the
native category.
For Hwif programs, the line
rcb=p_new(1,C_RSCFILE);
can be used instead, taking advantage of the fact that the value of the (normally hidden) symbolic
constant CAT_HWIF_OLIB is 1.
Which header files are needed
The symbolic constants C_RSCFILE, O_RS_READ, O_RS_READ_BUF, and O_RS_INIT, are defined in the object-
oriented include file appman.g.
Duplicates of these definitions are given in the special SDK file rscfile.xg.
The value of o_pEstroy (defined in olib.g) is 0. (See below for use of o_DESTROY.)
Run-time errors with the rscfile class
Broadly speaking, there are five kinds of run-time error that can arise with resource files:
there is insufficient memory to create or initialise the rscfile object
the resource file cannot be found (when the program starts)
the data in the resource file is bad
the SSD containing the resource file is removed or cannot be accessed
vA F&F WwW NY &
there is insufficient memory to load a specified resource.
Of these possibilities, the third is regarded simply as a programming error. Thus if some data in what
should be the index table part of the file effectively says that a certain resource has length 5398 bytes,
whereas the file itself is smaller than this size, the rscfile object will panic the application (with panic
number 141).
Otherwise, errors 1 and 2 can occur when initialising a rscfile object, whereas error 4 and 5 can occur
when subsequently using the object.
Possible errors during initialisation
The only reason the calls p_newl ibh or p_new in the above routine InitReb will fail is on account of lack of
memory. Applications can choose to discount this possibility if their minimum heap is appropriately
calibrated - see below.
The call to rs_init can fail with file-based errors on account of the filename in *rscname. The most
pertinent possibility (assuming that a well-formed name has been passed) is that the specified file does
not exist. Applications could guard against this by checking on the existence of the file prior to calling
InitReb. If the file does not exist, the user can be notified, and the program exited.
Errors during rs_read or rs_read_buf
The only errors that an application should in practice worry about, for the rs_read and rs_read_buf
services, are the fourth and fifth in the above list.
Running out of memory can occur only in the case of rs_read - when it is impossible to allocate a call
from the heap large enough to load the resource into. The implementation of rs_read_buf is guaranteed
never to fail with out of memory.
If calls to rs_read are made during program initialisation only, it may well be legitimate to ignore the
possibility of out of memory errors in this case too - provided the declared minimum heap of the
application is large enough. The point is that only memory in the dataspace of the application has to be
allocated - not any memory in another process such as the File Server (see the chapter Fundamental
Programming Guidelines in the General Programming Manual for related discussion).
However, applications calling either rs_read or rs_read_buf ought always to consider the possibility of
the user removing the SSD containing the resource file. What will happen in this case is as follows:
18
2 RESOURCE FILES
= — suppose the user removes the relevant SSD, not realising (or forgetting) that the program may
wish to access data on it
= the application makes a call to rs_read or rs_read_buf
= system code, detecting that the file is missing, presents a Notifier requesting the user to replace
the SSD; this Notifier has two exit options: Retry and Fail
= the user ought to replace the SSD and select Retry; however, it is possible that the Fail option
will be selected
® in this case, an error such as E_FILE_ABORT will be generated.
How rscfile errors are reported
The rscfile services rs_read and rs_read_buf do not return any error values; instead, they internally call
p_leave.
Applications performing sophisticated error handling, using p_enter, should be sure that p send calls to
rs_read OF rs_read_buf are (ultimately) enclosed in some call to p_enter - otherwise any errors will result
in their application being panicked, with panic number 47.
Applications not wishing to use p_enter should replace the above calls to p_send with calls to
p_entersend, as follows:
ret=p_entersend4(rcb,O_RS_ READ BUF, index, &buf [0] );
and
ret=p_entersend4(rcb,0_RS_READ,MENU_DATA_INDEX,& mdata);
Possible values of ret that can be returned are as follows:
positive value the length of the resource loaded (no error has occurred)
negative value an error has occurred: either E_GEN_NOMEMORY for out of memory, or some other
value in case the resource file could not be accessed.
Note incidentally that the complications over possible errors while reading resource files are by no means
exclusive to the .7sc format of resource files. An application could devise its own format of data file,
and its own library of routines to extract data from these files, but these routines would have to cope with
all the same error possibilities as for the rscfite routines. That is, the error possibilities stem not from
the rscfile class, but from the notion of resource files itself.
Dealing with errors in rs_read or rs_read_buf
(This section should be skipped on a first reading.)
There follows a more detailed example of how to deal with possible errors during an rs_read call. The
case for rs_read_buf is similar, albeit simpler (since there is no possibility of an out of memory error in
this case).
19
ADDITIONAL SYSTEM INFORMATION
LOCAL_C VOID ReadResource(VOID *ppcell,INT index)
INT ret;
FOREVER
{
ret=p_entersend4(rcb,O_RS_READ, index, ppcell);
if (ret>=0)
return;
while (ret<0)
¢
if (ret==E_GEN_NOMEMORY)
{
*ppcell=NULL;/* signal failure to caller */
Tel LNoMemory( );
return;
>
wsAlertW(WS_ALERT_CLIENT,0O,ReplaceDisk,0);
p_send2(rcb,0_DESTROY);
FOREVER
reb=p_newlibh(OlibCat,C_RSCFILE);
if (reb)
break;
Tel LNoMemory();
>
ret=p_entersend3(rcb,O RS_INIT,rscname);
>
}
>
One way to implement the routine Tel \NoMemory - which must never itself run out of memory - would be
as follows:
LOCAL_C VOID Tel lNoMemory(VOID)
TEXT buf £40];
p_errs(&buf [0] ,£_GEN_NOMEMORY );
wsALertW(WS_ALERT_CLIENT,0,&buf[0} ,0);
>
The way ReadResource works, in cases when the user has removed the SSD and has refused to replace it,
is to present another alert, wait for the user to respond (by pressing ESC), and then try to re-make the
connection with the resource file. For this purpose, various statics are accessed:
OlibCat The value of the category handle of olib.dyl, as returned by the earlier call to
p_findlib
rscname The full path name of where the resource file should be
ReplaceDisk Text that might read, in English, "Replace the application disk”.
Clearly, for multi-lingual applications, the string ReplaceDisk must itself be read from a resource file.
Since the channel to the application resource file is broken at this stage, it may be necessary to read in
this text during program initialisation.
Standard practice for applications on a Series3 is to bracket calls to wsAlertw with increments and
decrements to the reserved static DatLocked:
DatLocked++;
wsAlertW(...);
DatLocked--;
Incidentally, the error handling mechanism described above is implemented automatically for object
oriented programmers who use the appman class and its methods am_load_resource and am_res_buf to read
data from resource files (except that the error recovery code in appman is even better, in that it caters with
the case of the SSD being removed from one drive and replaced in another).
20
2 RESOURCE FILES
SSS ee ee ee
Advice on where to locate resource files
Mono-lingual applications
In the case of a mono-lingual application, the safest place to locate a resource file is within the image file.
The rscfile class will find any resource file in the second of the four possible add-file slots in an image
file.
For example, if the application is called archive.app and the resource file is called archive.rsc, an add-
file list archive.afl should be created, with the following contents:
archive.pic
archive.rsc
where archive.pic will be placed in add-file slot 1, and archive.rsc in add-file slot 2.
The named files will be added to the resultant image file, whenever this is made, just by virtue of the
existence of an .afl file with the same basic name as the image file.
In this case, the appropriate name to pass to rs_init is simply DatCommandPtr (recall that a zero-terminated
string giving the full path name of the image file is placed at this reserved static, by the operating system,
when the process is started):
p_entersend3(rcb,O_RS_INIT,DatCommandPtr);
Not only does this scheme have the advantage of simplicity, it also prevents accidents if users copy the
main image file to an SSD, but neglect to copy the associated resource file.
For a multi-lingual application, the above continues to apply in any case when a different .img file is re-
made (using the tool eremake) for each new language version. (For more details about eremake, see the
chapter Building an Application in the General Programming Manual.)
However, for multi-lingual applications in which the resource data for more than one language is shipped
together, the resource files must in general be separate from the main .img file. (There is no scope for an
indefinite number of add-files.) The documentation for the application should emphasise to users that if
the .app file (or the .img file) is copied from one SSD to another, for consolidation purposes, then
appropriate .rsc (or .7zc) files should also be copied.
Multi-lingual applications
One scheme that has much to recommend it is to rename the resource files as follows:
archivO2.rsc for a French language resource file
archiv03.rsc for a German language resource file
archiv18.rsc for a Dutch language resource file
and so on (for an application archive.app), where the numbers at the end of the filename are the language
codes of the target languages, listed in the documentation of p_get language in the Plib Reference manual.
These files should be located in a sub-directory underneath the directory containing the application
program file. The name of this subdirectory should be the same as the basic name of the program file.
For example, if the full pathname of the program file is \app\archive.app, the full pathnames of the
resource files should be \app\archive\archiv??.rsc. Again, resource files used by a program with full
pathname \imng\backup.img should be located as \img\backup\backup??.rsc.
Then code to determine the name of the resource file, suitable to the language of the computer at run
time, could be as follows:
21
ADDITIONAL SYSTEM INFORMATION
TEXT *FindRscName(VOID)
LOCAL_D TEXT RscNameBuf [P_FNAMESIZE];
TEXT *RscName;
P_INFO f;
RscName=(&RscNameBuf (0) );
p_atos(RscName,"\\app\\archive\\archivz0ed.rsc",p getlanguage());
p_fparse(RscName, DatCommandPtr ,RscName,NULL);
if (p_finfo(RscName,&f)<0)
p_scpy(RscName,DatCommandPtr);
return(RscName);
>
Note the check on the existence of the first filename generated by this routine; in case the language as
returned by p_getlanguage is not supported by the application, the routine defaults back to whatever
resource file is built into the application.
Copying of applications
The above recommendation for where resource files should be located conforms to the important general
rule that if users wish to copy an application \path\name.ext from one SSD to another (say from drive a:
to drive b-), all they need to do is type
copy a:\path\name.ext b:\path\name. ext
copy a:\path\name\*.* b:\path\name\*.*
in which case (assuming the application is not copy-protected!) all the files required or presupposed by
the application will be transferred.
ee ee es ae ee ee a en eee
General comments on multi-lingual applications
It is a common programming error to design an application too closely around the text of one language
(eg English), and to discover only at some late stage that various assumptions made fail when the
application is translated into another language.
For example, if the English text "Weekly" is to be read into some resource, it may be tempting to write
some code as follows:
TEXT buf [8];
p_entersend4(rcb,O_RS_READ_BUF ,WEEKLY_INDEX,&buf (01);
However, when the application is translated into German (say), with the entry for "Weekly" in the
resource file being changed into "Wéchentlich", the new application will most likely crash when the above
code is run. The reason is that the buffer of eight bytes, which was long enough to contain the text
"Weekly", is not long enough to contain "Wéchentlich".
Better therefore to decide in advance what a reasonable limit on the translation of this term should be,
and use that as the size of the buffer in the code (not forgetting to inform the translators what the limit
is).
The basic principle of independence of code from resource file
One basic guideline is that the code itself should not have to be altered, just because a new translation has
been undertaken. The original code should be general enough to start with.
The main problem with allowing code to change at a later date, to simplify the task of translators, is that
it is often difficult to foresee the side-effects of such a change. In practice, the most intense testing an
application receives is just prior to its launch in the original language; if changes are made at a later date,
these may introduce bugs which slip through subsequent testing, on account of that testing being less
severe.
For this approach to work, a special test plan has to be devised, focussing on the purely language
dependent parts of the application. This test plan should include means of loading, one by one, ail the
resources from the resource file, and displaying them on the screen for validation.
22
2 RESOURCE FILES
Provided changes made in response to problems thrown up by this test plan are restricted to the resource
files themselves, there can be some confidence that the original intensive testing still holds good. But if
code has to be changed, there is the risk of regression - something that used to work now no longer
works.
Careful design of screen layout
Design of screen layout is another area where things can go unexpectedly wrong when the contents of a
resource file is changed.
In some cases, screen layouts which (just) work in one language, become untenable in another language,
because there simply is no acceptable way of translating the text on the screen and still fitting within the
allowed display area. For this reason, displays which are already cramped in the original language
should be avoided: if they are cramped in one language, they will likely become "grid locked" in some
other language, with slightly longer words.
Even if there is ample room in some screen display, care should be taken to calculate various dimensions
dynamically, ie at run-time, using the widths of the actual characters used, rather than statically (ie at
compile-time).
Codesize problems
For related reasons, an application which, together with its resource file, only just fits on an SSD of a
certain size (say 128k), will be unlikely to fit on a similarly-sized SSD when the resource file has been
translated into another language.
Of course, as with the other problems above, it is always possible to insist that a sufficiently brief
translation be found, but this can result in abbreviations the user is likely to consider ridiculous. It is far
better to include some “spare” in the original budget, to allow for some measure of growth as the
translation takes place.
Varying keyboards
As well as the text of messages varying from one language to another, it is also possible for the keyboard
layout to alter. This does not just mean changing from qwerTy to AZERTY, but changes in which characters
can be typed in combination with various modifiers.
For example, an application in one translation may define the hot-key PSION +/ as the accelerator for
some menu command. However, a foreign language keyboard may move the / key into a place where it
cannot be pressed in conjunction with the PSION modifier. Thus on the Series3 keyboard, PSION together
with some keys changes the characters delivered, into altogether different ones. Therefore, the
accelerator would have to alter to some other keypress.
Something else that may have to change, on account of the keyboard changing, is references to the
keyboard within eg Help text (or inside "Action buttons"). For example, the DELETE key may become
the EFF key in a different language variant.
Conclusion
The possible problems of multi-lingual code form another item in the list of things that need to be
constantly under background consideration as an application is written.
The discipline of separating text into a resource file is a vital step in the right direction, but by itself, it
does not guarantee that all related problems will be solved. Every time text is used in an application, the
writer must ask the question: not what is the length of this text, but what might the length of this text be
in some foreign translation - and what would the consequences of that be?
LSS LSS ee a |
Creating .rsc files using rcomp.exe
The resource compiler is a tool rcomp.exe that operates on a so-called resource script, which is a text
file, to produce a resource file as output.
The process is akin to ordinary compilation:
*.c + compiler -> *.obj
*.rss + resource compiler -> *.rsc
with .rss being the usual extension for a resource script.
23
ADDITIONAL SYSTEM INFORMATION
As an example, suppose a file eg.rss has the following contents:
STRUCT STRING
TEXT str; /* zero terminated text string */
>
RESOURCE STRING res_start_cale {str="Starting calculation";}
RESOURCE STRING res_scanning {str="'Scanning";}
RESOURCE STRING res_items_found {str=""%d items found"';}
Then invoking the command line
rcomp eg
produces as output a file eg.7sc whose contents are exactly as described in the earlier section on the
format of .7sc files.
Note: some earlier versions of rcomp.exe do not accept the syntax
RESOURCE <struct-name> <identifier> <definition>
instead requiring the addition of the keyword GLOBAL:
GLOBAL RESOURCE <struct-name> <identifier> <definition>
Generated .rsg files
As well as producing a .rsc resource file, running rcomp.exe also has the effect of creating a generated
header file, with extension .rsg.
Thus the output of typing rcomp eg is not only the file eg.rsc but also the file eg.rsg, having the
following contents:
#define RES_START_CALC 1
#define RES_SCANNING 2
#define RES_ITEMS FOUND 3
In turn, C source files that need to specify resource indices ought to #inctude these generated .rsg files,
so that they can include code such as
InfoMsg(RES_SCANNING);
The present value of RES_SCANNING is 2. Suppose however that a new resource is added at the beginning
of eg.rss. This means that the resource "Scanning" is of course no longer the second in the resultant .7sc
file, but the third. Accordingly, any calls such as
InfoMsg(2);
have to change into calls such as
InfoMsg(3);
in order that they have the same effect as before. Note that having these lines of code instead as
InfoMsg(RES_SCANNING);
and recompiling the C source files after changing the resource script automatically ensures that the
desired outcome transpires.
The syntax of the rcomp command
The syntax for invoking rcomp.exe includes:
rcomp [-s]<name> [-o<oname> -h<hname>]
where
<name> is the name of the resource script
<oname> is the name of the resource file output
<hname> is the name of the generated header file.
One possible use of the fuller syntax is to redirect the generated header file to an .. \include\ directory.
24
2 RESOURCE FILES
ee SS Eee
Include files within a resource script
A resource file can contain lines such as
#include “archive.dh"
or
#include <archive.rh>
(no particular significance should be attached to the extensions used in these examples). As would be
expected, files specified using the quote form of #include are expected to be found in the local directory.
However, files specified using the angle bracket form of #include are expected to be found in the
directory (if any) specified by the value of the DOS environment variable INCLUDE.
If required, a batch file such as follows could be used to invoke rcomp..exe:
set OINCLUDE=%INCLUDEX
set INCLUDE=..\include
\sibosdk\sys\rcomp %1
set INCLUDE=ZOINCLUDEX
set OINCLUDE=
preserving any previous value of INCLUDE for other purposes that may apply on a PC.
Conditional compilation in resource files
Note that the resource compiler supports conditional compilation such as
#1 fdef BUILD_ONE
#endif
and
#ifndef BUILD_ONE
#endi f
Names (such as BUILD_ONE) may be defined when invoking the resource compiler using a -d flag as
follows:
rcomp resfile -dBUILD_ONE
This has the same effect as including the corresponding #define in the resource file, for example:
#define BUILD_ONE
ESE ———— ee a ee ae el
Contents of .rss files
Resource scripts (together with other files they #include) are made up of three types of statement:
= comments (identified by C-style /* and */ delimiters)
« declarations of structs and constants
= declarations of REsourcEs, which are instances of the structs defined.
All the declarations of structs have to precede the first definition of a RESOURCE.
White space is ignored (after the first white space character), except within quoted strings. Thus the
definitions
RESOURCE STRING res_start_cale {str="Starting calculation";}
and
RESOURCE STRING res_start_calc
str="Starting calculation";
>
25
ADDITIONAL SYSTEM INFORMATION
are equivalent. Any indentation of source lines in resource scripts is purely for convenience.
Declaring STRUCTs
STRUCTS are formed of a name and a series of member definitions. stRucT names must always be given in
upper case, whereas member names are given in lower case. For example,
STRUCT STRING
TEXT str;
>
defines a STRUCT with name STRING and just one member, which has type TEXT and member name str.
Again, the definition
STRUCT MENU_BAR_ITEM
{
LINK menu_id;
TEXT mb_item;
}
defines a struCT with name MENU_8AR_ITEM and with two members, the first with type LINK and the second
with type TEXT.
As is discussed below, member definitions can also include default initialisations.
Possible member types in STRUCTs
The set of allowed struct member types is as follows:
BYTE Stores a numerical value in one byte
WORD stores a numerical value in two bytes
LONG stores a numerical value in four bytes
DOUBLE stores a floating point numerical value in eight bytes
TEXT stores a zero-terminated sequence of bytes, including the terminating zero
LINK stores a two-byte reference to another RESOURCE
STRUCT Stores a sub-STRUCT in-line.
Of these types, only Text and struct have variable length (see below for more on variable length items).
worDs are stored low byte first then high byte. Similarly, LonGs are stored low word first, then high word.
The resource compiler accepts any value from -128 to +255 for a BYTE, so that C programs are free to
interpret the contents as either signed or unsigned. worD and Lonc can similarly be interpreted either as
signed or unsigned.
The resource compiler can undertake some limited arithmetical evaluation of data supplied in numeric
fields (eg val=4*3.18).
TEXT data can be entered as a combination of quoted strings, binary values, and symbolic constants:
str="This is a string.";
or
str=<84><104>"is a str<0x69>"ng"<46>;
or even
#def ine DOUBLE QUOTE <34>
str="Missing "DOUBLE_QUOTE;
Standard C-style processing of backslashes applies within quoted strings. Thus to enter a single
backslash in a string, the backslash character has to be repeated in the input, and so on. Thus the final
example above could also be given as
str="Missing \"";
26
2 RESOURCE FILES
Allowed values of LINK items are constants, symbolic constants, or (lower-case) identifiers of other
resources. In referring to another resource, both forward and backward references are possible.
Declaring RESOURCEs
A RESOURCE is declared by specifying:
= the name of the struct being instanced
a the identifier of the RESOURCE
= = initialisers: values of all the members of the struct.
The name of the struct must always be given in upper case, whereas the identifier of the RESOURCE must
always be given in lower case.
For example:
RESOURCE MENU_BAR_ITEM file_mbar_item
menu_id=file_menu;
mb_item="File";
>
During resource compilation, the various identifiers encountered are assigned the values 1, 2, 3, ....
There is no requirement to list the members of the struct in the same order as their definition. Nor is it
always necessary to give values for every member:
® any member omitted will be given the default value supplied for that member, in the declaration
of the struct, if any
® failing this, a "default default” value of zero will be supplied
s however, it is an error to omit altogether to give a value for a LINK member.
For example, it is possible to declare an instance of
STRUCT NCEDIT
{
WORD current;
WORD low;
WORD high=65535;
>
just by the line
RESOURCE NCEDIT ne_edit { }
in a resource script, in which case a 6-byte long resource will be created, with the three consecutive
words containing the values 0, 0, and 65535.
Again, the result of resource compiling the following:
STRUCT TEST
TEXT str;
BYTE byt;
STRUCT more;
>
RESOURCE STRUCT TEST empty € >
is a 2-byte long resource, with each byte being set to zero. (Note that "zero" sub-sTRUCTS are omitted in
their entirety, ie taking up zero length in the resource file.)
Declaring the values of sub-STRUCTs
Whereas the way to define the value of most members of REsourcEs is by a statement in the form
<member-name> = <constant>;
27
ADDITIONAL SYSTEM INFORMATION
the way to define the value of a sub-struct member is
<member-name> = <struct-name> {<initialisations>};
with the form of <initialisations>, if present, matching that of the definition of a REsouRcE itself. For
example:
STRUCT NCEDIT
WORD current;
WORD low;
WORD high=65535;
>
STRUCT TEST
TEXT str;
BYTE byt;
STRUCT more;
>
RESOURCE TEST values
str="This is a string";
byt=42;
more=NCEDIT {current=100;};
>
In the majority of cases, when a sTrucT is declared as having a sub-sTRUCT member, this member will be
intended to be a strucT of one particular type. Note, however, that the type of the sub-strucT member is
not specified by the struct in which it is declared (for example, Test does not specify that the sub-sTRuCT
more is of type NceDIT). In consequence, it is possible to have two or more resources that are both based
on the same struct definition, but use different types of sub-struct.
Leading byte and word length values
In cases when sTrUCTs contain sub-sTructs, it is frequently helpful to have the instance of the sub-sTRUCT
preceded by a byte or word giving the length of the instance. This is achieved by amending the
definition of the sub-struct: the keyword BYTE or WORD should be included before the opening curly
bracket prior to the definitions of the members of the struct.
For example, resource compiling
STRUCT FIRST BYTE
BYTE one;
>
STRUCT SECOND WORD
BYTE two;
>
STRUCT THIRD
BYTE three;
>
STRUCT FOURTH BYTE
{
STRUCT a;
STRUCT b;
STRUCT c;
}
RESOURCE FOURTH test
a=FIRST {one=1;);
b=SECOND ({two=2;};
c=THIRD {three=3;);
>
28
2 RESOURCE FILES
results in the following 6-byte long resource:
<01><01><01><00><02><03>
in which the first byte gives the length of the following sub-resource, the third and fourth bytes together
constitute a word giving the length of the second sub-resource, and the final sub-resource has no
preceding byte- or word- length value.
Note that the resource as a whole lacks a leading byte- or word- length value, despite the presence of the
BYTE qualifier in the definition of FourtH. These leading length values are inserted only when the instance
of the STRUCT is as a sub-resource.
Incidentally, it is common for definitions such as
STRUCT FIRST BYTE
BYTE one;
>
to be given instead in the equivalent form
STRUCT FIRST
BYTE ¢
BYTE one;
>
Arrays within resource files
The resource compiler is at perhaps its most powerful in dealing with arrays of resources - strictly
speaking, arrays of sub-resources.
In order to declare an array of sub-resources, a member definition in a struct definition such as
<type> <member-name>;
has to be changed into one of the forms
<type> <member-name> [<array-size>];
<type> <member-name>[ J;
LEN <type> <member-name>{ 1;
or
LEN BYTE <type> <member-name> [ 1;
For example,
STRUCT HELP_ARRAY
{
LINK topic_id=0;
TEXT topic;
LEN BYTE STRUCT strist{);
}
in which the initial LINK and TEXT sub-resources are followed by a variable number of sub-structs (the
number varying between different instances of HELP_ARRAY).
In all cases with arrays, the corresponding initialiser statement in a RESOURCE definition
<member-name> = <constant>;
changes into the form
<member-name> = { <constant>, <constant>, ..., <constant> };
with <constant> being replaced by <struct-name> {<initialisations>} in the case of an array of sub-
STRUCTS.
For a variable sized array, the array of sub-resources may be preceded in the resource file by a byte or
word giving the number of elements actually in the array. This count is recorded in a word if the prefix
LEN is used, and in a byte if the prefix LEN BYTE is used.
29
ADDITIONAL SYSTEM INFORMATION
Evidently, the number of sub-resources that actually occur in any given instance of the struct is
determined by the syntax of the intialiser, with all but the last element being preceded by a comma.
For example, resource compiling
STRUCT STRING
TEXT str;
}
STRUCT HELP_ARRAY
{
LINK topic_id=0;
TEXT topic;
LEN BYTE STRUCT strist{(];
>
RESOURCE HELP_ARRAY sys_help print
topic="How to print";
strist=
STRING {str="Set Printer Model with Print setup'";},
STRING {str="in Word/Agenda/Data, then use 'Print!";}
7
>
produces a single resource in which:
= the first word is zero (the supplied default value for the topic_id member)
® then there follows the sub-resource "How to print"
= next comes a byte containing the value 2, being the count of the items in the following array
® finally the strings "Set Printer ..." and "...Print'™ are juxtaposed.
Creating SYSTEM resource files
For completeness, it should be mentioned that the resource compiler enters a special mode if the first line
of a resource script is found to consist of precisely the single word
SYSTEM
In this mode, all LINK references are automatically resolved with the negative of the correct value.
Thus whereas the resource script
STRUCT STRING {TEXT str;}
STRUCT TEST {LINK Lnk;}>
RESOURCE STRING alpha {str="Xyz";}
RESOURCE TEST beta {Lnk=alpha;}>
results in the second resource consisting of the word 1, inserting a line
SYSTEM
at the beginning of the resource script changes the value of this resource to -1.
The rationale of this behaviour is connected with the facility offered to object-oriented programmers by
the appman class in olib.dyl, to load in resources from the so-called system resource file instead of from an
application-specific resource file, if the resource identifiers passed are negative. This system resource file
is built into the ROM of all machines that support HWIM programming. See the Resource Files chapter
of the Object Oriented Programming Guide and the APPMAN Application Manager Class chapter of the
OLIB Reference manual for more details.
30
CHAPTER 3
WDR PRINTING
Introduction
SIBO computers which contain form.dyl in their ROM (or on an SSD) support a wide range of services
connected with so-called WDR printing. These services include the interpretation of printer driver files
in the Psion-proprietary .wdr format, and the generation of suitable printer command sequences to effect
printing operations requested by applications. One key idea is that applications do not need to know
which particular printer driver has been selected by the user; system software takes care of converting
requests made by applications into command sequences suited to the current printer.
Another service which code in form.dyl can provide is opening the correct printer device - whether that
be the parallel port, the serial port, or a file. Once again the idea is that users can specify the printer
device, and have their choice picked up by system software, without any conscious intervention to this
effect by individual applications.
All versions of the Series3 have form.dyl in their ROM, as do suitably reprogrammed versions of the
Whilst the full power of the WDR printing system can be utilised only by object-oriented programmers,
applications that are not themselves object-oriented may still be able to make considerable use of these
services:
= picking up the choices made by the user as regards the printer device (these choices are stored in
environment variables)
« reading the contents of .wdr files directly (by themselves)
= reading the contents of .wdr files using services of the wdr class in form.dyl.
In addition, the Hwif library contains routines hPrintSetupDialog, hPrinterSetupDialog, hPrint,
hPrintSetSI, hPrintSensePageWidth, and hPrintSenseBufWidth, which layer over WDR printing services to
achieve impressive results adequate for many purposes - without requiring any explicit use of object-
oriented techniques (nor any explicit reference to the contents of .wdr files). See the Hwif Manual for
more details.
Creating .wdr files
The creation of .wdr files is a quite separate process from their use, once created. Psion can supply a set
of .wdr files covering some common printers, and other .wdr files may be available from third parties.
However, it may prove desirable to produce a .wdr file for another printer not presently supported - or to
enhance the .wdr file for a new version of a given printer.
Note that whatever the origin of the .wdr file, the file name must not begin with fax. Such filenames are
reserved for fax driver files and are automatically interpreted as such.
One way to create .wdr files is by using the Sibo printer driver translator, wdtran.exe, which creates .wdr
files from plain text input known as printer scripts typically having extension .wd.
The operation of wdtran.exe is described later in this chapter.
31
ADDITIONAL SYSTEM INFORMATION
The WDR printing environment variables
WDR printing software may at various times attempt to read or write the four environment variables psp,
PSS, PSF, and PSM:
PSD is one byte long, having the value '0' to denote that the user has chosen to print using the
parallel port, '1' to denote the choice of the serial port, and '2' to denote printing to file
PSS is twelve bytes long, being a copy of the P_SRCHAR struct matching the choices last made by
the user in any serial port and handshaking dialog(s)
PSF can be up to P_FNAMESIZE (128) bytes long, being a copy of the filename last chosen by the
user as the recipient of any data printed to file
PSM can be up to P_FNAMESIZE+1 (129) bytes long, the first byte recording the printer model
number (see below), and the remainder giving the full path name of the last . wdr file chosen
by the user.
Any software that attempts to read these environment variables should bear in mind that these variables
do not always exist. Ordinarily, they are created only when the user makes an explicit choice via a
dialog box. In the absence of one of the environment variables, the following defaults are assumed to
apply:
PSD effectively has the value '0', meaning that printing should be via the parallel port
PSS see below
PSF any printing to file is to the file p.lis
PSM the printer model number is 0 and the printer driver file rom::bj.wdr should be used.
The default values of the p_SRCHAR struct are as follows:
P_SRCHAR ser;
ser. tbaud=P_BAUD_9600;
ser.rbaud=P_BAUD_9600;
ser. frame=P_DATA_8;
ser.parity=0;
ser ..hand=P_OBEY_XOFF|P_OBEY_DSR|P_IGN_CTS;
ser .xof f=0x13;
ser .xon=0x11;
ser.flags=0;
ser.tmask=0;
For more details on the P_SRCHAR struct, see the Serial Port chapter in the I/O Devices Reference manual.
The essential point is that the contents of the P_SRCHAR struct should be used to P_FseT the serial port after
opening it.
For convenience, the printer model number is stored in printable form, with the value of '0' being added
to its numerical value. Thus to use the second model in a .war file - so that the printer model number
would be 1 - the first byte in psm should be 1+'0', ie '1'.
A note on reading environment variables
See the discussion on p_getenviron and p_getenv in the Plib Reference manual.
Note that it is also possible to read and modify environment variables (eg for experimental purposes) by
using the SIBO Debugger.
SS ee Se ee ee 6 a a |
Overview of the contents of a .wdr file
This section provides an overview of the contents of a .wdr file. More details are provided in later
sections.
32
3 WDR PRINTING
Just about the simplest possible .wdr file would have the following contents, when dumped:
0: 89 00 Oc 00 57 44 52 30 35 00 00 00 01 00 05 00 eee -WORO 5.......
10: 47 65 6e 65 72 61 6c 00 00 00 00 00 00 00 00 00 General. .....2..
20: 00 00 00 00 00 00 00 00 1700 00 00 00 00 0000 .......... wee eee
30: 00 00 00 00 00 00 00 01 Oc 01 Od 02 2a 0a 00 02~—i......... wee a ete
40: 2a 20 00 00 00 00 00 00 01 00 02 05 23 4d 6f Ge ME cicvelorere}..olsis #Mon
50: 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Ove ea ccc a snes
60: 00 00 00 00 00 03 00 01 O00 f0 00 00 00 0000 00_~—i........
70: 00 00 01 00 01 00 01 00 01 16 00 90 00 f0 00 00... wee eee
80: 00 00 00 00 00 01 00 04 00 04 00 28 00 48 00 4d_—ig..... sc (HOM
90: 00 7b 00 89 00 oleae
This conforms to the pattern
<header><resources><index table>
of Sibo standard .rsc resource files, as discussed in the Resource Files chapter in this manual.
Indeed, .wdr files are but examples of .rsc files, with the extension changed to denote the particular
purpose of being a wdr printer driver file.
In fact, .wdr files come in two types - compressed and uncompressed (standard), corresponding to the
.rzc and .7sc forms of resource file. Uncompressed files can be read by a variety of methods, as
discussed in the Resource Files chapter. However, in order to read compressed .wadr files, it is more or
less necessary to use some of the functionality of object-oriented classes in the ROM, using either:
= the rscfile class in olib.dyl
= the wdr class in form.dyl
with the preference being for the latter, since it contains more explicit knowledge of the particular
contents of .wdr files.
Various services provided by the wdr class are described later in this chapter.
Deciphering general.wdr
The above dump is in fact that produced from an (uncompressed) version of the file general.wdr that is
part of the Series3 ROM. This file describes the most basic kind of printer possible, possessing only one
font, which is monospaced, and assumed to be 12 point (ie six lines per inch - one point corresponding to
1/72 of an inch) and 10 cpi (characters per inch). For this printer, the only way to position the print
head horizontally is by emitting space characters or carriage returns, and the only way to position the
print head vertically is by emitting line feeds or form feeds.
The index table for the file starts at file offset 0x89 (as contained in the first word in the file). Reading
successive words from this index indicates that the individual resources in the file are to be found at file
offsets 0x04, 0x28, 0x48, Ox4d, and Ox7b.
The header resource
The first resource in any .wdr file is always the header resource, having the following structure:
= the first six bytes give a signature, which must always be "wor05" for a valid .wdr file
= the next word gives the so-called wdr-flags for the file - evidently 0 in this case
® the word after that gives the number of different printer models in the file - in this case, there is
only one in the file
s finally there is an array of WOR_MODEL_INDEX structs, one struct for each printer model in the file
= each WOR_MODEL_INDEX starts with a word giving the resource identifier for the model resource
(see later) giving more information about the printer model - this identifier has value 5 in this
case
= the WOR_MODEL_INDEX struct concludes with up to 24 bytes giving the public name of the model, in
a zero-terminated string - "General" in this case.
For general.wdr, the total size of the first resource is evidently 6+2+2+1*(2+24), ie 0x24. For other .wdr
files which contain more than one printer model, the first resource will be larger.
33
ADDITIONAL SYSTEM INFORMATION
The commands resource
The second resource in any .wdr is always the commands resource. This consists of:
= an array of command strings
= preceded by a count byte (the first byte in the resource)
= followed by a trailing word whose meaning is reserved for future expansion.
In general.wdr above, the value of the count byte is 0x17, ie 23.
Each command string that follows is given with a leading byte count, and without any terminating zero
(as is appropriate, given that the command strings can in general contain embedded zeros).
As can be seen, for general.wdr, all the 23 command strings are zero, except for (starting counting at
zero):
string 14 which has the value 0x0c
string 15 which has the value 0x0d
string 16 which has the value '*' 0x0a
string 18 which has the value '*' 0x20
The first 21 of the command strings in the command block have reserved meanings, best described in
simple terms by giving the descriptive text associated with these commands in .wd files (see Contents of
.wd files section later):
"RESET"
"FORM_LENGTH"
"PREAMBLE"
"POSTAMBLE"
"UNDERLINE_ON"
"UNDERLINE OFF"
"BOLD_ON"
"BOLD OFF"
"ITALIC_ON"
"ITALIC_OFF"
10 “SUPERSCRIPT_ON"
11 "SUPERSCRIPT_OFF"
12 "SUBSCRIPT_ON"
13 "SUBSCRIPT_OFF"
14 “NEW PAGE"
15 “CARRIAGE_RETURN"
16 "MOVE_DOWN"
17 "MOVE_RIGHT_PREFIX"
18 "MOVE_RIGHT"
19 "MOVE_RIGHT_SUFFIX"
20 “LANDSCAPE
OMNAUEP WN Oo
Additional command strings can be used to set various fonts, and are referenced by typeface resources,
discussed below.
Model resources
The resource identifiers of all model resources are listed in the header resource. As mentioned above, the
only model resource in general.wdr has identifier 5. Consulting the index table for the file indicates that
this resource starts at file offset 0x7b (recall that resource identifiers start at 1).
The structure of a model resource is as follows:
s The first five words give the values of the so-called minx, miny, skipx, skipy, and model-flags
for the printer model.
= Next comes a word giving the number of following typeface resource identifiers.
® This is followed by an array of the specified number of identifiers of typeface resources.
For general.wdr, the values of the various values are evidently as follows:
minx 0x90 (144)
34
3 WDR PRINTING
miny Oxf0 (240)
Skipx and skipy both zero
model-flags ZeTO
and there is just one reference to a typeface resource which, in this case, has resource identifier 4 (which,
via the index, locates it at file offset 0x4d).
Typeface resources
The structure of a typeface resource is as follows:
® The first 20 bytes contain the public name of the typeface, as a zero-terminated string. The text
of this name must not exceed 16 characters, not including the terminating zero.
= The next word gives the typeface number of the typeface.
= The word following contains typeface-flags.
= Next comes a word which, if non-zero, contains the identifier of a translates resource to be used
by the typeface.
= The word following that gives a count of the number of different sizes (or fonts) that the
typeface comes in.
® Finally there is an array of WOR_FONT structs, one struct for each font size supported by the
typeface. Each wor_FONT struct consists of nine words: height, height_max, height_delta,
width_scale, width_normal, width_italic, width_bold, width_italic, width_bold_italic, and
concludes with the number of the command string, in the commands resource, of the associated
printer instruction to set this particular font.
The difference between a “typeface” and a "font" is discussed in more detail below.
In general.wdr, the public name of the only typeface in the file is "Mono", the typeface number and the
typeface flags are both zero, the translates resource with identifier 3 is to be used, and there is only 1
WDR_FONT struct following in-line.
In a WOR_FONT struct:
® The fields height_max and height_delta are only relevant for so-called scalable typefaces
« The field width_scale is only relevant for proportional typefaces
= For monospaced typefaces, the values of the four fields width_normal through width_bold_italic
are to be interpreted as real numbers; for proportional typefaces, in which the widths of the
characters vary from character to character, these values are identifiers of font width table
resources.
There are no font width table resources in general.wdr. Incidentally, font width tables are stored in
difference form in .wdr files - see later for more details.
Translates resources
The first word in a translate resource gives the number of translates that follow in-line.
Each translate starts off with a byte giving the length of the remainder of the translate. The next byte is
the Ascii value of the character to be translated, and that is followed by a sequence of bytes into which
the character is to be translated.
In general.wadr, there is only one translates resource, which in turn only contains one translate, whose
effect is to convert every character with Ascii value 0x05 into one with value 0x23. This results in
telephone symbols (recorded internally on the Series3 as 0x05's) being printed as hash signs.
Summary of resource types in a .wdr file
The above survey contains one example of every possible type of resource in a .wdr file, except for font
width table resources.
In summary, the possible resource types are:
header (always the first resource in the .wdr file) containing an index of all the printer
models supported by the file, as well as some important wdr-flags
35
ADDITIONAL SYSTEM INFORMATION
commands (always the second resource in the .wdr file) containing the character command
sequences for resetting the printer, controlling the text format, moving the
print head position, selecting specified fonts, and so on
translates used to map the printer's character set onto that used by the SIBO computer
(which is based on IBM code page 850)
font width tables defining the widths of all the characters in proportional typefaces
models giving essential data governing the capabilities of a printer, and listing the
typefaces supported by the printer
typefaces describing the typefaces supported by a printer model, including the various
“font sizes" available for that typeface.
A ee re ||
More details on the contents of .wdr files
Possible wdr-flags
The only wdr-flag of any general significance is woR_DYL_LOAD, with value 0x01. If set (in the header
resource), this means that the contents of the .wdr file are insufficient, by themselves, to describe the
behaviour of the printer fully, and that the wdr printing system software should load a suitable external
dyl to additionally customise the print behaviour.
Examples of .wdr files with the wor_DYL_LoaD flag set are the printer driver files for postscript printers.
Further discussion of loading additional printer dyls is beyond the scope of this document.
Other bits set in the wdr-flags may have special significance for code in the extra print dyls.
The notion of “printer models”
The notion of a printer model is essentially a device to cover more than one printer using the same data.
Different printer models can be described in the same .wdr file, even if they support different sets of
typefaces or have other differing characteristics, so long as they have the same basic set of printer
command strings (and the same wdr-flags).
The public name of a printer model is what is presented to the user in any dialog offering a list of
“printer models" for selection.
Overview of the different command strings
As well as the command strings to select various fonts, a .wdr file contains commands to have the printer
perform other functions. These commands are by and large clearly named in the listing given earlier, eg
"ITALIC_ON" and "ITALIC_OFF", "BOLD_ON" and "BOLD_OFF", and "SUPERSCRIPT_ON" and "SUPERSCRIPT_OFF".
If a printer cannot support a given feature, the corresponding command string would generally be left
null (*"), One possible exception is italic which, if not supported, could be implemented as an underline.
(Note incidentally that it is possible for a printer which supports italic in one font not to support it in
another font, and so on. Again, a printer may support both italic and superscript, but not both at the
same time.)
The "LANDSCAPE" command, if non-null, is the command to cause the printer to enter landscape mode (as
opposed to portrait mode).
The string of commands sent to the printer when printing starts are among the most important, as regards
influencing the printed outcome. The very first command the software sends the printer is the "RESET"
command. Then it sends a "FORM_LENGTH" command, and then the "PREAMBLE" command, before starting to
print the document proper (together with headers and footers, etc). At the very end, a "POSTAMBLE"
command is sent.
The “POSTAMBLE" command may be needed to flush the printer buffer, and to restore the printer to its
default settings.
The "PREAMBLE" Command may have such drastic consequences as choosing the basic configuration of the
printer (possibly overriding defaults set via dip switches). In any case of doubt, the documentation for a
particular printer should be consulted carefully.
36
3 WDR PRINTING
Special characters in command strings
The commands "MOVE_RIGHT", "MOVE_DOWN", and "FORM_LENGTH" are each used in conjunction with a value
passed by the printer subsystem software. For example, the commands are to set the form length zo a
given value, or to move the printer position right by a given amount. This value may either end up in the
command string by a process of substitution, or it may result in the command being repeated as required:
= if any of these commands is defined as starting off with an asterisk character ('*'), what is
actually sent to the printer is the remainder of the command string (ie minus the initial asterisk)
repeated the specified number of times
« if the string "%d" is contained within the command string, the specified value is converted into
decimal representation and is substituted for the "%d" (like printf in C)
= likewise the string "%c"' means to substitute the specified value as a single byte (character), and
"%w" means to substitute it as a pair of bytes (low byte first).
For example, in some printer drivers "MOVE_DOWN" is defined as "*<10>", so that "MOVE_DOWN n" will be sent
to the printer as n line feed characters (line feed is Ascii 10).
Again, in the HP Laserjet III printer driver, "move_pown" is defined as "<27>&at+%dv", so that "MOVE_DOWN 6"
(say) will be sent to the printer as "<27>&a+6v".
This kind of substitution can also take place in the command strings to select a specific size of a so-called
scalable font - see below.
The MOVE_RIGHT commands
For some printers, the command to move right by a certain amount is of the general form
<prefix><repeated body><suffix>
with the central part being repeated as many times as required, depending on the amount by which the
print position is to be adjusted.
It is to cope with this case (as well as ones even more complicated) that the commands
"MOVE_RIGHT_PREFIX" and "MOVE_RIGHT_SUFFIX" are provided. These will be left null for most printers.
Printer units
The units for the "FoRM_LENGTH" command are always 1/6 of an inch. Thus if the print software wishes,
as part of initialising a printer, to set the form length to 12 inches, the command
"FORM_LENGTH 72"
should always be sent.
However, the units used in many other features of printer driver files varies from printer to printer. The
key quantities are the values of minx and miny, as specified in the model resource for a printer.
Minx and miny are themselves standardly given in so-called twips, where twenty twips make a point (so
that 1440 twips make an inch). For example, in the file general. wdr discussed above, minx has the value
144 twips, ie 1/10 of an inch, and miny has the value 240 twips, ie 1/6 of an inch. This matches the
basic assumptions made in general.wadr that the font printed is 12 point and 10 cpi (see earlier).
The fundamental significance of minx is that this is the smallest amount by which the print position can
be adjusted horizontally. Similarly, miny is the smallest amount by which the print position can be
adjusted vertically. Clearly, the smaller minx and miny are, the higher the resolution of the printer.
The above values make sense for general.wdr since the only way the print position can be adjusted
horizontally is by emitting a space character (or by emitting a carriage return, which resets the horizontal
position), and the only way the print position can be adjusted vertically is by emitting a linefeed character
(or by emitting a formfeed character, which effectively resets the vertical position).
A command such as "MOVE_RIGHT n" actually means to move the print position right by n times minx, and
similarly a command such as "MOVE_DOWN m" means to move the print position down by m times miny.
The value of skipx for a printer model is subtracted from the first "MovE_RIGHT" command in each line of
text, to compensate for the fact that many printers cannot print at the left edge of the paper. The value of
skipy is likewise subtracted from the first "MovE_bpoWN" command in each page, to compensate for the fact
that many printers cannot print at the very top of the paper.
37
ADDITIONAL SYSTEM INFORMATION
The values of skipx and skipy are themselves expressed in terms of minx and miny, respectively. Thus if
skipy is given as 36 whereas miny is given as 20, this translates to an actual height of some 20*36 twips, ie
half an inch, at the top of the paper which is inaccessible to the printer.
Possible model-flags
There are two bits that can be set in the model-flags in a model resource:
™ WDR_MODEL_LANDSCAPE_AVAILABLE (0x01) has to be set if the model supports being put into
landscape mode
®@ WDR_MODEL_MINX_IS_DOTS_PER_INCH (0x04) should be set if the value of minx is expressed, not in
twips (as standard), but in reciprocal inches (so that a minx of 300 would correspond to 1/300 of
an inch - which is not expressible as an exact number of twips).
Note that even if WR_MODEL_MINX_IS_DOTS_PER_INCH is set, the value of miny is always expressed in twips.
Typefaces and fonts
A typeface is considered to be a set of characters in a particular style, whereas a font is a particular size
of a typeface.
The public name of a typeface is what is presented to the user in any dialog offering a list of "fonts"
(actually typefaces) for selection. The various different fonts within a chosen typeface will be selected
via a secondary choice list, keyed by the notional height of the fonts.
There can be considerable scope for authors of .wdr files in deciding how to represent the different fonts
supported by a printer (especially dot matrix printers). For example, many dot matrix printers support a
condensed font: this may be represented as a typeface called "Pica condensed" (say) or as a smaller font
of the "Pica" typeface. It is generally more useful for the user to have a number of size variants (fonts)
of one typeface rather than a number of typefaces each having only one size. For this reason the second
of the above approaches is the recommended one. It also has the advantage that the typeface names will
then (generally) be language independent, whereas the addition of a phrase such as “double width" or
"condensed" immediately makes the .wdr file language dependent.
A dot matrix printer may support a number of variants of a font including: condensed, double height,
double width, condensed double width etc. For a twelve point base font it is recommended to map these
to the following heights:
condensed 7 point (140 twips)
normal 12 point (240 twips)
condensed double width 13 point (260 twips)
double width 16 point (320 twips)
double height 22 point (440 twips)
double height double width 24 point (480 twips)
Note that a taller font must have a larger size than a shorter font, in particular the point sizes of all the
double height fonts must be larger than all the single height fonts.
If a dot matrix printer supports a large number of variations on a base font, it may turn out that two
different variations would be mapped onto the same point size. In this case it would be perfectly
acceptable to just omit one of the fonts: if there are already 12,13,14,15 and 16 point fonts available then
omitting (say) a second 14 point is not really a hardship to the user. Alternatively, the font could be
incorporated in another typeface. In case it is decided to omit a font, bear in mind that double height
fonts generally look much better than double width fonts, so given a choice it is better to omit the latter.
Typeface numbers
The main significance of the typeface number of a typeface is when a document set up for one printer is
subsequently printed on another printer. Font "substitutions" have to be made - and these are done
according to the values set for the typeface number.
Thus if a document is prepared for one printer model, and some text is to be printed in a typeface having
typeface number 2, say, and then the user changes the printer model setting for the document to another
printer, that text, when printed, will be printed in the first typeface found in the new printer model,
having the same typeface number.
38
3 WDR PRINTING
In case no exact match in typeface number is possible, the first typeface defined in the new printer model
is used instead.
There are a large number of allowed typeface numbers, listed later in this chapter. Note that typeface
numbers are completely independent of the public names of typefaces.
Typeface numbers may also be used in some forms of RTF file conversion.
Possible typeface-flags
There are three bits that can be set in the typeface-flags in a typeface resource:
S WOR_TYPF_PROPROTIONAL (0x01) set if the widths of the characters in a font in this typeface can vary
among themselves (the alternative is that the fonts are monospaced)
" WDR_TYPF_SCALED (0x02) set if the fonts supported by the typeface are all generated by the printer
as being different scaled versions of one common pattern
= =WDR_TYPF_SERIF (0x04) set if the typeface is serif.
The wOR_TYPE_SERIF flag has significance only in certain types of RTF file transfer.
Note that scalable monospaced typefaces are not supported, so that scalable fonts always have to be
regarded as proportional, even if the widths of their characters do not vary in fact.
For scalable typefaces, there is only one woR_FONT struct per typeface, with all required information for
differently sized fonts being generated from this by arithmetical scaling.
Heights of fonts
The command string of a scalable typeface must include some kind of parameter (eg "%d") for the
particular size required to be specified when setting the font. This parameter will be filled in by system
software giving the height of the required font in point units.
However, heights of fonts in .wdr files are always given in twips (thus 240 for a 12 point font).
For non-scalable fonts, the height_max and height_delta fields in a woR_FONT struct are meaningless. For
scalable fonts, the set of supported font sizes is obtained by repeatedly incrementing by height-delta,
from the value of height to the value of height_max (so that the "height" field actually plays the role of a
“height_min" field).
In general, 4 points (80 twips) is a sensible minimum height for a font, whereas the maximum allowed
height is determined by the fact that the widths of characters must at all times remain less than 255.
Widths of characters in fonts
Widths of characters in fonts in .wdr files are expressed - as are all horizontal measurements in .wdr files
- in units of minx.
The wdr system allows for widths of characters altering as they are italicised or bolded, and again when
they are simultaneously italicised and bolded. In case there is no such variation, the values of the fields
width_normal, width_bold, width_ italic, and width_bold_italic, will merely duplicate each other.
For proportional fonts, these four fields each refer to font width tables. These are stored in difference
form in .wdr files. Thus if the array of stored widths is stored(}:
® width of character 0 = stored(0]
® width of character 1 = width of character 0 + stored{1]
« width of character 2 = width of character 1 + stored{21
« width of character 3 = width of character 2 + stored(3]
and so on. The rationale for this is that the differences are frequently zero, so that the font width table is
stored as an array, many of whose values are zero. In tur, this compresses much more markedly (for
compressed versions of .wdr files) than tables containing many different values - with the result that
smaller .wdr files get produced (bear in mind that font width tables potentially make up large parts of
these files).
The values obtained from a font width table should all be multiplied by the width_scale value for the
font. This mechanism avoids needless duplication of data in which two font width tables would
otherwise both be present in a .wdr file, even though one is merely a scaled version of the other.
39
ADDITIONAL SYSTEM INFORMATION
For scalable fonts themselves, the values in the font width table (once multiplied by any width_scale
value for the font) are what would apply to a fifty point high version of the font. These have to be
further scaled, in general, to match the chosen height of the font.
Note that in all cases, widths of characters cannot exceed 255.
ia ee ee ee ee ee ee
Creating .wdr files using wdtran.exe
The printer driver translator is a tool wdtran.exe that operates on a so-called printer script, which is a
text file, to produce a printer driver file as output.
The process is akin to ordinary compilation:
*,.c + compiler -> *.obj
*,wd + printer driver translator -> *.wdr
with .wd being the usual extension for a printer script.
Some sample .wd files are distributed as part of the optional component of the Sibosdk.
To produce eg general.wdr from general.wd, simply type
wdtran general
Contents of .wd files
The basic contents of .wd files correspond to the different resources in .wdr files (see earlier in this
chapter).
A .wd file consists of a number of resource definitions, of which there are five types: COMMANDS,
TRANSLATES, WIDTHS, TYPEFACE, and MODEL.
There must be one and only one commaNDs resource in a .wd file. There must be at least one MODEL
resource and at least one TYPEFACE resource, though there can be more of each. There can be any number
(including zero) of WIDTHS and TRANSLATES resources.
Note that there are no definitions in a .wd file directly corresponding to the header resource in a .wdr
file. The header resource is specially created by wdtran.exe.
Each resource definition consists of a header, a number of commands, and then a footer. The header is
of the form
<RESOURCE> [identifier]
with the identifier being required only if the resource is to be referenced by another resource (it may be
the name of a width table, for example).
The resource footer is of the form:
END_<RESOURCE>
Each intervening command is of the form:
keyword [parameter]
For example, the definition of a TYPEFACE resource looks like
TYPEFACE pica
END_TYPEFACE
3 WDR PRINTING
and the definition of a comMANDS resource looks like (this is the commanps resource for the file general.wd):
COMMANDS
RESET ut
FORM_LENGTH me
PREAMBLE Hes
POSTAMBLE wet
BOLD_ON eat
BOLD_OFF anet
ITALIC_ON aM
ITALIC_OFF a
UNDERLINE_ON me
UNDERLINE _OFF a
SUBSCRIPT_ON baat
SUBSCRIPT_OFF He
SUPERSCRIPT_ON es
SUPERSCRIPT_OFF st
MOVE_DOWN Wee 10>"
MOVE_RIGHT_PREFIX ="
MOVE_RIGHT We 32>"
MOVE_RIGHT_SUFFIX =o
NEW_PAGE m<12>u
CARRIAGE_RETURN N<13>"
END_COMMANDS
Parameters to keywords inside a resource definition may be of four types:
Numeric a decimal number which is interpreted as a value (eg a font width)
Constant an unquoted string which is interpreted as a numeric value (used only by TYPE
in a TYPEFACE resource definition)
Identifier a lower case unquoted string, used by a command to reference another
specified resource
Quoted string a sequence of characters in quotes that is sent to the printer to perform a
specific function (eg BOLD_oN); the string may contain control characters (see
below).
The printer driver translator ignores any characters between an exclamation mark ! and the end of a line
(unless the ! is in a quoted string). Blank lines are also ignored.
The block indentation scheme in standard .wd files is for convenience only.
Acceptable syntax within a COMMANDS resource definition
Any of the commands listed in the earlier section on command resources in .wdr files can be given.
However, command strings used to set individual fonts should be given within the relevant TYPEFACE
resource definition.
Control codes may be needed in the COMMANDS resource definition, or in the COMMAND keyword of a font
definition. A control code is specified by placing its decimal value in angle brackets ("<" and ">"). For
example the Esc control code (decimal value 27) is specified as <27>.
Other syntax that may occur within a COMMANDS resource definition are:
USE_DYL to set the woR_DYL_LoaD flag in the wdr-flags in the header resource for the .wdr
file
FLAGS <flags> to or in <flags> to the wdr-flags in the header resource
HP_PCL_COMPATIBLE of purely historical significance.
Acceptable commands within a TRANSLATES resource definition
Each line within the definition of a TRANSLATES block should be made up of one or more translations, with
adjacent translations on any one line being separated from each other by white space.
Individual translations should have the form
<byte>:<byte>
41
ADDITIONAL SYSTEM INFORMATION
or else
<byte>:<string>
For example:
5:35
156:"<27>R<3><35><27>R<0>"
Note that any width table for a font which uses translates must contain the correct width for each
character after it is translated. The printer driver translator does not check this.
Acceptable commands within a WIDTHS resource definition
Each line within the definition of a wiptus block should be made up of one or more character widths,
with adjacent character width definitions on any one line being separated from each other by white space.
Individual character width definitions should have the form
<byte>:<width>
Note that in contrast to .wdr files, which store font width tables in differenced form (see earlier in this
chapter), .wd files should define the widths of all characters in absolute terms. The differencing is
performed by wdtran.exe (just as the converse integration is performed by the wdr class in form.dyl
without the conscious intervention of any application software).
The printer driver translator will give an error if the widths of the non-breaking hyphen, potential
hyphen, and standard hyphen (character codes 7, 14, and 45) are not all the same.
Likewise, the widths given for the non-breaking space, the standard space, and the tab (character codes
15, 32, and 9) also all have to agree.
Acceptable commands within a TYPEFACE resource definition
The following commands may be present within the definition of a TYPEFACE resource:
PROPORTIONAL to set WOR_TYPF_PROPORTIONAL in the typeface-flags
SCALED to set WOR_TYPF_SCALED in the typeface-flags
SERIF to set WOR_TYPF_SERIF in the typeface-flags
MULTIPLE_FONT_WIDTH_TABLES of purely historical interest
NAME <name> to give the public name of the typeface
TYPE <type> to give the typeface number of the typeface
TRANSLATE <identifier> to specify a TRANSLATES resource to be used
FONT to commence the definition of a FonT sub-resource.
The Font keyword must appear at least once in each TYPEFACE definition, and can appear more than once.
The other keywords should only appear once, at the most.
Each FONT sub-resource definition follows the same general pattern as the other resources:
FONT
<keywords>
END_FONT
Possible keywords in the body of a FonT resource definition are HEIGHT, HEIGHT_MAX, HEIGHT _DELTA,
WIDTH_SCALE, WIDTH, WIDTH_BOLD, WIDTH_ITALIC, WIDTH_BOLD_ITALIC, and COMMAND - each having the
straightforward meaning of specifying a corresponding field within the wor_FoNT structure for that font
(see earlier in this chapter).
Acceptable commands within a MODEL resource definition
The following commands may be present within the definition of a MODEL resource:
LANDSCAPE_AVAILABLE to set WOR_MODEL_LANDSCAPE_AVAILABLE in the model-flags
MIN_X_IS_DOTS PER_INCH to set WOR_MODEL_MINX_IS_DOTS_PER_INCH in the model-flags
42
3 WDR PRINTING
NAME <name> to give a public name for the printer model
TYPEFACE <identifier> to specify a TYPEFACE resource supported by the printer model.
Additionally, the keywords MIN_X, MIN_Y, SKIP_X, and SKIP_Y straightforwardly specify the minx, miny,
skipx, and skipy values for the printer model.
In contrast to the case for TYPEFACE resources, which can only have one public name each, MODEL resources
can have more than one public name each. This avoids needless duplication in a .wd file, if it tums out
that two MODEL blocks would otherwise be identical. Note that one MopEL resource having two public
names is not in general the same thing as there being two different moDEL resources in the same .wd file
(though in each case, there will be two distinct entries in the Printer Model choice list).
Allowed typeface numbers
TYPE may take any of the values:
0 COURIER 22 OPTIONAL_SB 44 RUSSIAN
1 PICA 23 OPTIONAL_SC 45 OPTIONAL_B
2 ELITE 24 TIMES_ROMAN 46 OPTIONAL_C
3 PRESTIGE 25 CENTURY 47 OPTIONAL_D
4 LETTER_GOTHIC 26 PALATINO 48 NARRATOR
5 GOTHIC 27 SOUVENIR 49 EMPHASIS
6 CUBIC 28 GARAMOND 50 ZAPF_CHANCERY
7 LINEPRINTER 29 CALEDONIA 51 OPTIONAL_DA
8 HELVETICA 30 BODONI 52 OLD_ENGLISH
9 AVANT_GARDE 31 UNIVERSITY 53 OPTIONAL_DB
10 SPARTAN 32 SCRIPT 54 OPTIONAL_DC
11 METRO 33 SCRIPT_PS 55 COOPER_BLACK
12 PRESENTATION 34 OPTIONAL_SCA 56 SYMBOL
13 APL 35 OPTIONAL_SCB 57 LINE_DRAW
14 OCR_A 36 COMMERCIAL_SCRIPT 58 MATH_7
15 OCR_B 37 PARK_AVENUE 59 MATH_8
16 STANDARD_ROMAN 38 CORONET 60 DINGBATS
17 EMPEROR 39 OPTIONAL_SCC 61 EAN
18 MADELEINE 40 GREEK 62 PC_LINE
19 ZAPF_HUMANIST 41 KANA 63 OPTIONAL_SYA
20 CLASSIC 42 HEBREW
21 OPTIONAL_SA 43 OPTIONAL_A
Suppose, for example, a user has a document written when the Apple Laserwriter printer driver was
selected, and the document uses two typefaces, Times Roman and Palatino. The user then changes to a
HP Laserjet III printer driver. Times Roman on the Laserwriter and CGTimes on the HP IT both have a
TYPE Of TIMES_ROMAN and so the Times Roman typeface would be mapped to CGTimes. The HP III driver
has no typeface with a Type of PALATINO and so the Palatino font would be mapped to Courier.
The following rules are useful for guidance:
One of the printer's monospaced typefaces should be assigned a Type of courteRr: this should be the
typeface described as Courier or perhaps Pica in the printer's manual. The typeface's name should be as
in the manual (eg Pica).
If a printer supports only one proportional typeface it should be assigned a Type of TIMES_ROMAN, although
it may be given a different NAME (eg Proportional).
If a printer supports more than one proportional font then the one with serifs (if available) should be
assigned a TYPE Of TIMES ROMAN and the one without serifs should be assigned a Type of HELVETICA; their
NAMES should, however, be those used in the printer's manual, eg CGTimes and Univers for the HP
Laserjet III.
See also the Printer driver font mapping section of the Word Processor File Format chapter.
43
CHAPTER 4
DBF FILES
ey a a oe ae ee ee a ee ee]
Introduction
Database files (DBF files) are binary files containing typed, variable length records. Many SIBO
applications (for example, the MC Diary and the Series 3 Database) store their data in DBF files. The
data files created and manipulated by OPL are also examples of DBF files.
Database files are designed to be Flash-friendly, that is, they may be stored and manipulated in Flash
SSDs (or any other EPROM medium). A DBF file stored on such a medium may be modified by
appending, deleting, or replacing records without having to make a new copy of the entire file.
The chapter Database Files in the PLIB Reference manual describes DBF files from the point of view of
reading and writing them using PLIB function calls such as Dbfopen, DbfAppend, DbfFindRead, and
DbfNextRead. The JSAM Manual discusses more advanced techniques for using DBF files, in conjunction
with independent keyed index files. The present chapter focuses instead upon a description allowing
access to DBF files independently of these specialised PLIB and ISAM functions.
First, the basic structure of a general DBF file is reviewed, and then particular examples are given of
how various SIBO applications use DBF files. This information should assist the creation of file format
conversion programs such as might run on another computer, for example converting between Series 3
Agenda files and files that can be read directly by PC-based PIMs (Personal Information Managers).
a ee ee a eae
Basic structure of DBF files
The following discussion is based around a DBF file created by a simple OPL program. It is not
necessary to be familiar with OPL to follow the discussion, since the contents of the DBF file are
described independently of the OPL program. It just happens that OPL is a convenient way to create
DBF files quickly, so that experimentation is easier.
The OPL program creating the file is as follows:
PROC writedbf:
if exist("test.dbf") :delete "test.dbf" sendif
create "test.dbf",a,f1%, 2%, 3%, f4
a. f1$="Hello"”
a. feg=au
a. f3%=3
a. f4=4
append
a. f1$="World"'
append
close
beep 5,300
ENDP
The create statement creates a DBF file with the name test.dbf, by default in the \opd\ top-level
directory on the default drive. This file is assigned the logical handle a inside the program. Each record
in the file is to have four fields (called £18, f2$, £3%, and #4 inside the program). Standard OPL naming
conventions mean that these fields have types string, string, integer, and double, respectively.
45
ADDITIONAL SYSTEM INFORMATION
The two append statements mean that two records are written to the file, before it is closed.
Dumping the resulting file yields the following:
O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile.
10; Of 11 16 00 Of 11 04 20 03 03 00 02 12 10 05 48 — wane wee eee H
20: 65 6c 6c 6f 07 32 03 00 00 00 00 00 00 00 10 40 eOLlLO.2.. weeccee a
30: 12 10 05 57 6f 72 6c 64 01 32 03 00 00 00 00 00 eeeWorkd .2......
40: 00 00 10 40 ee)
This conforms to the standard DBF format of
<standard header><extended header><field information record><other records>
where
<standard header> always has length 22 bytes.
<extended header> can have variable length and is frequently of zero length (as
here).
<field information record> gives the structure of all type I records following.
<other records> are the main body of the DBF file.
The standard header
The first sixteen bytes of all standard DBF files are the zero-terminated string "opLDatabasef ile". This
string is used by all SIBO applications. Applications are allowed to use alternative strings although such
DBF files can not be read by OPL.
The two bytes at offset 0x10 and the two bytes at offset 0x14 represent software version numbers. See
the System Information section of the General System Services chapter of the PLIB Reference manual for
an explanation of the format of a version number.
The two bytes at file offset 0x10 represent the version number of the software that generated the file.
Files generated by the Series 3 and Series 3a Data applications have these bytes set to <0f><10>. Files
generated by OPL set these two bytes differently on different machines: on the HC and Series 3 they are
set to <Of><11> and on the Series 3a and Workabout they are set to <1f><11>. If generated by version 1 of
ISAM the two bytes are set to <00><10> (which, strictly speaking, is not a legal version number).
The two bytes at file offset 0x14 represent the minimum version number of DBF software that is required
to interpret the contents of the file. Files generated by the Series 3 and Series 3a Data applications have
these bytes set to <0f><10>. Files generated by OPL set these two bytes to <0f><11> on all machines. If
generated by version 1 of ISAM the two bytes are set to <00><10> (which, strictly speaking, is not a legal
version number).
The two bytes at file offset 0x12 contain the file offset for the start of the field information record. Thus
in the absence of an extended header they would contain <16><00> and for an extended header of length
256 bytes they would contain <16><01>.
The extended header
A DBF file has an extended header only if an application calls the PLIB function pbf€xtHeaderwrite. At
the time of writing SIBO applications neither make this call nor make use of the extended header.
The field information record
The field information record is a type 2 record.
The first byte contains the number of fields defined for each rype J record (see below for an explanation
of type I records). In the above example four fields were defined. The number of fields defined must be
an integer between 1 and 32 inclusive
The second byte always contains <20> (see below for an explanation).
The remaining bytes contains the field types. The first byte contains the type of the first field, the second
byte contains the type of the second field and so on. The following types are allowed:
= a type of 0 means that the field is an integer: a numeric value stored in two bytes, low byte first.
= a type of 1 means that the field is a Jong: a numeric value stored in 4 bytes.
46
4 DBF FILES
= a type of 2 means that the field is a double: a floating point value stored in 8 bytes in standard
IEEE format.
= a type of 3 means that the field is a string: a sequence of up to 255 bytes preceded by a byte
giving the length of the sequence.
The format of all records
All records contain a two byte header followed by a sequence of bytes constituting the body of the
record.
The highest nibble of the header word contains the record's type. The lowest three nibbles contain the
length of the record body (a nibble is four bits, thus each byte consists of two nibbles). This explains
why the second byte in the header of the field information record is always <20>.
In the example DBF file (see above) the record immediately following the field information record has
<12><10> as its header and is thus a type J record, with a body of length 0x12 bytes.
Counting past another 0x12 bytes leads to the header of the following record, which is also <12><10>.
Counting along yet another 0x12 bytes leads precisely to the end of the file.
Since each of these records are type ] they must all conform to the internal structure specified in the field
information record:
= a leading byte-counted string, for the first string field.
= asecond leading byte-counted string.
=" two bytes for the integer field.
® eight bytes for the double field.
Looking more closely at the above dump, it can now be appreciated how the details of the file contents
match the earlier OPL program.
Generally speaking, the only types of record that will be found in any DBF file produced by a SIBO
application are:
type 0 deleted record.
type 1 standard record.
type 2 field information record.
type 3 descriptive record.
Deleted records
Consider the following OPL program, which differs from the earlier one in only one line:
PROC writedbf:
if exist("test.dbf") :delete "test.dbf" sendif
create "test.dbf",a,f1$, f28, 3%, £4
a.fi$="Hello"
a.f2g="2"
a.f3%=3
a.f4=4
append
a. f1$="Wortd"
update
close
beep 5,300
ENDP
The change is that the second append instruction has become an update instruction, so that the end result
is that the file has only one record.
Dumping the DBF file output by this second program gives (provided the file is created on a Flash SSD):
O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile.
10: Of 11 16 00 Of 11 04 20 03 03 00 02 12 0005 48 ~~... wee H
20: 65 6c 6c 6f 01 32 03 00 O00 00 00 00 00 00 10 40 COE. oasis s.0'e0 a
30: 12 10 05 57 6f 72 6c 64 01 32 03 00 00 00 00 00 ---World .2......
40: 00 00 10 40 oo of
47
ADDITIONAL SYSTEM INFORMATION
This differs from the earlier dump only with regard to one nibble which gives the record type for the first
record in the file. The two bytes <12><10> at file offset 0xic have changed into <12><00>, indicating that
while the same length of data remains on the file, the first record is no longer type 1, but type 0, i.e. it
has been deleted.
Erased records remain in a DBF file until such time as the file is written out again, say in response to a
"Save As" menu command, or until the file is compressed (say in response to a "Compress" menu
command). (In fact, OPL programs automatically attempt to compress their DBF files whenever they are
closed, which explains why the above example gives different results unless the file is created on Flash.)
Although erased records may remain part of a DBF file long after the application has “deleted” or
"updated" them, they are inaccessible to normal software (eg to the PLIB bbfxxx calls and the OPL
database functions such as find and count).
For more discussion about the mechanism of deleting records, see the Database Files chapter in the PLIB
Reference manual.
The remaining examples of DBF files in this chapter all assume that any deleted records have been
removed.
Descriptive records
From most points of view, records of type 3 and upwards are all potentially "singular" records without
the usual software support. Operations such as "Find" do not usually find text within such records as
these record types are not used by standard SIBO applications (with one important exception, discussed
below). See the Database Files chapter in the PLIB Reference manual for more details of these record
types.
The exception is with a record of type 3, which is a so-called "descriptive" record. See later in this
chapter for examples of data that may be stored in a descriptive record.
There is usually at most one record of type 3 in any one DBF file.
By convention, a descriptive record's data is composed of a number of typed fields. Each field has a two
byte header that contains the field's type and length, in the same format as for a record header.
The types have variable meaning, depending on the application. Given that different versions of an
application may define different types of field within the descriptive record, it is good practice for
applications that encounter fields in a descriptive record that they do not understand, to preserve these
fields and to write them out again whenever the descriptive record needs to be changed.
More on type 1 records
It is not always necessary for a type I record to have entries for each field defined in the field information
record. Depending on the application, any trailing omitted fields will usually be assumed to be zero or
null.
It is also possible for a record to have more than 32 fields. This is allowed in the case where the
descriptive record explicitly defines 32 fields. In this case, any extra data in a record, beyond the 32nd
field, is interpreted as a sequence of additional string fields.
The Series 3 Database
In this section reference to the Series 3 Database is taken to include the Series 3a Database except where
explicitly stated otherwise.
The Series 3 Database stores its files in the DBF file format, as described in general terms at the
beginning of this chapter. By convention, the Series 3 Database uses file with extension .dbf.
Field information (type 2} record
The field information record of a Series 3 Database file is always as follows:
<20><20><03><03><03> ... <03><03><03>
there being 32 <03>s in all. As mentioned above, this actually means that any type J record in the file
consists of a variable arbitrary number of string fields (where this number can exceed or fall short of 32).
48
4 DBF FILES
Extended header
There are no extended headers on any Series 3 Database files.
Descriptive (type 3) record
For an example of a descriptive (type 3) record consider the following dump of a default newly-created
and exited Series 3 Database .dbf file (see below for a Series 3a example):
O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 Gc 65 00 OPLDatab aseFile.
10: Of 10 16 00 Of 10 20 20 03 03 03 03 03 03 03 03 1... cee eee
20: 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 nc cack cece ween
30: 03 03 03 03 03 03 03 03 31 30 02 10 04 0002 50_~=(i........ . .. ht ee P
40: 05 00 27 40 05 4e 61 6d 65 3a 07 05 20 48 6f 6d ..'d.Nam e:.. Hom
50: 65 3a 07 05 20 57 6f 72 6b 3a 08 41 64 64 72 65 e:.. Wor k:.Addre
60: 73 73 3a 00 06 4e 6f 74 65 73 3a ss:..Not es:
The header of the first record after the field information record is <31><30>. This indicates that the record
has type 3 and body length 0x31 bytes and therefore extends to the end of the file.
The body of a Database descriptive record contains a series of fields, each of which has a header that
gives its type and length, in the same format as the record header. A Series 3 descriptive record contains
the following fields:
® afield of type 1 and length 2.
= a field of type 5 and length 2.
= a field of type 4 and variable length; in the above example, the length is 0x27.
Series 3a Database files are longer because the descriptive records contain more fields. Here is a newly-
created and exited Series 3a Database .dbf file.
QO: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile.
10: Of 10 16 00 OF 10 20 20 03 03 03 03:03 03 03 03~—(iw.a
20: 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
30: 03 03 03 03 03 03 03 03 aa 30 02 10 04 00 02 50
40: 14 00 3a 60 82 2e c6 41 08 07 08 07 72 20 b6 33 we cipeecA cecal 33
50: dO 02 dO 02 00 00 00 00 01 00 ff ff 00 00 00 00
60: 0 00 00 00 00 00 00 00 f0O 00 O02 00 00 00 00 00
70: 00 00 00 00 00 00 f0 00 00 00 00 00 00 00 Od 70. ........ .... weep
80: 00 52 4f 4d 3a 3a 42 4a 2e 57 44 52 00 Oc 80 00 «ROM::BuJ .WDR....
90: 00 00 25 50 00 82 2e c6& 41 08 07 Oc 90 25 50 00 oehPoces Aree APe
a0: 82 2e c6 41 08 07 08 07 72 03 a0 01 00 01 04 bd SoA Mee” Mele e-c cee
: 00 00 ff ff 2e 40 05 4e 61 6d 65 3a 07 05 20 48~—tiw.... @.N ame:.. H
cO: 6f 6d 65 3a 07 05 20 57 6f 72 6b 3a 06 05 20 46 ome:.. Work:.. F
dO: 61 78 3a 08 41 64 64 72 65 73 73 3a 00 06 4e 6f ax:.Addr ess:..No
e0: 74 65 73 3a tes:
The header of the first record after the field information record is <aa><30>. This indicates that the record
has type 3 and body length Oxaa bytes and therefore extends to the end of the file.
The body of a Series 3a Database descriptive record contains the three fields described above, together
with the following additional fields:
= a field of type 6 and length 58.
= afield of type 7 and variable length.
= afield of type 8 and variable length.
= a field of type 9 and variable length.
= a field of type 10 and length 3.
= a field of type 11 and length 4.
The currently used field types are as follows:
type 1 the width of a tab, in columns.
type 4 template data, containing leading-byte-counted text for the labels of
consecutive lines of the display of a database entry (a line that has no label is
represented by a single zero byte).
49
ADDITIONAL SYSTEM INFORMATION
type 5 general flags options, described below.
type 6 printer setup information, in the form of a PRINTER_PARAMS Structure.
type 7 printer model: a zero terminated string that starts with the model number and
continues with the full file specification of the printer driver file.
type 8 text for the page header: a zero terminated string.
type 9 text for the page footer: a zero terminated string.
type 10 the diamond bar settings: bytes zero, one or two are non-zero if 'Find',
Change or 'Add', respectively, are included in the diamond bar.
type 11 the current search field data: the first two bytes specify the start field (with
0x0000 meaning search in all fields), the second two bytes specify the end field
(with Oxffff meaning search from the specified start field to the last field in the
record. For example, values of 0x0010 and 0x0020 would imply a search from
field sixteen to field thirty two inclusive.
For further details of the content of fields of type 6, 7, 8 and 9, see Saving and restoring print context
from file in the Printing chapter of the Object Oriented Programming Guide.
Other descriptive record field types may be used by other versions of the Database application (eg types 2
and 3 are used by the MC Database) and should be preserved intact when encountered.
In the above example it can be seen that the width of the tab is equal to 4 columns, as given by the third
and fourth bytes of the type J field that starts at offset 0x3b (remember that the first two bytes are the
record header). The value of the flags options is 0x05, and the contents of the labels can easily be read as
a sequence of leading byte-counted strings.
Note that the first character in a template field name can be a telephone symbol (0x05) in which case the
content of the corresponding field in any type 1 record can be used for automated dialling.
Flags options for the Series 3 Database
The meanings of possible bits in the general flags options (field type 5) are as follows:
0x01 the permanent status window is on
0x02 entries are word-wrapped
0x04 a template should be displayed.
All other bits are ignored and should, by default, be set to zero.
Flags options for the Series 3a Database
The type 5 field in a Series 3a Database descriptive record supports the following flags:
0x01 this bit is ignored by the Series 3a Database
0x02 entries are word-wrapped if this bit is set
0x04 a template should be displayed if this bit is set
0x08, 0x10 if both bits are clear there is no permanent status window; if bit 0x08 is set and
bit 0x10 is clear a small status window is displayed; if bit 0x10 is set and bit
0x08 is clear a large status window is displayed (bits 0x08 and 0x10 should not
both be set)
0x20, 0x40 these two bits record the zoom size of the text in the main display window
according to the following table:
0x00 Roman-11
0x20 Roman-13
0x40 Roman-16
0x60 Roman-8
All other bits are ignored and should, by default, be set to zero.
Type 1 records
Entries in the Database are stored as single type J records in the corresponding .dbf file.
50
4 DBF FILES
The following special (non-text) characters may occur within any string in a type 1 record in a .dbf file,
with these meanings:
0x15 forced line feed (with the two part-paragraphs on either side of the forced line break just
counting as one paragraph for the purposes of the template, even though each part word-
wraps separately)
0x05 prefixes a diallable telephone number (over and above any indication of diallability given in
the template text)
0x14 if this occurs as the first character in a string, it means this field should in fact be joined
together with the preceding one, as discussed in the following section.
Continuation sub-fields
The Series 3 Database uses a special mechanism in order to store fields of text exceeding 255 characters
in length. Any such fields are broken down into sub-fields with at most 255 characters of text:
® the first 255 characters form the first sub-field
= up to the next 254 characters form the second sub-field, with the special character 0x14 being
placed at the beginning of the string (and included in the preceding byte count)
= additional continuation sub-fields of up to 254 characters are used as required, in each case again
being preceded by the 0x14 character.
The continuation sub-field prefix character was in fact specially chosen so as to give a suggestive display
on the MC, should the .ddf file be read into the MC Database application.
5 a SS |
The Series 3 Agenda
This section describes only the Series 3 Agenda. The Series 3a Agenda is described in a separate chapter.
The Series 3 Agenda stores its files in the DBF file format, as described in general terms at the beginning
of this chapter. By convention, the Series 3 Agenda uses files with extension .agn.
Field information record
The field information record of a Series 3 Agenda file is always as follows:
<05><20><00><00><00><00><03>
indicating that each type 1 record in a .agn file consists of four integer fields followed by one string
field. More details of these fields are given below.
Extended header
There are no extended headers on any Series 3 Agenda files.
Descriptive record
For an example of a descriptive record, consider the following, which is a dump of a default newly-
created (and exited) Series 3 .agn file:
O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile.
10: Of 10 16 00 Of 10 05 20 00 00 00 00 03 0e 30 Oc ww... wwe 0.
20: f0 a4 01 3c 00 01 00 OF 00 1c 02 2e 00 seSecee. ome
The header of the first record after the field information record is <0e><30>. This means that the record
has type 3 and body length 0x0e bytes. Evidently, this record extends to the end of the file.
The body of this descriptive record is made up of a single field of type 15 and length ox0c. The body of
this single field consists of 6 integers, with the following meanings:
= the time (in minutes since midnight) for the first appointment slot of the day
= the default length of an appointment (in minutes)
= whether or not alarms are on by default
= the default advance time (in minutes) before a timed appointment for an alarm
51
ADDITIONAL SYSTEM INFORMATION
= the default time (in minutes since midnight) for the alarm for an untimed appointment
= the character (low byte only - the high byte is ignored) to be used as the time separator.
Evidently, these sub-fields match the various lines in the Settings dialog within the Agenda application.
Type 1 records
Entries in an Agenda are stored as single type 1 records in the corresponding .agn file.
Individual ToDo items and Repeated items are also stored as single type 1 records.
The five fields in Agenda type 1 records are
integer: DayNumber
integer: Duration
integer: Time
integer: AlarmTime
String: Text
DayNumber is the number of days since 1/1/1900 (which is day zero). As far as the Series 3 Agenda is
concerned, the first legal day is 1/1/1980, and the last legal day is 31/12/2049.
Duration, Time, and AlarmTime are all stored in minutes (ignoring for the moment the fact that some
calculations with these values have to be performed in places - as described below).
The MSB (most significant bit) of Time is a flag that indicates whether the item is timed or untimed. If
the MSB is set then the item is untimed. Accordingly, to extract the time from the Time field this value
must be anded with 0x7fff to remove the MSB
The LSB (least significant bit) of Duration is a flag that indicates whether the item has an alarm attached.
If the LSB is set then no alarm is attached. Accordingly, to extract the duration from the Duration field,
divide this value by 2 (thus removing the LSB and shifting down the duration).
If the item is untimed then the Time field contains the day note slot number and its MSB must be set (ie
or in 0x8000). In this case, the Duration field simply equals 0 if an alarm is attached or 0x01 if no alarm
is attached.
Note that the end time of a timed item (obtained by adding its start time and its duration) must always be
less than 1440 (ie midnight).
Calculating with AlarmTime
For internal efficiency reasons, the way in which the alarm pre-time (as defined by the user) is stored in
the .agn file is somewhat counter-intuitive.
To recover the pre-time of the alarm for a timed appointment, the values of Time and AlarmTime for the
entry should be added, and then the value (23*60+59) subtracted from this result.
For example, if the value of Time is 0x3fc and the value of AlarmTime is 0x1b2, the actual alarm pre-time
is
Ox3fe + Ox1b2 - (23*60 + 59)
ie 15 minutes (for an appointment actually at Spm in the afternoon).
In the case of untimed appointments, the integer value obtained when AlarmTime is divided by 24*60
gives the number of days previous to the appointment when the alarm is due. The time of day when the
alarm is due is obtained by subtracting the remainder when AlarmTime is divided by 24*60, from
23*60+59.
For example, if the value of Time is 0x8000 and the value of AlarmTime is 0xe87, note that
Oxe87 = 2*(24+60) + 839
so that the alarm is due two days in advance of the appointment, at 10am (since 23*60+59-839=600).
If required, appropriate values of AlarmTime to ensure given alarm pre-times can easily be calculated by
reversing the above formulae.
52
4 DBF FILES
Finally, note that if an appointment does not have an alarm set for it, the value of AlarmTime should be
set to Oxffff.
The text of an appointment
The text for an appointment is contained within the Text field of the record.
In all but the cases of repeated entries, the text is simply the entire contents of the field. For repeated
items, the final six bytes of the Text field have a special meaning, as discussed below.
In all cases, the length of the actual text for an appointment cannot exceed 63 characters.
ToDo items
ToDo items have a DayNumber of Oxf#ff, and must be stored as timed items (and so the MSB of the
Time field must be clear).
The Time field contains the item priority, that is a value from 1 to 9.
The Duration field contains a secondary integer key, which orders the ToDo items within a given
priority.
ToDo items cannot have alarms attached.
Repeat items
Timed and untimed repeat items are stored in the same general way as normal timed and untimed items,
except that they have a DayNumber of Oxfffe.
The specific repeat details are stored in the six bytes at the end of the Text field and have the following
format:
Byte: Type
Byte: Interval
Integer: StartDayNumber
Integer: EndDayNumber
The Type field can take the following values:
0 Repeat yearly
1 Repeat monthly by date
2 Repeat monthly by day
3 Repeat weekly
4 Repeat daily
5 Repeat workdays.
StartDayNumber and EndDayNumber are stored as the number of days since 1/1/1900 (which is day 0).
Setting EndDayNumber to zero means the item repeats "forever".
53
CHAPTER 5
SERIES 3A AGENDA FILE FORMAT
Series 3a Agenda files are binary files containing typed variable length records. They use the same basic
file and record structure as DBF files, but the file signature and internal record structure are NOT the
same.
In contrast, Series 3 Agenda files are DBF files and are described separately, in the DBF Files chapter.
SESE SS SS a a a ae ae TT
Basic structure of Agenda files
The basic file structure for Agenda files is as follows:
<standard header> Used to identify the file type and the version of the file structure.
<extended header> For future use, currently omitted.
<data records> The main body of the file, containing entries and preferences.
The standard header
The standard header is present at the start of all Agenda files and is always 32 bytes long.
AGD_SIG_SIZE 16
AGD_SPARE_SIZE 12
typedef struct
UBYTE sig (AGD_SIG_SIZE];
UWORD version;
UWORD hSize;
UBYTE spare[AGD_SPARE_SIZE];
> AGD_FILE_HEADER;
The first 16 bytes of the file are always the zero terminated string "AgendafiteType*". This is used to
identify the file as an Agenda file.
The two byte parameter version, at file offset 0x0010, is the file version number, as described in the
General System Services chapter of the Plib Reference manual. This is currently always 0x100F. The most
significant nibble is the major version number; any change in this indicates that the file format may not
be backwards compatible.
The two byte parameter hSize gives the combined size of the standard and extended header. This
effectively gives the file offset of the first data record within the file. Currently this is always 0x0020.
The array spare is reserved for future use by Psion.
The extended header
At present this is never used and is reserved for future expansion.
The data records
As in DBF files, all data is stored as variable length, typed records, with the type and length combined
into a single word (two bytes). The most significant nibble of the word gives the record type. The type
55
ADDITIONAL SYSTEM INFORMATION
determines how the contents of the record are to be interpreted. The remainder of the word gives the
length of the data that follows. This file structure is designed to be flash friendly in that deleted records
are not normally removed from the file but are marked with record type 0, which can be done in place.
This structure allows 16 record types 0x0 to Oxf, each of which are allowed to be up to Oxffe (4094) bytes
long. Although a record length of Oxfff is not explicitly illegal, it is not used.
SSS SS eee ee en eS ee ee ee)
Record Types
There are sixteen record types as follows.
Type Record
0 Deleted
1 Appointments Gimed day entries)
2 Day notes (un-timed day entries)
3 Anniversaries
4 To-do entries
5 Repeat records
6 Anonymous data
7 Reserved
8 Reserved
9 To-do list information
10 Descriptive records 1
11 Descriptive records 2
12 Descriptive records 3
13 Descriptive records 4
14 Descriptive records 5
15 Illegal (used to mark a write failure)
Currently record types 6, 7 & 8 are never generated by the Series 3a Agenda.
A number of the records contain day numbers and times. Unless stated otherwise all dates are given as a
daynum. A daynum is the number of days from 1 Jan. 1970. For technical reasons dates before 1 Jan.
1980 (daynum 3652) or after 31 Dec. 2049 (daynum 29219) are ignored by the Agenda and where
appropriate will be clipped to one or other of these dates (for example a repeating entry that starts on 10
June 1970 will have its start date 'clipped' to 1 Jan. 1980).
aS 6 ee eee oe ee ae
Type O - deleted record
As for DBF files, deleted records are not normally removed from the file but have their record type
changed to type 0. As any of the above record types may be converted to a type 0 record, there is nothing
that can usefully be said about the contents of such a record (indeed the record may not even have been a
valid Agenda record before it was deleted). Records of this type should be ignored except to calculate the
amount of space that would be freed by compressing the file.
There may be any number of such records in the file.
56
5 SERIES 3A AGENDA FILE FORMAT
ESE SSS SS SS ee ee ee ee eS a
Types 1 to 4 - entry records
Records of type 1 to 4 contain details of individual Agenda entries. Each has the same conceptual
structure as follows:
<Entry details field> This is dependent on the entry type.
<Title field> Obligatory, variable length field containing the text of the entry.
<Alarm field> Optional, fixed length field containing alarm time and sound.
<Memo field> Optional variable length field containing any memo for the entry.
The record type is used to determine the length and meaning of the first field. Although these have some
similarities all four are individually described in details below.
coe
AIK
This field contains most of the non-textual information describing when an entry occurs, what other
fields it has and various bits of type specific information, such as the duration for timed appointments.
Type 1 (timed day entry/appointment)
A type 1 record stores details of entries that occur at a specific time on a specific day. In the Series 3a
Agenda these are called timed day entries.
The details field for a timed day entry consists of eight bytes structured as follows:
UWORD day;
UWORD time;
UBYTE attr;
UBYTE code;
UWORD dur;
day is the daynur of the day on which the entry appears.
time is the time of the start of the appointment in minutes from midnight.
attr is a byte containing flags for attributes the entry may or may not have (see
below).
code is the ASCII character code for the symbol that is to be associated with the
entry when it is visible in the Year view. Values less than 32 are ignored and
treated as if the entry should not appear in the Year view.
dur is the duration of the appointment measured in minutes. It is constrained such
that the appointment cannot end after 11:59 PM. i.e. this field is between 0
and 1439 - time (inclusive).
Type 2 (untimed day entry/note)
A type 2 record stores details of entries that appear on a specific day but do not have a time associated
with them. In the Series 3a Agenda these are called untimed day entries.
The details field for an untimed day entry consists of six bytes structured as follows:
UWORD day;
UWORD slot;
UBYTE attr;
UBYTE code;
day is the daynum of the day on which the entry appears.
stot is the time slot (in minutes from midnight) in which the entry will appear in
the Day and Week views. For example a stot value of 780 would show the
entry at the start of the 1pm slot. If this is oxffff then the entry will appear in
the default slot.
attr is the attributes byte (see below).
57
ADDITIONAL SYSTEM INFORMATION
code is the ASCII character code for the symbol that is to be associated with the
entry when it is visible in the Year view. Values less than 32 are ignored and
treated as if the entry should not appear in the Year view.
Type 3 details (anniversaries)
A type 3 record stores details of anniversaries (entries which appear in the Anniversary view). Although
these are usually repeated there are cases where a single anniversary entry will exist. For details of
repeated entries see type 5 records below.
The details field for an anniversary record consists of nine bytes structured as follows:
UWORD day;
UWORD slot;
UBYTE attr;
UBYTE code;
UWORD baseYear;
UBYTE displayAs;
day is the daynum for the day the anniversary entry will appear on.
slot is the time slot (in minutes from midnight) in which the entry will appear in
the Day and Week views. For example a slot value of 780 would show the
entry at the start of the Ipm slot. If this is oxffff then the anniversary will
appear in the default slot.
attr is the attributes byte (see below).
code is the ASCII code for the character to display when the entry is visible in the
Year view. Values less than 32 are illegal and cause the entry not to appear in
the Year view.
baseYear is the year of the event that the anniversary commemorates. Positive values
indicate AD years e.g. 55 means 55 AD and negative values indicate BC e.g.
-5 means 5 BC. A value of zero indicates that there is no baseYear. The
allowed range is from 30000 BC to 2049 AD
displayAs contains flags detailing how the entry is to be displayed. The flags are as
follows: 0x01 for baseYear displayed, 0x02 for elapsed years displayed, 0x03
for both of the preceding options and 0x00 for none of them.
Type 4 details (To-do)
A type 4 record holds details of to-do entries.
These are entries which usually have an associated due date and a display from date. They appear in the
corresponding to-do list, and depending on the preference settings will appear in the Day view from the
displayFrom date until they are crossed out or deleted.
The details field for a to-do entry consists of 14 bytes structured as follows:
UWORD displayFrom;
UWORD slot;
UBYTE attr;
UBYTE code;
UWORD dueDate;
UBYTE listNo;
UBYTE priDisp;
ULONG order;
displayFrom the daynum of the day on which the entry first appears in the Day/Week views
of the Agenda. This must normally be the same or less than the dueDate value.
If the entry is crossed out (see the description of the attr byte below) this is
the daynum of the day on which the entry was crossed out. In this case, and
only in this case, the displayFrom can be later than the dueDate.
If the disptayFrom daynum is Oxffff, then this is an un-dated to-do i.e. one that
always appears on today. In this case the dueDate will also be Oxffff.
slot the time slot (in minutes from midnight) in which the entry will appear in the
Day and Week views. If this is oxffff then the entry will appear in the default
slot of the appropriate to-do list.
58
5 SERIES 3A AGENDA FILE FORMAT
attr the attributes byte (see below).
code the ASCII code for the character to display when the entry is visible in the
Year view. Values less than 32 are illegal and cause the entry not to appear in
the Year view.
dueDate the daynum of the day the to-do should be done by. If this value is oxffff the
record is an undated to-do (i.e. one which always appears on today when it
appears in the Day/Week views).
ListNo the ID (in the range 0 to 255 inclusive) of the to-do list in which the entry will
appear. Note that a value of zero does nor necessarily mean that the entry
appears on the first to-do list in the To-do view - the order is determined by
the contents of a type 11 record. See the description of type 9 records for
further details of this ID.
pridisp this byte consists of two nibbles that give the priority and the method of
displaying the to-do.
The least significant nibble (bottom four bits) has a value one less than the
priority of the to-do. Thus a priority one to-do has value zero, priority two has
value one etc. This will currently always be in the range zero to eight inclusive
and all other values are illegal.
The most significant nibble (top four bits), determines how the due date should
be displayed. There are currently four legal values:
0 - Automatic, shown as a date until within one week of the due date, then
shown as, for example, "Next Wed".
1 - Always shown as a date.
2 - Shown as the number of days until the due date.
3 - The due date is never shown.
order this determines the position of the entry in its to-do list when the list is
displayed in manual order. This field is not assigned consecutively. Thus a
value of 3 for example in this field does not necessarily mean that the entry
appears third (or fourth) on the to-do list.
The attributes byte aftr.
The above record types (1 to 4) contain an attributes byte as the fifth byte within the record data. This
byte contains flags which indicate which of the two optional fields are present in the record, whether or
not the entry is repeated etc. The following flags are currently defined for the attributes byte (all other
bits should be 0).
Bit Meaning
00000001 Once only: if this bit is set the entry appears only once in the Agenda. If it is
clear the entry is repeating and there will be an associated type 5 repeat record
elsewhere in the file.
00000010 Pending: this bit is set if the entry has not been crossed out. If it is clear the
entry has been crossed out. In the case of to-do entries this alters the meaning
of the displayFrom field of the details.
00000100 Display code: if this bit is set the entry should be displayed in the Year view
(providing it has a legal code field): if it is clear the entry should not appear in
the Year view, regardless of the value of the code field.
00001000 No alarm: this bit is set if the entry does not have an associated alarm in which
case there will be no alarm field at the end of the record. If it is clear there is
an alarm field immediately after the title field.
00010000 No memo: this bit is set if there is no memo associated with the entry, in
which case there will be no memo field at the end of the record.
The wie Geld
The title field must be present for entry records of all four types. This field follows immediately after the
details field and contains the text for the entry as well as flag for how that text should be displayed e.g.
bold, italic etc.
The format of the title field is:
59
ADDITIONAL SYSTEM INFORMATION
UBYTE style;
UBYTE len;
title text.
style contains flags indicating how the text should appear. The flags are as follows:
0x01 for bold, 0x02 for underline, 0x20 for italic.
len is the length of the text comprising the title, and the number of bytes
following. This may take any value from 0 - 254.
title text is len bytes of the title. Note that this text is not zero terminated.
This fixed length field is only present if the attributes byte does not have bit 3 (0x08) set, i.e. there is an
alarm set for the entry.
When present this entry immediately follows the title field and has the following format:
UWORD preTime;
UBYTE len;
UBYTE sound [8];
preTime is the time at which the alarm should occur given in minutes before 11.59 on
the day the entry appears on. (In the case of a type-4 to-do record this is the
due date). This field can be between 0 and 46079 (midnight before, 31 days
" before the entry).
len this gives the length of the text in the sound element.
sound is always eight bytes long the first ten of which contain the name of the WVE
file for the alarm. A number of WVE files having names of the form
SYS$ALnn are built-in to the ROM. In addition name can be set to an ASCII
character with value between 1 and 16 inclusive: currently only "\0x01",
"\0x02" and "\0x10" are used corresponding to the rings, chimes and silent
alarms. If the name of the file is less than eight bytes long, all remaining bytes
should be zero.
This variable length field is only present if the attributes byte (in the details field) does not have bit 4
(0x10) set, i.e. there is a memo attached to the entry.
When present this field comes at the end of the record, immediately after the alarm field if there is one,
and after the title field if there is not. The field has the following format:
UWORD dataLength;
UWORD Leni;
UWORD len2;
UBYTE data [I];
UBYTE data2[];
dataLength is the length (in bytes) of the data in the memo field. This can be between 0
and 3600 (inclusive) and includes two separate blocks of data.
tent the length of the first block of data, with the two most significant bits used for
flags
len2 the length of the second block of data
data contains len1&0x3fff bytes of data. If teni has the bit 0x4000 set, the first ten
bytes contain options data, as described for the options data (type 1) record in
the Word Processor Files Format chapter, otherwise a default set of options
(the word processor default options) is used. If ten1 has the bit 0x8000 set, the
memo is password-protected. In this case the next eighteen bytes contain
password-matching information and the following data is encrypted. The
remaining bytes contain the plain text of the memo, with each paragraph
terminated by a zero byte. As described for the word processor file format, the
data does not include the final zero terminator.
60
5 SERIES 3A AGENDA FILE FORMAT
data2 len2 bytes of data containing the document index for the memo. This is in
exactly the same format as described in the Word Processor File Format
chapter for the document index (type 9) record.
EEE ee ee eee ee ee ea
Type 5 - repeats
When an entry is set to repeat in the Agenda, a second record is written to the file in addition to the type
1 - 4 entry record. This record contains the date to repeat until, the days to repeat on and a list of those
dates for which the repeat should be suppressed.
Repeat records are always paired with an entry record which has bit 0 (0x01) of the attributes byte clear.
Because of the way the Series3a Agenda writes the file a type 5 repeat record will always occur after the
associated entry record, but this is not necessary and there is no reason why it should not occur earlier in
the file. If a repeat record is missing its associated entry record or if a repeated entry record exists for
which there is no associated repeat record, then the record in the file will be ignored.
The repeat record is structured as follows:
UBYTE alg;
UBYTE ival;
UWORD endDate;
UBYTE type;
UBYTE tags[n];
ULONG filePos;
UWORD exceptions [];
alg is the repeat algorithm and various flags. The bottom three bits of this byte
may take one of the following values: 0 - repeat daily, 1 - repeat weekly, 2 -
monthly by date, 3 - monthly by days, 4 - repeat annually.
If bit 3 (0x08), of this byte is set, the repeat should only appear once in the
dated views on the first occurrence after today. Otherwise all valid occurrences
are shown. All other bits in this byte should be 0.
ival is the daily repeat interval. This is zero if the entry repeats daily, 1 if the entry
repeats every other day etc. A value of 255 is not valid.
endDate this is the daynum of the last day on which the entry can repeat. This is not
necessarily the last day on which it will appear. The start date is taken from
the day value at the start of the details field in the entry record. In the case of a
repeating to-do this is the displayFrom field that is normally used to give the
date from which to display the entry. Here it is used to determine the start date
of the repeat algorithm and hence determine which due dates will be associated
with the todos. To work out the display from dates for each instance of the
repeated to-do use the dueDate-displayFrom in the entry record to determine the
number of days warning for each instance of the repeat.
Note that the Agenda does not support anniversaries that repeat for limited
periods. In consequence, it is recommended (but not required) that a repeat
record for an anniversary (type 3) record should have an endDate set to the
value Oxffff.
type is the type (1-4) of the associated entry record. The Agenda requires this
information to be present, even though it is technically redundant (since it can
be determined from the associated record itself).
61
ADDITIONAL SYSTEM INFORMATION
tags is n bytes that determine which days occur in the repeat sequence. The number
of bytes n and their meaning is determined by the repeat algorithm. For repeat
daily/annually there are no tag bytes since the start date and ival determine
which dates to repeat over.
For weekly repeats there are two tag bytes. The first has a bit set for each day
of the week on which the repeat occurs. Bit 0 for Monday, bit 1 for Tuesday
etc. Bit 8 is not used and should always be 0. The second byte determines
which is the first day of the week, 0 for Monday, 1 for Tuesday etc. This is
significant when the repeat does not occur every week. A repeat which occurs
on say, Tuesday and Thursday of every other week, occurs on different dates if
the week starts on Monday than it does if the week starts on Wednesday.
For monthly by date repeats there are four tag bytes. Each bit in these bytes
represents a different day of the month. Bit 0 in the first byte is the ist of the
month, bit 1 the second and bit 7 the eighth of the month. Bit 0 of the second
tag byte is set if the repeat occurs on the 9th and so on. Bit 7 of the fourth byte
is not used and should be 0.
Monthly by days repeats have five tag bytes. Bytes 0 to 3 correspond to the
first, second, third and fourth occurrences of each day, for example bit 1 of
byte 2 is set if the algorithm repeats on the 3rd Tuesday of each month. The
last tag byte contains bits set if the repeat should occur on the last Monday,
say, of the month.
filePos is the offset from the start of the file at which the corresponding entry record
can be found. This is given in bytes from the start of the file (not the start of
the data records), and gives the position of the type length word at the start of
the record. Note that this mechanism of associating repeat records with the
underlying entry relies on the deleted entries not being removed from the file:
they are just marked with the deleted record type. Removing such records
would require all FitePos fields to be recalculated.
exceptions The remainder of the record consists of words, each of which is the daynum of
a day on which the repeat should be suppressed. The number of exceptions is
determined by the length of the record. Although the Series 3a Agenda
currently always writes these exceptions in strictly increasing order, there is no
guarantee that this will always be the case. Any illegal values (either outside
the valid range for the Agenda or on a day which is not normally a repeat
instance) should be ignored but preserved.
Type 6 - anonymous data
This record type is currently not used and is set aside for storing non-displayable text carried with the
Agenda. It is intended that this information will be used by, say, conversion programs that convert other
Agenda file formats to that of the Series 3a. This allows the file to be converted back without losing
information from the original file. These records are ignored by the series 3a engine except when
merging files. In this case incoming anonymous data records are added to the file into which data is being
merged.
Types 7 and 8 - reserved
These record types are reserved for future expansion and should not be used.
Type 9 - to-do list information
There is one record of this type for each to-do list in the Agenda. Each contains the settings for the to-do
list and the to-do list number (as in type 4 to-do records) that corresponds to the list.
The format for these records is as follows:
5 SERIES 3A AGENDA FILE FORMAT
UBYTE sig;
UBYTE cat;
TEXT name[16+1};
UBYTE catid;
UWORD flags;
UWORD vis_slot;
UBYTE advance_days;
UBYTE yearcode;
AGPREF_ALARM a;
UBYTE style;
UBYTE spare;
sig a signature byte which determines the format of the rest of the record.
Currently the only legal value is Oxff
cat the ID, in the range 0 to 255 inclusive,! of the to-do list to which the type 9
record refers. The settings apply to all to-do entries (type 4 records) that have
a value of the ListNo field that is equal to the value of cat. See the description
of the type 11 record for the order of appearance of to-do lists in the To-do
view.
name [1 the name of the to-do list, containing up to 16 characters. The remaining bytes
of name] are all NULL
catid the to-do list ID, as in cat, repeated for reasons of coding convenience
flags the contents of this field are described below
vis_slot the default position in the Day view, in minutes from midnight
advance_days
the default number of days advance warning for alarms. The value is retained
even when the list is not dated
yearcode the ASCII code of the character used in the year view. This character is always
specified, even if the to-do list is not visible in other views
a an AGPREF_ALARM struct that specifies any untimed alarm. See the explanation of
this struct in the later description of the General Descriptive (type 13) record
style the default style for entries. Its value is either G_STY_NORMAL, or any
combination of G_STY_BOLD, G_STY_ITALIC and G_STY_UNDERLINE
spare this field is not currently used in Agenda files, but should be set to zero. It is
reserved for use by future file versions.
The flags field
This field contains, in its least significant four bits, a value between one and nine inclusive. This
specifies the lowest priority of item that will be displayed in other views.
The two flag values 0x0010 and 0x0020 are mutually exclusive and determine the order in which items are
listed. If bit 0x0020 is set, the items in the to-do list are listed in a user-specified order. Alternatively, if
bit 0x0010 is set, the items are ordered by priority, with items of the same priority listed by date. If
neither bit is set, items are listed in date order, with items of the same date listed by priority.
If bit 0x0040 is set, crossed-out entries are shown in the list.
If bit 0x0080 is set, crossed-out entries are shown in other views, provided that bit 0x0200 is also set.
If bit 0x0100 is set, the entries are displayed with sequentially numbered bullets, otherwise they are
bulleted with their priorities.
Setting bit 0x0200 specifies that the entries are displayed in other views.
Setting bit 0x0400 specifies that entries are dated by default.
Bit 0x0800 is used internally by the Agenda application and may be set or clear in a type 9 record. It is
ignored when the record is read.
1 There is no need for to-do list IDs to be consecutive. An ID can have any value up to, and including,
255. However, a to-do list ID generated from within the Agenda application will always lie within the
range O to 98 inclusive.
63
ADDITIONAL SYSTEM INFORMATION
The most significant four bits are not used, and should be set to zero. (
ee ea et et ee eee ee ey eee
Types 10 to 14 - descriptive records
Records of types 10 to 14 inclusive contain the preferences settings for the Agenda (these may be set via
the preferences dialog). Only one record of each type is allowed per Agenda file. If there is more than
one record of any type, only the last record of each type is significant.
A descriptive record consists of the usual header word followed by the record body. The record body
contains either simple data or a set of type/length/value (TLV) fields. A TLV field consists of a one word
header followed by the field body. The top four bits of the field header contain the field type. The
bottom 12 bits contain the length of the field body. No more than one of each of the specified fields can
be present in a given record.
The structure of these records should not be extended (extra TLV fields should not added even though
these would be ignored).
Type 10 to 14 records are described in greater detail below.
== SSeS ee ee ey (
Type 10 - styles descriptive record
The styles descriptive record contains the styles and emphases that are used by the Memo editor for all
memos in the file.
This record is written when a memo has been created for the first time, and thereafter whenever its
content has changed.
The body of this record contains the following:
UWORD stylen;
UWORD emphlen;
UBYTE stydata[stylen];
UBYTE emphdatalemphlenj;
stylen the total length of the following style data
emphLen the total length of the following emphasis data
stydata styten bytes of data, consisting of one or more styles. Each style occupies 80
bytes and is of the same structure as described in the Word Processor File
Format chapter for the body of the word processor style data (type 6) record
emphdata emphlen bytes of data, consisting of one or more emphases. Each emphasis
occupies 28 bytes and is of the same structure as described in the Word
Processor File Format chapter for the body of the word processor emphasis
data (type 7) record
SS Se Se en a re
Type 11 - to-do manager descriptive record
This record is written on creation of a new Agenda and so is always present. It gets rewritten whenever
changes have been made.
This record contains the information that the Agenda needs to determine which position each to-do list
has in the To-do view. The body of the record consists of three or more bytes, structured as follows:
UBYTE sig;
UBYTE ncats;
UBYTE catid[ncats]
sig is the signature and is always Oxéc.
neats is the number of categories, and must not exceed 99.
5 SERIES 3A AGENDA FILE FORMAT
catidincats] determines the order of appearance of to-do lists in the To-do view. The array
contains the IDs, in display order, of all the to-do lists in the Agenda file.
Thus catidt0] holds the ID of the first displayed list, catid(1] the ID of the
second, and so on, up to a maximum of catid[98}.
Type 12 - frequently changing data descriptive record
This record is written on creation of a new Agenda and so is always present. However, as it contains data
that changes frequently, it is only rewritten when the file is closed.
This record contains zoom, wrap and status window settings for each view. The body consists of a TLV
header word (type zero, length 18) followed by six viEw_SCREEN_CFG structures for the Day, Week, Year,
To-do, Anniversary and List views respectively. A VIEW_SCREEN_CFG structure consists of three bytes and
is structured as follows:
UBYTE statmode;
UBYTE wrapmode;
UBYTE zoom;
statmode this field is a flag for the status window. It is 0 if a status window is not
visible, 1 if the small status window is visible and 2 if the large status window
is visible. This flag applies to all views.
wrapmode in all views except the Year view the wrapmode field is 1 if wrap is on, and is
otherwise 0. In the Year view (which does not use wrapping) the wrapmode field
contains the index of the month that is displayed in the first row of the planner
(0 = January, 11 = December).
zoom this field takes the value 0 to 3 corresponding to Roman fonts of height 8, 11,
13 and 16 respectively. It is relevant for the Day, Week, To-do, Anniversary
and List views. The zoom field is unused in the Year view entry and is set to 0.
Type 13 - general descriptive record
This record is written on creation of a new Agenda and so is always present. It stores data shown in the
dialogs under the Preferences menu. It gets written whenever the values shown in one of these dialogs are
changed.
This record contains entry defaults and all individual view preferences (to-do entry defaults are stored in
to-do list records). Each record has the normal Agenda type/length header followed by one or more TLV
fields. There are sixteen possible type fields only some of which are currently used: the rest are reserved
for future use. If a field is not found the Agenda will use the corresponding default values. The fields can
be in any order.
Type Field
4 Diamond list setup
5 Day entry defaults
6 Anniversary defaults
7 General defaults
8 Day view settings
9 Week view settings
10 Year view settings
11 To-do view settings
12 Anniversary view settings
13 List view settings
14
Diamond list setup field =
The diamond list setup field indicates which views should be included in the diamond list. It consists of
six bytes structured as follows:
UBYTE fnbar [6] ;
65
ADDITIONAL SYSTEM INFORMATION
fnbar contains six bytes corresponding to the Day, Week, Year, To-do, List and
Anniversary views respectively. Each byte is either TRUE or FALSE depending on
whether or not the view is to be included in the diamond list.
The day entry defaults field contains the defaults for entries in the Day view. The field consists of 38
bytes structured as follows:
UWORD DefUntimedEntViewT ime;
UWORD DefTimedEntT ime;
UWORD DefTimedEntDuration;
UBYTE DefTimedByDefault;
UBYTE DefYearSym;
AGPREF_ALARM UntimedAlarmefs;
AGPREF_ALARM TimedAlarmefs;
UBYTE style;
UBYTE spare;
DefUntimedEntViewTime is the default display time for untimed entries in minutes since 00:00.
DefT imedEntT ime is the default display time for timed entries in minutes since 00:00.
DefT imedEntDuration is the default duration for a timed entry in minutes.
DefT imedByDefault is 1 if entries are timed by default, otherwise it is 0.
DefYearSym is the character code for the default year symbol.
Unt imedAlarmDefs contains details of the default alarm for untimed entries (see below for a
description of the AGPREF_ALARM structure).
TimedA Larmefs contains details of the default alarm for timed entries (see below for a
description of the AGPREF_ALARM structure).
style is the style of the font used for the entry. It should be a suitable ored
combination of the Wserv c_sTy_xxx flags: 0x00 for normal, 0x01 for bold, 0x02
for underline and 0x20 for italics.
spare is reserved and is set to 0.
An AGPREF_ALARM structure contains default alarm details. It consists of 14 bytes structured as follows:
UBYTE on;
UBYTE ndays;
UWORD minutes;
SE_SND snd;
on is 1 if an entry has an alarm by default and 0 otherwise.
minutes for timed entries minutes is the time interval in minutes between the alarm
going off and the start of the entry. For untimed entries minutes is the default
alarm time in minutes from midnight.
ndays for timed entries ndays is unused but should be set to 0. For untimed entries
ndays is the default number of days between the alarm going off and the start
of the entry.
snd contains details of the default alarm sound (see below for a description of the
SE_SND structure).
The SE_SND structure contains details of the default alarm sound. It consists of ten bytes structured as
follows:
UBYTE len;
TEXT name [8] ;
UBYTE zero_term;
Len is the length of the name of the alarm.
name contains the name of the alarm stored as a sequence of len characters. When
len is less than eight the first unused byte contains a NULL character. Any
remaining unused bytes can take any value.
66
5 SERIES 3A AGENDA FILE FORMAT
zero_term contains the NULL character.
An anniversary entry defaults field contains the defaults for entries in the Anniversary view. It consists of
20 bytes structured as follows:
UWORD DefEntViewT ime;
UBYTE AutoApplyYearSym;
UBYTE DefYearSym;
AGPREF_ALARM AlarmDefs;
UBYTE style;
UBYTE spare;
DefEntViewT ime is the default display time for anniversaries in minutes since midnight.
AutoApplyYearSym is 1 if the year symbol is on by default, otherwise it is 0.
DefYearSym is the character code of the default year symbol.
Alarmefs contains the default alarm details for timed and untimed entries (see the Day
entry defaults field for details of the AGPREF_ALARM structure).
style is the style of the font used for the entry. It should be a suitable ored
combination of the Wserv G_sty_xxx flags: 0x00 for normal, 0x01 for bold 0x02
for underline and 0x20 for italics.
spare is reserved and is set to 0.
UBYTE p_psion_enter;
UBYTE timesep;
p_psion_enter is set to TRUE if PSION+ENTER is used to complete an entry without going into
the Entry details dialog. Otherwise p_psion_enter is FALSE.
timesep is the character code for the Agenda time separator character.
UWORD agnv_flags;
ADENTVU_PREF left;
ADENTVU_PREF right;
agnv_flags this field contains both general view flags and Day view flags (all bits not used
are reserved). The general view flags are as follows:
0x01 for show appointment duration (Day, List, Week and Year views),
0x02 for show appointment end time (Day, List, Week and Year views only),
0x100 for show untimed day notes (Day, List and Week views only),
0x200 for show anniversaries (Day, List and Week views only),
0x400 for show to-dos (Day, List and Week views only) and
0x800 for show timed day notes (Day, List and Week views only).
The Day view flags are as follows:
0x04 for title to go on right hand side,
0x08 for slot compression off,
0x10 for duration arrows off and
0x20 for show overlap bars off.
teft contains the preferences for the left hand side of the Day view (see below for a
description of the ADENTVU_PREF structure).
right contains the preferences for the right hand side of the Day view (see below for
a description of the ADENTVU_PREF structure).
An ADENTVU_PREF structure consists of 12 bytes structured as follows:
67
ADDITIONAL SYSTEM INFORMATION
UWORD flags;
UWORD begintime;
UWORD beginvis;
UWORD endvis;
UWORD endtime;
UWORD slotdur;
flags oo a combination of the slot lines on flag (0x01) and the slot times on flag
x .
begint ime is O for the left hand side and beginvis for the right hand side.
beginvis is the start time of the first slot in minutes from midnight.
endvis is the start time of the last slot in minutes from midnight.
endt ime is right.beginvis for the left hand side and 1440 for the right hand side.
slotdur is the slot duration in minutes.
The Week view settings field consists of two bytes as follows:
UWORD pref_flags;
pref_flags contains both general view flags (see above under the Day view settings field),
and Week view flags. Currently there is only one Week view flag: 0x4 for
show title on right hand side.
The Year view settings field consists of two bytes as follows:
UWORD pref_flags;
pref_flags contains a combination of the general flags (see under the Day view settings
field above) for showing appointment duration and/or end time or neither.
The To-do view settings field consists of two bytes structured as follows:
UWORD ncols;
ncols contains the number of columns to be shown in the To-do view. The value of
ncols should not be more than the number of existing categories.
The Anniversary view settings field consists of two bytes structured as follows:
UWORD ncols;
ncols contains the number of columns to be shown in the Anniversary view (1 to 4).
The List view settings field consists of two bytes structured as follows:
UWORD pref_flags;
pref_flags contains a combination of general view and Day view flags (see under the Day
view settings field above) and the show-repeats-once flag (0x04).
68
3 SERIES 3A AGENDA FILE FORMAT
—SSS SSS ee ee ee ee ee
Type 14 - print setup descriptive record
This record does not initially exist. It is created/rewritten to contain a new copy of the data for the
Agenda print setup after using the Agenda Print setup dialog. It is also created/rewritten after a memo
has been created or edited and Print setup data has been changed. Hence it is possible that the record will
only contain Agenda Print setup data or Memo Print setup data.
The record consists of a one word header followed by a series of TLV fields.
Field types 0 to 3 and 6 to 9 are allowed. Field types 0 to 3 are used for the main Agenda print setup.
Field types 6 to 9 are identical to field types 0 to 3 and are used for the memo print setup.
Field type O and 6
Contains printer parameters in a PRINTER_PARAMS structure as returned by the PR_GET_PARAMS method of the
printer active object of the FORM dyl.
Field types 1 and 7
Contain printer model data from the PR_SENSE_MODEL method of the printer active object. The first byte is
the model number as returned by PR_SENSE_MODEL, followed by the name, up to and including the NULL.
Field types 2 and 8
Contain printer header text from the PR_GET_HD method of the printer active object including the
terminating NULL.
Field types 3 and 9
Contain printer footer text from the pR_GET_HD method of the printer active object including the
terminating NULL.
LSS SSS SS ee ee ee ae ee ae)
Type 15 - illegal
This record type is illegal and is used to protect the Agenda against write failures on a flash SSD.
Writing to a flash SSD can fail at any time due to, say, a low battery. To protect as much as possible
against this the Agenda will write the whole of the rest of the record before 'blowing down' the byte
containing the record type to its correct value. This means that any file which contains a record with type
15 (Oxf) has suffered a write failure and data beyond this point cannot be trusted.
This record type is probably best thought of as an End Of File record, and any program finding a file
with a type 15 record should start by setting the end of the file to the start (the type length word) of the
record.
CHAPTER 6
WORD PROCESSOR FILE FORMAT
This document describes the structure of a Psion word processor document file. The description to a level
that allows other software to read and write non-password-protected document files.
Psion word processor document files contain a file header, followed by a number of type-length-value
records, from the following list:
= options data
= printer-related data
= printer model data
= page header
= page footer
= style data
= emphasis data
= document text
® document index
Document files created by the word processor will contain records in the order listed above. Each record
consists of:
# atwo-byte record type
= atwo-byte record length, len
= Len bytes of data
Unless stated otherwise, all dimensions are stored in twips (1/1440 inch).
Reserved locations
All locations reserved for future use contain a value of zero.
ee ee ee ae aR a eS a a,
The document header
The document header is 40 bytes long. It starts with the 16-byte zero terminated file signature
"PSIONWPDATAFILE” followed by a two byte file version number.
Following this is a 20-byte struct, containing password data. For a non-password-protected document
there are two bytes of zero followed by eighteen bytes, each containing OxeEA.
The remaining two bytes of the header are reserved for future use.
71
ADDITIONAL SYSTEM INFORMATION
3 == ae en ee a ee
Record types
The options data record contains the following items:
UWORD cpos the saved cursor position
UBYTE symbols specifies the visibility of screen symbols, as indicated below
UBYTE backup/statzoom on the MC, a non-zero value indicates that backup files are to be maintained
on the Series 3a this byte stores the current status window and zoom states: the
top four bits indicate the current zoom state (0x22 by default) and the lowest
four bits indicate the status window size: 0, 1 or 2 for off, small or big
respectively
this byte is not used on the Series 3
UBYTE style TRUE to show style bar at the left of the text
for the OPL program editor, a TRUE value sets the use of a bold typeface
UBYTE mono TRUE to load text by line, else by paragraph
for the OPL program editor, a TRUE value sets the use of a monospaced
typeface
UBYTE outlevel lowest outline level to display
not used for the OPL program editor
UBYTE spare! reserved for future use, but may contain the OPL program editor data as
follows:
used by the OPL program editor, where a TRUE value specifies the use of auto
indentation. Set to TRUE by default
UWORD spare2 reserved for future use, but may contain the OPL program editor data as
follows:
used by the OPL program editor, to specify the column spacing for tabs. Set to
2 by default
Displayed screen symbols are determined by any combination of the following bit fields in symbols:
0x01 show tabs
0x02 show spaces
0x04 show paragraph end markers
0x08 show hyphens
0x10 show forced line breaks
i ta record {t: 1 2
This record contains information required to format the document for the printer and to control the
printing process. It includes, amongst other items, descriptions of the page size and margins, the page
numbering style, header and footer position and alignment.
This record consists of a structure that is used to control the display and WDR printing of formatted text
in all applications that require such services. It therefore contains some fields that are not relevant to the
word processor.
The following description is in terms of the P_EXTENT, SCRLAY_FONT and PAGES HEADER structs, defined as:
typedef struct
{
WORD x;
WORD y;
} P_POINT;
72
6 WORD PROCESSOR FILE FORMAT
typedef struct
P_POINT tl;
WORD width;
WORD height;
> P_EXTENT;
typedef struct
UWORD fid;
UWORD style;
UWORD height;
}> SCRLAY_FONT;
typedef struct
SCRLAY_FONT f;
UBYTE align;
UBYTE first_page;
} PAGES_HEADER;
/* typeface number */ (1)
/* font style */ (2)
/* height of font in twips */
/* font data */
/* header alignment */ (3)
/* TRUE to emit on first page */
In these terms, the content of the printer-related record is:
PAGE DATA
WORD width
WORD height
P_EXTENT body
WORD hdtop
WORD hdbot
WORD pdrflags
WORD docflags
UWORD pgbeg
UWORD pgend
RUNNING PAGE HEADERS
PAGES_HEADER top
PAGES HEADER bot
PAGE NUMBERING
WORD offset
WORD last
WORD style
MISCELLANEOUS
SCRLAY_FONT f
UBYTE size_choice
UBYTE wo_control
UWORD spare
UWORD spare2
page width
page height
body print region, with respect to top left of page (4)
page header position (5)
page footer position (6)
0 for portrait, 1 for landscape
can be 3 or 0, depending on whether the document has or has not been printed
page number to start printing (first page is 1)
last page number to print (7)
page header
page footer
page numbering offset
page count, for %m (always reset by pagination)
page number style (8)
base font for body print region (9)
paper size index (10)
TRUE to disable widow and orphan control
reserved for future use
reserved for future use
73
ADDITIONAL SYSTEM INFORMATION
Notes
(1) Typeface numbers are defined in the following list:
0 COURIER 22 OPTIONAL_SB 44 RUSSIAN
1 PICA 23 OPTIONAL_SC 45 OPTIONAL_B
2 ELITE 24 TIMES ROMAN 46 OPTIONAL_C
3 PRESTIGE 25 CENTURY 47 OPTIONAL_D
4 LETTER_GOTHIC 26 PALATINO 48 NARRATOR
5 GOTHIC 27 SOUVENIR 49 EMPHASIS
6 CUBIC 28 GARAMOND 50 ZAPF_CHANCERY
7 LINEPRINTER 29 CALEDONIA 51 OPTIONAL_DA
8 HELVETICA 30 BODONI 52 OLD_ENGLISH
9 AVANT_GARDE 31 UNIVERSITY 53 OPTIONAL_DB
10 SPARTAN 32 SCRIPT 54 OPTIONAL_DC
11 METRO 33 SCRIPT_PS 55 COOPER_BLACK
12 PRESENTATION 34 OPTIONAL_SCA 56 SYMBOL
13. APL 35 OPTIONAL_SCB 57 LINE_DRAW
14 OCR_A 36 COMMERCIAL_SCRIPT 58 MATH_7
15 OCR_B 37 PARK_AVENUE 59 MATH_8
16 STANDARD_ROMAN 38 CORONET 60 DINGBATS
17 EMPEROR 39 OPTIONAL_SCC 61 EAN
18 MADELEINE 40 GREEK 62 PC_LINE
19 ZAPF_HUMANIST 41 KANA 63 OPTIONAL_SYA
20 CLASSIC 42 HEBREW
21 OPTIONAL_SA 43 OPTIONAL_A
A typeface that is not supported by the current printer will be mapped to a supported typeface. See the
later Printer driver font mapping section.
In addition, a typeface number of -1, indicating an inherited font, is allowed in all emphases and in all
paragraph styles except Body text. An emphasis inherits its font from the surrounding paragraph; a
paragraph style inherits its font from the Body text style.
(2) The font style may be zero, or any sensible combination of the following attributes:
0x01 underline
0x02 bold
0x04 italic
0x08 superscript
0x10 subscript
Styles or style combinations that are not supported by the current printer are ignored.
The value 0x4000 is used internally by the word processor and may or may not be set in the font style data
in the document. If set, it can safely be ignored.
(3) The running page header alignment may be any one of:
0 left aligned
1 right aligned
2 centred
4 2-column
5 3-column
(4) In terms of the body struct and the page width and height, the page margins are:
left body. tl.x
top body.tl.y
right width-body.tl.x-body. width
bottom height-body.tl.y-body. height
(5) The page header position measures the vertical distance between the bottom of the header text and the
top edge of the page body print region.
(6) The page footer position measures the vertical distance between the bottom of the footer text and the
bottom edge of the page body print region.
(7) To print all pages, the last page number should be set to Oxffff.
74
6 WORD PROCESSOR FILE FORMAT
(8) The page number style is one of:
i) Arabic
1 Roman, upper case
2 Roman, lower case.
(9) The body area base font data is not used by word processor documents. It should always specify the
default font, with font number 0 (Courier) a style of 0 (normal) and a size of 240 (12 points).
(10) The page size choice should correspond with the earlier page width and height. The following
(English) page sizes are recognised:
Choice Pagetype Width Height
A4
0 11906 16838
1 Custom - -
2 Executive 10440 15120
3 Legal 12240 20160
4 Letter 12240 15840
5 Monarch 5580 10800
6 DL 6236 12472
Note that items 2 to 6 may be different in non-English versions of the software.
The record consists of a zero terminated string, containing the full path name of the current printer driver
file, preceded by a one byte index to the printer model within the file.
The default value is:
0
"ROM: :\BJ.WDR"
The record contains the page header text as a zero terminated string. The string may not exceed 80 bytes.
eee
The record contains the page footer text as a zero terminated string. The string may not exceed 80 bytes.
The file may contain up to 64 such records, each of which defines a single style.
The following description is in terms of the SCRLAY_FONT struct (described above) and the SCRLAY_MARGINS,
SCRLAY_SPACING and SCRLAY_TABSTOP structs, defined as:
typedef struct
{
UWORD Left; /* left margin */ (1)
UWORD right; /* right margin */
UWORD indent; /* left margin for first line of a paragraph */
UWORD align; /* alignment */ (2)
} SCRLAY_MARGINS;
typedef struct
{
UWORD Line; /* space between lines in a paragraph */
UWORD above; /* space above paragraph */
UWORD below; /* space below paragraph */
UWORD flags; /* keep together/next and new page */ (3)
} SCRLAY_SPACING;
typedef struct
{
UWORD x; /* tab position */
UWORD type; /* tab type */ (4)
} SCRLAY_TABSTOP;
75
ADDITIONAL SYSTEM INFORMATION
In these terms, the content of the style data record is:
TEXT sc([2] two-letter short code (5)
TEXT tag[16] style tag name (6)
UWORD sflags style control flags (7)
SCRLAY_FONT f paragraph base font (8)
UWORD inherit inherited attributes (9)
SCRLAY_MARGINS marg margin positions
SCRLAY_SPACING spe paragraph vertical spacing
UWORD olevel outliner level
UWORD ntabs number of tabstops in following table
SCRLAY_TABSTOP tabI[8] up to 8 tabstops, in ascending position order
Notes
(1) Paragraph margins are relative to the page margins (the left and right edges of the body print region).
(2) The paragraph alignment may be one of:
i) left aligned
1 right aligned
2 centred
3 justified
(3) The spacing flags may be any combination of:
0x01 keep on same page as following paragraph
0x02 keep whole paragraph on one page
0x04 paragraph starts a new page
(4) The tab type may be any one of the following:
0 left tab
1 right tab
2 centred tab
(5) The short code must contain two alphabetic characters and must be unique (it must not be duplicated
in either a style or an emphasis). If no meaningful short code can be assigned, it is recommended that
unique short codes be generated in the sequence ZA,ZB,...,ZZ,YA,...,YZ,XA,...
(6) Although not currently enforced by the software, the text of the tag name should be unique (it should
not be duplicated in either a style or an emphasis). If no meaningful tag name can be assigned, it is
recomended that the tag name should duplicate the short code.
(7) The style control flags may contain any combination of:
0x02 undeletable
0x04 default
There must be one default style and at least one undeletable style in every document (in all Psion
documents they are the same - style BT). It does not make sense for the default style to be deletable.
The value 0x8000 is used internally by the word processor and may or may not be set in the style control
flags data in the document. If set, it can safely be ignored.
(8) In addition to the typeface numbers listed earlier, a typeface number of -1 is used to signify that the
typeface and font size are to be inherited from the default style. In such a case the font size is
conventionally set to zero.
(9) The inherited attributes field may contain any combination of:
0x01 underline
0x02 bold
0x04 italic
For each bit that is set, the corresponding bit in the style field of the ScRLAY_FoNT struct must be clear.
Inherited attributes are taken from the default style.
Emphasis data record (type 7, length 28}
The file may contain up to 16 such records, each of which defines a single emphasis.
76
6 WORD PROCESSOR FILE FORMAT
The following description is in terms of the scRLAY_FONT struct (described above). In these terms, the
content of the emphasis data record is:
TEXT sc(2] two-letter short code (1)
TEXT tag{16] emphasis tag name (2)
UWORD sflags emphasis control flags (3)
SCRLAY_FONT f emphasis font (4)
UWORD inherit inherited attributes (5)
Notes
(1) The short code must contain two alphabetic characters and must be unique (it must not be duplicated
in either a style or an emphasis). If no meaningful short code can be assigned, it is recommended that
unique short codes be generated in the sequence ZA,ZB,...,ZZ,YA,...,.YZ,XA,...
(2) Although not currently enforced by the software, the text of the tag name should be unique (it should
not be duplicated in either a style or an emphasis). If no meaningful tag name can be assigned, it is
recomended that the tag name should duplicate the short code.
(3) The emphasis control flags must contain the value 0x01, together with any combination of:
0x02 undeletable
0x04 default
There must be one default emphasis and at least one undeletable emphasis in every document (in all Psion
documents they are the same - emphasis NN). It does not make sense for the default emphasis to be
deletable.
(4) In addition to the typeface numbers listed earlier, a typeface number of -1 is used to signify that the
typeface and font size are to be inherited from the enclosing paragraph style (which may itself inherit
from the default style). In such a case the font size is conventionally set to zero.
(5) The inherited attributes field may contain any sensible combination of:
0x01 underline
0x02 bold
0x04 italic
0x08 superscript
0x10 subscript
For each bit that is set, the corresponding bit in the styte field of the scRLAY_FONT struct must be clear.
Inherited attributes are taken from the enclosing paragraph style (which may itself inherit from the
default style).
terminated by a zero.
The content conforms with the IBM Code Page 850 symbol set, together with the following additional
symbols:
Symbol ASCH Meaning
END_PARAGRAPH 0x00 paragraph terminator
HARD_HYPHEN 0x07 unbreakable hyphen, not a word delimiter
TAB 0x09 tab character
LINE_FEED Ox0a forced line break
SOFT_HYPHEN Ox0e optional, or potential, hyphen
HARD_SPACE Ox0f unbreakable space, not a word delimiter
nt index record (type 9, variable length}
This record contains a number of six byte entries which are used to apply style and emphasis to the
document text. Each entry consists of:
= a length (word)
= the two character short code of a style
77
ADDITIONAL SYSTEM INFORMATION
= the two character short code of an emphasis
The entries conform to the following rules:
® the sum of their lengths is one more than the length of the document text record (i.e. the
document size, including the final paragraph terminator that is not contained in the document
text record).
= there is at least one index entry for each paragraph in the document
= the final index entry for each paragraph includes the zero that terminates the paragraph
= the short codes must correspond with styles and emphases contained in the earlier style data and
emphasis data records
It must be stressed that a single index entry may not apply to text that is contained in more than one
paragraph.
aS re ee a ee Se a a]
Template files
Word processor template files have exactly the same structure as normal word processor files. The only
differences are that they:
= have a.wrt extension, rather than .wrd;
® are stored in a \wdr directory.
Template files for program editor aliases of the word processor contain only:
= a40 byte header, as for other word processor files;
= atype 1 options data record;
® atype 8 document text record.
The meanings of some items in the options data record differ from those of a normal word processor file:
UWORD cpos the saved cursor position, as for normal word processor files
UBYTE symbols the visibility of screen symbols, as for normal word processor files
UBYTE backup/statzoom backup state or status window and zoom settings, as for normal word
processor files
UBYTE style TRUE to set the use of a bold typeface
UBYTE mono TRUE to set the use of a monospaced typeface
UBYTE outlevel always TRUE for program editor aliases, to enable the use of templates
UBYTE spare TRUE to specify the use of auto indentation
UWORD spare2 the spacing, in column units, for tabs
LSS ae ae a
Printer driver font mapping
The font ID associated with a particular emphasis or paragraph style is determined by a selection from
the fonts available from the current printer driver at the time the emphasis or style was created. When a
different printer driver is installed, the font IDs associated with emphases and styles do not change (so
that the exact appearance of the document will be restored when the original printer driver is reinstalled).
The actual font to use when printing the document is determined by mapping each fixed font ID to one of
the available fonts supplied by the current printer driver. A perfect match occurs when the font ID
matches the font number of one of the fonts supported by the printer driver. Otherwise, an attempt is
made to make a simple fixed mapping, by font characteristics, onto a basic set of COURIER (mono),
HELVETICA (proportional, sans serif) or TIMES ROMAN (proportional, serif).
78
6 WORD PROCESSOR FILE FORMAT
If the current printer driver does not contain fonts with font numbers HELVETICA or TIMES ROMAN,
thease are also mapped to COURIER (font number zero). This is assumed always to be set for the
printer's default font - usually a 10 or 12 point font - whatever it is called.
79
CHAPTER 7
SERIES 3/3A AND MC SPREADSHEET FILE FORMAT
This document describes the structure of the .spr files that are used by the MC, Series 3 and Series 3a
spreadsheets. The description is to a level that allows other software to read and write non-password-
protected spreadsheet files.
i a re ae ee eee a
File header
The spreadsheet starts with the following header:
TEXT fid£16]="SPREADSHEET" packed with trailing zeros
UWORD vers=0
UWORD offset=0
UWORD rtvers=0
This header must be supplied exactly as described, otherwise all current versions of the Spreadsheet will
refuse to load the file. The only exception is that a password-protected Series 3a spreadsheet file has a
file type identifier string (in fid(}) of "SPREADSHEETB". This prevents it from being recognised on Series 3
and MC machines, where password protection of spreadsheet files is not supported.
Sa a a es ee ee a ee ee a eee
Records
The remainder of the file consists of type/length records, each of which has the following structure:
UWORD type the record type
UWORD Len the record length
record body len bytes of data
The structure of the data in the record body is dependent on the record type. Currently the following
types are defined:
Formula
Cell contents
Column width
Default column width
Status information
Display information
Named range
Print range
Database/criteria ranges
10 Table
11 Print setup (MC)
12 Font (MC)
13 Graph (S3)
14 Current graph index (S3)
15 Font palette (S3)
16 Print data (S3)
17 Printer model (S3)
18 Header text (S3)
19 Footer text (S3)
WO IA MAR WHR
81
ADDITIONAL SYSTEM INFORMATION
20 Display extras (S3)
21 3a Display extras (S3a)
22 Password (S3a)
As indicated in the above table, some of the above types are specific to the MC version and some to the
Series 3/3a.
In general records can appear in any order, but there are currently three exceptions:
= All formula (type 1) records must appear before the cell (type 2) records that access them, and
the order in which the formula records appear must be preserved.
= The 3a Display extras (type 21) record, when present, should immediately precede the Display
information (type 6) record. Otherwise the 3a Display extras record will be ignored.
«s The Display extras (type 20) record, when present, should immediately precede the 3a Display
extras (type 21) record, if one exists. In the absence of a 3a Display extras record, the Display
extras record should immediately precede the Display information (type 6) record. Otherwise the
Display extras record will be ignored.
Some record types may appear many times, and not all record types need be present. Some record types
are expected to appear only once in the file. If more than one of each record of such a type is present, the
last record will be read and earlier records of the same type will be ignored. The number of times that a
particular type of record is expected to occur is indicated in the following descriptions of the record
types.
Range references
Within any record, a range reference specifies the top left and bottom right cells of the range in column
and row units. These references are inclusive so that, for example, the range reference {0,0}, 1,23}
describes the range A1:B3.
A Spreadsheet file may contain any number of Formula records.
Each formula is stored separately from the cell or cells that use it. This allows memory savings to be
made by storing only one copy of a commonly used formula.
The order in which the formula records appear is significant. This determines the index, counting from
zero, used to reference a formula from a cell record.
The body of a Formula record is structured as follows:
UWORD use usage count
UBYTE Len formula length (253 bytes maximum)
UBYTE form{Len] the formula
The formula is stored in reverse Polish notation (RPN). Each operand is preceded by a byte that
identifies its type. Each function or operator is identified by a single byte that follows the operands upon
which it acts.
Brackets are stored in the formula exactly as they were entered, but are ignored when a formula is
evaluated. They are retained only so that the formula can be reproduced and displayed in exactly the
same form as it was typed in.
The RPN structure is broken for the set of functions that act upon argument lists of variable length
(AVG, COUNT, MAX, MIN, STD, SUM and VAR). For these functions a Start token precedes the
argument list and an End token follows it. In addition, each operand within the list is preceded by a
special token.
The tokens used in formulae are as follows:
Operators
0x01 ~— Less than
0x02 _—_—_ Less than or equal
0x03 = Greater than
0x04 Greater than or equal
0x05 = Not equal
0x06 = Equal
0x07. 3=Add
82
0x08
0x09
Ox0a
0x0b
Ox0c
Ox0d
Ox0e
Ox0f
0x10
Ox11
Delimiters
0x12
0x13
0x14
0x15
Operands
0x16
0x17
0x18
0x19
Oxla
Functions
Subtract
Multiply
Divide
Power
Unary plus
Unary minus
Logical NOT
Logical AND
Logical OR
String concatenate
Open bracket
Close bracket
Comma
End of formula
7 SERIES 3/3A AND MC SPREADSHEET FILE FORMAT
Double constant (IEEE floating point number)
Integer constant (WORD)
Text string (leading-byte-counted string)
Cell reference (WORD col, WORD row)
Range reference (WORD tiCol, WORD tlRow, WORD brCol, WORD brRow)
Column and/or row references can be either absolute or relative. If the top bit of the WORD is set, the
reference is relative, otherwise the reference is absolute. Relative references are treated as a signed offset
(ignoring the top bit) from the cell that uses the formula. Note that cell Al is 0,0.
In the following list, 'x' refers to a numeric argument, 'str' a string and range a range reference.
Ox1b
Oxlc
Oxld
Oxle
Oxl1f
0x20
0x21
0x22
0x23
0x24
0x25
0x26
0x27
0x28
0x29
Ox2a
0x2b
Ox2c
Ox2d
Ox2e
Ox2f
0x30
0x31
0x32
0x33
0x34
0x35
0x36
0x37
0x38
0x39
Ox3a
0x3b
Ox3c
0x3d
Cellpointer(x)
Char(x)
Code(str)
Cols(range)
Cos(x)
Datevalue(str)
Day(x)
Exp(x)
Hour(x)
Int(x)
Iserr(range)
Isna(range)
Isnum(range)
Isstr(range)
Len(str)
Ln(x)
Log(x)
Lower(str)
Minute(x)
Month(x)
N(range)
Proper(str)
Rows(range)
83
ADDITIONAL SYSTEM INFORMATION
84
0x3e
Ox3f
0x40
0x41
0x42
0x43
0x44
0x45
0x46
0x47
0x48
0x49
Ox4a
Ox4b
Ox4c
Ox4d
Ox4e
Ox4f
0x50
0x51
0x52
0x53
0x54
0x55
0x56
0x57
0x58
0x59
Ox5a
0x5b
Ox5c
Ox5d
OxSe
Ox5f
0x60
0x61
0x62
0x63
0x64
0x65
0x66
0x67
0x68
0x69
Ox6a
Ox6b
Ox6c
Ox6d
Ox6e
Ox6f
0x70
0x71
0x72
0x73
0x74
0x75
0x76
0x77
0x78
0x79
Ox7a
0x7b
Ox7c
Ox7d
Ox7e
Ox7f
0x80
0x81
S(range)
Second(x)
Sin(x)
Sqrt(x)
Tan(x)
Timevalue(str)
Trim(str)
Upper(str)
Value(str)
Year(x)
Atan2(x,x)
Cell(x,range)
Exact(str,str)
Irr(x,x)
Left(str,x)
Mod(x,x)
Npv(x,x)
Not used
Repeat(str,x)
Right(str,x)
Round(x,x)
String(x,x)
Cterm(x,x)
Date(x,x)
Davg(range,x,range)
Dcount(range,x,range)
Dmax(range,x,range)
Dmin(range,x,range)
Dstd(range,x,range)
Dsum(range,x,range)
Dvar(range,x,range)
Find(str,str,x)
Fv(x,xX,X)
Hlookup(x,range,x)
If(x,x,X)
Index(range,x,x)
Mid(str,x,x)
Pmt(x,x,x)
Pv(x,x,X)
Rate(x,x,x)
Sin(x)
Term(x,x,X)
Time(x,x,x)
VLookup(range,x,x)
Ddb(x,x,x,x)
Replace(str,x,x,str)
Syd(x,x,x,x)
End of avgQ
End of chooseQ)
End of count()
End of maxQ
End of minO
End of stdO
End of sumQ)
End of varQ)
Start of avg()
Start of choose()
Start of count(Q)
Start of maxQ)
Start of minQ
Start of stdQ
Start of sum()
Start of var()
Range in avgQ
Range in choose()
Range in count()
Range in max()
Range in min()
7 SERIES 3/3A AND MC SPREADSHEET FILE FORMAT
0x82 Range in stdO
0x83 ~—s- Range in sumQ)
0x84 ~=—- Range in var()
Ox85 = Cell in avg0)
0x86 ~—- Cell in chooseQ
0x87 = Cell in count()
0x88 = Cell in maxQ)
0x89 = Cell in minQ)
Ox8a = Cell in std
Ox8b = Cell in sum()
Ox8c Cell in varO
file.
The body of a Cell record is structured as follows:
UWORD column Cell co-ordinates (cell Ai is 0,0)
UWORD row
UBYTE flags See below
UBYTE format See below
cell contents
Flags
The ftags byte contains information about the display alignment of the cell and the cell type.
Xeussene used by the natural order sort and should be left as is
sXeusces changed flag, TRUE if (and only if) the cell has changed since the last recalc
ooXeunes numeric alignment, 1 left aligned, 0 right aligned
oeeXXene text alignment, 00 repeated, 01 left, 10 right, 11 centered
200 eXXX cell type, defines the format of the contents data as follows:
000 (0) Blank - contains only the format data shown above and has no contents
data
001 (1) Double - contains a floating point constant as a DOUBLE value
010 (2) Text - contains leading-byte-counted text
011 (3) Integer - contains an integer (WORD) constant
101 (5) Double formula - contains a formula that evaluates to a numeric result.
The contents data is a WORD containing the formula reference, immediately
followed by a DOUBLE that contains the current resultant value for the cell
110 (6) Text formula - The cell contains a formula that evaluates to a text
result. The contents data is a WORD containing the formula reference,
immediately followed by the leading-byte counted text that represents the
current resultant value for the cell.
Each formula reference is an index, counting from zero, determined by the order in which the formula
records appear in the file.
85
ADDITIONAL SYSTEM INFORMATION
Format
The format byte records whether or not the cell is currently protected and the way in which numeric
values should be displayed.
Xevensce Set if the cell is currently protected
aXXXXXXX Gives the numeric display format as follows:
s000XXXx Fixed (xxxx decimal places)
»001XXXxX Scientific (xxxx decimal places)
#010Xxxx Currency (Xxxxx decimal places)
©011XXXX Percentage (xxxx decimal places)
» 100Xxxx Comma (xxxx decimal places)
«1110000 Bargraph
»1110001 General
*1110010 Date (Lotus DD-MM-YY)
#1110101 Show formulae
1110110 Hidden
©1110111 Time (Lotus HH:MM:SS)
»1111111 Default
For the MC Spreadsheet this is the full extent of the cell record. In files generated on the Series 3/3a
there is an extra trailing byte, following the cell details described above. This extra byte contains a font
style number, in the range 0-3 inclusive, allowing selection of one of the four fonts that are defined by a
Font palette (type 15) record. The presence or absence of this additional byte can be deduced by
calculating the length of the other data in the record and subtracting this value from from the length of
the record.
A record of this type is present for each column that is not of the default width. The record body is as
follows:
UBYTE column the column number (0 for column A)
UBYTE width the width of the column (in characters)
A Spreadsheet file contains only one record of this type. The record body is as follows:
UWORD width width (in characters)
This record specifies the width of all columns for which there is no specific Column width (type 3)
record.
A Spreadsheet file contains only one record of this type. It stores assorted information that relates to the
spreadsheet as a whole. The body of a Status information record is structured as follows:
UWORD flags see below
UBYTE defForm the default numeric display format
UBYTE defAlign the default text and numeric alignments
The numeric display format is one of the values described earlier for a Cell (type 2) record. It is the
display format used for all cells whose Cell record specifies the default numeric display format. Clearly,
defForm may not itself be set to the default value.
The value of defAlign contains the default text and numeric alignments, as described earlier for a Cell
(type 2) record. Each newly created cell is set to use the alignments specified by defAtign.
Flags
The four least significant bits of flags are used for the following purposes:
eusenesX set if auto recalc is on
seseoeXe set is protection override is on
sunenXee set if cells have been deleted since last recalc
anenXene set if Table recalc is on
86
7 SERIES 3/3A AND MC SPREADSHEET FILE FORMAT
ory one Display information record is ae to appear in the file. The ebaGFOI of a record of this type
contains the current state of the display for the spreadsheet. It is structured as follows:
UWORD titleTLCol range for the titles
UWORD titleTlRow
UWORD titleBrCol
UWORD titleBrRow
UWORD topCol
UWORD topRow
UWORD selTICol select range
UWORD selTLRow
UWORD selBrCol
UWORD selBrCol
UWORD cursorCol position of cursor
UWORD cursorRow
UBYTE lines true if grid lines are to be displayed
UBYTE hideZeros TRUE if zero values are hidden
Ni ; e 7, length
Each Named range record specifies a range or cell to be associated with a name. There may be any
number of such records in a file. The body of the record is structured as follows:
TEXT name [16] zero terminated text string
UWORD the range associated with name
range_left_column
UWORD range_top_row
UWORD
range_right_column reference type
UWORD range_bottom_row
UWORD type
The value of type is 25 (0x19) for a cell reference and 26 (0x1a) for a range reference. These values are
chosen to match the reference tokens used in formulae.
A record of this type specifies a range to be offered for selective printing. There may be any number of
these records in the file. The body of a Print range record is structured as follows:
UWORD the range
range_left_column
UWORD range_top_row
UWORD
range_right_column
UWORD range_bottom_row
oe 9, length 16) —
A record of this type ne ihe criterion and database ranges to be used by the database commands. A
Spreadsheet file is expected to contain zero or one Database/criterion records. The body of the record is
structured as follows:
UWORD crit_left_col criterion range
UWORD crit_top_row
UWORD crit_right_col
UWORD crit_bottom_row
UWORD dbase_left_col database range
UWORD dbase_top_row
UWORD dbase_right_col
UWORD dbase_bottom_row
formation {type 10, length 16)
A Spreadsheet file is expexted to contain zero or one Table information records. The body of the record
is structured as follows:
87
ADDITIONAL SYSTEM INFORMATION
UWORD range_left_col table range
UWORD range_top_row
UWORD range_right_col
UWORD range_bottom_row
UWORD input1_col input cell i
UWORD input1_row
UWORD input2_col input cell 2
UWORD input2_row
For table 2 both input cells are valid. For table 1 input2_colt must be set to Oxf fff (65535).
to appear in the file. The body of the record is structured as follows:
UWORD type
Allowed values for type are:
eensesnnX if TRUE show values, else show formulae
sescccsXe if TRUE, show hidden cells
scccasXen if TRUE, show column seperators
sueeeXeas if TRUE, show headers
The Font record only appears in an MC Spreadsheet file, and only only one such record is expected to
appear in the file. The body of the record is structured as follows:
UWORD type
TEXT name[16] font name
The value of type specifies the associated style, as indicated below:
eanesnnX bold
euseXaca double height
88
7 SERIES 3/3A AND MC SPREADSHEET FILE FORMAT
A Graph record dtcaly, appears in a Series 3/3a Spreadsheet file, and there may be any number of records
of this type in the file. Each record defines a displayable graph. The body of the record is structured as
follows:
TEXT name [16] zero terminated name for the graph
UWORD A_range[4] a data range left_col, top_row, right_col, bottom_row
UWORD B_range[4]
UWORD C_range[4]
UWORD D_range[4]
UWORD E_range([4]
UWORD F_range[4]
UWORD X_range[4]
UWORD A_labels [4] range containing labels for data set A
UWORD B_labels[4)
UWORD C_labels [4]
UWORD D_labels [4]
UWORD E_labels [4]
UWORD F_labels [4]
UBYTE fmts [6]
UBYTE aligns [6]
UBYTE xAxisScaling
UBYTE xAxisFormat
DOUBLE xAxisLowerLimit
DOUBLE xAxisUpperLimit
UBYTE yAxisScaling
UBYTE yAxisFormat
DOUBLE yAxisLowerLimit
DOUBLE yAxisUpperLimit
UBYTE graphType
UBYTE gridFlags
UBYTE colour
UBYTE rangefF lags
UBYTE LabelFlags
UBYTE otherF lags
WORD skip
ten strings
There are ten zero terminated strings packed consecutively, following skip. These strings are, in order:
First line of title - max length 40
Second line of title - max len 40
Title for x axis - max len 40
Title for y axis - max len 40
Legend for A range - max len 20
Legend for F range - max len 20
A record af this type shine appears in a Series 3/3a a Sorseithioet file, and vail one Current sn avanhite index
record is expected to appear in the file. The body of the record is structured as follows:
UWORD curGraph
It contains the index of the graph that is currently selected, as set by the 'Use graph menu item. Graphs
are indexed in the order that the corresponding Graph (type 13) records appear in the file, with an index
of 0 referring to the first graph.
89
ADDITIONAL SYSTEM INFORMATION
penewate
A record of this type only appears in a Series 3/3a Spreadsheet file, and only one Font palette record is
expected to appear in the file. The body of the record is structured as follows:
SCRLAY_FONT font1
SCRLAY_FONT font2
SCRLAY_FONT font3
SCRLAY_FONT font4
Each ScRLAY_FONT structure determines one of the four selectable fonts and their corresponding styles
(bold, italic etc.). The SCRLAY_FONT struct is defined in scrlay.g as:
typedef struct
{
UWORD fid; window server font id
UWORD style; font style (eg bold)
UWORD height; height of printer font in decipoints
} SCRLAY_FONT;
A Print data record only appears in a Series 3/3a Spreadsheet file, and only one record of this type is
expected to appear in the file.
This record contains a PRINTER_PARAMS struct that supplies information required to format the document
for the printer. It includes, amongst other items, descriptions of the page size and margins, the page
numbering style, header and footer position and alignment.
The detailed description of this record is outside the scope of this document. For some further details of
this record, and of the other printer-related records (types 17, 18 and 19), see Saving and restoring print
context from file in the Printing chapter of the Object Oriented Programming Guide.
A Printer model record only appears in a Series 3/3a Spreadsheet file, and only one record of this type is
expected to appear in the file. The body of the record is structured as follows:
UBYTE model Index
TEXT ztsDriver
The data consists of a zero terminated string, containing the full path name of the current printer driver
file, preceded by a one byte index to the printer model within the file. The default value is:
0
"ROM: :Bd.WDR"
This record type only appears in a Series 3/3a Spreadsheet file, and only one Header text record is
expected to appear in the file. The body of the record is structured as follows:
TEXT zts
The zero terminated string contains the text used for the page header when printing.
Foote
This record type only appears in a Series 3/3a Spreadsheet file, and only one Footer text record is
expected to appear in the file. The body of the record is structured as follows:
TEXT zts
The zero terminated string contains the text used for the page footer when printing.
90
7 SERIES 3/3A AND MC SPREADSHEET FILE FORMAT
A Display extras record only appears in a Series 3/3a Spreadsheet file. A record of this type is ignored
unless it immediately precedes either the 3a Display extras (type 21) record, if it exists, or the Display
information (type 6) record. The body of the record is structured as follows:
UWORD flags
Only two bits of flags are used:
sescenoX set if grid labels are shown
euseeaXe set if small font is used (this is over-ridden if a 3a Display extras (type 21)
record is present.
A 3a Display extras record only appears in a Series 3a Spreadsheet file. A record of this type is ignored
unless it immediately precedes the Display information (type 6) record. The body of the record is
structured as follows:
UBYTE font font used
UBYTE statwin status window
WORD spare for future expansion
Font
This takes one of the values:
255 smallest font available
8 Swiss 8 pixel font
9 Swiss 11 pixel font
10 Swiss 13 pixel font
11 Swiss 16 pixel font
Statwin
This takes one of the values:
0 No status window
1 Small status window
2 Large status window
SBS AAS ESA ASAE RSNA BERANE ANI st NaS tomate ae NS ames SSL anette
This record is present only if the spreadsheet is password-protected. Its content is used as part of the
spreadsheet encryption/decryption process.
91
CHAPTER 8
WRITING DEVICE DRIVERS
waa SS re ee ee ee Se ee
Introduction
This chapter is aimed at the programmer who wishes to write an installable device driver and anyone who
wishes to improve their general device driver background. The details of communicating with device
drivers can be found in the J/O System chapter of the PLIB Reference manual. Details of the resident
device drivers can be found in the appropriate chapters of the J/O Devices manual and the PLIB Reference
manual. The Borland Turbo assembler was used throughout. See also the following Example Device
Drivers chapter.
Psion SIBO machines are supplied with a set of resident device drivers built in to the ROM each of which
can be replaced with an installable device driver having the same name. Installable device drivers can
also be added to increase the number of available device drivers. Installing a device driver is carried out
dynamically without resetting the machine (this is not the case with many operating systems).
The device driver performs the logical processing required to translate low level hardware instructions
into high level services suitable for an application. Conventionally, device drivers are divided into a
logical layer riding astride a physical layer. The physical device driver (PDD) contains the code required
for talking directly with the hardware device and provides a set of low level hardware specific services.
The logical device driver (LDD) performs the logical processing that transforms these low level services
into the high level services used by an application.
The following example illustrates the two layer nature of device drivers. An application using the serial
driver decides that it requires RTS/CTS handshaking. It calls an LDD which decides whether or not a
line should be driven. If the answer is yes the LDD calls the appropriate PDD and asks for a specific line
to be driven to a specific state. The PDD duly carries out the requested service.
In the above example the LDD could have talked directly with the hardware. However Psion SIBO
machines will often use the same LDD with a PDD written specifically for each version of the hardware
device. Splitting the device driver is thus highly desirable.
An LDD must provide eight functions for use by the operating system. The functions are passed to the
operating system via a table of function offsets (sometimes called the vector function table). These
functions are mandatory. Similarly a PDD must provide two functions for use by the operating system
and may provide a further two if required.
An LDD will usually provide further services/functions for use by an application. The form that these
take is dependent on the LDD requirements and the functions supplied by the associated PDD(s). It is
advisable to adopt the predefined system defines for these services as this allows the LDD to receive I/O
requests via the usual route (p_read, p_write etc).
A PDD will usually define further services specifically for use by LDDs or (less frequently)
applications. ~
The operating system will send device drivers system events not sent to other applications. Examples are
events generated by the machine being switched on or off, memory segments being moved about and the
owning application being panicked.
Any device driver configuration that has associated hardware interrupts must contain at least an LDD.
The EPOC operating system can handle a maximum of 32 device drivers on a Series3 machine and 48 on
other machines.
93
ADDITIONAL SYSTEM INFORMATION
The location of device drivers
Resident device drivers are built into the operating system, with the code residing in the ROM.
Installable device drivers are loaded into a device memory segment from the file in which they exist. The
device memory segments are created, owned and managed by the SYS$FSRV process.
Under no circumstances should any application or device driver attempt to create, delete or change the
size of a device memory segment.
Device Driver Names
Device drivers are known to the EPOC operating system by their names.
A logical device driver name always has three characters followed by a colon. For example:
= TTY: is the serial LDD
8 TIM: is the timer LDD
m@ SND: is the sound LDD
A physical device driver name always has three characters followed by a period, a further three
characters and a colon. For example:
@ =TTY.UAR: is the 16450 UART driver
m 6TTY.AS5: is the ASICS driver
The first three characters of a PDD name are the name of the LDD to which the PDD belongs. The
second set of three characters uniquely identify the PDD. In the above examples both PDDs belong to the
TTY: LDD.
The name of the device driver is the mechanism by which an application can obtain a channel to the
device driver.
Device Driver Channels
To obtain a channel to an LDD, an application should call the 1o0pen operating system service. A channel
can be opened by calling the PLIB library function p_open. For example:
= p_open(&chan,"SND:", -1)
® p_open(&chan,"TIM:",-1)
To obtain a channel to a PDD, an application should call the DevOpenPop operating system service.
Typically only LDDs open PDDs. The p_open library function can be used to open a PDD indirectly as
described below.
For a device driver configuration consisting of an LDD and a PDD the application will usually open a
channel to the LDD only: the LDD as part of its initialisation would open a channel to the required
PDD. A channel can be opened by calling the PLIB library function p_open. For example:
=» p_open(&chan,"TTY.UAR=",-1)
* p_open(&chan,"TTY.AS5:",-1)
If the LDD requires a PDD and none is specified, it is up to the LDD to either fail the open request or
hunt for a loaded PDD that it can use. The Try: device hunts for an appropriate PDD.
A device driver may be capable of supporting more than one open channel at a time. In order to
distinguish the channels, a qualifier can be added to the open request as part of the device name. It is up
to the device driver to specify the format of the qualifier. By convention channels are allocated a single
character sequentially from the character 'A'. For example, the parallel driver can support two open
channels, 'A' and 'B'. The LDD requires one of these qualifiers in order to open a parallel driver
channel.
® p_open(&chan,""PAR:A",-1)
* p_open(&chan, "PAR:B", -1)
LDDs have been designed to be accessed via the I/O system. I/O requests on the opened channel will
reach the strategy vector of the device driver.
94
8 WRITING DEVICE DRIVERS
PDDs have been designed to be accessed by an LDD either via far calls or the Devvector operating system
function.
Searching for PDDs
In the case that an LDD requires a PDD to provide some hardware specific functionality and the open
LDD request does not specify a PDD, the LDD should search for a PDD to use. In this case either there
is only one PDD for that machine (but is different across machines) or the PDDs are capable of
determining whether it can drive the specified channel.
For example the serial LDD requires a PDD. However there is currently only one serial PDD on each
machine (each machine has a different PDD though). By searching for the appropriate serial PDD, the
serial LDD can be the same on all machines.
On the other hand there are several filing system PDDs each of which is capable of reading an ID byte
from a SIBO pack. The PDD can then determine if it is the correct PDD for that hardware or not.
To search for a PDD, an LDD should use the DevFind service. For example the Fsy: LDD would search
for all Fsy.* PDDs. As each PDD is found, it can be requested to open the appropriate channel by using
the DevOpenPbD operating system service.
Device Driver Hierarchies And Attached Drivers
LDDs are classified as either root or attached drivers.
Device drivers exist in a hierarchy the first of which is termed the root driver. The other drivers in the
hierarchy are termed attached drivers. In the language of object oriented programming, an attached driver
subclasses the root driver. In this document, the driver to which another driver is attached is referred to
as the underlying driver.
An attached device driver requires the underlying driver to provide a specified set of functions. How
these are implemented is of no concern to an attached driver. For example, the Xmodem device driver is
an attached driver which can, for example, attach to the serial driver which happens to be a root device
driver. The Xmodem driver requires the underlying driver to support the serial sense, serial set, read,
write and close functions. The power of attached drivers comes from the fact that the Xmodem driver
does not need to know anything about the physical transmission medium, and can run on either serial
port quite happily. In fact the Xmodem driver could run over any physical medium e.g. telephone,
parallel, radio, infra-red etc as long as the underlying driver supported the small set of functions
required.
Additional power comes from the fact that a driver does not have to be attached to the root driver
directly: other attached drivers may exist in the hierarchy. For example an Xmodem driver can be
attached to a modem driver that provides modem configuration and dialling functions. This can in turn be
attached to the resident serial driver.
Notice that the Xmodem driver neither knows nor cares about the driver hierarchy.
There is no limit to the number of drivers that exist in a device driver hierarchy.
When the operating system routes an I/O request to a device driver, it follows this hierarchy and calls the
strategy vector of the device driver at the top of the hierarchy. The device driver at the top of the
hierarchy is the last opened device driver on that I/O channel.
The routing mechanism is best explained by an example of an application that wishes to use the parallel
driver with a timeout facility. In its raw form, the parallel driver does not allow for timeouts. Although
the application could handle this, a neater solution (in terms of application code) is to use an attached
driver. The application opens the parallel driver in the normal way and then opens the attached driver
(written as part of the application) passing the currently opened parallel device channel handle to the open
vector. The attached driver will open a timer channel for itself and use the 1oFuncAttach I/O service on
the passed opened channel. This request will go to the parallel driver since it is the next down the
hierarchy. The parallel driver, not supporting this function, passes it on to the operating system (using
the IoRoot service) to perform the attach service. The parallel drivers open channel handle is returned by
the attached driver to the caller of the 100pen service. From this point on all I/O requests made on the
parallel drivers I/O channel handle will be directed to the strategy vector of the attached driver first
which can then process it and pass on any requests it feels necessary. For example, the loFuncWrite
request would go to the attached drivers strategy vector. It would queue a timer for an appropriate length
of time and then pass on the loFuncWrite request to the parallel driver. If the timer expired before the
write completed, the attached driver would cancel the outstanding write request on the parallel driver and
inform the application that the timer expired.
a5
ADDITIONAL SYSTEM INFORMATION
In the above example the same attached driver could in fact attach itself to any device driver that requires
a timeout on the 1oFuneWrite request.
An attached driver is written in exactly the same way as any other driver. However, if the driver does not
support a requested function, the strategy vector of an attached driver calls the toSuper operating system
service rather than the 1oRoot system service.
R———E—E—EE EE ES ee
Interrupts and Interrupt Service Routines
Device drivers that talk to hardware tend to have interrupt service routines associated with them,
especially if they are receiving data from an external source.
The EPOC operating system provides a framework within which an interrupt service routine can be
written relatively easily.
The SIBO architecture allows for eight independent hardware interrupt sources, some of which are pre-
allocated to system components (see the ASIC1 section of the Hardware Reference manual for details).
The operating system provides the GenSetRevector service to allow a device driver to install an interrupt
service routine for any of the eight hardware interrupt sources.
A device driver should use this system service and not poke directly into the 8086 interrupt vector table.
The address passed to the GensetRevector service is not written into the interrupt vector table but to an
internal table.
When an interrupt occurs, the operating system builds the mandatory operating system call frame,
preserving all registers on route. The interrupt service routine is then called as a FAR routine. Since the
operating system preserves all registers the interrupt service routine is free to use any register.
To remove the interrupt service routine address, the operating system service GenResetRevector should be
used. This will reset the internal table entry to the default held in the ROM.
As with all interrupt service routines various rules apply:
= Interrupt service routines should execute as fast as possible. Operating system interrupt service
routines are tuned to last no longer than one millisecond.
« Typically, interrupt service routines do not enable interrupts unless the routine can handle
Teentrancy.
= Interrupt service routines run in the context of whatever process is running at the time of the
interrupt. An interrupt service routine should not attempt to obtain admissibility to the process
that opened the channel but access the internal driver space only which in general is its own code
space.
= An interrupt service routine must not directly cause a reschedule as this would significantly
delay its completion. It must use the 1oSignalByPidNoReSched system service in order to indicate
that an event has occurred to the owning process. The handler function of the device driver must
pick up the event and inform the owning process.
= An interrupt service routine should return with the carry flag clear if it requires a reschedule to
occur (it has called 10SignalByPidNoReSched) otherwise return with the carry flag set. This will
cause the operating system to reschedule if the internal state allows such an action otherwise the
reschedule request is effectively queued until such time that the operating system can reschedule.
Device Driver 1/O Semaphore Waithandlers
An LDD may nominate one of its functions to be called by the operating system every time the I/O
semaphore of the process that opened the channel is signalled. The nominated function will only be called
if the application is waiting for an outstanding I/O request to complete. For well written applications this
is practically all the time.
By convention the vector table entry after the mandatory vectors contains the handler vector.
A handler routine is similar to an interrupt service routine in that it appears to run from nowhere.
Comparing handlers and interrupt services routines shows that:
96
8 WRITING DEVICE DRIVERS
« A handler will always run in the context of the process that has opened a channel. An interrupt
service routine will run in the context of whatever process happens to be running at the time of
the interrupt.
=» A handler can access the data space of the process that opened the channel. The interrupt service
routine must not. An interrupt service routine should only access the data space in the driver
which is usually its own CS space.
=s A handler can cause a reschedule. An interrupt service routine must not cause a reschedule. If it
did, the interrupt would not be fully serviced (the rest of the interrupt service routine would not
be executed until a reschedule back to the process running at the time of the interrupt, which
may not happen for a significant length of time). The interrupt service routine must only use the
loSignalByPidNoReSched to signal the channel owner.
The handler is the mechanism by which hardware interrupt events can be filtered through to the process
using the I/O channel.
Eur ee a a ee eee
Loadable Logical Device Driver Structure
A loadable LDD must obey the following rules:
= There must be a single code segment and no data segments.
s The code segment must start with a Lib€nt structure.
= There must be at least eight supported functions.
Single Code Segment
An LDD must be written to contain any internal variables within its own code segment. In general these
variables are only concerned with unit allocation and the hardware state.
Data space for a particular open channel can be allocated in the heap space of the process that opens the
device. This data space will however disappear if the process terminates. Therefore any variables
pce aie for 'freeing' the hardware after a process terminates must exist in the code space of the device
The LibEnt Structure
A Libént structure has the following format:
= two byte signature
= eight byte name
=" two byte vector count
= A vector table
The two byte signature should contain the 'LopSignature define.
The eight byte name contains the name of the device driver stored as a zero terminated string. Note that
the trailing colon is omitted.
The two byte vector count contains the number of vectors that follow immediately after the count. This
should be equal to at least eight.
For example:
97
ADDITIONAL SYSTEM INFORMATION
dw LODSignature 3; Its an LOD
db 'DVR',0,0,0,0,0 ; Name of the driver
dw (VectorEnd-Vector)/2 ; Number of vectors
Vector:
dw Dvrinstall 3; Install vector
dw DvrRemove ; Remove vector
dw DvrHold ; Hold vector
dw DvrResume ; Resume vector
dw DvrReset ; Reset Vector
dw DvrUnits ; Units Vector
dw DvrOpen ; Open Vector
dw DvrStrategy ; Strategy vector
VectorEnd:
The vector table contains the offsets within the device drivers code segment for the functions required by
the EPOC operating system. Throughout this document the terms vector and function are used
interchangeably. The vector table must have the entries in the order shown in the example.
Mandatory LDD Functions
All LDDs must support the following eight functions:
@ DevFuncInstall called on device installation.
™ DevFuncRemove called on device removal.
= DevFuncHold called to temporarily disable the driver.
®@ DevFuncResume called to enable the driver after it has been temporarily disabled.
= DevFuncReset called when an application terminates without closing the channel.
® DevFuncUnits called to query the number of supported units (i.e. channels).
@ DevFuncOpen called to open a channel to an LDD.
= DevFuncStrategy called to access the device drivers functionality from the I/O system.
All of the routines pointed at by the function vector table will be called FAR by the operating system and
should consequently use a FAR return machine code instruction to return back to the operating system.
Since the FAR retum address is to the operating system it does not matter if the operating system moves
memory whilst code in the LDD is being executed: the operating system cannot move its own code.
This function is called by the operating system when the device driver is loaded in order to initialise any
internal variables. It can not be called directly by an application process.
The Devinstall operating system service will cause this function to be called. Applications should not call
this service directly and should call instead the DevLoadLDD service.
An installable device driver may have the same name as a resident device driver. When the operating
system loads a device driver, it places it at the end of the device driver table. The operating system will
search this table for the appropriate device driver when it wishes to establish a channel. The search starts
at the end and thus will locate the most recently installed device driver (if any) or if not, the resident
driver. By this mechanism an installable driver can replace any resident driver.
When called, the DS and ES segment registers are in an unknown state. The device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
The operating system will not move memory whilst in this function, thus the normal mules governing DS
and ES may be ignored.
All operating system services may be called, except those concerning file or device access.
PASSED
No values are passed to the install vector.
98
8 WRITING DEVICE DRIVERS
RETURN
If the installation was successful, return with the carry flag clear.
If the installation failed, return with the carry flag set and the error number in the AL register.
PANIC
The install vector must not panic: it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the install function.
BD chemo 0
This function will be called by the operating system when the device driver is requested to be unloaded.
It can not be called directly by an application process.
The DevRemove operating system service will cause this function to be called. Applications should not call
this directly, they should use the Dewelete service.
Before the remove function is requested, the device driver will have received a hold request. Thus
devices will only ever be removed when in a heid state.
If the device driver is currently busy serving a client, the remove request should return an error.
All resident device drivers will return an error since there is no mechanism by which they can be re-
installed.
When called, the DS and ES segment registers are in an unknown state; the device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
The operating system will not move memory whilst in this function, thus the normal rules governing DS
and ES may be ignored.
All operating system services may be called, except those concerning file or device access.
PASSED
No values are passed to the remove vector.
RETURN
If the remove was successful, return with the carry flag clear.
If the remove failed, return with the carry flag set and the error number in the AL register.
PANIC
The remove vector must not panic: it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the remove vector.
hold vector is called in the context of the operating system.
The DevHold operating system service will cause this vector to be called. Applications should not call this
service.
The operating system will call the hold vector under three conditions:
= Device memory segments are about to be moved.
= The machine is about to switch off due to the auto switch off timeout or user request, it enters
the standby state.
99
ADDITIONAL SYSTEM INFORMATION
s The machine is about to switch off due to the power source being removed.
In all cases the device driver must respond to the request as quickly as possible. It must also ensure that
ALL interrupts from the hardware device that it is driving are disabled.
Device memory segments can only be moved if an installable device driver is being installed or removed.
If the LDD uses an attached PDD and uses the faster FAR call mechanism to call the PDD strategy
vector, the PDD strategy vector address will potentially move, thus the FAR address will be wrong. This
address can be resolved in the resume vector. The LDD must not call the PDD between a hold and
resume. Typically, the device driver only needs to disable its interrupts. When a resume occurs, the
device driver should continue as though nothing had happened.
If the machine is about to switch off due to the auto switch off or user request mechanisms (enter the
standby state), the device driver should make an orderly shut down of the device such that the state
before the shut down can be recovered when the system powers up again. The device driver should also
attempt to ensure that no data is lost. For example, in the serial driver the current state of the hardware
handshaking lines should be noted so that each state can be restored on power up. For this type of power
down the hold vector is allowed to take a significant length of time to shut down a device. For example
in a serial driver the hold vector should wait until the remote end stops transmitting data after any
hardware handshaking has been applied. Of course, the time taken should be kept to a minimum: in the
case of the serial driver above the time is roughly equivalent to 3 character transmission times. When a
resume occurs the device driver should continue as though nothing had happened.
If the machine is about to switch off due to the power source being removed, the device driver should
reset the device in the minimum possible time: no attempt should be made to perform an orderly shut-
down. The device driver is not expected to be able to recover the hardware state. When a resume occurs,
the device driver would typically fail any outstanding application requests. If the hold vector takes too
long the voltage will fall below the threshold to hold the state of the internal RAM. If this occurs the
machine will perform a warm re-boot when powering up, all data in the internal memory of the machine
will be lost including the device driver code! On power fail there is about 2ms available to power down
all devices.
On a power failure hold, the operating system will already have sent a 'reset' to all the SIBO serial
channels. Any device drivers using these channels need only record the hold reason for the resume
vector. Any other peripherals should be designed to allow a power fail mechanism with the minimum
amount of code.
It must be noted that the power fail type hold can occur whilst the device driver is in the memory move
hold state. In this case, the device driver will receive two hold requests before seeing a resume request. A
device driver must be capable of handling this. In this case, the device driver will also receive two
resume requests. A device driver will not get a power fail hold whilst in power down hold.
A call to the hold vector will always be followed by a call to the resume vector (except when a device is
requested to be removed).
When called, the DS and ES segment registers are in an unknown state; the device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
The device driver should not call any operating system services due to the time taken, especially on
power failure.
PASSED
The AH register takes one of the following
® DevHoltdNormal Device memory is about to be moved.
= = DevHoldPowerDown The system is about to enter the standby state.
= ~DevHoldPowerFail The system has lost its power supply.
RETURN
None.
PANIC
The hold vector must not panic: it will cause an operating system kernel fault if it does.
100
8 WRITING DEVICE DRIVERS
PRESERVE
The SS, SP and BP registers must be preserved by the hold vector.
resume vector is called in the context of the operating system.
The DevResume operating system service will cause this vector to be called. Applications should not call
this service.
The resume vector will be called either when memory has finished being moved or when the machine
powers back up. In both cases the hold vector will have been called before this vector is called.
The device driver is expected to recover from the previous hold request (except power fail) and resume
any I/O that was suspended.
If the device driver has an interrupt service routine, it should reset the interrupt service routine's address
since the device driver may have moved in memory; its absolute segment address will be different.
If the hold was a device memory segment move type hold, interrupts should be re-enabled. If the LDD
uses an attached PDD and uses the FAR call mechanism to access the PDD strategy vector, the address of
the PDD should be reset by using the DevGetPopAddress operating system service before enabling
interrupts. Typically, the PDD will have a call back to the LDD and it needs to be informed of the
change of address of the LDD call back function; the LDD-PDD interface definition should allow such a
function request.
If the hold was a power down type hold, the resume vector needs to power up the peripheral and set it to
the state that it was in before the power down occurred. If this is not possible or data has been lost, the
device driver should inform any outstanding requests of this fact.
It is also possible that the hardware device that the driver is associated with has been removed. The
driver should be able to handle this properly.
If the device driver is expected to generate events due to an external state change, the driver should check
the external state and generate appropriate events. For example, the serial driver may be requested to
inform an application when the DTR line changes state. The remote end may have changed the state of
DTR whilst the driver is held.
If the hold was a power failure type hold, the resume vector should power up the peripheral and put it
into a known state, preferably the state that the application software thinks that the device is in and fail
any outstanding requests as data is quite likely to have been lost.
When called, the DS and ES segment registers are in an unknown state. The device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
All operating system services may be called, except those concerning file or device access.
PASSED
None
RETURN
None.
PANIC
The resume vector must not panic, it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the resume vector.
“uncReset 2 se.
This function will be called by the operating system when the device driver is requested to reset a
channel. The reset function is called in the context of the operating system.
101
ADDITIONAL SYSTEM INFORMATION
The device driver must request that the operating system call the reset function. This is achieved by
calling the 1oRequestReset system service, usually in the open vector. To cancel this request, the device
driver should cali the 1oRequestResetCancel system service. The cancel service is usually called as part of
the close functionality in the strategy vector.
The reset vector will be called when the operating system is tidying up resources owned by a process that
has terminated. If a process terminated before it closed the device driver channel and no reset service is
requested, that channel would remain allocated; no process will ever close the channel. The reset vector
allows a device driver to reset itself and allow the channel to be opened again.
Any data required to perform the reset must be stored in the device driver. The data space belonging to
the process that originally opened the channel has been returned to the operating system memory pool
and is no longer valid.
If a device driver can handle multiple channels then the data passed to the 1oRequestReset system service
should identify the channel. This data will be passed in the CX register to the reset vector.
The device driver should only have a reset request outstanding with the operating system while a process
has a channel open.
When called, the DS and ES segment registers are in an unknown state; the device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
All operating system services may be called, except those concerning file or device access.
PASSED
This function is passed data in the CX register that the device driver requested it be sent to determine
which channel should be reset.
RETURN
None.
PANIC
The reset vector must not panic; it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the reset vector.
This function will be called by the operating system when the device driver is requested to report the
number of units (i.e. channels) the device driver can support. This function is called in the context of the
operating system.
The operating system places no significance on the number of channels a device driver can support. It is
primarily used for informational purposes.
An application may use the number of units to attempt to open any available channel on that device
driver.
When called, the DS and ES segment registers are in an unknown state; the device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
All operating system services may be called, except those concerning file or device access.
PASSED
None.
RETURN
The AX register should contain the number of channels supported. If a device driver can support multiple
channels (limited only by memory constraints) then the driver may return -1. A serial device driver, for
example, might only support two channels (TTY:A and TTY:8) whereas the file device driver can open an
unlimited number of files.
102
8 WRITING DEVICE DRIVERS
PANIC
The channels units vector must not panic; it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the units vector.
This function w system when a channel to the device driver is required to be
opened. This function is called in the context of the process that called the 100pen system service.
The device driver is passed two parameters, its device handle and a pointer to an OpenEnt structure.
The device handle is the entry in the system device table of this device driver. The device driver is
required to place this handle in the chant ibHandle field of the chanent structure which must be allocated in
the user's data space. The operating system uses the device handle to route any I/O requests on the
opened channel to the correct device driver.
The OpenEnt structure contains three fields, openNamePtr, OpenMode and OpenChan.
The OpenNamePtr field contains a pointer to the character that exists after the device name as passed to the
loOpen system service. For example, if the to0pen service was passed a name of PaR:A, the OpenNamePtr
field would point to the colon. If the 1odpen service was passed a name of TTY.AS5:B the OpenNamePtr field
would point to the full stop. The device driver should process the name appropriately, opening the
correct PDD as required.
The openMode field contains the mode for opening the device driver. The available modes are specified by
the device driver writers. For example, a combined Xmodem and Ymodem device driver could use the
mode to specify whether the Xmodem or the Ymodem protocol is to be used.
The Openchan field contains the I/O channel handle of the device that this driver is required to attach to.
Attached device drivers are dealt with later in the chapter.
The code in a device driver open vector tends to follow a very similar pattern. This is demonstrated by
the following code fragments and associated comments.
The first stage is to allocate some data space in the calling process heap space. This will contain the I/O
channel control block:
mov cx, (size DeviceEnt)
HeapAl LocateCelt
jc noMemory
mov bx, ax ; cell handle
If the device driver requires a WaitHandler (described later):
mov al, (VectorHandler-Vector)/2
ToAddkKandler
jc endFreeMemory
mov [bx] .OriverHandler, ax
If the device driver's DevFuncReset vector is required to be called:
push bx
mov cx, ChannelIndicator 3 unique per channel
mov bx, dx ; the device handle
ToRequestReset
pop bx 3 restore alloc cell
The chanent field of the priverEnt structure must be initialised:
mov [bx] .Driverlo.ChanNext, bx
mov (bx] .Driverlo.ChanSignature, IoChanSignature
mov (bx] .Driverlo.ChanLibHandle, dx
The chanNext field is used by attached drivers and will usually be set to be the allocated cell handle of the
device driver being opened. The loFuncAttach and IoFuncDetach functions manipulate these fields. The
I/O system uses this field to direct the I/O request to the correct driver.
103
ADDITIONAL SYSTEM INFORMATION
The ChanSignature field is checked by the operating system during any I/O requests for the value
loChanSignature. If it does not contain that value, the process calling the I/O service will be panicked for
having passed an invalid I/O channel handle.
The ChanlibHandle field is used by the operating system to route an application's I/O request to this
device. The I/O request will call the DevFuncStrategy vector of the device driver.
- If the driver is an attached driver the following is required:
allocated channel
channel attaching to
return in BX the
channel attached to
mov cx, bx
mov bx, [si] .OpenChan
mov al, IoFuncAttach
ToWithWait
ma me me Be
Finally, if the channel has been successfully opened:
cic ; Opened Ok
ret ¢ return BX and DX
The error recover code typically follows the following pattern:
endFreeReset:
push ax
push bx
mov cx, Channel Indicator
mov bx, dx
loRequestResetCancel
pop bx
pop ax
endFreeHandler:
push ax
push bx
mov bx, [bx] .DriverHandler
loRemoveHandler
pop bx
pop ax
endFreeMemory:
push ax
HeapFreeCel L
pop ax
ste
noMemory:
ret
If a device driver supports a fixed number of channels, it typically contains static control blocks. In order
to determine if a requested channel is currently open, a field should be interrogated. The device driver
should ensure that interrupts are disabled during this sort of check since a context switch could occur and
another process request the opening of the same channel. This is the classic test and set' problem
encountered in multi-tasking environments.
When called, the DS and ES segment registers point to the data segment of the application process
attempting to open a device channel. The application should ensure that the DS and ES segment registers
do in fact point to its data segment. The device driver must obey the normal rules concerning segment
register manipulation. The DS and ES segment registers can be reloaded if required from the tntEnt
structure pointed at by the BP register.
All operating system services may be called.
PASSED
DX contains the device handle of the device driver.
SI is a pointer to the OpenEnt structure
BP is a pointer to the IntEnt structure.
RETURN
If the channel open was successful, return with the carry flag clear and the BX register containing the
open channel.
If the open failed, return with the carry flag set and the error number in the AL register.
104
8 WRITING DEVICE DRIVERS
PANIC
The open vector can panic; it will cause the process requesting the device open to terminate. It is
however more usual to return an error to the calling process.
PRESERVE
The DS, ES, SS, SP, BP and DX registers must be preserved by the open vector.
When an application makes an I/O request on the opened device driver channel the request is routed to
this vector by the operating system. A device driver defines the set of functions that it supports. These
typically include 1oFuncSet, loFuncSense, IoFuncRead, IofuncWrite and IoFuncClose. A device driver does
not have to support any particular function, as it is a matter of design between a device driver writer and
application writer as to what functions and associated parameters are provided.
To obtain the power of attached device drivers, it is recommended that the device driver use the system
defines with their appropriate functionality, for example, the 1oFuncWwrite function number should always
be associated with writing data.
The strategy function is passed the channel handle as allocated in the open vector in the BX register. This
typically contains control information concerning the current state of the I/O channel.
The SI register contains a pointer to a RqEnt structure. This structure contains four fields, RqFunction,
RqStatusPtr, RqAiPtr and RqA2Ptr.
The RqFunction field contains the function number as passed to the 1oWithWait (or loAsynchronous) I/O
request by the application. If a device driver does not support the specified function, it should pass the
request on to its parent device driver.
The RqStatus pointer contains a pointer to a memory location in the application process's data space that
receives the I/O requests completion status. The device driver must set this memory location to the value
Pendingerr whilst the I/O request is outstanding and a completion code when the I/O request completes.
An J/O request may complete within the strategy vector or it may complete some time in the future,
presumably from some interrupt.
The RqAiPtr and RqAzPtr fields contain the argument 1 and 2 parameters as passed to the IoWithwait (or
loAsynchronous) system services. The device driver is free to specify what these parameters are (if any).
The operating system defines a set of common function numbers used by device drivers referred to as the
IoFuncxxx set of defines. By convention, a device driver should select from this list, particularly if some
of the more advanced features of the I/O system are to be used, such as attached device drivers. The more
common defines are:
= ToFuncRead ; read from the device.
B [oFuneWrite ; write to the device.
B loFuncClose ; close device channel.
= = IoFuneCancel ; cancel an I/O request.
= JoFuneSet ; set driver characteristics
B® —IoFuncSense ; sense driver characteristics.
® = loFuncFlush ; flush any buffers.
The PLIB library functions p_read, p_write and p close will call the device driver with the I oFuncRead,
loFuneWrite and IoFuncClose function numbers. Thus, if the device driver choses an alternative function
number set, an application will not be able to use the supplied library functions.
All resident device drivers obey the following conventions:
= A cancel request will cancel any outstanding requests. A cancel request will not return any error.
= A close request will ensure that any outstanding requests are completed before closing the
channel. A close request will not return any error.
= Only one request of a particular type can be outstanding at any one time. If a second request is
made the device driver will panic the calling application.
105
ADDITIONAL SYSTEM INFORMATION
Any functions that the strategy function does not support should be passed on to the next driver down the
driver hierarchy. If the driver is a root driver (attached driver), this is achieved using the IoRoot
(IoSuper)system service. If the requested function is not supported by any driver, the operating system
will return a NotSupported error.
When called, the DS and ES segment registers point to the data segment of the application process
making the I/O function request. The application should ensure that the DS and ES segment registers do
in fact point to its data segment. The device driver must obey the normal rules concerning segment
register manipulation. The DS and ES segment registers can be reloaded if required from the IntEnt
structure pointed at by the BP register.
All operating system services may be called.
PASSED
BX contains the allocated channel control block.
DX contains the device handle of the device driver.
SI is a pointer to the RqEnt structure.
BP is a pointer to the IntEnt structure.
RETURN
If the function request is successful, the strategy vector should return with carry clear. A request
typically causes some I/O. If the I/O is completed by the strategy vector (eg the close function), the
completion status should be written back to the RqStatusPtr location and the I/O semaphore signalled
(using the IoSignal system service). If the request has not yet completed, the RqStatusPtr location should
contain the value PendingErr and the I/O semaphore should not be signalled.
If the function request failed the strategy vector should return with carry set and the error code in AL.
Typically no I/O requests will be completed.
PANIC
The strategy vector can panic; it will cause the process making the J/O request to terminate. In most cases
it is usual to return an error to the calling process. A major exception to this is if the calling process
makes an I/O request of the same type as one that is currently outstanding and the device driver only
supports one I/O request of a particular type at a time; by convention the device driver should panic the
calling process with the PanicloPending panic code.
PRESERVE
The DS, ES, SS, SP and BP registers must be preserved by the strategy vector.
a eee re
Loadable Physical Device Driver Structure
A loadable PDD must obey the following rules:
«® There must be a single code segment and no data segments.
= The code segment must start with a LibEnt structure.
® There must be at least two supported functions, with typically a further two defined.
Single Code Segment
A PDD must be written to contain any internal variables within its own code segment. Typically, these
variables are only concerned with unit (i.e. channel) allocation and hardware state.
Data space for a particular open channel can be allocated in the heap space of the process that opens the
device. This data space will however disappear if the process terminates, thus any variables required for
freeing the hardware after a process terminates must exist in the code space of the device driver.
The LibEnt Structure
A Libent structure has the following format:
106
8 WRITING DEVICE DRIVERS
2 A two byte signature
= An eight byte name
=» A two byte vector count
® A vector table
The two byte signature should contain the 'PDDSignature define.
The eight byte name contains a zero terminated name, being that of the device driver. Note that there is
no trailing colon.
The two byte vector count contains the number of vectors that follow immediately after the count. There
should be at least two.
For example:
dw PDDSignature z Its an PDD driver
db DVR.HW1',0 ; Name of the driver
dw (VectorEnd-Vector )/2 ; Number of vectors
Vector
dw Dvrinstall 3; Install vector
dw DvrRemove ; Remove vector
VectorEnd:
Most PDDs also define a further two vectors:
dw DvrOpen
dw OvrStrategy
Open Vector
Strategy vector
=e
me
The table of vectors is a table of offsets within the device drivers code segment of the routines that
implement the required functionality. The vector table must have the entries in the order shown in the
example.
Mandatory PDD functions
All PDDs must support the following two functions:
B DevFuncInstal LPDD called on device installation.
® DevFuncRemovePDD called on device removal.
Most PDDs will support the following two additional functions:
® DevFuncOpenPDD called to open a PDD
® DevFuncStrategyPDD called to provide PDD functionality
All of the routines pointed at by the function vector table will be called FAR by the operating system and
should consequently use a FAR return machine code instruction to return back to the operating system.
Since the FAR return address is to the operating system, it does not matter if the operating system moves
memory whilst code in the LDD is being executed; the operating system cannot move.
This vector will be called by the operating system when the device driver is loaded to initialise any of its
internal variables. The install vector is called in the context of the operating system and not the process
that is loading the device driver.
The Devinstall operating system service will cause this vector to be called. Applications should not call
this directly, they should use the DevLoadPpp service.
An installable device driver may have the same name as a currently installed device driver. When
installed, the driver is added to the end of the device driver table. When a channel to a device driver is
being established by the operating system, it searches the device table from the end first, thus the latest
installed device driver with the required name will be asked first for a channel. By this mechanism,
installable device drivers can replace any of the resident drivers.
When called, the DS and ES segment registers are in an unknown state. The device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
107
ADDITIONAL SYSTEM INFORMATION
The operating system will not move memory whilst in this function, thus the normal rules governing DS
and ES may be ignored.
All operating system services may be called except those concerning file or device access.
PASSED
No values are passed to the install vector.
RETURN
If the installation was successful, return with the carry flag clear.
If the installation failed, return with the carry flag set and the error number in the AL register.
PANIC
The install vector must not panic; it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the install vector.
ePD
This vector will be called by the operating system when the device driver is requested to be unloaded.
The remove vector is called in the context of the operating system and not the process that requests the
unload.
The DevRemove operating system service will cause this vector to be called. Applications should not call
this service directly; instead, they should call the Dewelete service.
Before the remove function is requested, the operating system will send a DevFuncHold request to all
LDDs. The LDD is responsible for ensuring that no activity will occur during the remove. Note that any
device driver that handles hardware interrupts must contain an LDD since only LDDs receive a hold
request.
If the device driver is currently busy serving a client, the remove request should return an error.
All resident device drivers will return an error since there is no mechanism by which they can be re-
installed.
When called, the DS and ES segment registers are in an unknown state; the device driver should take
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this
involves setting the DS and ES registers to the CS register.
The operating system will not move memory whilst in this function, thus the normal rules governing DS
and ES may be ignored.
All operating system services may be called except those concerning file or device access.
PASSED
No values are passed to the remove vector.
RETURN
If the remove was successful, return with the carry flag clear.
If the remove failed, return with the carry flag set and the error number in the AL register.
PANIC
The remove vector must not panic; it will cause an operating system kernel fault if it does.
PRESERVE
The SS, SP and BP registers must be preserved by the remove vector.
108
8 WRITING DEVICE DRIVERS
When an application opens a channel to an LDD, it normally uses the todpen system service. If the name
specifies, or the LDD requires, a PDD then it needs to open a channel to a PDD. The Devopenpod system
service will call this PDD vector to establish a channel. The LDD now has a choice of calling a PDD
vector using the Dewvector system service or calling the fourth vector in the vector table directly. The
fourth vector is assumed to be a strategy vector to which any parameters as required by the LDD-PDD
interface can be passed. The FAR address of the strategy vector is returned by the DevGetPDDAddress.
When an LDD receives a DevFuncResume it should call DevGetPpDAddress again to ensure that if the PDD
has moved the LDD still has its correct address.
As a design, a PDD could provide many vectors, one for each required function. The LDD would then
use the Dewvector system service to access each of these functions. The DevGetPpDAddress will only return
the FAR address of the fourth vector.
When called, the DS and ES segment registers point to the data segment of the application process
making the open function request. The application should ensure that this is indeed the case. The device
driver must obey the normal rules concerning segment register manipulation.
All operating system services may be called.
PASSED
The BX register contains a pointer to the PDD unit name. The pointer passed to the Devopenppp service is
used to find the PDD device to open. The BX register is loaded with a pointer to the trailing colon (if
any) in the PDD unit name. For example if the name TTY.AS5:A was passed to the DevOpenPpp service, BX
would contain a pointer to :A upon calling the open vector.
RETURN
If the open was successful, return with the carry flag clear.
If the open failed, return with the carry flag set and the error number in the AL register.
PANIC
The open vector can panic; it will cause the process requesting the device open to terminate. It is
however more usual to return an error to the calling process.
PRESERVE
The SS, SP and BP registers must be preserved by the open vector.
This function is defined as a convenience function for the LDD-PDD interface.
Typically, all application function requests are routed through the strategy vector. To speed the calling
interface, the DevGetPDDAddress operating system function will return a FAR address of this vector.
The device driver writer defines all the functions and return values as required.
When called, the DS and ES segment registers point to the data segment of the application process
making the function request. The application should ensure that the DS and ES segment registers do in
fact point to its data segment. The device driver must obey the normal rules concerning segment register
manipulation.
All operating system services may be called.
PASSED
The parameters passed are defined by the device driver write.
RETURN
All returns are defined by the device driver writer.
109
ADDITIONAL SYSTEM INFORMATION
PANIC
The strategy vector can panic; it will cause the process requesting the function to terminate. It is however
more usual to return an error to the calling process.
PRESERVE
Which registers are preserved is defined by the device driver writer.
110
CHAPTER 9
EXAMPLE DEVICE DRIVERS
This chapter contains explanatory notes for the example device drivers supplied with the Psion C SDK.
The source code for these examples can be found in \sibosdk\ldd. The Borland Turbo assembler is used
throughout.
See also the preceding Writing Device Drivers chapter and the appropriate chapters in the J/O Devices
Reference manual.
SaaS SS SS ea a ee eT
An Attached Device Driver Example
The code in atimdvr.asm contains an example of an attached device driver. Attached drivers add
functionality to, or replace, a service provided by an underlying device driver. The example is a generic
timeout device driver that adds a timeout facility to the underlying device driver's Pp_FREAD requests. The
example driver may be attached to either the serial or the parallel drivers.
The example code in ¢_atim.c shows how the device driver is loaded and attached to a serial driver. It
also shows how the additional functionality becomes transparent to the application once the driver has
been attached.
The device table
The start of the file consists of the device driver header. The name of the driver is specified to be ATM.
The driver is an LDD type driver consisting of nine callable functions, the first eight of which are
mandatory. The ninth function (a wait handler) is required by the device driver to function correctly.
Note that the following notes apply specifically to the functions as used in the example driver.
The Install Function
The install function does not have to perform any actions apart from report that it has completed
successfully.
The Remove Function
The remove function does not have to perform any actions apart from reporting that it has completed
successfully. This makes the reasonable assumption that the user of the device driver will not attempt to
remove it if it is associated with any open channels.
The Hold Function
The hold function is not required to do anything since it does not access or use hardware directly.
The Resume Function
Since the hold function does not do anything that needs to be undone, the resume function is not required
to do anything (otherwise it might have performed tasks such as stopping interrupts, shutting down
hardware etc).
The Reset Function
The reset function is not required to do anything: it can never be called since the driver does not ask the
operating system to call this function if its client terminates without closing an open channel. The timer
111
ADDITIONAL SYSTEM INFORMATION
device driver and the driver attached to are responsible for releasing system resources if a client
terminates. Thus this driver can leave it up to those drivers to tidy up.
The Units Function
The driver can support an unlimited number of open requests subject to system memory and timer
channel availability.
The Open Function
The open function is called by the operating system when an application uses the Io0pen system service to
open the ATM: device. This is usually done via the PLIB library function p_open.
The open function runs in the context of the process that makes the open request. Thus resource
allocation (e.g. memory allocation requests) will be associated with that process.
The open function allocates enough memory to hold all of the required internal variables and initialises
the memory to zero. It then makes function nine in the device table a wait handler function by using the
loAddHandler system service. This installs the function in the linked list of wait handler functions. The
wait handler by default is not callable, and should, for performance reasons, only be made callable when
it has some processing to do.
A channel to a timer device is opened, the name TIM: is generated on the run time stack.
The I/O system channel header is set up, the I/O system requires that a device driver has a Chanent
structure as the first item in the allocated cell.
Finally, if all has gone well, our driver attaches itself to the underlying driver whose already open handle
was passed to the open function.
If any errors occur, the device driver is responsible for tidying up all of the currently allocated resources.
It may be noted that any I/O requests made by the device driver on its own channel (as allocated) after
the attach request has been made will be routed to the underlying driver rather than starting from the top
of the driver chain. Thus for example in the cancelRead procedure the lofuncCancel request will be routed
to the strategy function of the attached to driver and not to the strategy function of our attached driver.
The Strategy Function
Once opened, the strategy function will be called when an application makes an I/O request. All I/O
requests on the open channel will be routed to our example driver which must decide how they are to be
handled. Some I/O requests are not recognised by the example driver and should be passed to the
underlying driver. This may be done using the loSuper system service (note that a root device driver
would make an foRoot system service request to pass on any meaningless I/O requests).
Some requests may be redefined; the example driver redefines the meaning of the IofuncSet and
loFuncSense (P_FSET and P_FSENSE) Services to allow an application to set and sense the timeout values to
use. The application that attaches the example driver to the serial driver must be careful when using these
services, since they produce different results depending on whether the time out driver has been attached
or not (in one case they set and sense the serial characteristics and in the other they set and sense a time
out value).
Some requests may be modified to enhance them; this driver enhances the IoFuncRead (P_FREAD) service
and, as a side effect, the loFuncCancel (P_FCANCEL) service causing the read request to time out. This type
of modification is transparent to an application. It may use the 1ofuncRead service identically regardless of
whether this time out driver has been attached (the IoFuncRead service will of course not time out if this
driver has not been attached).
Because the loFuncRead service effectively runs two I/O requests, that is the lower driver's loFuncRead and
a timer channel's toFuncRead, both requests must be cancelled by the example driver if the application
wishes to cancel the original request. Thus the example driver is required to add functionality to the
loFuncCancel service.
It should be noted that an 1oFuncClose (P_FCLOSE) request should only detach itself from the lower driver
and release any resources allocated by this drivers open function. It should not attempt to pass on the
loFuncClose request to the lower level driver (after a detach the I/O system will no longer be able to route
any I/O requests to a lower driver).
The Wait Handler Function
When an application makes an 1oFuncRead request, the example driver makes two asynchronous I/O
requests, one on the timer and one on the lower driver. In order for the device driver to gain some
112
9 EXAMPLE DEVICE DRIVERS
processing time, so as to find out what happened to these requests, it needs to enable the already installed
wait handler routine. When the I/O semaphore is signalled, the wait handler function will be called by
the operating system (only if the application is currently waiting for an I/O request to complete) so it can
check to see if either of the two asynchronous requests that it made have completed.
It is possible that neither of the outstanding requests has completed in which case the wait handler
function should return with the carry flag clear.
If either of the outstanding requests has completed, this driver cancels the other request using up the
signal generated by cancelling. The wait handler should return with the carry flag set and the AL register
set to zero since there is no more processing to do at this time.
Although synchronous I/O requests are used within the wait handler (in cancelling and using up signals)
the wait handler will not be called, i.e. it is not called re-entrantly by the operating system.
SSS ae ee ae ee ee ae Sree pee pe ee ae)
Non Interrupt Based Sound Driver
The code in snddvr.asm contains an example of a root device driver that does not require interrupt
service routines.
The driver accesses the sound chip within the Series3 and can play notes passed to it from an application.
The sound system within a Series3 can only be accessed by a single process at a time. The operating
system has some state variables that can be used (via system services) as mutual exclusion semaphores.
When the channel to the sound driver is opened, it requests exclusive use of the sound system. When the
channel is closed it releases this resource. The hardware sound device is switched on only when sound is
to be played.
The example device driver times the duration of the notes using a system timer. This limits the device
driver to ten notes per second as the system timer can not go beyond a resolution of one tenth of a
second. This is not a particularly high resolution for the note duration.
As well as the system timer, the device driver makes use of a wait handler function in order play the
notes.
The example code in ¢_mus.c shows how the device driver is loaded and the functions provided are used
to generate sound.
The device table
The start of the file contains the device driver header. The name of the driver is specified to be mus:. The
driver is an LDD type driver consisting of nine callable functions, the first eight of which are mandatory.
The ninth function (nominated to be a wait handler function) is required by the device driver to function
correctly.
Note that the following notes apply specifically to the functions as used in the example driver.
The Install Function
The install function should indicate that the device driver has no channel open on it yet. This variable (in
the device driver space) is required to know how to handle the remove, hold and resume requests.
The Remove Function
If the device driver currently owns the sound channel, the remove function will stop the playing of sound
and release to the operating system the sound channel resource.
In the normal course of events, the remove function would not be called when an application has an open
channel to the device driver. It is however quite possible for this to occur and a device driver should
accommodate such a possibility. The stopsound routine and HwFreeCombo operating system service should
only be called if the driver owns the sound channel otherwise any sound and ownership from other device
drivers (e.g. alarms) will be adversely affected when this driver is removed.
The Hold Function
The hold function will stop any sound that is currently being made if this driver currently owns the
systems sound resource. This device driver does not attempt to determine how far through the current
note (duration) it has got. When the resume function is called, the following note (if any) will be played.
113
ADDITIONAL SYSTEM INFORMATION
The Resume Function
The resume function will, if the driver currently owns the systems sound resource, simply switch back on
the hardware sound device. No note is played at this point. Because the driver uses the services of the
timer device driver, any outstanding timeout will eventually complete causing the device driver's wait
handler routine to be run. This in turn determines whether or not more notes are to be played.
The Reset Function
Since the reset function can only be called when there is an open channel, the device driver does not have
to check that it owns the systems sound resource. The reset function simply stops any current sound,
powers down the sound system and marks the channel as closed.
The Units Function
The sound system can support no more than one user; thus the device driver supports no more than one
open channel at any given time. Note that the device driver will report that it supports one sound channel
whether or not that one channel is available.
The Open Function
The open function is called by the operating system when an application wishes to obtain a channel to a
device called mus: (the example device driver's name). The open function attempts to obtain exclusive use
of the sound resource by calling the HwGetCombo operating system service. It returns with the carry flag
clear if the driver has successfully obtained the sound resource.
The open function then allocates the I/O control block, adds function nine as a wait handler function and
obtains a channel to a timer device. If any of these requests fail, the driver tidies up after itself.
It finally requests that the operating system call the reset function if the client terminates without closing
the I/O channel. Once successfully opened, the internal variable is set to indicate this.
The Strategy Function
The example device driver supports three functions: playing sound, cancelling the playing and closing the
channel. This implementation uses the 1oFuncWrite (P_FWRITE) service to play sound, the loFuncCancel
(P_FCANCEL) service to cancel playing and the IofuncClose (P_FCLOSE) service to close the channel.
The playing of a sound is achieved by writing the user specified note at the required volume to the sound
generation chip. The specified timeout is used to queue a timeout request on the timer channel opened by
this device driver. When the timeout occurs, the timer device driver will write the completion status
word and signal the I/O semaphore. Providing the application is waiting for an I/O request to complete,
the device driver's wait handler will be called. The wait handler writes the next note into the sound chip
thus playing the required tune.
Here lies a fundamental difference between wait handlers and interrupt service routines. Not only does an
application have to be waiting for an I/O request to complete but it must also be able to obtain processing
time in which to run the wait handler code. If a higher priority process is using all of the CPU (even if
only for a short period of time), the sound application will not get a chance to run the wait handler
function. Thus applications using this device driver will find that notes sometimes play for a lot longer
than originally intended.
This effect can be observed by running the example program and switching to the system task (by
pressing the System button on the Series3 machine for example ) forcing the system to update the lists.
The loFuncCancel service simply cancels any outstanding write request by cancelling the outstanding
timer request, waiting for its completion and then completing the write request with the E_FILE_CANCEL
completion status. The wait handler is also disabled, primarily for system performance reasons.
The 1oFuncClose request will cancel any outstanding write close the timer channel, cancel the reset
request and release the sound resource back to the operating system.
The Wait Handler Function
This function should check whether the outstanding timer request has completed and, if so, start playing
the next note. If there are no more notes to play, the original write request is completed with zero
completion status.
114
9 EXAMPLE DEVICE DRIVERS
Exercising the vectors
The hold and resume vectors can be exercised simply by switching the machine off and then back on
again. The sound should stop when switched off and resume when switched back on.
The reset function can be exercised by running the example program, switching to the system task and
terminating the example program. If the example program can be re-run and generate sound and/or the
alarms still work then the driver has tidied up any system resources it needed to.
a a ar a Oe ee ee ee a ea a al
Interrupt Driven Sound Driver
The code in sndfrc.asm contains an example of a root device driver that uses the FRC (free running
counter) as an interrupt source to drive a sound system.
The driver accesses the sound chip within the Series3 and has the ability to play the notes passed to it
from an application.
The sound system within a Series3 should only be accessed by a single process at a time. The operating
system has some state variables that can be used (via system services) as mutual exclusion semaphores.
Similarly the FRC should only be accessed by a single process at a time. If a second process grabs the
FRC without the first knowing then the first will probably never receive another FRC interrupt and hence
appear to hang.
When the channel to the sound driver is opened, it requests exclusive use of the sound system and the
FRC; when the channel is closed it releases these resources. It is only when some sound is to be made
that the hardware is switched on and the notes played.
This device driver uses the FRC as a timer to time the duration of notes. The FRC can be programmed to
Tun at either 32Hz or 512kHz, thus allowing a much greater resolution than the system timer device
driver that can only provide 1/10th of a second resolution. This version allows for a minimum duration
of 10ms, allowing notes of shorter duration and hence increasing the frequency with which the interrupt
service routine is called causing a very high percentage of the processor bandwidth to be used.
For this driver an eight bit number is used to specify the duration of a note and hence the maximum
duration is 2.56 seconds.
Since the notes are changed in the interrupt service routine which is independent of most other system
activity, a high level of accuracy of note duration can be obtained.
The example code in ¢_musfrc.c shows how the device driver is loaded and the functions provided are
used to generate sound.
The device table
The start of the file contains the device driver header. The name of the driver is specified to be mus:. The
driver is an LDD consisting of nine callable functions, the first eight of which are mandatory. The ninth
function (nominated to be a wait handler function) is required by the device driver in order to function
correctly.
Note that the following notes apply specifically to the functions as used in the example driver.
The Install Function
The install function should set the fact that the device driver has no channel open on it yet. This variable
(in the device driver space) is required to know how to handle the remove, hold and resume requests.
The Remove Function
The remove function will, if the driver currently owns the systems sound resource, stop any sound being
made, stop the FRC from generating interrupts, remove the FRC interrupt service routine address and
free the sound channel.
In the normal course of events, the remove function would not be called when an application has an open
channel to the device driver. It is however quite possible for this to occur and a device driver should
accommodate such a possibility. The stopSound routine and HwFreeCombo operating system service should
only be called if the driver owns the sound channel, otherwise any sound and ownership from other
device drivers (eg alarms) will be adversely affected when this driver is removed.
115
ADDITIONAL SYSTEM INFORMATION
The Hold Function
The hold function will, if the driver currently owns the systems sound resource, stop any sound that is
currently being made and stop the FRC from generating interrupts.
The device driver does not attempt to determine how far through the current note (duration) it has got;
when the resume function is called the following note (if any) will be played.
The Resume Function
The resume function will, if the driver currently owns the systems sound resource, reset the FRC
interrupt service routine address held by the operating system to point to the drivers interrupt service
routine code. The device driver may have moved in memory and thus the absolute CS address will be
wrong. If a write request is currently queued (i.e. a hold request was made while the driver was playing
some sounds), the sound hardware and FRC interrupts are re-enabled.
After a power down type hold the FRC is reset and hence needs to be re-programmed to generate
interrupts at the required frequency. With a memory move type hold the FRC will continue its
countdown and, if the count reaches zero, generate the next interrupt. This will be ignored by this device
driver since the FRC is re-programmed in the reset function.
The Reset Function
Since the reset function can only be called when there is an open channel the device driver does not have
to check that it owns the systems sound resource. The reset function stops any current sound, powers
down the sound system, disables FRC interrupts, resets the FRC interrupt address back to the default
address and marks the channel as closed.
The Units Function
The sound system will support no more than one user and hence the device driver supports only one open
channel at any given time. Note that the device driver does not guarantee that a channel is available by
reporting that it supports one channel; another system component may own the sound resource when the
open request is made.
The Open Function
The open function is called by the operating system when an application wishes to obtain a channel to a
device called mus: (our device driver name). The open function attempts to obtain exclusive use of the
sound resource by calling the KwGetCombo operating system service. If this returns with the carry flag clear
then the driver has successfully obtained the sound resource.
The open function then attempts to obtain exclusive use of the FRC resource by calling HwGetChannel with
the interrupt channel number as the hardware resource required. If this returns with the carry flag clear
then the driver has successfully obtained the FRC resource.
The open function then allocates the I/O control block, adds function nine as a wait handler function, and
requests that the operating system call the reset function if the client terminates without closing the I/O
channel.
Once successfully opened, the Soundchan.Pid internal variable is set to the process id of the client process
(required by the interrupt service routine) and the soundChan.OpenFrcChan is set to indicate the channel has
been opened (as required by the hold, resume and remove vectors).
The Strategy Function
This device driver supports three functions: playing sound, cancelling the playing and closing the
channel. This implementation chose to use the IoFuncwrite (P_FWRITE) service to mean play sound, the
loFuneCancel (P_FCANCEL) service to cancel playing and the 1oFuncClose (P_FCLOSE) service to close the
channel.
The playing of a sound is achieved by writing the user specified note at the required volume to the sound
generation chip. The FRC interrupt service routine is the routine that actually writes the data to the sound
chip. As it is an interrupt service routine, it cannot gain addressability to its client data space. Thus the
sound data to be played must be copied into the device driver space. This has a side effect that the
maximum number of notes that can be played (by this driver) is limited by the size of the internal buffer
as defined by the driver. The buffer can be made any size although in the majority of cases a larger buffer
will most probably waste space.
The device driver could be written to handle arbitrarily long sequences of notes. When the interrupt
service routine reaches a low water mark of notes to play, it can signal the wait handler routine which
116
9 EXAMPLE DEVICE DRIVERS
will eventually run to copy more data from the client process space into the internal buffer. This is,
however, a fairly complex task.
When all the notes in the device driver's internal buffer have been played, the interrupt service routine
will cali the 1oSignalByPidNoReSched system service to signal the client process that the playing of sound
has completed.
The wait handler function will pick up the fact that the interrupt service routine has finished (from the
SoundChan.WriteStat variable) and report the completion status to the client; the wait handler runs in the
context of the client process and can thus write back the completion status word.
The loFuncCancel service simply cancels any outstanding write request by stopping any more FRC
interrupts, stopping the sound generation, switching off the hardware and then completing the write
request with the E_FILE_CANCEL completion status. The wait handler is also disabled, primarily for system
performance reasons.
The loFuneClose request will cancel any outstanding write, cancel the reset request and release the sound
and FRC resources back to the operating system.
The Wait Handler Function
This function should check whether all the notes have been played in which case it has completed the
users request.
117
CHAPTER 10
WORD FILE FORMAT CONVERSION DYLS
This chapter describes the creation of file format conversion DYLs that may be used with the Series 3/3a
Word application. If suitable file conversion DYLs are placed in a \wdr subdirectory of the root of any
local drive they will be detected by the Word application and used to offer additional options in the 'File
type list of both the 'Open' and Save as dialogs.
The associated software can be installed into a \sibosdk\fconv directory from the Optional disk.
Two file conversion DYLs are required for each file format: one to read (load) the file and one to write
(save) it. A loader file conversion DYL must have a name of the form wifxxx.dyl and a saver file
conversion DYL must have a name of the form ws$xxx.dyl. In both cases the characters given as xxx
identify the nature of the file conversion. This part of the DYL name may be from three to five
characters in length and is presented as the corresponding entry in the File type' list. Thus, for example,
the Microsoft Rich Text Format (RTF) conversion dialogs that are included in the software supplied with
the 3Link serial interface are named wi$rtf.dyl and ws$rif.dyl, and add an 'Rtf' file type option. The text
file conversion examples that are described at the end of this chapter would add a 'Txt' option. Where
feasible, this text should be restricted to three characters and should represent the file name extension of a
file in the corresponding format.
If a file conversion is selected in the 'Open' or Save as dialogs, the Word application loads the
appropriate DYL, creates an instance of the first class that it contains (with class number zero) and sends
this instance a message with message function number one (in most objects this is usually some form of
initialisation method). This method is expected not to return until the file conversion is complete.
It is expected that the file conversion mechanism will use an active object to provide overall control, thus
maintaining the Word application's responsiveness to other events. A standard file converter has this
active object as the first class in its category. Word will therefore create an instance of this class and send
it am AO_INIT message (since, for an active object, this is the method with method number one). The basic
mechanism is illustrated in the example code later in this chapter.
The code of the file converter interfaces with the Series 3/3a Word application via an interface library,
s3fconv.lib, whose services are described in the following three sections. The services are classified by
their intended usage, although there is no formal restriction as to their actual use. If necessary for some
particular purpose, save interface services may be used in a loader file conversion and vice versa.
Communication between the Word application and the DYL is via the magic statics DatApp1 to DatApp5
inclusive. DatAppi, DatApp2, DatApp3 and DatApp4 are used by the interface software and must not be used
by DYL code. pDatApp5 points to a buffer, guaranteed to be at least P_FNAMESIZE bytes in length, containing
a file name. The file name in this buffer may be read and, if necessary, modified by DYL code. patAppé
and DatApp7 are available for use by DYL code.
Save interface services
The services described in this section are mainly intended for use in a file conversion DYL that saves a
word processor document to a file in some other format.
__ Present file overwrite dialog
INT DoConfirmOverwrite(VOID);
Present a dialog to confirm the overwriting of an existing file.
119
ADDITIONAL SYSTEM INFORMATION
Returns TRuE if the used confirms that the file is to be overwritten, otherwise returns FALSE.
UINT CountTags(VOID);
Return a count of the current document's index tags, in preparation for one or more calls to SenseTag! tem.
UINT SenseTagItem(UINT item, PAR_STYLE *par, PHR_STYLE *phr);
Write, to the structs pointed to by par and phr respectively, copies of the paragraph and emphasis data for
the text associated with index tag number item.
Returns the number of characters to which the tag refers.
UINT CountParaStyles(VOID);
Return a count of the total number of the paragraph styles associated with the current document. This is
normally called in preparation for a sequence of calls to SenseParaStyleByIndex.
UINT CountEmphStyles(VOID);
Return a count of the total number of the emphasis styles associated with the current document. This is
normally called in preparation for a sequence of calls to SenseEmphStyl eBy!I ndex.
ryieB:
PARA_STYLE *SenseParaStyleBylIndex(UINT index);
Return a pointer to the PARA_STYLE struct containing the paragraph style data for style number index.
It is a programming error if the value of index does not lie between zero and n-1 (inclusive) where n is
the value returned by an earlier call to CountParaStyles.
EMPH_STYLE *SenseEmphStyleByIndex(UINT index);
Return a pointer to the EMPH_STYLE struct containing the emphasis style data for style number index.
It is a programming error if the value of index does not lie between zero and n-1 (inclusive) where n is
the value returned by an earlier call to CountEmphStyles.
PAR_STYLE *SenseParaStyleBySC(TEXT *psc);
Return a pointer to the PARA_STYLE struct containing the paragraph style data for the style with the two-
character shortcode pointed to by psc. The text pointed to by psc does not need to be null terminated. A
paragraph style with this shortcode must exist.
EMPH_STYLE *SenseEmphStyleBySC(TEXT *psc);
Return a pointer to the EMPH_STYLE struct containing the emphasis style data for the emphasis with the
two-character shortcode pointed to by psc. The text pointed to by psc does not need to be null terminated.
An emphasis style with this shortcode must exist.
120
10 WORD FILE FORMAT CONVERSION DYLS
VOID ExtractText(UINT pos, TEXT *buf, UINT len);
Copy len bytes of document text, starting at document position pos, into the buffer pointed to by buf.
VOID SetFileErrCINT err);
Set the Word application's file read/write error to err, for subsequent error reporting by Word.
This would normally be used only for reporting a failure to write a converted file.
ee a a ee Pee eee ee ee eee ee en ee
Load interface services
The services described in this section are mainly intended for use in a file conversion DYL that loads a
word processor document from a file in some other format.
VOID CloseCurrentFile(VOID);
Close the Word application's current file. This action must be performed before new data is loaded.
UINT SwitchToNewFile(TEXT *pname);
Direct the Word application to open the file whose full file specification is pointed to by pname. This
action must be performed on successful completion of the loading of a file.
PARA_STYLE *AppendParaStyle(PARA_STYLE *pstyle);
Append the paragraph style described by the PARA_STYLE struct pointed to by pstyle. A paragraph or
emphasis style with the same shortcode must not exist.
EMPH_STYLE *AppendEmphStyle(EMPH_STYLE *pstyle);
Append the emphasis described by the EMPH_STYLE struct pointed to by pstyle. An emphasis or paragraph
style with the same shortcode must not exist.
VOID DoApplyParaStyleCUINT spos, UINT epos, PARA_STYLE “*par);
Apply the paragraph style described by the PARA_STYLE struct pointed to by par to the text between the
start and end document positions spos and epos.
The paragraph style is applied to to entire paragraphs, from the start of the paragraph that contains the
position spos, to the end of the paragraph containing position epos. The end of the extended range
includes the NULL that terminates the last paragraph in the range.
When adding text to a document, paragraph styles must be applied to each single paragraph in turn, and
never to a range of two or more paragraphs. To ensure that application of the style does not extend to any
following paragraph, value of epos passed to DoApplyParaStyle should not include the paragraph's
terminating NULL. It is an absolute requirement that the range never includes the NULL that terminates the
last paragraph of the document.
121
ADDITIONAL SYSTEM INFORMATION
VOID DoApplyEmphasis(UINT spos, UINT epos, EMPH_STYLE emph);
Apply the emphasis described by the EMPH_STYLE struct pointed to by emph (which must point to a struct
that was previously set up by either SetDefaultStyles or AppendEmphStyle) to the text between the start and
end document positions spos and epos.
The specified range may extend across paragraph boundaries but, while inserting text, should preferably
lie within a single paragraph. If the end of the range is immediately before a paragraph's terminating
NULL, the emphasis will also be applied to the terminating NULL.
To ensure that application of the emphasis does not extend to any following paragraph, the value of epos
passed to DoApplyEmphStyle should not include a paragraph's terminating NULL. It is an absolute
requirement that the range never includes the NuLL that terminates the last paragraph of the document.
VOID SetDefaultStyles(INT npara, INT nemph);
Delete the document content and any exisiting paragraph and emphasis styles. Create a set of standard
paragraph styles and text emphases.
Setting npara to a value of one to four inclusive causes from one to four standard standard paragraph
styles to be created. These are the same as the default paragraph styles that are provided by Word when a
new document is created:
No. Name Shortcode
1 Body text BT
2 Heading A HA
3 Heading B HB
4 Bulleted list BL
Thus, setting npara to three causes the three paragraph styles BT, HA and HB to be created.
Setting nemph to a value of one to six inclusive causes from one to six standard emphasis styles to be
created. These are the same as the default emphasis styles that are provided by Word when a new
document is created:
No. Name Shortcode
1 Normal NN
2 Underline UU
3 Bold BB
4 Italic Il
5 Superscript EE
6 Subscript ss
Thus, setting nemph to four causes the four emphasis styles NN, UU, BB and 11 to be created.
A special case is selected by calling setDefaultStyles with a value of -1 (in this case the value of nemph is
ignored). This creates default styles and emphases suitable for loading a Microsoft Rich Text Format
(RTF) file. This option is used by the RTF file conversion DYLs that are supplied with 3Link. It creates
a single Body text paragraph style, with shortcode B1, and six emphasis styles, with names and
shortcodes as listed above. The attributes of these styles are adjusted to be suitable defaults for the
loading of RTF files.
On return from this call the document content is a single empty paragraph, to which the Body text (BT)
paragraph style and Normal (Nn) emphasis are applied. The character content is a single NULL (the
paragraph terminator). Note that this terminator must never be deleted, and characters must never be
inserted after it.
122
10 WORD FILE FORMAT CONVERSION DYLS
VOID InsertText(UINT pos, TEXT *buf, UINT Len);
Insert Len bytes of text, from the buffer pointed to by buf, at document position pos in the current
document.
The intended use is for the serial insertion of document text that has been read from the inpiut file. In no
circumstances should the insertion position be set to be after the document's final terminating NULL.
VOID DeleteText(UINT post, UINT pos2);
Delete and discard the text between document positions posi and pos2 in the current document.
The document's final terminating NULL must never be deleted.
SSeS SS aS ee ee ee a ee ee a ey
Common interface services
The services described in this section are intended for use in all file conversion DYLs, regardless of
whether they save or load files.
VOID StartActive(VOID *hand);
Start the active object, with handle hand, that performs a file conversion.
The active object is first added to the application manager's active object queue with priority
PRIORITY_ACTIVE_FILES. The Word application is set to a 'Busy' status and, on the Series 3, is marked as
locked, so that it will not respond to Switchfiles or Shutdown messages from the System screen.
The active object is started by sending it an AO_QUEUVE message and the application manager is sent an
AM_START message. The call to StartActive will not return until stopActive has been called at the
completion of the file conversion.
VOID StopActive(VOID);
Mark the termination of the active object file conversion, removing the Busy status from the Word
application and, on the Series 3, removing the lock so that it will respond to Switchfiles or Shutdown
messages from the System Screen.
Sends the application manager an am_sTop message, allowing the earlier call to startactive to return.
Void SetBusyStatus(UINT flag);
If #lag is TRUE, set the Word application's Busy status, otherwise clear it.
: _ sé printer data
PRINTER_PARAMS *SensePrinterParams(VOID **phand);
Return a pointer to the Word application's PRINTER_PARAMS struct. The data in this structure may be read
or written.
If phand is not NULL, the handle of the Word application's instance of the PRINTER class is written to
*phand. File conversion software is free to use all the methods of the PRINTER class.
123
ADDITIONAL SYSTEM INFORMATION
WDR_MODEL *SensePrinterModel (VOID);
Return a pointer to the Word application's printer model data, contained in a WOR_MODEL struct. The data
in this structure may be read or written.
VOID *SenseWDR(VOID);
Return the handle of the Word application's instance of the wor class. File conversion software is free to
use all the methods of the wor class.
SS SSS a a Se ae
Example Code
This code in the following examples provides file conversions to and from a simple plain text format.
Save plain text
To avoid obscuring the basic mechanisms, the nature of the conversion and the format of the saved file
has been kept as simple as possible. The end of each text record is marked by a single carriage return
character.
Each record in a text file must not exceed 256 characters in length, but the example code makes no
attempt to enforce this. It simply saves each paragraph as a single plain text record, regardless of its
length. In order to create files that can be loaded by the following plain text loader example, the Word
file that is saved must not contain paragraphs that exceed 256 characters in length. A more robust
converter would break longer paragraphs into two or more records of less than 256 characters, and could
use an empty record to mark the end of a paragraph.
The saver DYL's category file, ws$nxt.car, is listed below:
LIBRARY wsStxt
EXTERNAL olib
INCLUDE p_std.h
INCLUDE p_object.h
INCLUDE olib.g
INCLUDE appman.g
CLASS txtsave active
NB Must be first class in the category
REPLACE destroy
REPLACE ao_init
REPLACE ao_run
REPLACE ao_abrun
CONSTANTS
CHAR_CR 13
TXTSAVE_BUFFER_LEN 256
>
PROPERTY
UINT ntags; total number of index tags
UINT curtag; current tag number
UINT pos; current position in document text
TEXT buf {TXTSAVE_BUFFER_LEN]; buffer for extracting document text
>
}
As can be seen, it only contains the single class TXTSAVE - a more complex converter may need additional
classes. The converter's active object class must be the first class in the category file and will always
replace the destroy, ao_init, ao_run and ao_abrun methods. It may optionally replace the ao_queue
method, as illustrated in a later example.
124
10 WORD FILE FORMAT CONVERSION DYLS
The methods of the TxTsave class are as shown in the following listing:
/*
TXTWRITE.C
ies
#include <p_std.h>
#include <p_file.h>
#include <ws$txt.g>
#include "wofconv.h"
GLREF_D VOID *DatApp5;
LOCAL_C INT OpenFile(PR_TXTSAVE *self)
/* forces a .TXT extension */
TEXT extension[6];
P_INFO info;
TEXT name {P_FNAMESIZE] ;
*(CUWORD *)&extension(0) =". '+¢'T'<<8)>
*(CUWORD *)&extension[2] ='X'+('T'<<B);
extension(4]=0;
f_fparse(&extension [0] ,DatApp5 ,&name(0] , NULL);
if (!p_finfo(&name [0] ,&info))
{
if (!DoConfirmOverwrite())
return(FALSE);
>
f_open(&sel f->active. pcb, &name [0] ,P_FUPDATE |P_FREPLACE |P_FSTREAM_TEXT);
return(TRUE);
>
LOCAL_C VOID ReplaceNulls(TEXT *p,UINT len)
/*
Replace the end-of-paragraph nulls with CR characters
*/
{
TEXT *pe;
for (pe=p+len;p<pe; p++)
if (!*p)
*p=CHAR_CR;
}
>
#pragma METHOD_CALL
METHOD VOID txtsave_ao_init(PR_TXTSAVE *self)
{
OpenFile(self);
self->txtsave.ntags=CountTags();
StartActive(self); /* does not return until the conversion is complete */
>
125
ADDITIONAL SYSTEM INFORMATION
METHOD INT txtsave_ao_run(PR_TXTSAVE *self)
{
PARA_STYLE style;
EMPH_STYLE emphasis;
UINT taglen, txtlen;
taglen=SenseTagI tem(sel f->txtsave.curtagt+, &style, &emphasis);
while (taglen)
{ /* looping here means that a record is too long to read with WLSDYL */
txtlen=taglen>TXTSAVE_BUFFER_LEN ? TXTSAVE_BUFFER_LEN : taglen;
ExtractText(self->txtsave.pos,&sel f->txtsave. buf [0], txtlen);
ReplaceNul ls(&sel f->txtsave.buf [0] , txtlen);
f_write(sel f->active.pcb, &sel f->txtsave.buf [0] ,txtlen);
self->txtsave.post=txtlen;
taglen-=txtlen;
>
if (self->txtsave.curtag<sel f->txtsave.ntags)
p_send2(self,O_AO QUEUE);
else
p_send2(self,O DESTROY);
return(RUN_ACTIVE_USED);
>
METHOD VOID txtsave_ao_abrun(PR_TXTSAVE *self)
p_close(sel f->active.peb);
StopActive();
p_supersend2(self,O_AO_ABRUN);
p_supersend2(self,O0_DESTROY);
>
METHOD VOID txtsave_destroy(PR_TXTSAVE *self)
StopActive():
p_supersend2(sel f,O_DESTROY);
>
The document is scanned by use of the document's index tags, each of which marks a range of characters
that are formatted in the same way. If the conversion format includes formatting information, the format
of the text may be read from the emphasis and paragraph styles that are associated with each index tag
(pointers to these are supplied by each call to SenseTag! tem).
This example uses a synchronous write to the file in the active object's ao_run method and uses the
ao_queue method of the AcTIve superclass.
Load plain text
This example opens the input file as a true text file and thus assumes that no single record contains more
than 256 characters. Each record is considered to be a whole paragraph.
LIBRARY wl$txt
EXTERNAL olib
INCLUDE p_std.h
INCLUDE p_object.h
INCLUDE olib.g
INCLUDE appman.g
126
10 WORD FILE FORMAT CONVERSION DYLS
CLASS txtread active
NB Must be first class in DYL
REPLACE destroy
REPLACE ao_init
REPLACE ao_queue
REPLACE ao_run
REPLACE ao_abrun
CONSTANTS
{
TXTREAD_BUFLEN 256
}
PROPERTY
{
UWORD pos; current document character content offset
UWORD lastpos; document offset to start of the previous paragraph
TEXT eopara; NULL - the end of paragraph marker character
TEXT dummy;
UWORD Len; length of text in buf {J
TEXT buf CTXTREAD_BUFLEN] ; input text buffer
>
>
As in the previous example, the category file contains only the single class TXTREAD - again, a more
complex converter may need additional classes. The converter's active object class must be the first class
in the category file and will always replace the destroy, ao_init, ao_run and ao_abrun methods. In this
example the ao_queue method is also replaced.
The methods of the TXTREAD class are as shown in the following listing:
/*
TXTREAD.C
*f
#include <p_std.h>
#include <p_file.h>
#include <wl$txt.g>
#include "wofconv.h"
GLREF_D VOID *DatApp5; /* used for file conversion DYLs... */
#define FileName DatApp5 /* ...to point to the source file's name */
LOCAL_C VOID InsertBuf(PR_TXTREAD *self, TEXT *buf, UINT len)
InsertText (sel f->txtread.pos, buf, len);
self->txtread.post+=len;
}
LOCAL_C VOID ApplyPlainStyle(PR_TXTREAD *sel f)
PARA_STYLE *para;
EMPH_STYLE *emph;
TEXT paracode (2);
TEXT emphcode [2];
*(WORD *)&paracode[0]='B'+('T'<<8);
para=SenseParaStyl eBySC(&paracode [0] );
DoApplyParaStyle(sel f->txtread. lastpos, sel f->txtread.pos, para);
*(WORD *)&emphcode [0] ='N'+('N'<<8);
emph=(EMPH_STYLE *)SenseEmphStyleBySC(&emphcode [0] );
DoApplyEmphasis(sel f->txtread. lastpos,sel f->txtread.pos,emph);
>
127
ADDITIONAL SYSTEM INFORMATION
#pragma METHOD_CALL
METHOD VOID txtread_ao_init(PR_TXTREAD *selLf)
/*
Keep the supplied filename extension.
*7
{
f_open((VOID **)&sel f->active.pcb, FileName, P_FOPEN|P_FTEXT);
CloseCurrentFile();
SetDefaultStyles(4,6);
StartActive(self);
d
METHOD VOID txtread_ao_queue(PR_TXTREAD *self)
self->active. isact ive=TRUE;
sel f->txtread. len=TXTREAD_BUFLEN;
p_ioc5(self->active.pcb,P_FREAD,&self->active.stat,&sel f->txtread.buf [0],
&self->txtread. len);
>
METHOD INT txtread_ao_run(PR_TXTREAD *self)
if (self->active.stat==E_FILE_EOF)
ApplyPlainStyle(self); /* apply style to the final paragraph */
SwitchToNewFilecFileName);
p_send2(self,O_DESTROY);
return(RUN_ACTIVE_USED);
>
f_leave(sel f->active.stat);
if (sel f->txtread.pos)
{
ApplyPlainStyle(self); /* range does not include the terminating NULL */
InsertBuf(self,&self->txtread.eopara, 1);
self->txtread. lastpos=sel f->txtread.pos;
}
InsertBuf(self ,&sel f->txtread.buf [0] ,self->txtread. len); /* add text of next paragraph */
p_send2(self,0_AO_QUEUE);
return(RUN_ACTIVE_USED);
>
METHOD VOID txtread_ao_abrun(PR_TXTREAD *self)
/*
The application is shut down after reporting any error on Loading.
No data is ever lost by doing this, since any previous file will
already have been saved.
ied
{
StopActive();
p_supersend2(sel f,0_AO_ABRUN);
p_exit (0);
>
METHOD VOID txtread_destroy(PR_TXTREAD *self)
StopActive();
p_supersend2(sel f ,O_DESTROY);
>
As an alternative to the code of ttwrite.c, this example reads the file asynchronously by means of a call
to p_ioc in the replacement ao_queue method.
128
10 WORD FILE FORMAT CONVERSION DYLS
Na a EE HET Te SI
Debugging a conversion DYL
Although the conversion DYLs will run on both the Series 3 and the Series 3a, debugging a conversion
DYL must be performed on a Series 3a machine. You should use the normal arrangement, with the Series
3a set up for debugging from a PC by means of the SIBO debugger provided with the 'C' SDK.. The
DYL must, of course, have been built for debugging, and must have been copied into a \wdr
subdirectory of the root of any local drive on the Series 3a.
Since the DYL is only loaded into memory just before it is used, and is unloaded immediately after its
work is done, it is not possible to use the debugger to set a breakpoint directly in the DYL code. The
easiest solution is to set a breakpoint at a suitable point in the Word application and step into the DYL
code. Once the debugger is displaying the code of the DYL, you can then debug it in the normal way,
setting any further breakpoints that you need.
The Series 3a's Word application is in the machine's ROM, so it is not possible to set a breakpoint in it.
For this reason, a copy of the Word application is provided. Copy the supplied word.app into the
m:\app\ directory of the Series 3a. From the System screen's App menu, use the Remove option to
remove the built-in Word application and then use the Install option to install the copy from Internal.
Then run this Word application.
From the PC, start up a remote debugging session and break into the running Word application, using the
Break into option of the Debugger's Process menu. Then set a breakpoint at 0x30a3 and apply the break
point by selecting the Apply BP option from the Debugger's Process menu.
At this point you can cause a Word conversion DYL to run by selecting either Save as or Open file from
Word's File menu. In the resulting dialog, select the drive and file as normal, but select the File type to
be the one that will use the appropriate DYL. For example, to debug ws$nxt.dyl, use the Save as option
and select a File type of Txt. Then press Enter to exit the dialog.
The Word application will hit the breakpoint, with the window showing the line:
WORD:30A3 €81724 CALL 54BD
Step into this call, and then step to the following Lib€nter call, when the window will show the line:
WORD:54DF CDD2 LibEnter
Step into this call, when the window will show the line:
WORD:54FF CDCF = LibSend
Stepping into this LibSend call will bring you to the first executable line of the DYL code, at the top of an
ao_init method. If, for example, you are debugging ws$nt.dyl, you will be at the start of the
txtsave_ao_init method function.
From this point the DYL code can be debugged as normal.
129
7 h:
on : 7 a Pas
Aion epee te Gree .
= SS a ee SSeS vr - ae = ®
ppmmscecveraess
dere hate fab
moa Poin Ae bp Seems 2
«Mm Sra, i a tral ye ag
7 Rotts ihe hack, “ioe rey ity 4
dea sri u of a?
Fatt de nye m we'd a ge rere feat on 7 o > ueG t * lay
> aa. | we pria oy uhm
> Je ee aa) eT ae me igo ii tre wd tlie Bier i
5 “er Sea
or Letre are atl? parse
i ae el eo Newil Hs 4
rl BEA)
eters 2a 9 bat gf LM tg, ged kat meth: AP poe . ue
ion she 4 Goma qurnen J tee a? am. lp wt a8) omelt ©
: me 40 ans tena of Ynud wa accel * yom ~
weg) P40 © > ere ers wae! ue area Wt vrs (uty sith?
= Po de in aw oil green Orel lene vw i i oon pe Fe
wap.) @ @ a? Wu Pee! atehin onan | ie i 1M ashi aru nal ol
het = - =~ wnejeedY Yas ewe aA we Tarai = 9%
nd ~ ee : @ s te +
= > OP aa «@ sees te an Pe pe ow Me oil ap
Rene" 2* em ee
sg) oll eae Op fe & safe fy Sli oe ey
mi; 9) * ed
- 7. ™- = = & = | — = @ A » Ge, Cary, 4m, is
bd Ce en = gor * 2° tates A on