#LyX 1.1 created this file. For more info see http://www.lyx.org/
\lyxformat 218
\textclass article
\language english
\inputencoding latin1
\fontscheme times
\graphics default
\paperfontsize default
\spacing single 
\papersize a4paper
\paperpackage a4
\use_geometry 0
\use_amsmath 0
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\quotes_times 2
\papercolumns 1
\papersides 1
\paperpagestyle default

\layout Title

LibDsk v1.0.0 
\layout Author

John Elliott
\layout Abstract

LibDsk is a library intended to give transparent access to floppy drives
 and to the 
\begin_inset Quotes eld
\end_inset 

disc image files
\begin_inset Quotes erd
\end_inset 

 used by emulators to represent floppy drives.
\layout Abstract

This library is free software, released under the GNU Library GPL.
 See COPYING for details.
\layout Standard
\pagebreak_top \pagebreak_bottom 

\begin_inset LatexCommand \tableofcontents{}

\end_inset 


\layout Section

Introduction
\layout Standard

LibDsk is a library for accessing floppy drives and disc images transparently.
 It currently supports the following disc image formats:
\layout Itemize

Raw 
\begin_inset Quotes eld
\end_inset 

dd if=foo of=bar
\begin_inset Quotes erd
\end_inset 

 images; 
\layout Itemize

CPCEMU-format .DSK images (normal and extended); 
\layout Itemize

MYZ80-format hard drive images; 
\layout Itemize

CFI-format disc images, as produced by FDCOPY.COM under DOS and used to distribut
e some Amstrad system discs; 
\layout Itemize

The floppy drive under Linux; 
\layout Itemize

The floppy drive under Windows.
 Windows support is a complicated subject - see section 
\begin_inset LatexCommand \ref{ldwindows}

\end_inset 

 below.
\layout Itemize

The floppy drive under DOS.
\layout Standard

LibDsk also supports compressed disc images in the following formats: 
\layout Itemize

Squeeze (Huffman coded) 
\layout Itemize

GZip (Deflate ) 
\layout Itemize

BZip2 (Burrows-Wheeler; support is read-only)
\layout Subsection

What's new? 
\layout Standard

For full details, see the file ChangeLog.
\layout Itemize

LibDsk compiles under DOS.
 Makefiles are provided for DJGPP and Pacific C.
\layout Itemize

LibDsk compiles under 16-bit Windows.
 Project files are provided for the Borland and Microsoft compilers.
 
\layout Itemize

A bug fix in the Posix and MYZ80 drivers, in which files were extended with
 zeroes (Unix) or random data (Win32).
\layout Itemize

IMPORTANT CHANGES: Version 0.9.0 breaks backward compatibility in a number
 of ways.
 Most importantly, you must replace 
\begin_inset Quotes eld
\end_inset 

DSK_DRIVER *
\begin_inset Quotes erd
\end_inset 

 with 
\begin_inset Quotes eld
\end_inset 

DSK_PDRIVER 
\begin_inset Quotes eld
\end_inset 

 throughout your programs.
\layout Itemize

Disc images can be compressed and decompressed on the fly.
\layout Subsection

Terms and definitions
\layout Standard

In this document, I use the word 
\noun on 
cylinder
\noun toggle 
 to refer to a position on a floppy disc, and 
\noun on 
track
\noun toggle 
 to refer to the data within a cylinder on one side of the disc.
 For a single-sided disc, these are the same; for a double-sided disc, there
 are twice as many tracks as cylinders.
 
\layout Section

Architecture 
\layout Standard

LibDsk is composed of a fixed core (files named 
\family typewriter 
dsk*.c
\family default 
) and a number of drivers (files named 
\family typewriter 
drv*.c
\family default 
).
 When you open an image or a drive (using 
\family typewriter 
dsk_open()
\family default 
 or 
\family typewriter 
dsk_creat()
\family default 
 ) then a driver is chosen.
 This driver is then used until it's closed (
\family typewriter 
dsk_close()
\family default 
).
 
\layout Standard

Each driver is identified by a name.
 To get a list of available drivers, use 
\family typewriter 
dsk_type_enum()
\family default 
.
 To get the driver that is being used by an open DSK image, use 
\family typewriter 
dsk_drvname()
\family default 
 or 
\family typewriter 
dsk_drvdesc()
\family default 
.
\layout Subsection

Logical and physical sectors
\layout Standard

LibDsk has two models of disc geometry.
 One is as a linear array of 
\begin_inset Quotes eld
\end_inset 

logical
\begin_inset Quotes erd
\end_inset 

 sectors - for example, a 720k floppy appears as 1440 512-byte sectors numbered
 0 to 1439.
 The other locates each sector using a (Cylinder, Head, Sector) triple -
 so on the 720k floppy described earlier, sectors would run from (0,0,1)
 to (79,1,9).
 
\layout Standard

Internally, all LibDsk drivers are written to use the Cylinder/Head/Sector
 model.
 For those calls which take parameters in logical sectors, LibDsk uses the
 information in a 
\family typewriter 
DSK_GEOMETRY
\family default 
 structure to convert to C/H/S.
 
\family typewriter 
DSK_GEOMETRY
\family default 
 also contains information such as the sector size and data rate used to
 access a given disc.
 
\layout Standard

Those functions which deal with whole tracks (such as the command to format
 a track) use logical tracks and (cylinder,head) pairs instead.
 To initialise a 
\family typewriter 
DSK_GEOMETRY
\family default 
 structure, either: 
\layout Itemize

call 
\family typewriter 
dsk_getgeom()
\family default 
 to try and detect it from the disc; or 
\layout Itemize

call 
\family typewriter 
dg_stdformat()
\family default 
 to select one of the 
\begin_inset Quotes eld
\end_inset 

standard
\begin_inset Quotes erd
\end_inset 

 formats that LibDsk knows about; or 
\layout Itemize

call 
\family typewriter 
dg_dosgeom()
\family default 
 / 
\family typewriter 
dg_cpm86geom()
\family default 
 / 
\family typewriter 
dg_pcwgeom()
\family default 
 to initialise it from a copy of a DOS / CP/M86 / PCW boot sector; or 
\layout Itemize

Set all the members manually.
\layout Subsubsection


\begin_inset LatexCommand \label{sec: dskgeom}

\end_inset 

DSK_GEOMETRY in detail
\layout LyX-Code

typedef struct
\layout LyX-Code

{
\layout Description


\family typewriter 
dsk_sides_t\SpecialChar ~
dg_sidedness;
\family default 
 /* This describes the logical sequence of tracks on the disc - the order
 in which their host system reads them.
 This will only be used if 
\family typewriter 
dg_heads
\family default 
 is greater than 1 (otherwise all the methods are equivalent) and you are
 using functions that take logical sectors or tracks as parameters.
 It will be one of: 
\begin_deeper 
\layout Description


\family typewriter 
SIDES_ALT
\family default 
 The tracks are ordered Cylinder 0 Head 0; C0H1; C1H0; C1H1; C2H0; C2H1
 etc.
 This layout is used by most PC-hosted operating systems, including DOS
 and Linux.
 Amstrad's 8-bit operating systems also use this ordering.
\layout Description


\family typewriter 
SIDES_OUTBACK
\family default 
 The tracks go out to the edge on Head 0, and then back in on Head 1 (so
 Cylinder 0 Head 0 is the first track, while Cylinder 0 Head 1 is the last).
 This layout is used by Freek Heite's 144FEAT driver (for CP/M-86 on the
 PC) but I have not seen it elsewhere.
\layout Description


\family typewriter 
SIDES_OUTOUT
\family default 
 The tracks go out to the edge on Head 0, then out again on Head 1 (so the
 order goes C(last)H0, C0H1, C1H1, ..., C(last)H1).
 This ordering is used by Acorn-format discs.
\layout Standard

*/
\end_deeper 
\layout Description


\family typewriter 
dsk_pcyl_t\SpecialChar ~
dg_cylinders;
\family default 
 /* The number of cylinders this disc has.
 Usually 40 or 80.
 */
\layout Description


\family typewriter 
dsk_phead_t\SpecialChar ~
dg_heads;
\family default 
 /* The number of heads (sides) the disc has.
 Usually 1 or 2.
 */
\layout Description


\family typewriter 
dsk_psect_t\SpecialChar ~
dg_sectors;
\family default 
 /* The number of sectors per track.
 */
\layout Description


\family typewriter 
dsk_psect_t\SpecialChar ~
dg_secbase;
\family default 
 /* The first physical sector number.
 Most systems start numbering their sectors at 1; Acorn systems start at
 0, and Amstrad CPCs start at 65 or 193.
 */
\layout Description


\family typewriter 
size_t\SpecialChar ~
dg_secsize;
\family default 
 /* Sector size in bytes.
 Note that several drivers rely on this being a power of 2.
 */
\layout Description


\family typewriter 
dsk_rate_t\SpecialChar ~
dg_datarate;
\family default 
 /* Data rate.
 This will be one of:
\begin_deeper 
\layout Description


\family typewriter 
RATE_HD 
\family default 
High-density disc (1.4Mb or 1.2Mb)
\layout Description


\family typewriter 
RATE_DD 
\family default 
Double-density disc in 1.2Mb drive (ie, 360k disc in 1.2Mb drive)
\layout Description


\family typewriter 
RATE_SD
\family default 
 Double-density disc in 1.4Mb or 720k drive
\layout Description


\family typewriter 
RATE_ED
\family default 
 Extra-density disc (2.8Mb) */
\end_deeper 
\layout Description


\family typewriter 
dsk_gap_t\SpecialChar ~
dg_rwgap;
\family default 
 /* Read/write gap length */
\layout Description


\family typewriter 
dsk_gap_t\SpecialChar ~
dg_fmtgap; 
\family default 
/* Format gap length */
\layout Description


\family typewriter 
int\SpecialChar ~
dg_fm;
\family default 
 /* Set to nonzero to use FM (single density) recording mode.
 Not all PC floppy controllers support this mode; the National Semiconductor
 PC87306 and the Future Domain TMC series SCSI controllers seem to.
 The BBC Micro used FM recording for its 100k and 200k DFS formats.
 The Windows / DOS floppy drivers do not support FM recording.
 */
\layout Description


\family typewriter 
int\SpecialChar ~
dg_nomulti; 
\family default 
/* Set to nonzero to disable multitrack mode.
 This only affects attempts to read normal data from tracks containing deleted
 data (or vice versa).
 */
\layout Description


\family typewriter 
int\SpecialChar ~
dg_noskip;
\family default 
 /* Set to nonzero to disable skipping deleted data when searching for non-delet
ed data (or vice versa).
 */
\layout LyX-Code

} DSK_GEOMETRY;
\layout Section

LibDsk Function Reference 
\layout Subsection

dsk_open: Open an existing disc image
\layout LyX-Code

dsk_err_t dsk_open(DSK_PDRIVER *self, const char *filename, const char *type,
 const char *compress)
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is the address of a DSK_PDRIVER variable (treat it as a handle to a drive
 / disc file).
 On return, the variable will be non-null (if the operation succeeded) or
 null (if the operation failed).
  
\layout Itemize


\begin_inset Quotes eld
\end_inset 

filename
\begin_inset Quotes erd
\end_inset 

 is the name of the disc image file.
 On Win32, 
\begin_inset Quotes eld
\end_inset 

A:
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

B:
\begin_inset Quotes erd
\end_inset 

 refer to the two floppy drives.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 is NULL to detect the disc image format automatically, or the name of a
 LibDsk driver to force that driver to be used.
 See 
\family typewriter 
dsk_type_enum()
\family default 
 below.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

compress
\begin_inset Quotes erd
\end_inset 

 is NULL to auto-detect compressed files, or the name of a LibDsk compression
 scheme.
 See 
\family typewriter 
dsk_comp_enum()
\family default 
.
 
\layout Standard

Returns: A 
\family typewriter 
dsk_err_t,
\family default 
 which will be 0 (
\family typewriter 
DSK_ERR_OK
\family default 
) if successful, or a negative integer if failed.
 See 
\family typewriter 
dsk_strerror()
\family default 
.
 The error 
\family typewriter 
DSK_ERR_NOTME
\family default 
 means either that no driver was able to open the disc / disc image (if
 
\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 was NULL) or that the requested driver could not open the file (if 
\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 was not NULL).
\layout Standard

Standard LibDsk drivers are: 
\layout Description


\begin_inset Quotes eld
\end_inset 

dsk
\begin_inset Quotes erd
\end_inset 

 : Disc image in the DSK format used by CPCEMU.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

edsk
\begin_inset Quotes erd
\end_inset 

 : Disc image in the extended CPCEMU DSK format.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 : Raw disc image - as produced by 
\begin_inset Quotes eld
\end_inset 


\family typewriter 
dd if=/dev/fd0 of=image
\family default 

\begin_inset Quotes erd
\end_inset 

.
 On systems other than Linux, DOS or Windows, this is also used to access
 the host system's floppy drive.
\layout Description


\begin_inset Quotes eld
\end_inset 

floppy
\begin_inset Quotes erd
\end_inset 

 : Host system's floppy drive (under Linux, DOS or Windows).
 
\layout Description


\begin_inset Quotes eld
\end_inset 

myz80
\begin_inset Quotes erd
\end_inset 

 : MYZ80 hard drive image, which is 
\emph on 
nearly
\emph toggle 
 the same as 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 but has a 256 byte header.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

cfi
\begin_inset Quotes erd
\end_inset 

 : Compressed floppy image, as produced by FDCOPY.COM under DOS.
 Its format is described in cfi.html.
\layout Standard

Compression schemes are: 
\layout Description


\begin_inset Quotes eld
\end_inset 

sq
\begin_inset Quotes erd
\end_inset 

 : Huffman (squeezed).
 The reason for the inclusion of this system is to support .DQK images (see
 appendix 
\begin_inset LatexCommand \ref{sec: dqk}

\end_inset 

).
 
\layout Description


\begin_inset Quotes eld
\end_inset 

gz
\begin_inset Quotes erd
\end_inset 

 : GZip (deflate).
 This will only be present if libdsk was built with zlib support.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

bz2
\begin_inset Quotes erd
\end_inset 

 : BZip2 (Burrows-Wheeler compression).
 This support is currently read-only, and will only be present if LibDsk
 was built with bzlib support.
\layout Subsection

dsk_creat: Create a new disc image
\layout LyX-Code

dsk_err_t dsk_creat(DSK_PDRIVER *self, const char *filename, const char
 *type)
\layout Standard

In the case of floppy drives, this acts exactly as 
\family typewriter 
dsk_open()
\family default 
.
 For image files, the file will be deleted and recreated.
 Parameters and results are as for 
\family typewriter 
dsk_open()
\family default 
, except that 
\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 cannot be NULL (it must specify the type of disc image to be created) and
 if 
\begin_inset Quotes eld
\end_inset 

compress
\begin_inset Quotes erd
\end_inset 

 is NULL, it means that the file being created should not be compressed.
\layout Subsection

dsk_close: Close a drive or disc image
\layout LyX-Code

dsk_err_t dsk_close(DSK_PDRIVER *self)
\layout Standard

Pass the address of an opaque pointer returned from 
\family typewriter 
dsk_open() 
\family default 
/ 
\family typewriter 
dsk_creat()
\family default 
.
 On return, the drive will have been closed and the pointer set to NULL.
 
\layout Subsection

dsk_pread, dsk_lread : Read a sector
\layout LyX-Code

dsk_err_t dsk_pread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector) 
\layout LyX-Code

dsk_err_t dsk_lread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_lsect_t sector)
\layout Standard

These functions read a single sector from the disc.
 There are two of them, depending on whether you are using logical or physical
 sector addresses.
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

buf
\begin_inset Quotes erd
\end_inset 

 is the buffer into which data will be loaded.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

, 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

sector
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_pread
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

sector
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_lread
\family default 
) give the location of the sector.
 
\layout Standard

Returns: 
\layout Itemize

If successful, DSK_ERR_OK.
 Otherwise, a negative DSK_ERR_* value.
 
\layout Itemize

If the driver cannot read sectors, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_pwrite, dsk_lwrite: Write a sector
\layout LyX-Code

dsk_err_t dsk_pwrite(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector) 
\layout LyX-Code

dsk_err_t dsk_lwrite(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_lsect_t sector)
\layout Standard

As dsk_pread / dsk_lread, but write their buffers to disc rather than reading
 them from disc.
 If the driver cannot write sectors, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_pcheck, dsk_lcheck: Verify sectors on disc against memory
\layout LyX-Code

dsk_err_t dsk_pcheck(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector) 
\layout LyX-Code

dsk_err_t dsk_lcheck(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_lsect_t sector)
\layout Standard

As 
\family typewriter 
dsk_pread
\family default 
 / 
\family typewriter 
dsk_lread
\family default 
, but rather than reading their buffers from disc, they compare the contents
 of their buffers with the data already on the disc.
 If the data match, the functions return DSK_ERR_OK.
 If there is a mismatch, they return DSK_ERR_MISMATCH.
 In case of error, other DSK_ERR_* values are returned.
 If the driver cannot read sectors, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_pformat, dsk_lformat: Format a disc track
\layout LyX-Code

dsk_err_t dsk_pformat(DSK_PDRIVER self, DSK_GEOMETRY *geom, dsk_pcyl_t cylinder,
 dsk_phead_t head, const DSK_FORMAT *format, unsigned char filler) 
\layout LyX-Code

dsk_err_t dsk_lformat(DSK_PDRIVER self, DSK_GEOMETRY *geom, dsk_ltrack_t
 track, const DSK_FORMAT *format, unsigned char filler)
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 The formatter may modify this if (for example) it's asked to format track
 41 of a 40-track drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 / 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_pformat
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

track
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_lformat
\family default 
) give the location of the track to format.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

format
\begin_inset Quotes erd
\end_inset 

 should be an array of (
\family typewriter 
geom->dg_sectors
\family default 
) DSK_FORMAT structures.
 These structures must contain sector headers for the track being formatted.
 For example, to format the first track of a 720k disc, you would pass in
 an array of 9 such structures: { 0, 0, 1, 512 }, { 0, 0, 2, 512, } ..., {
 0, 0, 9, 512 } 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

filler
\begin_inset Quotes erd
\end_inset 

 should be the filler byte to use.
 Currently the Win32 driver ignores this parameter.
 If the driver cannot format tracks, DSK_ERR_NOTIMPL will be returned.
\layout Standard

Note that when formatting a .DSK file that has more than one head, you must
 format cylinder 0 for each head before formatting other cylinders.
\layout Subsection

dsk_apform, dsk_alform: Automatic format
\layout LyX-Code

dsk_err_t dsk_apform(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, unsigned char filler) 
\layout LyX-Code

dsk_err_t dsk_alform(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track, unsigned char filler)
\layout Standard

These function calls behave as 
\family typewriter 
dsk_pformat()
\family default 
 and 
\family typewriter 
dsk_lformat() 
\family default 
above, except that the sector headers are automatically generated.
 This saves time and trouble setting up sector headers on discs with standard
 layouts such as DOS, PCW or Linux floppies.
 If the driver cannot format tracks, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_psecid, dsk_lsecid: Read a sector ID.
\layout LyX-Code

dsk_err_t dsk_psecid(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, DSK_FORMAT *result) 
\layout LyX-Code

dsk_err_t dsk_lsecid(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track, DSK_FORMAT *result)
\layout Standard

Read a sector ID from the given track.
 This can be used to probe for discs with oddly-numbered sectors (eg, numbered
 65-74).
 Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 / 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_psecid
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

track
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_lsecid
\family default 
) give the location of the track to read the sector from.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

 points to an uninitialised 
\family typewriter 
DSK_FORMAT
\family default 
 structure.
 
\layout Standard

On return: 
\layout Itemize

If successful, the buffer at 
\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

 will be initialised with the sector header found, and DSK_ERR_OK will be
 returned.
 
\layout Itemize

If the driver cannot provide this functionality (for example, the Win32
 driver under NT), DSK_ERR_NOTIMPL will be returned.
\layout Standard

Note that the DOS, Win16 and Win32 (under Win9x) drivers implement a limited
 version of this call, which will work on normal DOS / CP/M86 / PCW discs
 and CPC discs.
 However it will not be usable for other purposes.
\layout Subsection

dsk_xread, dsk_xwrite: Low-level reading and writing
\layout LyX-Code

dsk_err_t dsk_xread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected, dsk_psect_t sector, size_t sector_len, int *deleted); 
\layout LyX-Code

dsk_err_t dsk_xwrite(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead
_t head_expected, dsk_psect_t sector, size_t sector_len, int deleted);
\layout Standard

dsk_xread() and dsk_xwrite() are extended versions of dsk_pread() and dsk_pwrite
().
 They allow the caller to read/write sectors whose sector ID differs from
 the physical location of the sector, or to read/write deleted data..
 The 
\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 arguments specify where to look; the 
\begin_inset Quotes eld
\end_inset 

cyl_expected
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head_expected
\begin_inset Quotes erd
\end_inset 

 are the values to search for in the sector header.
 
\layout Standard

These functions are only supported by the CPCEMU driver and the Linux floppy
 driver.
 Other drivers will return DSK_ERR_NOTIMPL.
 Unless you are emulating a floppy controller, or you need to read discs
 that contain deleted data or misnumbered sectors, it should not be necessary
 to call these functions.
\layout Subsubsection

dsk_xread(), dsk_xwrite(): Deleted data 
\layout Standard

The 
\begin_inset Quotes eld
\end_inset 

deleted
\begin_inset Quotes erd
\end_inset 

 argument is used if you want to read or write sectors that have been marked
 as deleted.
 In 
\family typewriter 
dsk_xwrite()
\family default 
, this is a simple value; pass 0 to write normal data, or 1 to write deleted
 data.
 In 
\family typewriter 
dsk_xread()
\family default 
, pass the address of an integer containing 0 (read normal data) or 1 (read
 deleted data).
 On return, the integer will contain: 
\layout Itemize

If the requested data type was read: 0 
\layout Itemize

If the other data type was read: 1 
\layout Itemize

If the command failed: Value is meaningless.
 
\layout Standard

Passing 
\family typewriter 
NULL
\family default 
 acts the same as passing a pointer to 0.
\layout Standard

The opposite type of data will only be read if you set 
\family typewriter 
geom->dg_noskip
\family default 
 to nonzero.
 Some examples:
\layout Standard
\added_space_top 0.3cm \added_space_bottom 0.3cm \align center 

\begin_inset  Tabular
<lyxtabular version="2" rows="8" columns="5">
<features rotate="false" islongtable="false" endhead="0" endfirsthead="0" endfoot="0" endlastfoot="0">
<column alignment="center" valignment="top" leftline="true" rightline="false" width="" special="">
<column alignment="center" valignment="top" leftline="true" rightline="false" width="" special="">
<column alignment="center" valignment="top" leftline="true" rightline="true" width="" special="">
<column alignment="center" valignment="top" leftline="true" rightline="false" width="" special="">
<column alignment="center" valignment="top" leftline="true" rightline="true" width="" special="">
<row topline="true" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

geom->dg_noskip
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

deleted
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Data on disc
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Results
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

*deleted becomes
\end_inset 
</cell>
</row>
<row topline="true" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Normal
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
</row>
<row topline="false" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_NODATA
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

??
\end_inset 
</cell>
</row>
<row topline="false" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_NODATA
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

??
\end_inset 
</cell>
</row>
<row topline="false" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Normal
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
</row>
<row topline="false" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
</row>
<row topline="false" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Normal
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
</row>
<row topline="false" bottomline="true" newpage="false">
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

-> 1
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="false" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell multicolumn="0" alignment="center" valignment="top" topline="false" bottomline="true" leftline="true" rightline="true" rotate="false" usebox="none" width="" special="">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
</row>
</lyxtabular>

\end_inset 


\layout Subsection

dsk_ltread, dsk_ptread, dsk_xtread 
\layout LyX-Code

dsk_err_t dsk_ltread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_ltrack_t track) 
\layout LyX-Code

dsk_err_t dsk_ptread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head) 
\layout LyX-Code

dsk_err_t dsk_xtread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected)
\layout Standard

These functions read a track from the disc, using the FDC's 
\begin_inset Quotes eld
\end_inset 

READ TRACK
\begin_inset Quotes erd
\end_inset 

 command.
 There are three of them - logical, physical and extended physical.
\layout Standard

If the driver does not support this functionality, LibDsk will attempt to
 simulate it using multiple sector reads.
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

buf
\begin_inset Quotes erd
\end_inset 

 is the buffer into which data will be loaded.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_ptread
\family default 
, 
\family typewriter 
dsk_xtread
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

track
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_ltread
\family default 
) give the location of the track to read.
 
\layout Itemize

(
\family typewriter 
dsk_xtread
\family default 
) 
\begin_inset Quotes eld
\end_inset 

cyl_expected
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head_expected
\begin_inset Quotes erd
\end_inset 

 are used as the values to search for in the sector headers.
 
\layout Standard

Returns: 
\layout Itemize

If successful, DSK_ERR_OK.
 Otherwise, a negative DSK_ERR_* value.
 
\layout Itemize

(
\family typewriter 
dsk_xtread()
\family default 
 only) If the driver does not support extended sector reads/writes, then
 DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_lseek, dsk_pseek 
\layout LyX-Code

dsk_err_t dsk_lseek(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track)
\layout LyX-Code

dsk_err_t dsk_pseek(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head)
\layout Standard

Seek to a given cylinder.
 Only the CPCEMU driver and the Linux floppy driver support this; other
 drivers return DSK_ERR_NOTIMPL.
 You should not normally need to call these functions.
 They have been provided to support programs that emulate a uPD765A controller.
\layout Subsection

dsk_drive_status 
\layout LyX-Code

dsk_err_t dsk_drive_status(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_phead
_t head, unsigned char *result)
\layout Standard

Get the drive's status (ready, read-only etc.).
 The byte 
\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

 will have one or more of the following bits set:
\layout Description

DSK_ST3_FAULT: Drive fault 
\layout Description

DSK_ST3_RO: Read-only 
\layout Description

DSK_ST3_READY: Ready 
\layout Description

DSK_ST3_TRACK0: Head is over track 0 
\layout Description

DSK_ST3_DSDRIVE: Drive is double-sided 
\layout Description

DSK_ST3_HEAD1: Current head is head 1, not head 0.
 Usually this just depends on the value of the 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 parameter to this function.
 
\layout Standard

Which bits will be 
\begin_inset Quotes eld
\end_inset 

live
\begin_inset Quotes erd
\end_inset 

 depends on which driver is in use, but the most trustworthy will be DSK_ST3_REA
DY and DSK_ST3_RO.
 This function will never return DSK_ERR_NOTIMPL; if the facility is not
 provided by the driver, a default version will be used.
 
\layout Subsection

dsk_getgeom: Guess disc geometry
\layout LyX-Code

dsk_err_t dsk_getgeom(DSK_PDRIVER self, DSK_GEOMETRY *geom)
\layout Standard

This attempts to determine the geometry of a disc (number of cylinders,
 tracks, sectors etc.) by loading the boot sector.
 It understands DOS, CP/M-86 and PCW boot sectors.
 If the geometry could be guessed, then 
\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 will be initialised and DSK_ERR_OK will be returned.
 If no guess could be made, then DSK_ERR_BADFMT will be returned.
 Other values will result if the disc could not be read.
\layout Standard

Some drivers (in particular the MYZ80 driver, and the Win32 driver under
 NT) only support certain fixed disc geometries.
 In this case, the geometry returned will reflect what the driver can use,
 rather than what the boot sector says.
\layout Subsection

dg_*geom : Initialise disc geometry from boot sector
\layout LyX-Code

dsk_err_t dg_dosgeom(DSK_GEOMETRY *self, const unsigned char *bootsect)
 
\layout LyX-Code

dsk_err_t dg_pcwgeom(DSK_GEOMETRY *self, const unsigned char *bootsect)
 
\layout LyX-Code

dsk_err_t dg_cpm86geom(DSK_GEOMETRY *self, const unsigned char *bootsect)
\layout Standard

These functions are used by 
\family typewriter 
dsk_getgeom()
\family default 
, but can also be called independently.
 Enter them with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is the structure to initialise;
\layout Itemize


\begin_inset Quotes eld
\end_inset 

bootsect
\begin_inset Quotes erd
\end_inset 

 is the boot sector to initialise the structure from.
\layout Standard

Returns DSK_ERR_BADFMT if the sector does not contain a suitable disc specificat
ion, or DSK_ERR_OK otherwise.
\layout Subsection

dg_stdformat : Initialise disc geometry from a standard LibDsk format.
\layout LyX-Code

dsk_err_t dg_stdformat(DSK_GEOMETRY *self, dsk_format_t formatid, dsk_cchar_t
 *fname, dsk_cchar_t *fdesc)
\layout Standard

Initialises a DSK_GEOMETRY structure with one of the standard formats LibDsk
 knows about.
 Formats are:
\layout Description

FMT_180K: 180k, 9 512 byte sectors, 40 tracks, 1 side 
\layout Description

FMT_200K: 200k, 10 512 byte sectors, 40 tracks, 1 side 
\layout Description

FMT_CPCSYS: Amstrad CPC system format - as FMT_180K, but physical sectors
 are numbered 65-73 
\layout Description

FMT_CPCDATA: Amstrad CPC data format - as FMT_180K, but physical sectors
 are numbered 193-201 
\layout Description

FMT_720K: 720k, 9 512 byte sectors, 80 tracks, 2 sides 
\layout Description

FMT_800K: 800k, 10 512 byte sectors, 80 tracks, 2 sides 
\layout Description

FMT_1440K: 1.4M, 18 512 byte sectors, 80 tracks, 2 sides 
\layout Description

FMT_160K: 160k, 8 512 byte sectors, 40 tracks, 1 side 
\layout Description

FMT_320K: As FMT_160K, but 2 sides 
\layout Description

FMT_360K: As FMT_180K, but 2 sides 
\layout Description

FMT_720F: As FMT_720K, but the physical/logical sector mapping is 
\begin_inset Quotes eld
\end_inset 

out-and-back
\begin_inset Quotes erd
\end_inset 

 rather than 
\begin_inset Quotes eld
\end_inset 

alternate sides
\begin_inset Quotes erd
\end_inset 

.
 See section 
\begin_inset LatexCommand \ref{sec: dskgeom}

\end_inset 

 for details.
 
\layout Description

FMT_1200F: As FMT_720F, but with 15 sectors 
\layout Description

FMT_1440F: As FMT_720F, but with 18 sectors 
\layout Description

FMT_ACORN160: Acorn 40 track single sided 160k (used by ADFS 'S' format)
 
\layout Description

FMT_ACORN320: Acorn 80 track single sided 320k (used by ADFS 'M' format)
 
\layout Description

FMT_ACORN640: Acorn 80 track double sided 640k (used by ADFS 'L' format)
 
\layout Description

FMT_ACORN800: Acorn 80 track double sided 800k (used by ADFS 'D' and 'E')
 
\layout Description

FMT_ACORN1600: Acorn 80 track high density 1600k (used by ADFS 'F' format)
 
\layout Description

FMT_BBC100 BBC micro 40 track single sided 100k (using FM encoding) 
\layout Description

FMT_BBC200 BBC micro 80 track single sided 200k (using FM encoding)
\layout Standard

If the 
\begin_inset Quotes eld
\end_inset 

fname
\begin_inset Quotes erd
\end_inset 

 is not NULL, it will be pointed at a short name for the format (suitable
 for use as a program option; see 
\family typewriter 
tools/dskform.c
\family default 
).
 
\layout Standard

If the 
\begin_inset Quotes eld
\end_inset 

fdesc
\begin_inset Quotes erd
\end_inset 

 is not NULL, it will be pointed at a description string for the format.
 With these two, it's possible to enumerate geometries supported by the
 library without keeping a separate list in your program - see 
\family typewriter 
tools/formnames.c
\family default 
 for example code that does this.
\layout Subsection

dsk_*_forcehead: Override disc head
\layout LyX-Code

dsk_err_t dsk_set_forcehead(DSK_PDRIVER self, int force) 
\layout LyX-Code

dsk_err_t dsk_get_forcehead(DSK_PDRIVER self, int *force)
\layout Standard

(This option is only effective for the Linux floppy driver)
\layout Standard

Forces the driver to ignore the head number passed to it and always use
 either side 0 or side 1 of the disc.
 This is used to read discs recorded on PCW / CPC / Spectrum+3 add-on 3.5"
 drives.
 Instead of the system software being programmed to use both sides of the
 disc, a switch on the drive was used to set which side was being used.
 Thus discs would end up with both sides saying they were head 0.
\layout Standard

Anyway, when using dsk_set_forcehead, pass: 
\layout Description

-1: Normal - the head passed as a parameter to other calls is used.
 
\layout Description

0: Always use side 0.
 
\layout Description

1: Always use side 1.
\layout Subsection

dsk_type_enum 
\layout LyX-Code

dsk_err_t dsk_type_enum(int index, char **drvname)
\layout Standard

If 
\begin_inset Quotes eld
\end_inset 

index
\begin_inset Quotes erd
\end_inset 

 is in the range 0 -> number of LibDsk drivers, (
\family typewriter 
*drvname
\family default 
) is set to the short name for that driver (eg: 
\begin_inset Quotes eld
\end_inset 

myz80
\begin_inset Quotes erd
\end_inset 

 or 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

).
 If not, (*drvname) is set to 
\family typewriter 
NULL
\family default 
.
\layout Subsection

dsk_comp_enum 
\layout LyX-Code

dsk_err_t dsk_comp_enum(int index, char **compname)
\layout Standard

As 
\family typewriter 
dsk_type_enum()
\family default 
, but lists supported compression schemes.
\layout Subsection

dsk_drvname, dsk_drvdesc 
\layout LyX-Code

const char *dsk_drvname(DSK_PDRIVER self) 
\layout LyX-Code

const char *dsk_drvdesc(DSK_PDRIVER self)
\layout Standard

Returns the driver name (eg: 
\begin_inset Quotes eld
\end_inset 

myz80
\begin_inset Quotes erd
\end_inset 

) or description (eg 
\begin_inset Quotes eld
\end_inset 

MYZ80 hard drive driver
\begin_inset Quotes erd
\end_inset 

) for an open disc image.
\layout Subsection

dsk_compname, dsk_compdesc 
\layout LyX-Code

const char *dsk_compname(DSK_PDRIVER self); 
\layout LyX-Code

const char *dsk_compdesc(DSK_PDRIVER self);
\layout Standard

Returns the compression system name (eg: 
\begin_inset Quotes eld
\end_inset 

gz
\begin_inset Quotes erd
\end_inset 

; NULL if the disc image isn't compressed) or description (eg: 
\begin_inset Quotes eld
\end_inset 

GZip compressed
\begin_inset Quotes erd
\end_inset 

) for an open disc image.
\layout Subsection

dg_ps2ls, dg_ls2ps, dg_pt2lt, dg_lt2pt 
\layout Standard

Convert between logical sectors and physical cylinder/head/sector addresses.
 Normally these functions are called internally and you don't need to use
 them.
\layout LyX-Code

dsk_err_t dg_ps2ls(const DSK_GEOMETRY *self, dsk_pcyl_t cyl, dsk_phead_t
 head, dsk_psect_t sec, dsk_lsect_t *logical)
\layout Standard

Converts physical C/H/S to logical sector.
\layout LyX-Code

dsk_err_t dg_ls2ps(const DSK_GEOMETRY *self, dsk_lsect_t logical, dsk_pcyl_t
 *cyl, dsk_phead_t *head, dsk_psect_t *sec)
\layout Standard

Converts logical sector to physical C/H/S.
\layout LyX-Code

dsk_err_t dg_pt2lt(const DSK_GEOMETRY *self, dsk_pcyl_t cyl, dsk_phead_t
 head, dsk_ltrack_t *logical)
\layout Standard

Converts physical C/H to logical track.
\layout LyX-Code

dsk_err_t dg_lt2pt(const DSK_GEOMETRY *self, dsk_ltrack_t logical, dsk_pcyl_t
 *cyl, dsk_phead_t *head)
\layout Standard

Converts logical track to physical C/H.
\layout Subsection

dsk_strerror: Convert error code to string
\layout LyX-Code

char *dsk_strerror(dsk_err_t err)
\layout Standard

Converts an error code returned by one of the other LibDsk functions into
 a printable string.
\layout Subsection

dsk_get_psh 
\layout LyX-Code

unsigned char dsk_get_psh(size_t sector_size)
\layout Standard

Converts a sector size into the sector shift used by the uPD765A controller
 (eg: 128 -> 0, 256 -> 1, 512 -> 2 etc.) You should not need to use this.
 The reverse operation is: sectorsize = (128 << psh).
\layout Subsection

Structure: DSK_FORMAT
\layout Standard

This structure is used to represent a sector header.
 It has four members:
\layout Description

fmt_cylinder: Cylinder number.
 
\layout Description

fmt_head: Head number.
 
\layout Description

fmt_sector: Sector number.
 
\layout Description

fmt_secsize: Sector size in bytes.
\layout Subsection

LibDsk errors 
\layout Description

DSK_ERR_OK: No error.
\layout Description

DSK_ERR_BADPTR: A null or otherwise invalid pointer was passed to a LibDsk
 routine.
 
\layout Description

DSK_ERR_DIVZERO: Division by zero: For example, a DSK_GEOMETRY is set to
 have zero sectors.
 
\layout Description

DSK_ERR_BADPARM: Bad parameter (eg: if a DSK_GEOMETRY is set up with 
\family typewriter 
dg_cylinders
\family default 
 = 40, trying to convert a sector in cylinder 65 to a logical sector will
 give this error).
 
\layout Description

DSK_ERR_NODRVR: Requested driver not found in 
\family typewriter 
dsk_open()
\family default 
 / 
\family typewriter 
dsk_creat()
\family default 
.
 
\layout Description

DSK_ERR_NOTME: Disc image could not be opened by requested driver.
\layout Description

DSK_ERR_SYSERR: System call failed.
 errno holds the reason.
 
\layout Description

DSK_ERR_NOMEM: 
\family typewriter 
malloc()
\family default 
 failed to allocate memory.
 
\layout Description

DSK_ERR_NOTIMPL: Function is not implemented (eg, this driver doesn't support
 
\family typewriter 
dsk_xread()
\family default 
).
 
\layout Description

DSK_ERR_MISMATCH: In 
\family typewriter 
dsk_lcheck() 
\family default 
/ 
\family typewriter 
dsk_pcheck()
\family default 
, sectors didn't match.
 
\layout Description

DSK_ERR_NOTRDY: Drive is not ready.
 
\layout Description

DSK_ERR_RDONLY: Disc is read-only.
 
\layout Description

DSK_ERR_SEEKFAIL: Seek fail.
 
\layout Description

DSK_ERR_DATAERR: Data error.
 
\layout Description

DSK_ERR_NODATA: Sector ID found, but not sector data.
 
\layout Description

DSK_ERR_NOADDR: Sector not found at all.
 
\layout Description

DSK_ERR_BADFMT: Not a valid format.
 
\layout Description

DSK_ERR_CHANGED: Disc has been changed unexpectedly.
 
\layout Description

DSK_ERR_ECHECK: Equipment check.
 
\layout Description

DSK_ERR_OVERRUN: Overrun.
 
\layout Description

DSK_ERR_ACCESS: Access denied.
 
\layout Description

DSK_ERR_CTRLR: Controller failed.
 
\layout Description

DSK_ERR_COMPRESS: Compressed file is corrupt.
 
\layout Description

DSK_ERR_UNKNOWN: Unknown error
\layout Subsection

Miscellaneous 
\layout Standard

LIBDSK_VERSION is a macro, defined as a string containing the library version
 - eg 
\begin_inset Quotes eld
\end_inset 

0.9.0
\begin_inset Quotes erd
\end_inset 


\layout Section


\begin_inset LatexCommand \label{ldwindows}

\end_inset 

LibDsk under Windows
\layout Standard

This section mainly deals with the subject of direct floppy drive access.
 Other aspects of LibDSK remain relatively consistent across Windows versions.
\layout Standard

As with so many other aspects of Windows, direct access to the floppy drive
 is a case of 
\begin_inset Quotes eld
\end_inset 

write once - debug everywhere
\begin_inset Quotes erd
\end_inset 


\begin_float footnote 
\layout Standard

Originally said by Microsoft respect to Java.
 Pot.
 Kettle.
 Black.
\end_float 
.
 Not only does support vary across different systems, it varies depending
 on whether LibDsk was compiled with a 16-bit compiler or a 32-bit one.
\layout Subsection

Windows 3.x
\layout Standard

Only the 16-bit build of LibDsk will run.
 The floppy support in Win16 is pretty much the same as in DOS; there is
 support for discs with arbitrary numbers of tracks and sectors, and arbitrary
 sector sizes.
 This means that LibDsk can, for example, read Acorn ADFS floppies.
 
\layout Subsection

Windows 4.x (95, 98 and ME)
\layout Standard

Both the 16-bit and 32-bit versions of LibDsk will run.
 The 16-bit version is more capable, but less stable; it can read Acorn
 ADFS floppies, which the 32-bit version cannot.
 Unfortunately, 32-bit programs can't link to the 16-bit version of LibDsk;
 this would only be possible using some form of RPC (such as mailslots)
\begin_float footnote 
\layout Standard

And no, the Generic Thunk isn't good enough.
 I've tried it.
\end_float 
.
 
\layout Subsection

Windows NT (NT 3.x, NT 4.x, 2000, XP)
\layout Standard

The floppy drive can only read/write formats which are supported by the
 floppy driver.
 This is the case using either version of LibDsk.
\layout Subsection

General comments on programming floppy access for Windows
\layout Standard

LibDsk has three independent drivers for accessing floppies under Windows.
 They are:
\layout Subsubsection

The Win16 driver.
 
\layout Standard

This uses INT 0x13 to do the reads and writes, just as in MSDOS.
 Again as in MSDOS, there is a diskette parameter table pointed to by INT
 0x1E.
 This table seems not to be documented, which is perhaps why the Win16 subsystem
 in Windows 2000/XP doesn't implement it.
 You can, fortunately, tell if this is the case; if the first two bytes
 are both 0xC4, then what you have is a Windows 2000 trap rather than a
 diskette parameter table.
 
\layout Subsubsection

The Win32c driver.
\layout Standard

This driver uses VWIN32 services to make INT 0x13-style calls under Windows9x.
 However, there is no VWIN32 call to change the diskette parameter table,
 which is why the Win16 driver can do things the Win32 drivers can't.
 It isn't possible to get round this by thunking to a 16-bit DLL either;
 the INT 0x1E vector is zero for 16-bit DLLs in 32-bit processes.
\layout Subsubsection

The Win32 driver.
\layout Standard

Windows NT gets close (but not close enough) to the UNIX idea that everything
 is a file.
 So while in theory it would be enough to use the normal 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 driver on 
\begin_inset Quotes eld
\end_inset 


\family typewriter 

\backslash 

\backslash 
.
\backslash 
A:
\family default 

\begin_inset Quotes eld
\end_inset 

 , in practice there are a number of nasty subtleties relating to such things
 as memory alignment and file locking.
\layout Subsubsection

Other floppy APIs
\layout Standard

Sydex produce a replacement floppy driver for 32-bit versions of Windows
 (SydexFDD) which removes most of the restrictions that Windows places on
 acceptable floppy formats.
 LibDsk does not support this.
 
\layout Section

Writing new drivers
\layout Standard

The interface between LibDsk and its drivers is defined by the DRV_CLASS
 structure.
 To add a new driver, you create a new DRV_CLASS structure and add it to
 various files.
\layout Subsection

The driver header 
\layout Standard

Firstly, create a header for this driver, basing it on (for example) 
\family typewriter 
lib/drvposix.h
\family default 
.
 The first thing in the header (after the LGPL banner) is: 
\layout LyX-Code

typedef struct 
\layout LyX-Code

{ 
\layout LyX-Code

    DSK_DRIVER px_super; 
\layout LyX-Code

    FILE *px_fp; 
\layout LyX-Code

    int px_readonly;
\layout LyX-Code

    long px_filesize;
\layout LyX-Code

} POSIX_DSK_DRIVER;
\layout Standard

This is where you define any variables that your driver needs to store for
 each disc image.
 In the case of the 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 driver, this consists of a FILE pointer to access the underlying disc file,
 a 
\begin_inset Quotes eld
\end_inset 

readonly
\begin_inset Quotes erd
\end_inset 

 flag, and the current size of the drive image file.
 The first member of this structure must be of type DSK_DRIVER.
\layout Standard

The rest of this header consists of function prototypes, which I will come
 back to later.
\layout Subsection

The driver source file
\layout Standard

Secondly, create a .c file for your driver.
 Again, it's probably easiest to base this on lib/drvposix.c.
 At the start of this file, create a DRV_CLASS structure, such as:
\layout LyX-Code

DRV_CLASS dc_posix = 
\layout LyX-Code

{ 
\layout LyX-Code

    sizeof(POSIX_DSK_DRIVER), 
\layout LyX-Code

    "raw", 
\layout LyX-Code

    "Raw file driver", 
\layout LyX-Code

    posix_open, 
\layout LyX-Code

    posix_creat, 
\layout LyX-Code

    posix_close 
\layout LyX-Code

}; 
\layout Standard

The first three entries in this structure are: 
\layout Itemize

The size of your driver's instance data; 
\layout Itemize

The driver's name (as passed to 
\family typewriter 
dsk_open()
\family default 
 / 
\family typewriter 
dsk_creat()
\family default 
 ) 
\layout Itemize

The driver's description string.
 
\layout Standard

The remainder of the structure is composed of function pointers; the types
 of these are given in drv.h.
 At the very least, you will need to provide the first three pointers (*_open,
 *_creat and *_close); to make the driver vaguely useful, you will also
 need to implement some of the others.
\layout Standard

Once you have created this structure, edit: 
\layout Itemize

drivers.h.
 Add a declaration for your DRV_CLASS structure, such as 
\layout LyX-Code

extern DRV_CLASS dc_myformat; 
\layout Itemize

drivers.inc.
 Insert a reference to your structure (eg: 
\begin_inset Quotes eld
\end_inset 


\family typewriter 
&dc_myformat,
\family default 

\begin_inset Quotes erd
\end_inset 

) in the list.
 Note that order is important; the comments in drivers.inc describe how to
 decide where things go.
\layout Standard

Edit 
\begin_inset Quotes eld
\end_inset 

lib/Makefile.am
\begin_inset Quotes erd
\end_inset 

.
 Near the top of this file is a list of drivers and their header files;
 just add your .c and .h to this list.
\layout Standard

If your driver depends on certain system headers (as all the floppy drivers
 do) then you will need to add checks for these to 
\begin_inset Quotes eld
\end_inset 

configure.in
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

lib/drvi.h
\begin_inset Quotes erd
\end_inset 

; then run 
\begin_inset Quotes eld
\end_inset 

autoconf
\begin_inset Quotes erd
\end_inset 

 to rebuild the configure script.
\layout Standard

The function pointers in the DRV_CLASS structure are described in drv.h.
 The first parameter to all of them (
\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

) is declared as a pointer to DSK_DRIVER.
 In fact, it is a pointer to the first member of your instance data structure.
 Just cast the pointer to the correct type:
\layout LyX-Code

/* Sanity check: Is this meant for our driver? */ 
\layout LyX-Code

if (self->dr_class != &dc_posix) return DSK_ERR_BADPTR; 
\layout LyX-Code

pxself = (POSIX_DSK_PDRIVER )self;
\layout Standard

and you're in business.
\layout Subsection

Driver functions
\layout Subsubsection

dc_open
\layout LyX-Code

dsk_err_t (*dc_open )(DSK_PDRIVER self, const char *filename)
\layout Standard

Attempt to open a disc image.
 Entered with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 points to the instance data for this disc image (see above); it will have
 been initialised to zeroes using memset().
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

filename
\begin_inset Quotes erd
\end_inset 

 is the name of the image to open.
 
\layout Standard

Return: 
\layout Description

DSK_ERR_OK: The driver has successfully opened the image.
 
\layout Description

DSK_ERR_NOTME: The driver cannot handle this image.
 Other drivers should be allowed to try to use it.
 
\layout Description

other: The driver cannot handle this image.
 No other drivers should be tried (eg: the image was recognised by this
 driver, but is corrupt).
\layout Subsubsection

dc_creat
\layout LyX-Code

dsk_err_t (*dc_creat)(DSK_PDRIVER self, const char *filename)
\layout Standard

Attempt to create a new disc image.
 For the 
\begin_inset Quotes eld
\end_inset 

floppy
\begin_inset Quotes erd
\end_inset 

 drivers, behaves exactly as dc_open.
 Parameters and results are the same as for dc_open, except that DSK_ERR_NOTME
 is treated like any other error.
\layout Subsubsection

dc_close
\layout Standard

dsk_err_t (*dc_close)(DSK_PDRIVER self)
\layout Standard

Close the disc image.
 This will be the last call your driver will receive for a given disc image
 file, and it should free any resources it is using.
 Whether it returns DSK_ERR_OK or an error, this disc image will not be
 used again.
\layout Subsubsection

dc_read 
\layout LyX-Code

dsk_err_t (*dc_read)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector)
\layout Standard

Read a sector.
 Note that sector addresses passed to drivers are _always_ in C/H/S format.
 This function has the same parameters and return values as dsk_pread().
\layout Subsubsection

dc_write 
\layout LyX-Code

dsk_err_t (*dc_write)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const
 void *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector)
\layout Standard

Write a sector.
 This function has the same parameters and return values as dsk_pwrite().
 If your driver is read-only, leave this function pointer NULL.
\layout Subsubsection

dc_format 
\layout LyX-Code

dsk_err_t (*dc_format)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, const DSK_FORMAT *format, unsigned char filler)
\layout Standard

Format a track.
 This function has the same parameters and return values as dsk_pformat().
 If your driver cannot format tracks, leave this function pointer NULL.
\layout Subsubsection

dc_getgeom
\layout LyX-Code

dsk_err_t (*dc_getgeom)(DSK_PDRIVER self, DSK_GEOMETRY *geom)
\layout Standard

Get the disc geometry.
 Leave this function pointer as NULL unless your disc image does not allow
 a caller to use an arbitrary disc geometry.
 
\layout Standard

The two drivers which currently do this are the Win32 one, because Windows
 NT decides on the geometry itself and doesn't let programs change it; and
 the MYZ80 one, which has a single fixed geometry.
\layout Standard

Return DSK_ERR_OK if successful; DSK_ERR_NOTME to fall back to the standard
 LibDsk geometry probe; other values to indicate failure.
\layout Subsubsection

dc_secid 
\layout LyX-Code

dsk_err_t (*dc_secid)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, DSK_FORMAT *result)
\layout Standard

Read the ID of a random sector on a certain track/head, and put it in 
\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

.
 This function is primarily used to test for discs in CPC format (which
 have oddly-numbered physical sectors); if the disc image can't support
 this (eg: the 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 or Win32 drivers) then leave the function pointer NULL.
\layout Subsubsection

dc_xseek 
\layout LyX-Code

dsk_err_t (*dc_xseek)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head);
\layout Standard

Seek to a given cylinder / head.
 For disc images, just return DSK_ERR_OK if the cylinder/head are in range,
 or DSK_ERR_SEEKFAIL otherwise.
 For a floppy driver, only implement this function if your FDC can perform
 a seek by itself.
\layout Subsubsection

dc_xread, dc_xwrite 
\layout LyX-Code

dsk_err_t (*dc_xread)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected, dsk_psect_t sector, size_t bytes_to_write, int *deleted);
 
\layout LyX-Code

dsk_err_t (*dc_xwrite)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const
 void *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected,
 dsk_phead_t head_expected, dsk_psect_t sector, size_t bytes_to_read, int
 *deleted);
\layout Standard

Read / write sector whose ID may not match its position on disc, or which
 is marked as deleted.
 Only implement this if your disc image emulates sector IDs or your floppy
 driver exposes this level of functionality.
 Currently it is only implemented in the Linux and CPCEMU drivers.
\layout Subsubsection

dc_status 
\layout LyX-Code

dsk_err_t (*dc_status)(DSK_PDRIVER self, const DSK_GEOMETRY &geom, dsk_phead_t
 head, unsigned char *result); 
\layout Standard

Return the drive status (see dsk_drive_status() for the bits to return).
 
\begin_inset Quotes eld
\end_inset 

*result
\begin_inset Quotes erd
\end_inset 

 will contain the value calculated by the default implementation; for most
 image file drivers, all you have to do is set the read-only bit if appropriate.
\layout Subsubsection

dc_tread 
\layout LyX-Code

dsk_err_t (*dc_tread)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head);
\layout Standard

Read a track.
 You need only implement this if your floppy driver exposes the relevant
 functionality; if you don't, the library will use multiple calls to dc_read()
 instead.
 This function has the same parameters and return values as dsk_ptread().
\layout Subsubsection

dc_xtread
\layout LyX-Code

dsk_err_t (*dc_xread)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected);
\layout Standard

Read a track, with extended sector matching (sector headers on disc differ
 from physical location).
 This function has the same parameters and return values as dsk_xtread().
 As with dc_tread(), you need only implement this function if your floppy
 driver has a special READ TRACK command.
\layout Section

Adding new compression methods
\layout Standard

Adding a new compression method is very similar to adding a driver, though
 you only have to implement four functions.
\layout Standard

To add a new driver, you create a new COMPRESS_CLASS structure and add it
 to various files.
\layout Subsection

Driver header 
\layout Standard

This is done as for disc drivers.
 If you don't need any extra variables (for example, gzip and bzip2 compression
 don't) then you don't have to declare a new structure type - see lib/compgz.h
 for an example.
\layout Subsection

Driver implementation 
\layout Standard

Secondly, create a .c file for your driver.
 It's probably easiest to base this on lib/compgz.c.
 At the start of this file, create a COMPRESS_CLASS structure, such as:
\layout LyX-Code

COMPRESS_CLASS cc_gz = 
\layout LyX-Code

{ 
\layout LyX-Code

    sizeof(COMPRESS_DATA), 
\layout LyX-Code

    "gz", 
\layout LyX-Code

    "Gzip (deflate compression)", 
\layout LyX-Code

    gz_open, /* open */ 
\layout LyX-Code

    gz_creat, /* create new */ 
\layout LyX-Code

    gz_commit, /* commit */ 
\layout LyX-Code

    gz_abort /* abort */ 
\layout LyX-Code

};
\layout Standard

The first three entries in this structure are: 
\layout Itemize

The size of your driver's instance data.
 The GZip driver has no instance data and so just uses COMPRESS_DATA.
 If it had extra data these would be in a struct called GZ_COMPRESS_DATA,
 so the size here would be sizeof(GZ_COMPRESS_DATA).
 
\layout Itemize

The driver's name (as passed to dsk_open() / dsk_creat() ) 
\layout Itemize

The driver's description string.
 
\layout Standard

The remainder of the structure is composed of function pointers.
 The types of these are given in drv.h.
 You must implement all four.
\layout Standard

Once you have created this structure, edit: 
\layout Itemize

comp.h.
 Include your header.
 
\layout Itemize

compress.inc.
 Insert a reference to your structure (eg: 
\begin_inset Quotes eld
\end_inset 

&cc_myzip,
\begin_inset Quotes erd
\end_inset 

) in the list.
 Note that order is important.
\layout Standard

Edit 
\begin_inset Quotes eld
\end_inset 

lib/Makefile.am
\begin_inset Quotes erd
\end_inset 

.
 At the bottom of this file is a list of drivers and their header files;
 just add your .c and .h to this list.
\layout Standard

If your driver depends on certain system headers (eg, the gzip one depends
 on zlib.h) then you will need to add checks for these to 
\begin_inset Quotes eld
\end_inset 

configure.in
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

lib/compi.h
\begin_inset Quotes erd
\end_inset 

; then run 
\begin_inset Quotes eld
\end_inset 

autoconf
\begin_inset Quotes erd
\end_inset 

 to rebuild the configure script.
\layout Standard

The function pointers in the COMPRESS_CLASS structure are described in lib/compr
ess.h.
 The first parameter to all of them (
\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

) is declared as a pointer to COMPRESS_DATA.
 In fact, it is a pointer to the first member of your instance data structure.
 Just cast the pointer to the correct type:
\layout LyX-Code

/* Sanity check: Is this meant for our driver? */ 
\layout LyX-Code

if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR; 
\layout LyX-Code

sqself = (SQ_COMPRESS_DATA *)self;
\layout Standard

and you're in business.
\layout Subsection

Compression functions
\layout Subsubsection

cc_open 
\layout LyX-Code

dsk_err_t (*cc_open )(COMPRESS_DATA *self)
\layout Standard

Attempt to decompress a compressed file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 points to the instance data for this disc image.
 
\layout Itemize

self->cd_cfilename is the filename of the file to decompress.
\layout Standard

Return: 
\layout Description

DSK_ERR_OK: The file has been decompressed.
 
\layout Description

DSK_ERR_NOTME: The file is not compressed using this driver's method.
 
\layout Description

other: The file does belong to this driver, but it is corrupt or some other
 error occurred.
\layout Standard

Two helper functions may be useful when you are writing cc_open:
\layout LyX-Code

dsk_err_t comp_fopen(COMPRESS_DATA *self, FILE **pfp);
\layout Standard

Open the the file whose name is given at 
\family typewriter 
self->cd_cfilename
\family default 
.
 If successful, 
\family typewriter 
*pfp 
\family default 
will be the opened stream.
 If not, it will be NULL.
 If the file can only be opened read-only, sets 
\family typewriter 
self->cd_readonly
\family default 
 to 1.
\layout LyX-Code

dsk_err_t comp_mktemp(COMPRESS_DATA *cd, FILE **pfp);
\layout Standard

Create a temporary file and store its name at 
\family typewriter 
self->cd_ufilename
\family default 
.
 You should use this to create the file that you decompress into.
\layout Subsubsection

cc_creat
\layout LyX-Code

dsk_err_t (*cc_creat)(COMPRESS_DATA *cd)
\layout Standard

Warn the compression engine that a disc image file is being created, and
 when closed it will be compressed.
 The filename is stored at 
\family typewriter 
self->cd_cfilename
\family default 
.
 Normally this just returns DSK_ERR_OK.
\layout Subsubsection

cc_commit
\layout LyX-Code

dsk_err_t (*cc_commit)(COMPRESS_DATA *cd)
\layout Standard

Compress an uncompressed file.
 
\family typewriter 
self->cd_ufilename
\family default 
 is the name of the file to compress.
 
\family typewriter 
self->cd_cfilename
\family default 
 is the name of the output file.
\layout Subsubsection

cc_abort 
\layout LyX-Code

dsk_err_t (*cc_abort)(COMPRESS_DATA *cd)
\layout Standard

This is used if a file was decompressed and it's now being closed without
 having been changed.
 There is therefore no need to compress it again.
 This normally just returns DSK_ERR_OK.
\layout Section
\start_of_appendix 

\begin_inset LatexCommand \label{sec: dqk}

\end_inset 

DQK Files 
\layout Standard

A DQK file is a .DSK file compressed using Richard Greenlaw's Squeeze file
 format (originally from CP/M as SQ.COM, and later built in to NSWP.COM; versions
 also exist for DOS and UNIX).
 SQ was used in preference to more efficient compressors such as gzip because
 it can be readily decoded on 8-bit and 16-bit computers.
\layout Standard

The original reason for DQK files was software distribution.
 A disc image of a 180k disc won't fit on a 180k disc, owing to various
 overheads.
 However, the compressed DQK version may fit onto such a disc, and leave
 room for a tool to write the DQK back out as well.
 
\layout Standard

Such a tool has been included in the 
\begin_inset Quotes eld
\end_inset 

dskwrite
\begin_inset Quotes erd
\end_inset 

 directory in this distribution.
 It contains the following files:
\layout Itemize

dskwrite.com: Program to write .DSK or .DQK files out to a real disc.
 The .COM file works on PCs, Amstrad PCWs and Sinclair Spectrum +3s.
 
\layout Itemize

dskwrite.txt: Documentation for dskwrite.
 
\layout Itemize

dskwrite.z80: Z80 source for the CP/M version.
 
\layout Itemize

dskwrite.asm: 8086 source for the DOS version.
 
\layout Itemize

dskwrsea.com: The dskwrite distribution file - a self-extracting archive.
 It will self-extract under CP/M or DOS.
\layout Standard

Note that the files in the 
\begin_inset Quotes eld
\end_inset 

dskwrite
\begin_inset Quotes erd
\end_inset 

 directory are not GPLed or LGPLed.
 They are public domain.
 You may do whatsoever you please with them.
\layout Standard

LibDsk has been given .DQK support (use the 
\begin_inset Quotes eld
\end_inset 

dsk
\begin_inset Quotes erd
\end_inset 

 driver with 
\begin_inset Quotes eld
\end_inset 

sq
\begin_inset Quotes erd
\end_inset 

 compression) so that .DQK files don't have to be created and compressed
 in a two-state process.
 
\the_end
