mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Merge pull request #667 from davidgiven/options
Overhaul the options system.
This commit is contained in:
54
Makefile
54
Makefile
@@ -177,38 +177,40 @@ endef
|
|||||||
|
|
||||||
$(call do-encodedecodetest,agat840)
|
$(call do-encodedecodetest,agat840)
|
||||||
$(call do-encodedecodetest,amiga)
|
$(call do-encodedecodetest,amiga)
|
||||||
$(call do-encodedecodetest,appleii140)
|
$(call do-encodedecodetest,apple2,,--140)
|
||||||
$(call do-encodedecodetest,atarist360)
|
$(call do-encodedecodetest,atarist,,--360)
|
||||||
$(call do-encodedecodetest,atarist370)
|
$(call do-encodedecodetest,atarist,,--370)
|
||||||
$(call do-encodedecodetest,atarist400)
|
$(call do-encodedecodetest,atarist,,--400)
|
||||||
$(call do-encodedecodetest,atarist410)
|
$(call do-encodedecodetest,atarist,,--410)
|
||||||
$(call do-encodedecodetest,atarist720)
|
$(call do-encodedecodetest,atarist,,--720)
|
||||||
$(call do-encodedecodetest,atarist740)
|
$(call do-encodedecodetest,atarist,,--740)
|
||||||
$(call do-encodedecodetest,atarist800)
|
$(call do-encodedecodetest,atarist,,--800)
|
||||||
$(call do-encodedecodetest,atarist820)
|
$(call do-encodedecodetest,atarist,,--820)
|
||||||
$(call do-encodedecodetest,bk800)
|
$(call do-encodedecodetest,bk800)
|
||||||
$(call do-encodedecodetest,brother120)
|
$(call do-encodedecodetest,brother,,--120)
|
||||||
$(call do-encodedecodetest,brother240)
|
$(call do-encodedecodetest,brother,,--240)
|
||||||
$(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb,--35)
|
$(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb,--171)
|
||||||
$(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb,--40)
|
$(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb,--192)
|
||||||
$(call do-encodedecodetest,commodore1581)
|
$(call do-encodedecodetest,commodore1581)
|
||||||
$(call do-encodedecodetest,cmd_fd2000)
|
$(call do-encodedecodetest,cmd_fd2000)
|
||||||
$(call do-encodedecodetest,hp9121)
|
$(call do-encodedecodetest,hplif,,--264)
|
||||||
$(call do-encodedecodetest,ibm1200)
|
$(call do-encodedecodetest,hplif,,--616)
|
||||||
$(call do-encodedecodetest,ibm1232)
|
$(call do-encodedecodetest,hplif,,--770)
|
||||||
$(call do-encodedecodetest,ibm1440)
|
$(call do-encodedecodetest,ibm,,--1200)
|
||||||
$(call do-encodedecodetest,ibm180)
|
$(call do-encodedecodetest,ibm,,--1232)
|
||||||
$(call do-encodedecodetest,ibm160)
|
$(call do-encodedecodetest,ibm,,--1440)
|
||||||
$(call do-encodedecodetest,ibm320)
|
$(call do-encodedecodetest,ibm,,--180)
|
||||||
$(call do-encodedecodetest,ibm360)
|
$(call do-encodedecodetest,ibm,,--160)
|
||||||
$(call do-encodedecodetest,ibm720)
|
$(call do-encodedecodetest,ibm,,--320)
|
||||||
$(call do-encodedecodetest,mac400,scripts/mac400_test.textpb)
|
$(call do-encodedecodetest,ibm,,--360)
|
||||||
$(call do-encodedecodetest,mac800,scripts/mac800_test.textpb)
|
$(call do-encodedecodetest,ibm,,--720)
|
||||||
|
$(call do-encodedecodetest,mac,scripts/mac400_test.textpb,--400)
|
||||||
|
$(call do-encodedecodetest,mac,scripts/mac800_test.textpb,--800)
|
||||||
$(call do-encodedecodetest,n88basic)
|
$(call do-encodedecodetest,n88basic)
|
||||||
$(call do-encodedecodetest,rx50)
|
$(call do-encodedecodetest,rx50)
|
||||||
$(call do-encodedecodetest,tids990)
|
$(call do-encodedecodetest,tids990)
|
||||||
$(call do-encodedecodetest,victor9k_ss)
|
$(call do-encodedecodetest,victor9k,,--612)
|
||||||
$(call do-encodedecodetest,victor9k_ds)
|
$(call do-encodedecodetest,victor9k,,--1224)
|
||||||
|
|
||||||
$(OBJDIR)/%.a:
|
$(OBJDIR)/%.a:
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
|
|||||||
@@ -19,13 +19,15 @@ Reading discs
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read ampro400
|
fluxengine read ampro <format>
|
||||||
```
|
```
|
||||||
|
|
||||||
You should end up with an `ampro.img` which is 409600. If you have a
|
...where `<format>` is one of `--400` for a 40-track disk or `--800` for an
|
||||||
double-sided disk, use `ampro800`, which will give you a file819200 bytes long.
|
80-track disk. These are an alias for `fluxengine read ibm` with preconfigured
|
||||||
These is an alias for `fluxengine read ibm` with preconfigured parameters. You
|
parameters.
|
||||||
can pass this straight into [cpmtools](http://www.moria.de/~michael/cpmtools/):
|
|
||||||
|
FluxEngine has direct filesystem support for these disks, or you can pass the
|
||||||
|
disk images into [cpmtools](http://www.moria.de/~michael/cpmtools/):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cpmls -f ampdsdd ampro.img
|
$ cpmls -f ampdsdd ampro.img
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ FluxEngine can remap the sectors from physical to logical using modifiers. If
|
|||||||
you don't specify a remapping modifier, you get the sectors in the order they
|
you don't specify a remapping modifier, you get the sectors in the order they
|
||||||
appear on the disk.
|
appear on the disk.
|
||||||
|
|
||||||
If you don't want an image in physical sector order, specify one of these options:
|
If you don't want an image in physical sector order, specify one of these
|
||||||
|
options:
|
||||||
|
|
||||||
- `--appledos` Selects AppleDOS sector translation
|
- `--appledos` Selects AppleDOS sector translation
|
||||||
- `--prodos` Selects ProDOS sector translation
|
- `--prodos` Selects ProDOS sector translation
|
||||||
@@ -40,15 +41,21 @@ These options also select the appropriate file system; FluxEngine has read-only
|
|||||||
support for all of these. For example:
|
support for all of these. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine ls appleii140 --appledos -f image.flux
|
fluxengine ls apple2 --appledos -f image.flux
|
||||||
```
|
```
|
||||||
|
|
||||||
In addition, some third-party systems use 80-track double sides drives, with
|
In addition, some third-party systems use 80-track double sides drives, with
|
||||||
the same underlying disk format. These are supported with the `appleii640`
|
the same underlying disk format. The full list of formats supported is:
|
||||||
profile. The complication here is that the AppleDOS filesystem only supports up
|
|
||||||
|
- `--140` 35-track single-sided (the normal Apple II format)
|
||||||
|
- `--640` 80-track double-sided
|
||||||
|
|
||||||
|
`--140` is the default.
|
||||||
|
|
||||||
|
The complication here is that the AppleDOS filesystem only supports up
|
||||||
to 50 tracks, so it needs tweaking to support larger disks. It treats the
|
to 50 tracks, so it needs tweaking to support larger disks. It treats the
|
||||||
second side of the disk as a completely different volume. To access these
|
second side of the disk as a completely different volume. To access these
|
||||||
files, use `--appledos --side1`.
|
files, use `--640 --appledos --side1`.
|
||||||
|
|
||||||
[^1]: CP/M disks use the ProDOS translation for the first three tracks and a
|
[^1]: CP/M disks use the ProDOS translation for the first three tracks and a
|
||||||
different translation for all the tracks thereafter.
|
different translation for all the tracks thereafter.
|
||||||
@@ -65,12 +72,12 @@ Reading discs
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read appleii140
|
fluxengine read apple2
|
||||||
```
|
```
|
||||||
|
|
||||||
(or `appleii640`)
|
(or `apple2 --640`)
|
||||||
|
|
||||||
You should end up with an `appleii140.img` which is 143360 bytes long. It will
|
You should end up with an `apple2.img` which is 143360 bytes long. It will
|
||||||
be in physical sector ordering if you don't specify a file system format as
|
be in physical sector ordering if you don't specify a file system format as
|
||||||
described above.
|
described above.
|
||||||
|
|
||||||
@@ -79,7 +86,7 @@ Writing discs
|
|||||||
|
|
||||||
Just do:
|
Just do:
|
||||||
```
|
```
|
||||||
fluxengine write appleii140 -i appleii140.img
|
fluxengine write apple2 -i apple2.img
|
||||||
```
|
```
|
||||||
|
|
||||||
The image will be expected to be in physical sector ordering if you don't
|
The image will be expected to be in physical sector ordering if you don't
|
||||||
|
|||||||
@@ -33,29 +33,29 @@ FluxEngine can also write Atari ST scheme disks.
|
|||||||
|
|
||||||
The syntax is:
|
The syntax is:
|
||||||
|
|
||||||
fluxengine write <format> -i input.st
|
fluxengine write atarist -i input.st <format>
|
||||||
|
|
||||||
Available formats
|
Available formats
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
`<format>` can be one of these:
|
`<format>` can be one of these:
|
||||||
|
|
||||||
- `atarist360`: a 360kB 3.5" disk, with 80 cylinders, 1 side, and 9 sectors
|
- `--360`: a 360kB 3.5" disk, with 80 cylinders, 1 side, and 9 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist370`: a 370kB 3.5" disk, with 82 cylinders, 1 side, and 9 sectors
|
- `--370`: a 370kB 3.5" disk, with 82 cylinders, 1 side, and 9 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist400`: a 400kB 3.5" disk, with 80 cylinders, 1 side, and 10 sectors
|
- `--400`: a 400kB 3.5" disk, with 80 cylinders, 1 side, and 10 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist410`: a 410kB 3.5" disk, with 82 cylinders, 1 side, and 10 sectors
|
- `--410`: a 410kB 3.5" disk, with 82 cylinders, 1 side, and 10 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist720`: a 720kB 3.5" disk, with 80 cylinders, 2 sides, and 9 sectors
|
- `--720`: a 720kB 3.5" disk, with 80 cylinders, 2 sides, and 9 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist740`: a 740kB 3.5" disk, with 82 cylinders, 2 sides, and 9 sectors
|
- `--740`: a 740kB 3.5" disk, with 82 cylinders, 2 sides, and 9 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist800`: a 800kB 3.5" disk, with 80 cylinders, 2 sides, and 10 sectors
|
- `--800`: a 800kB 3.5" disk, with 80 cylinders, 2 sides, and 10 sectors per
|
||||||
per track.
|
track.
|
||||||
- `atarist820`: a 820kB 3.5" disk, with 82 cylinders, 2 sides, and 10 sectors
|
- `--820`: a 820kB 3.5" disk, with 82 cylinders, 2 sides, and 10 sectors per
|
||||||
per track.
|
track.
|
||||||
|
|
||||||
See [the IBM format documentation](disk-ibm.md) for more information. Note that
|
See [the IBM format documentation](disk-ibm.md) for more information. Note that
|
||||||
only some PC 3.5" floppy disk drives are capable of seeking to the 82nd track.
|
only some PC 3.5" floppy disk drives are capable of seeking to the 82nd track.
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ Reading disks
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read `<format>`
|
fluxengine read brother `<format>`
|
||||||
```
|
```
|
||||||
|
|
||||||
... where `<format>` can be `brother120` or `brother240`. You should end up
|
... where `<format>` can be `--120` or `--240`. You should end up
|
||||||
with a `brother.img` which is either 119808 or 239616 bytes long.
|
with a `brother.img` which is either 119808 or 239616 bytes long.
|
||||||
|
|
||||||
Writing disks
|
Writing disks
|
||||||
@@ -53,7 +53,7 @@ Just do:
|
|||||||
fluxengine write `<format>` -i brother.img
|
fluxengine write `<format>` -i brother.img
|
||||||
```
|
```
|
||||||
|
|
||||||
...where `<format>` can be `brother120` or `brother240`.
|
...where `<format>` can be `--120` or `--240`.
|
||||||
|
|
||||||
Dealing with misaligned disks
|
Dealing with misaligned disks
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -102,7 +102,8 @@ record.) The sector order is 05a3816b4927, which gives a sector skew of 5.
|
|||||||
High level format
|
High level format
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Once decoded, you end up with a file system image.
|
Once decoded, you end up with a file system image. FluxEngine supports direct
|
||||||
|
filesystem access for both kinds of disks.
|
||||||
|
|
||||||
### 120kB disks
|
### 120kB disks
|
||||||
|
|
||||||
|
|||||||
@@ -33,29 +33,28 @@ Reading 1541 disks
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read commodore1541 -o commodore1541.d64
|
fluxengine read commodore -o commodore.d64
|
||||||
```
|
```
|
||||||
|
|
||||||
You should end up with an `commodore1541.d64` file which is 174848 bytes long.
|
You should end up with an `commodore.d64` file which is 174848 bytes long.
|
||||||
You can load this straight into a Commodore 64 emulator such as
|
You can load this straight into a Commodore 64 emulator such as
|
||||||
[VICE](http://vice-emu.sourceforge.net/).
|
[VICE](http://vice-emu.sourceforge.net/).
|
||||||
|
|
||||||
If you have a 40-track disk, add `--40`.
|
If you have a 40-track disk, add `--196`.
|
||||||
|
|
||||||
**Big warning!** Commodore 64 disk images are complicated due to the way the
|
**Big warning!** Commodore 64 disk images are complicated due to the way the
|
||||||
tracks are different sizes and the odd sector size, so you need the special D64
|
tracks are different sizes and the odd sector size, so you need the special D64
|
||||||
or LDBS output formats to represent them sensibly. Don't use IMG unless you
|
or LDBS output formats to represent them sensibly.
|
||||||
know what you're doing.
|
|
||||||
|
|
||||||
Writing 1541 disks
|
Writing 1541 disks
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Just do:
|
Just do:
|
||||||
```
|
```
|
||||||
fluxengine write commodore1541 -i file.d64
|
fluxengine write commodore -i file.d64
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have a 40-track disk, add `--40`.
|
If you have a 40-track disk, add `--196`.
|
||||||
|
|
||||||
Note that only standard Commodore 64 BAM file systems can be written this way,
|
Note that only standard Commodore 64 BAM file systems can be written this way,
|
||||||
as the disk ID in the BAM has to be copied to every sector on the disk.
|
as the disk ID in the BAM has to be copied to every sector on the disk.
|
||||||
|
|||||||
@@ -38,15 +38,16 @@ Reading disks
|
|||||||
|
|
||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
fluxengine read `<format>`
|
fluxengine read ibm `<format>`
|
||||||
|
|
||||||
...and you'll end up with a `<format>.img` file. This should work on most PC
|
...and you'll end up with an `ibm.img` file. You'll need to specify which
|
||||||
disks (including FM 360kB disks, 3.5" 1440kB disks, 5.25" 1200kB disks, etc.)
|
format to use; this can be one of `--160`, `--180`, `--320`, `--360`, `--720`,
|
||||||
The size of the disk image will vary depending on the format.
|
`--1200`, `--1232` or `--1400` depending. The size of the disk image will vary
|
||||||
|
depending on the format.
|
||||||
|
|
||||||
The common PC formats are `ibm720` and `ibm1440`, but there are _many_ others,
|
The common PC formats are `--720` and `--1440`, but there are _many_ others,
|
||||||
and there's too many configuration options to usefully list. Use `fluxengine
|
and there's too many configuration options to usefully list. Use `fluxengine
|
||||||
write` to list all formats, and try `fluxengine write ibm1440 --config` to see
|
write` to list all formats, and try `fluxengine write ibm --1440 --config` to see
|
||||||
a sample configuration.
|
a sample configuration.
|
||||||
|
|
||||||
Configuration options you'll want include:
|
Configuration options you'll want include:
|
||||||
@@ -84,16 +85,13 @@ makes things slightly awkward. Preconfigured profiles are available.
|
|||||||
|
|
||||||
The syntax is:
|
The syntax is:
|
||||||
|
|
||||||
fluxengine write <format> -i input.img <options>
|
fluxengine write ibm <format> -i input.img <options>
|
||||||
|
|
||||||
The common PC formats are `ibm720` and `ibm1440`, but there are _many_ others,
|
See above for the formats.
|
||||||
and there's too many configuration options to usefully list. Use `fluxengine
|
|
||||||
write` to list all formats, and try `fluxengine write ibm1440 --config` to see
|
|
||||||
a sample configuration.
|
|
||||||
|
|
||||||
Some image formats, such as DIM, specify the image format, For these you can
|
Some image formats, such as DIM, specify the image format, For these you can
|
||||||
specify the `ibm` format and FluxEngine will automatically determine the
|
specify the `--auto` format (which is the default) and FluxEngine will
|
||||||
correct format to use.
|
automatically determine the correct format to use.
|
||||||
|
|
||||||
Mixed-format disks
|
Mixed-format disks
|
||||||
------------------
|
------------------
|
||||||
@@ -131,11 +129,7 @@ drives, feature "tri-mode" support which in addition to normal 300rpm modes,
|
|||||||
can change their speed to read and write 360rpm DD and HD disks.
|
can change their speed to read and write 360rpm DD and HD disks.
|
||||||
|
|
||||||
Neither the FluxEngine or Greaseweazle hardware can currently command a
|
Neither the FluxEngine or Greaseweazle hardware can currently command a
|
||||||
tri-mode drive to spin at 360rpm, however an older 360rpm-only drive will work
|
tri-mode drive to spin at 360rpm. However on both devices the FluxEngine
|
||||||
to read these formats.
|
software is capable of both reading and writing 300rpm disks at 360rpm and vice
|
||||||
|
versa, so it shouldn't matter.
|
||||||
|
|
||||||
Alternately, the FluxEngine software can rescale the flux pulses to enable
|
|
||||||
reading and writing these formats with a plain 300rpm drive. To do this,
|
|
||||||
specify the following two additional options:
|
|
||||||
|
|
||||||
--flux_source.rescale=1.2 --flux_sink.rescale=1.2
|
|
||||||
|
|||||||
@@ -37,20 +37,19 @@ Reading discs
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read <format> -o mac.dsk
|
fluxengine read mac <format> -o mac.dsk
|
||||||
```
|
```
|
||||||
|
|
||||||
...where `<format>` can be `mac400` or `mac800`.
|
...where `<format>` can be `--400` or `--800`.
|
||||||
|
|
||||||
You should end up with a `mac.dsk` file containing a raw sector image
|
You should end up with a `mac.dsk` file containing a raw sector image
|
||||||
(equivalent to `.img`).
|
(equivalent to `.img`).
|
||||||
|
|
||||||
**Big warning!** Mac disk images are complicated due to the way the tracks are
|
The Mac disk format contains an extra twelve bytes of data per sector which can
|
||||||
different sizes and the odd sector size. What you get above is a triangular
|
be used for filesystem metadata. In practice, this was never used by anyone,
|
||||||
disk image, which contains all the 512-byte user data areas concatenated
|
and so the default is to omit these. If you want them, specify that you want
|
||||||
together in filesystem order. It does not contain the twelve bytes of metadata.
|
524 byte sectors with `--layout.layoutdata.sector_size=524`. The metadata will
|
||||||
If you want these as well, specify that you want 524 byte sectors with
|
follow the
|
||||||
`--output.image.img.trackdata.sector_size=512`. The metadata will follow the
|
|
||||||
512 bytes of user data.
|
512 bytes of user data.
|
||||||
|
|
||||||
FluxEngine also supports DiskCopy 4.2 disk images, which may be a better option
|
FluxEngine also supports DiskCopy 4.2 disk images, which may be a better option
|
||||||
@@ -64,16 +63,13 @@ Writing discs
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine write <format> -i mac.dsk
|
fluxengine write mac <format> -i mac.dsk
|
||||||
```
|
```
|
||||||
|
|
||||||
...where `<format>` can be `mac400` or `mac800`.
|
...where `<format>` can be `400` or `800`.
|
||||||
|
|
||||||
It'll read the image file and write it out.
|
It'll read the image file and write it out.
|
||||||
|
|
||||||
The same warning as above applies --- you can use normal `.dsk` files but it's
|
|
||||||
problematic. Consider using DiskCopy 4.2 files instead.
|
|
||||||
|
|
||||||
Useful references
|
Useful references
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ Reading disks
|
|||||||
Based on your floppy drive, just do one of:
|
Based on your floppy drive, just do one of:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read micropolis143 # single-sided Mod I
|
fluxengine read micropolis --143 # single-sided Mod I
|
||||||
fluxengine read micropolis287 # double-sided Mod I
|
fluxengine read micropolis --287 # double-sided Mod I
|
||||||
fluxengine read micropolis315 # single-sided Mod II
|
fluxengine read micropolis --315 # single-sided Mod II
|
||||||
fluxengine read micropolis630 # double-sided Mod II
|
fluxengine read micropolis --630 # double-sided Mod II
|
||||||
```
|
```
|
||||||
|
|
||||||
You should end up with a `micropolis.img` of the corresponding size. The image
|
You should end up with a `micropolis.img` of the corresponding size. The image
|
||||||
@@ -45,10 +45,10 @@ It's also possible to output to VGI, which retains OS-specific "user data" and
|
|||||||
machine-specific ECC. Add `--vgi` to the command line after the chosen
|
machine-specific ECC. Add `--vgi` to the command line after the chosen
|
||||||
Micropolis profile:
|
Micropolis profile:
|
||||||
```
|
```
|
||||||
fluxengine read micropolis143 --vgi # single-sided Mod I
|
fluxengine read micropolis --143 --vgi # single-sided Mod I
|
||||||
fluxengine read micropolis287 --vgi # double-sided Mod I
|
fluxengine read micropolis --287 --vgi # double-sided Mod I
|
||||||
fluxengine read micropolis315 --vgi # single-sided Mod II
|
fluxengine read micropolis --315 --vgi # single-sided Mod II
|
||||||
fluxengine read micropolis630 --vgi # double-sided Mod II
|
fluxengine read micropolis --630 --vgi # double-sided Mod II
|
||||||
```
|
```
|
||||||
|
|
||||||
You should end up with a `micropolis.vgi` instead. The format is well-defined
|
You should end up with a `micropolis.vgi` instead. The format is well-defined
|
||||||
@@ -72,15 +72,15 @@ Writing disks
|
|||||||
Just do one of:
|
Just do one of:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine write micropolis143 # single-sided Mod I
|
fluxengine write micropolis --143 # single-sided Mod I
|
||||||
fluxengine write micropolis287 # double-sided Mod I
|
fluxengine write micropolis --287 # double-sided Mod I
|
||||||
fluxengine write micropolis315 # single-sided Mod II
|
fluxengine write micropolis --315 # single-sided Mod II
|
||||||
fluxengine write micropolis630 # double-sided Mod II
|
fluxengine write micropolis --630 # double-sided Mod II
|
||||||
|
|
||||||
fluxengine write micropolis143 --vgi # single-sided Mod I
|
fluxengine write micropolis --143 --vgi # single-sided Mod I
|
||||||
fluxengine write micropolis287 --vgi # double-sided Mod I
|
fluxengine write micropolis --287 --vgi # double-sided Mod I
|
||||||
fluxengine write micropolis315 --vgi # single-sided Mod II
|
fluxengine write micropolis --315 --vgi # single-sided Mod II
|
||||||
fluxengine write micropolis630 --vgi # double-sided Mod II
|
fluxengine write micropolis --630 --vgi # double-sided Mod II
|
||||||
```
|
```
|
||||||
|
|
||||||
Useful references
|
Useful references
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ clone of the PDP-11. The MX board was an early floppy drive controller board
|
|||||||
for it.
|
for it.
|
||||||
|
|
||||||
<div style="text-align: center">
|
<div style="text-align: center">
|
||||||
<a href="http://www.leningrad.su/museum/show_big.php?n=1006"><img src="dvk3m.jpg" style="max-width: 60%" alt="A Durango F85, held precariously"></a>
|
<a href="http://www.leningrad.su/museum/show_big.php?n=1006"><img src="dvk3m.jpg" style="max-width: 60%" alt="A DVK computer"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
The MX format is interesting in that it has to be read a track at a time. The
|
The MX format is interesting in that it has to be read a track at a time. The
|
||||||
@@ -42,15 +42,17 @@ Reading discs
|
|||||||
-------------
|
-------------
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read mx440
|
fluxengine read mx
|
||||||
```
|
```
|
||||||
|
|
||||||
You should end up with an `mx.img` which will vary in length depending on the format. The default is double-sided 80-track. For the other formats, use:
|
You should end up with an `mx.img` which will vary in length depending on the
|
||||||
|
format. The default is double-sided 80-track. For the other formats, add one of
|
||||||
|
the following options:
|
||||||
|
|
||||||
* single-sided 40-track: `mx110`
|
* single-sided 40-track: `--110`
|
||||||
* double-sided 40-track: `mx220_ds`
|
* double-sided 40-track: `--220ds`
|
||||||
* single-sided 80-track: `mx220_ss`
|
* single-sided 80-track: `--220ss`
|
||||||
* double-sided 80-track: `mx440`
|
* double-sided 80-track: `--440`
|
||||||
|
|
||||||
|
|
||||||
Useful references
|
Useful references
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ equivalent to .img images.
|
|||||||
Reading disks
|
Reading disks
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
You must use a 48-TPI (40-track) 300RPM 5.25" floppy drive.
|
|
||||||
|
|
||||||
To read a double-sided North Star floppy, run:
|
To read a double-sided North Star floppy, run:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read <format>
|
fluxengine read northstar <format>
|
||||||
```
|
```
|
||||||
|
|
||||||
...where `<format>` is one of the formats listed below.
|
...where `<format>` is one of the formats listed below.
|
||||||
@@ -37,13 +35,10 @@ disk type.
|
|||||||
Writing disks
|
Writing disks
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
You must use a 48-TPI (40-track) 300RPM 5.25" floppy drive and make
|
|
||||||
sure that the drive's spindle speed is adjusted to exactly 300RPM.
|
|
||||||
|
|
||||||
To write a double-sided North Star floppy, run:
|
To write a double-sided North Star floppy, run:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine write <format> -i image_to_write.nsi
|
fluxengine write northstar <format> -i image_to_write.nsi
|
||||||
```
|
```
|
||||||
|
|
||||||
...where `<format>` is one of the formats listed below.
|
...where `<format>` is one of the formats listed below.
|
||||||
@@ -55,9 +50,9 @@ The following formats are supported:
|
|||||||
|
|
||||||
| Format name | Disk Type | File Size (bytes) |
|
| Format name | Disk Type | File Size (bytes) |
|
||||||
| -------------- | ----------------------------------- | ----------------- |
|
| -------------- | ----------------------------------- | ----------------- |
|
||||||
| `northstar87` | Single-Sided, Single-Density (SSSD) | 89,600 |
|
| `--87` | Single-Sided, Single-Density (SSSD) | 89,600 |
|
||||||
| `northstar175` | Single-Sided, Double-Density (SSDD) | 179,200 |
|
| `--175` | Single-Sided, Double-Density (SSDD) | 179,200 |
|
||||||
| `northstar350` | Double-Sided, Double-Density (DSDD) | 358,400 |
|
| `--350` | Double-Sided, Double-Density (DSDD) | 358,400 |
|
||||||
|
|
||||||
Useful references
|
Useful references
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ sector GCR disks, with a variable-speed drive and a varying number of sectors
|
|||||||
per track --- from 19 to 12. Disks can be double-sided, meaning that they can
|
per track --- from 19 to 12. Disks can be double-sided, meaning that they can
|
||||||
store 1224kB per disk, which was almost unheard of back then. Because the way
|
store 1224kB per disk, which was almost unheard of back then. Because the way
|
||||||
that the tracks on head 1 are offset from head 0 (this happens with all disks),
|
that the tracks on head 1 are offset from head 0 (this happens with all disks),
|
||||||
the speed zone allocation on head 1 differ from head 0...
|
the speed zone allocation on head 1 differs from head 0...
|
||||||
|
|
||||||
| Zone | Head 0 tracks | Head 1 tracks | Sectors | Original period (ms) |
|
| Zone | Head 0 tracks | Head 1 tracks | Sectors | Original period (ms) |
|
||||||
|:----:|:-------------:|:-------------:|:-------:|:--------------------:|
|
|:----:|:-------------:|:-------------:|:-------:|:--------------------:|
|
||||||
@@ -40,18 +40,12 @@ Reading discs
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read <format>
|
fluxengine read victor9k <format>
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
...where `<format>` can be `victor9k_ss` or `victor9k_ds`.
|
...where `<format>` can be `--612` for a single-sided disk or `--1224` for a
|
||||||
|
double-sided disk.
|
||||||
For `victor9k_ss` you should end up with an `victor9k.img` which is 627200 bytes long.
|
|
||||||
For `victor9k_ds` you should end up with an `victor9k.img` which is 1224192 bytes long.
|
|
||||||
|
|
||||||
**Big warning!** The image is triangular, where each track occupies a different
|
|
||||||
amount of space. Victor disk images are complicated due to the way the tracks
|
|
||||||
are different sizes and the odd sector size.
|
|
||||||
|
|
||||||
Writing discs
|
Writing discs
|
||||||
-------------
|
-------------
|
||||||
@@ -59,11 +53,10 @@ Writing discs
|
|||||||
Just do:
|
Just do:
|
||||||
|
|
||||||
```
|
```
|
||||||
fluxengine read victor9k_ss -i victor9k.img
|
fluxengine write victor9k <format> -i victor9k.img
|
||||||
```
|
```
|
||||||
|
|
||||||
**Big warning!** This uses the same triangular disk image that reading uses.
|
`<format>` is as above.
|
||||||
|
|
||||||
|
|
||||||
Useful references
|
Useful references
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ LIBFLUXENGINE_SRCS = \
|
|||||||
lib/vfs/cbmfs.cc \
|
lib/vfs/cbmfs.cc \
|
||||||
lib/vfs/cpmfs.cc \
|
lib/vfs/cpmfs.cc \
|
||||||
lib/vfs/fatfs.cc \
|
lib/vfs/fatfs.cc \
|
||||||
|
lib/vfs/lif.cc \
|
||||||
lib/vfs/machfs.cc \
|
lib/vfs/machfs.cc \
|
||||||
lib/vfs/prodos.cc \
|
lib/vfs/prodos.cc \
|
||||||
lib/vfs/smaky6fs.cc \
|
lib/vfs/smaky6fs.cc \
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import "lib/drive.proto";
|
|||||||
import "lib/common.proto";
|
import "lib/common.proto";
|
||||||
import "lib/layout.proto";
|
import "lib/layout.proto";
|
||||||
|
|
||||||
// NEXT_TAG: 21
|
// NEXT_TAG: 23
|
||||||
message ConfigProto
|
message ConfigProto
|
||||||
{
|
{
|
||||||
optional string comment = 8;
|
optional string comment = 8;
|
||||||
@@ -39,18 +39,27 @@ message ConfigProto
|
|||||||
optional FilesystemProto filesystem = 17;
|
optional FilesystemProto filesystem = 17;
|
||||||
|
|
||||||
repeated OptionProto option = 20;
|
repeated OptionProto option = 20;
|
||||||
|
repeated OptionGroupProto option_group = 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEXT_TAG: 7
|
||||||
message OptionProto
|
message OptionProto
|
||||||
{
|
{
|
||||||
optional string name = 1 [ (help) = "option name" ];
|
optional string name = 1 [ (help) = "option name" ];
|
||||||
optional string comment = 2 [ (help) = "help text for option" ];
|
optional string comment = 2 [ (help) = "help text for option" ];
|
||||||
optional string message = 3
|
optional string message = 3
|
||||||
[ (help) = "message to display when option is in use" ];
|
[ (help) = "message to display when option is in use" ];
|
||||||
optional string exclusivity_group = 5 [
|
optional bool set_by_default = 6 [
|
||||||
(help) =
|
(help) = "this option is applied by default",
|
||||||
"options with the same group cannot be selected at the same time"
|
default = false
|
||||||
];
|
];
|
||||||
optional ConfigProto config = 4
|
optional ConfigProto config = 4
|
||||||
[ (help) = "option data", (recurse) = false ];
|
[ (help) = "option data", (recurse) = false ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message OptionGroupProto
|
||||||
|
{
|
||||||
|
optional string comment = 1 [ (help) = "help text for option group" ];
|
||||||
|
repeated OptionProto option = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
788
lib/flags.cc
788
lib/flags.cc
@@ -1,364 +1,424 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include <google/protobuf/text_format.h>
|
#include <google/protobuf/text_format.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
static FlagGroup* currentFlagGroup;
|
static FlagGroup* currentFlagGroup;
|
||||||
static std::vector<Flag*> all_flags;
|
static std::vector<Flag*> all_flags;
|
||||||
static std::map<const std::string, Flag*> flags_by_name;
|
static std::map<const std::string, Flag*> flags_by_name;
|
||||||
|
|
||||||
static void doHelp();
|
static void doHelp();
|
||||||
static void doShowConfig();
|
static void doShowConfig();
|
||||||
static void doDoc();
|
static void doDoc();
|
||||||
|
|
||||||
static FlagGroup helpGroup;
|
static FlagGroup helpGroup;
|
||||||
static ActionFlag helpFlag = ActionFlag({"--help"}, "Shows the help.", doHelp);
|
static ActionFlag helpFlag = ActionFlag({"--help"}, "Shows the help.", doHelp);
|
||||||
|
|
||||||
static ActionFlag showConfigFlag = ActionFlag({"--config", "-C"},
|
static ActionFlag showConfigFlag = ActionFlag({"--config", "-C"},
|
||||||
"Shows the currently set configuration and halts.",
|
"Shows the currently set configuration and halts.",
|
||||||
doShowConfig);
|
doShowConfig);
|
||||||
|
|
||||||
static ActionFlag docFlag = ActionFlag(
|
static ActionFlag docFlag = ActionFlag(
|
||||||
{"--doc"}, "Shows the available configuration options and halts.", doDoc);
|
{"--doc"}, "Shows the available configuration options and halts.", doDoc);
|
||||||
|
|
||||||
FlagGroup::FlagGroup()
|
FlagGroup::FlagGroup()
|
||||||
{
|
{
|
||||||
currentFlagGroup = this;
|
currentFlagGroup = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlagGroup::FlagGroup(std::initializer_list<FlagGroup*> groups): _groups(groups)
|
FlagGroup::FlagGroup(std::initializer_list<FlagGroup*> groups): _groups(groups)
|
||||||
{
|
{
|
||||||
currentFlagGroup = this;
|
currentFlagGroup = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlagGroup::addFlag(Flag* flag)
|
void FlagGroup::addFlag(Flag* flag)
|
||||||
{
|
{
|
||||||
_flags.push_back(flag);
|
_flags.push_back(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool setFallbackFlag(
|
void FlagGroup::applyOption(const OptionProto& option)
|
||||||
const std::string& key, const std::string& value, bool uses_that)
|
{
|
||||||
{
|
if (option.config().option_size() > 0)
|
||||||
if (beginsWith(key, "--"))
|
Error() << fmt::format(
|
||||||
{
|
"option '{}' has an option inside it, which isn't "
|
||||||
std::string path = key.substr(2);
|
"allowed",
|
||||||
if (key.find('.') != std::string::npos)
|
option.name());
|
||||||
{
|
if (option.config().option_group_size() > 0)
|
||||||
ProtoField protoField = resolveProtoPath(&config, path);
|
Error() << fmt::format(
|
||||||
setProtoFieldFromString(protoField, value);
|
"option '{}' has an option group inside it, which isn't "
|
||||||
return uses_that;
|
"allowed",
|
||||||
}
|
option.name());
|
||||||
else
|
if (option.config().include_size() > 0)
|
||||||
{
|
Error() << fmt::format(
|
||||||
if (FlagGroup::applyOption(path))
|
"option '{}' is trying to include something, which "
|
||||||
return false;
|
"isn't allowed",
|
||||||
}
|
option.name());
|
||||||
}
|
|
||||||
Error() << "unrecognised flag; try --help";
|
Logger() << fmt::format("OPTION: {}",
|
||||||
}
|
option.has_message() ? option.message() : option.comment());
|
||||||
|
|
||||||
bool FlagGroup::applyOption(const std::string& option)
|
config.MergeFrom(option.config());
|
||||||
{
|
}
|
||||||
for (const auto& configs : config.option())
|
|
||||||
{
|
bool FlagGroup::applyOption(const std::string& optionName)
|
||||||
if (option == configs.name())
|
{
|
||||||
{
|
auto searchOptionList = [&](auto& optionList)
|
||||||
if (configs.config().option_size() > 0)
|
{
|
||||||
Error() << fmt::format(
|
for (const auto& option : optionList)
|
||||||
"option '{}' has an option inside it, which isn't "
|
{
|
||||||
"allowed",
|
if (optionName == option.name())
|
||||||
option);
|
{
|
||||||
if (configs.config().include_size() > 0)
|
applyOption(option);
|
||||||
Error() << fmt::format(
|
return true;
|
||||||
"option '{}' is trying to include something, which "
|
}
|
||||||
"isn't allowed",
|
}
|
||||||
option);
|
return false;
|
||||||
|
};
|
||||||
Logger() << fmt::format("OPTION: {}", configs.message());
|
|
||||||
config.MergeFrom(configs.config());
|
if (searchOptionList(config.option()))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
for (const auto& optionGroup : config.option_group())
|
||||||
|
{
|
||||||
return false;
|
if (searchOptionList(optionGroup.option()))
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
std::vector<std::string> FlagGroup::parseFlagsWithFilenames(int argc,
|
|
||||||
const char* argv[],
|
return false;
|
||||||
std::function<bool(const std::string&)> callback)
|
}
|
||||||
{
|
|
||||||
if (_initialised)
|
std::vector<std::string> FlagGroup::parseFlagsWithFilenames(int argc,
|
||||||
throw std::runtime_error("called parseFlags() twice");
|
const char* argv[],
|
||||||
|
std::function<bool(const std::string&)> callback)
|
||||||
/* Recursively accumulate a list of all flags. */
|
{
|
||||||
|
if (_initialised)
|
||||||
all_flags.clear();
|
throw std::runtime_error("called parseFlags() twice");
|
||||||
flags_by_name.clear();
|
|
||||||
std::function<void(FlagGroup*)> recurse;
|
/* Recursively accumulate a list of all flags. */
|
||||||
recurse = [&](FlagGroup* group)
|
|
||||||
{
|
all_flags.clear();
|
||||||
if (group->_initialised)
|
flags_by_name.clear();
|
||||||
return;
|
std::function<void(FlagGroup*)> recurse;
|
||||||
|
recurse = [&](FlagGroup* group)
|
||||||
for (FlagGroup* subgroup : group->_groups)
|
{
|
||||||
recurse(subgroup);
|
if (group->_initialised)
|
||||||
|
return;
|
||||||
for (Flag* flag : group->_flags)
|
|
||||||
{
|
for (FlagGroup* subgroup : group->_groups)
|
||||||
for (const auto& name : flag->names())
|
recurse(subgroup);
|
||||||
{
|
|
||||||
if (flags_by_name.find(name) != flags_by_name.end())
|
for (Flag* flag : group->_flags)
|
||||||
Error() << "two flags use the name '" << name << "'";
|
{
|
||||||
flags_by_name[name] = flag;
|
for (const auto& name : flag->names())
|
||||||
}
|
{
|
||||||
|
if (flags_by_name.find(name) != flags_by_name.end())
|
||||||
all_flags.push_back(flag);
|
Error() << "two flags use the name '" << name << "'";
|
||||||
}
|
flags_by_name[name] = flag;
|
||||||
|
}
|
||||||
group->_initialised = true;
|
|
||||||
};
|
all_flags.push_back(flag);
|
||||||
recurse(this);
|
}
|
||||||
recurse(&helpGroup);
|
|
||||||
|
group->_initialised = true;
|
||||||
/* Now actually parse them. */
|
};
|
||||||
|
recurse(this);
|
||||||
std::vector<std::string> filenames;
|
recurse(&helpGroup);
|
||||||
int index = 1;
|
|
||||||
while (index < argc)
|
/* Now actually parse them. */
|
||||||
{
|
|
||||||
std::string thisarg = argv[index];
|
std::set<std::string> options;
|
||||||
std::string thatarg = (index < (argc - 1)) ? argv[index + 1] : "";
|
std::vector<std::pair<std::string, std::string>> overrides;
|
||||||
|
std::vector<std::string> filenames;
|
||||||
std::string key;
|
int index = 1;
|
||||||
std::string value;
|
while (index < argc)
|
||||||
bool usesthat = false;
|
{
|
||||||
|
std::string thisarg = argv[index];
|
||||||
if (thisarg.size() == 0)
|
std::string thatarg = (index < (argc - 1)) ? argv[index + 1] : "";
|
||||||
{
|
|
||||||
/* Ignore this argument. */
|
std::string key;
|
||||||
}
|
std::string value;
|
||||||
else if (thisarg[0] != '-')
|
bool usesthat = false;
|
||||||
{
|
|
||||||
/* This is a filename. Pass it to the callback, and if not consumed
|
if (thisarg.size() == 0)
|
||||||
* queue it. */
|
{
|
||||||
if (!callback(thisarg))
|
/* Ignore this argument. */
|
||||||
filenames.push_back(thisarg);
|
}
|
||||||
}
|
else if (thisarg[0] != '-')
|
||||||
else
|
{
|
||||||
{
|
/* This is a filename. Pass it to the callback, and if not consumed
|
||||||
/* This is a flag. */
|
* queue it. */
|
||||||
|
if (!callback(thisarg))
|
||||||
if ((thisarg.size() > 1) && (thisarg[1] == '-'))
|
filenames.push_back(thisarg);
|
||||||
{
|
}
|
||||||
/* Long option. */
|
else
|
||||||
|
{
|
||||||
auto equals = thisarg.rfind('=');
|
/* This is a flag. */
|
||||||
if (equals != std::string::npos)
|
|
||||||
{
|
if ((thisarg.size() > 1) && (thisarg[1] == '-'))
|
||||||
key = thisarg.substr(0, equals);
|
{
|
||||||
value = thisarg.substr(equals + 1);
|
/* Long option. */
|
||||||
}
|
|
||||||
else
|
auto equals = thisarg.rfind('=');
|
||||||
{
|
if (equals != std::string::npos)
|
||||||
key = thisarg;
|
{
|
||||||
value = thatarg;
|
key = thisarg.substr(0, equals);
|
||||||
usesthat = true;
|
value = thisarg.substr(equals + 1);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
key = thisarg;
|
||||||
/* Short option. */
|
value = thatarg;
|
||||||
|
usesthat = true;
|
||||||
if (thisarg.size() > 2)
|
}
|
||||||
{
|
}
|
||||||
key = thisarg.substr(0, 2);
|
else
|
||||||
value = thisarg.substr(2);
|
{
|
||||||
}
|
/* Short option. */
|
||||||
else
|
|
||||||
{
|
if (thisarg.size() > 2)
|
||||||
key = thisarg;
|
{
|
||||||
value = thatarg;
|
key = thisarg.substr(0, 2);
|
||||||
usesthat = true;
|
value = thisarg.substr(2);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
auto flag = flags_by_name.find(key);
|
key = thisarg;
|
||||||
if (flag == flags_by_name.end())
|
value = thatarg;
|
||||||
{
|
usesthat = true;
|
||||||
if (setFallbackFlag(key, value, usesthat))
|
}
|
||||||
index++;
|
}
|
||||||
}
|
|
||||||
else
|
auto flag = flags_by_name.find(key);
|
||||||
{
|
if (flag == flags_by_name.end())
|
||||||
flag->second->set(value);
|
{
|
||||||
if (usesthat && flag->second->hasArgument())
|
if (beginsWith(key, "--"))
|
||||||
index++;
|
{
|
||||||
}
|
std::string path = key.substr(2);
|
||||||
}
|
if (key.find('.') != std::string::npos)
|
||||||
|
{
|
||||||
index++;
|
overrides.push_back(std::make_pair(path, value));
|
||||||
}
|
index += usesthat;
|
||||||
|
}
|
||||||
return filenames;
|
else
|
||||||
}
|
options.insert(path);
|
||||||
|
}
|
||||||
void FlagGroup::parseFlags(int argc,
|
else
|
||||||
const char* argv[],
|
Error() << "unrecognised flag; try --help";
|
||||||
std::function<bool(const std::string&)> callback)
|
}
|
||||||
{
|
else
|
||||||
auto filenames = parseFlagsWithFilenames(argc, argv, callback);
|
{
|
||||||
if (!filenames.empty())
|
flag->second->set(value);
|
||||||
Error() << "non-option parameter " << *filenames.begin()
|
if (usesthat && flag->second->hasArgument())
|
||||||
<< " seen (try --help)";
|
index++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void FlagGroup::parseFlagsWithConfigFiles(int argc,
|
|
||||||
const char* argv[],
|
index++;
|
||||||
const std::map<std::string, std::string>& configFiles)
|
}
|
||||||
{
|
|
||||||
parseFlags(argc,
|
/* Apply any default options in groups. */
|
||||||
argv,
|
|
||||||
[&](const auto& filename)
|
for (auto& group : config.option_group())
|
||||||
{
|
{
|
||||||
parseConfigFile(filename, configFiles);
|
const OptionProto* defaultOption = &*group.option().begin();
|
||||||
return true;
|
bool isSet = false;
|
||||||
});
|
|
||||||
}
|
for (auto& option : group.option())
|
||||||
|
{
|
||||||
ConfigProto FlagGroup::parseSingleConfigFile(const std::string& filename,
|
if (options.find(option.name()) != options.end())
|
||||||
const std::map<std::string, std::string>& configFiles)
|
{
|
||||||
{
|
defaultOption = &option;
|
||||||
const auto& it = configFiles.find(filename);
|
options.erase(option.name());
|
||||||
if (it != configFiles.end())
|
}
|
||||||
{
|
}
|
||||||
ConfigProto config;
|
|
||||||
if (!config.ParseFromString(it->second))
|
FlagGroup::applyOption(*defaultOption);
|
||||||
Error() << "couldn't load built-in config proto";
|
}
|
||||||
return config;
|
|
||||||
}
|
/* Next, any standalone options. */
|
||||||
else
|
|
||||||
{
|
for (auto& option : config.option())
|
||||||
std::ifstream f(filename, std::ios::out);
|
{
|
||||||
if (f.fail())
|
if (options.find(option.name()) != options.end())
|
||||||
Error() << fmt::format(
|
{
|
||||||
"Cannot open '{}': {}", filename, strerror(errno));
|
FlagGroup::applyOption(option);
|
||||||
|
options.erase(option.name());
|
||||||
std::ostringstream ss;
|
}
|
||||||
ss << f.rdbuf();
|
}
|
||||||
|
|
||||||
ConfigProto config;
|
if (!options.empty())
|
||||||
if (!google::protobuf::TextFormat::MergeFromString(ss.str(), &config))
|
Error() << fmt::format(
|
||||||
Error() << "couldn't load external config proto";
|
"--{} is not a known flag or format option; try --help",
|
||||||
return config;
|
*options.begin());
|
||||||
}
|
|
||||||
}
|
/* Now apply any value overrides (in order). */
|
||||||
|
|
||||||
void FlagGroup::parseConfigFile(const std::string& filename,
|
for (auto [k, v] : overrides)
|
||||||
const std::map<std::string, std::string>& configFiles)
|
{
|
||||||
{
|
ProtoField protoField = resolveProtoPath(&config, k);
|
||||||
auto newConfig = parseSingleConfigFile(filename, configFiles);
|
setProtoFieldFromString(protoField, v);
|
||||||
|
}
|
||||||
/* The includes need to be merged _first_. */
|
|
||||||
|
return filenames;
|
||||||
for (const auto& include : newConfig.include())
|
}
|
||||||
{
|
|
||||||
auto included = parseSingleConfigFile(include, configFiles);
|
void FlagGroup::parseFlags(int argc,
|
||||||
if (included.include_size() != 0)
|
const char* argv[],
|
||||||
Error() << "only one level of config file includes are supported "
|
std::function<bool(const std::string&)> callback)
|
||||||
"(so far, if you need this, complain)";
|
{
|
||||||
|
auto filenames = parseFlagsWithFilenames(argc, argv, callback);
|
||||||
config.MergeFrom(included);
|
if (!filenames.empty())
|
||||||
}
|
Error() << "non-option parameter " << *filenames.begin()
|
||||||
|
<< " seen (try --help)";
|
||||||
config.MergeFrom(newConfig);
|
}
|
||||||
}
|
|
||||||
|
void FlagGroup::parseFlagsWithConfigFiles(int argc,
|
||||||
void FlagGroup::checkInitialised() const
|
const char* argv[],
|
||||||
{
|
const std::map<std::string, std::string>& configFiles)
|
||||||
if (!_initialised)
|
{
|
||||||
throw std::runtime_error("Attempt to access uninitialised flag");
|
parseFlags(argc,
|
||||||
}
|
argv,
|
||||||
|
[&](const auto& filename)
|
||||||
Flag::Flag(const std::vector<std::string>& names, const std::string helptext):
|
{
|
||||||
_group(*currentFlagGroup),
|
parseConfigFile(filename, configFiles);
|
||||||
_names(names),
|
return true;
|
||||||
_helptext(helptext)
|
});
|
||||||
{
|
}
|
||||||
if (!currentFlagGroup)
|
|
||||||
Error() << "no flag group defined for " << *names.begin();
|
ConfigProto FlagGroup::parseSingleConfigFile(const std::string& filename,
|
||||||
_group.addFlag(this);
|
const std::map<std::string, std::string>& configFiles)
|
||||||
}
|
{
|
||||||
|
const auto& it = configFiles.find(filename);
|
||||||
void BoolFlag::set(const std::string& value)
|
if (it != configFiles.end())
|
||||||
{
|
{
|
||||||
if ((value == "true") || (value == "y"))
|
ConfigProto config;
|
||||||
_value = true;
|
if (!config.ParseFromString(it->second))
|
||||||
else if ((value == "false") || (value == "n"))
|
Error() << "couldn't load built-in config proto";
|
||||||
_value = false;
|
return config;
|
||||||
else
|
}
|
||||||
Error() << "can't parse '" << value << "'; try 'true' or 'false'";
|
else
|
||||||
_callback(_value);
|
{
|
||||||
_isSet = true;
|
std::ifstream f(filename, std::ios::out);
|
||||||
}
|
if (f.fail())
|
||||||
|
Error() << fmt::format(
|
||||||
const std::string HexIntFlag::defaultValueAsString() const
|
"Cannot open '{}': {}", filename, strerror(errno));
|
||||||
{
|
|
||||||
return fmt::format("0x{:x}", _defaultValue);
|
std::ostringstream ss;
|
||||||
}
|
ss << f.rdbuf();
|
||||||
|
|
||||||
static void doHelp()
|
ConfigProto config;
|
||||||
{
|
if (!google::protobuf::TextFormat::MergeFromString(ss.str(), &config))
|
||||||
std::cout << "FluxEngine options:\n";
|
Error() << "couldn't load external config proto";
|
||||||
std::cout
|
return config;
|
||||||
<< "Note: options are processed left to right and order matters!\n";
|
}
|
||||||
for (auto flag : all_flags)
|
}
|
||||||
{
|
|
||||||
std::cout << " ";
|
void FlagGroup::parseConfigFile(const std::string& filename,
|
||||||
bool firstname = true;
|
const std::map<std::string, std::string>& configFiles)
|
||||||
for (auto name : flag->names())
|
{
|
||||||
{
|
auto newConfig = parseSingleConfigFile(filename, configFiles);
|
||||||
if (!firstname)
|
|
||||||
std::cout << ", ";
|
/* The includes need to be merged _first_. */
|
||||||
std::cout << name;
|
|
||||||
firstname = false;
|
for (const auto& include : newConfig.include())
|
||||||
}
|
{
|
||||||
|
auto included = parseSingleConfigFile(include, configFiles);
|
||||||
if (flag->hasArgument())
|
if (included.include_size() != 0)
|
||||||
std::cout << " <default: \"" << flag->defaultValueAsString()
|
Error() << "only one level of config file includes are supported "
|
||||||
<< "\">";
|
"(so far, if you need this, complain)";
|
||||||
std::cout << ": " << flag->helptext() << std::endl;
|
|
||||||
}
|
config.MergeFrom(included);
|
||||||
exit(0);
|
}
|
||||||
}
|
|
||||||
|
config.MergeFrom(newConfig);
|
||||||
static void doShowConfig()
|
}
|
||||||
{
|
|
||||||
std::string s;
|
void FlagGroup::checkInitialised() const
|
||||||
google::protobuf::TextFormat::PrintToString(config, &s);
|
{
|
||||||
std::cout << s << '\n';
|
if (!_initialised)
|
||||||
|
throw std::runtime_error("Attempt to access uninitialised flag");
|
||||||
exit(0);
|
}
|
||||||
}
|
|
||||||
|
Flag::Flag(const std::vector<std::string>& names, const std::string helptext):
|
||||||
static void doDoc()
|
_group(*currentFlagGroup),
|
||||||
{
|
_names(names),
|
||||||
const auto fields = findAllProtoFields(&config);
|
_helptext(helptext)
|
||||||
for (const auto field : fields)
|
{
|
||||||
{
|
if (!currentFlagGroup)
|
||||||
const std::string& path = field.first;
|
Error() << "no flag group defined for " << *names.begin();
|
||||||
const google::protobuf::FieldDescriptor* f = field.second;
|
_group.addFlag(this);
|
||||||
|
}
|
||||||
if (f->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
|
|
||||||
continue;
|
void BoolFlag::set(const std::string& value)
|
||||||
|
{
|
||||||
std::string helpText = f->options().GetExtension(help);
|
if ((value == "true") || (value == "y"))
|
||||||
std::cout << fmt::format("{}: {}\n", path, helpText);
|
_value = true;
|
||||||
}
|
else if ((value == "false") || (value == "n"))
|
||||||
|
_value = false;
|
||||||
exit(0);
|
else
|
||||||
}
|
Error() << "can't parse '" << value << "'; try 'true' or 'false'";
|
||||||
|
_callback(_value);
|
||||||
|
_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string HexIntFlag::defaultValueAsString() const
|
||||||
|
{
|
||||||
|
return fmt::format("0x{:x}", _defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doHelp()
|
||||||
|
{
|
||||||
|
std::cout << "FluxEngine options:\n";
|
||||||
|
std::cout
|
||||||
|
<< "Note: options are processed left to right and order matters!\n";
|
||||||
|
for (auto flag : all_flags)
|
||||||
|
{
|
||||||
|
std::cout << " ";
|
||||||
|
bool firstname = true;
|
||||||
|
for (auto name : flag->names())
|
||||||
|
{
|
||||||
|
if (!firstname)
|
||||||
|
std::cout << ", ";
|
||||||
|
std::cout << name;
|
||||||
|
firstname = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag->hasArgument())
|
||||||
|
std::cout << " <default: \"" << flag->defaultValueAsString()
|
||||||
|
<< "\">";
|
||||||
|
std::cout << ": " << flag->helptext() << std::endl;
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doShowConfig()
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
google::protobuf::TextFormat::PrintToString(config, &s);
|
||||||
|
std::cout << s << '\n';
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doDoc()
|
||||||
|
{
|
||||||
|
const auto fields = findAllProtoFields(&config);
|
||||||
|
for (const auto field : fields)
|
||||||
|
{
|
||||||
|
const std::string& path = field.first;
|
||||||
|
const google::protobuf::FieldDescriptor* f = field.second;
|
||||||
|
|
||||||
|
if (f->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string helpText = f->options().GetExtension(help);
|
||||||
|
std::cout << fmt::format("{}: {}\n", path, helpText);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|||||||
656
lib/flags.h
656
lib/flags.h
@@ -1,327 +1,329 @@
|
|||||||
#ifndef FLAGS_H
|
#ifndef FLAGS_H
|
||||||
#define FLAGS_H
|
#define FLAGS_H
|
||||||
|
|
||||||
class DataSpec;
|
class DataSpec;
|
||||||
class Flag;
|
class Flag;
|
||||||
class ConfigProto;
|
class ConfigProto;
|
||||||
|
class OptionProto;
|
||||||
class FlagGroup
|
|
||||||
{
|
class FlagGroup
|
||||||
public:
|
{
|
||||||
FlagGroup();
|
public:
|
||||||
FlagGroup(std::initializer_list<FlagGroup*> groups);
|
FlagGroup();
|
||||||
|
FlagGroup(std::initializer_list<FlagGroup*> groups);
|
||||||
public:
|
|
||||||
void parseFlags(
|
public:
|
||||||
int argc,
|
void parseFlags(
|
||||||
const char* argv[],
|
int argc,
|
||||||
std::function<bool(const std::string&)> callback =
|
const char* argv[],
|
||||||
[](const auto&)
|
std::function<bool(const std::string&)> callback =
|
||||||
{
|
[](const auto&)
|
||||||
return false;
|
{
|
||||||
});
|
return false;
|
||||||
std::vector<std::string> parseFlagsWithFilenames(
|
});
|
||||||
int argc,
|
std::vector<std::string> parseFlagsWithFilenames(
|
||||||
const char* argv[],
|
int argc,
|
||||||
std::function<bool(const std::string&)> callback =
|
const char* argv[],
|
||||||
[](const auto&)
|
std::function<bool(const std::string&)> callback =
|
||||||
{
|
[](const auto&)
|
||||||
return false;
|
{
|
||||||
});
|
return false;
|
||||||
void parseFlagsWithConfigFiles(int argc,
|
});
|
||||||
const char* argv[],
|
void parseFlagsWithConfigFiles(int argc,
|
||||||
const std::map<std::string, std::string>& configFiles);
|
const char* argv[],
|
||||||
|
const std::map<std::string, std::string>& configFiles);
|
||||||
/* Load one config file (or internal config file), without expanding
|
|
||||||
* includes. */
|
/* Load one config file (or internal config file), without expanding
|
||||||
|
* includes. */
|
||||||
static ConfigProto parseSingleConfigFile(const std::string& filename,
|
|
||||||
const std::map<std::string, std::string>& configFiles);
|
static ConfigProto parseSingleConfigFile(const std::string& filename,
|
||||||
|
const std::map<std::string, std::string>& configFiles);
|
||||||
/* Load a top-level config file (or internal config file), expanding
|
|
||||||
* includes. */
|
/* Load a top-level config file (or internal config file), expanding
|
||||||
|
* includes. */
|
||||||
static void parseConfigFile(const std::string& filename,
|
|
||||||
const std::map<std::string, std::string>& configFiles);
|
static void parseConfigFile(const std::string& filename,
|
||||||
|
const std::map<std::string, std::string>& configFiles);
|
||||||
/* Modify the current config to engage the named option. */
|
|
||||||
|
/* Modify the current config to engage the named option. */
|
||||||
static bool applyOption(const std::string& option);
|
|
||||||
|
static void applyOption(const OptionProto& option);
|
||||||
void addFlag(Flag* flag);
|
static bool applyOption(const std::string& option);
|
||||||
void checkInitialised() const;
|
|
||||||
|
void addFlag(Flag* flag);
|
||||||
private:
|
void checkInitialised() const;
|
||||||
bool _initialised = false;
|
|
||||||
const std::vector<FlagGroup*> _groups;
|
private:
|
||||||
std::vector<Flag*> _flags;
|
bool _initialised = false;
|
||||||
};
|
const std::vector<FlagGroup*> _groups;
|
||||||
|
std::vector<Flag*> _flags;
|
||||||
class Flag
|
};
|
||||||
{
|
|
||||||
public:
|
class Flag
|
||||||
Flag(const std::vector<std::string>& names, const std::string helptext);
|
{
|
||||||
virtual ~Flag(){};
|
public:
|
||||||
|
Flag(const std::vector<std::string>& names, const std::string helptext);
|
||||||
void checkInitialised() const
|
virtual ~Flag(){};
|
||||||
{
|
|
||||||
_group.checkInitialised();
|
void checkInitialised() const
|
||||||
}
|
{
|
||||||
|
_group.checkInitialised();
|
||||||
const std::string& name() const
|
}
|
||||||
{
|
|
||||||
return _names[0];
|
const std::string& name() const
|
||||||
}
|
{
|
||||||
const std::vector<std::string> names() const
|
return _names[0];
|
||||||
{
|
}
|
||||||
return _names;
|
const std::vector<std::string> names() const
|
||||||
}
|
{
|
||||||
const std::string& helptext() const
|
return _names;
|
||||||
{
|
}
|
||||||
return _helptext;
|
const std::string& helptext() const
|
||||||
}
|
{
|
||||||
|
return _helptext;
|
||||||
virtual bool hasArgument() const = 0;
|
}
|
||||||
virtual const std::string defaultValueAsString() const = 0;
|
|
||||||
virtual void set(const std::string& value) = 0;
|
virtual bool hasArgument() const = 0;
|
||||||
|
virtual const std::string defaultValueAsString() const = 0;
|
||||||
private:
|
virtual void set(const std::string& value) = 0;
|
||||||
FlagGroup& _group;
|
|
||||||
const std::vector<std::string> _names;
|
private:
|
||||||
const std::string _helptext;
|
FlagGroup& _group;
|
||||||
};
|
const std::vector<std::string> _names;
|
||||||
|
const std::string _helptext;
|
||||||
class ActionFlag : Flag
|
};
|
||||||
{
|
|
||||||
public:
|
class ActionFlag : Flag
|
||||||
ActionFlag(const std::vector<std::string>& names,
|
{
|
||||||
const std::string helptext,
|
public:
|
||||||
std::function<void(void)> callback):
|
ActionFlag(const std::vector<std::string>& names,
|
||||||
Flag(names, helptext),
|
const std::string helptext,
|
||||||
_callback(callback)
|
std::function<void(void)> callback):
|
||||||
{
|
Flag(names, helptext),
|
||||||
}
|
_callback(callback)
|
||||||
|
{
|
||||||
bool hasArgument() const
|
}
|
||||||
{
|
|
||||||
return false;
|
bool hasArgument() const
|
||||||
}
|
{
|
||||||
const std::string defaultValueAsString() const
|
return false;
|
||||||
{
|
}
|
||||||
return "";
|
const std::string defaultValueAsString() const
|
||||||
}
|
{
|
||||||
void set(const std::string& value)
|
return "";
|
||||||
{
|
}
|
||||||
_callback();
|
void set(const std::string& value)
|
||||||
}
|
{
|
||||||
|
_callback();
|
||||||
private:
|
}
|
||||||
const std::function<void(void)> _callback;
|
|
||||||
};
|
private:
|
||||||
|
const std::function<void(void)> _callback;
|
||||||
class SettableFlag : public Flag
|
};
|
||||||
{
|
|
||||||
public:
|
class SettableFlag : public Flag
|
||||||
SettableFlag(
|
{
|
||||||
const std::vector<std::string>& names, const std::string helptext):
|
public:
|
||||||
Flag(names, helptext)
|
SettableFlag(
|
||||||
{
|
const std::vector<std::string>& names, const std::string helptext):
|
||||||
}
|
Flag(names, helptext)
|
||||||
|
{
|
||||||
operator bool() const
|
}
|
||||||
{
|
|
||||||
checkInitialised();
|
operator bool() const
|
||||||
return _value;
|
{
|
||||||
}
|
checkInitialised();
|
||||||
|
return _value;
|
||||||
bool hasArgument() const
|
}
|
||||||
{
|
|
||||||
return false;
|
bool hasArgument() const
|
||||||
}
|
{
|
||||||
const std::string defaultValueAsString() const
|
return false;
|
||||||
{
|
}
|
||||||
return "false";
|
const std::string defaultValueAsString() const
|
||||||
}
|
{
|
||||||
void set(const std::string& value)
|
return "false";
|
||||||
{
|
}
|
||||||
_value = true;
|
void set(const std::string& value)
|
||||||
}
|
{
|
||||||
|
_value = true;
|
||||||
private:
|
}
|
||||||
bool _value = false;
|
|
||||||
};
|
private:
|
||||||
|
bool _value = false;
|
||||||
template <typename T>
|
};
|
||||||
class ValueFlag : public Flag
|
|
||||||
{
|
template <typename T>
|
||||||
public:
|
class ValueFlag : public Flag
|
||||||
ValueFlag(
|
{
|
||||||
const std::vector<std::string>& names,
|
public:
|
||||||
const std::string helptext,
|
ValueFlag(
|
||||||
const T defaultValue,
|
const std::vector<std::string>& names,
|
||||||
std::function<void(const T&)> callback =
|
const std::string helptext,
|
||||||
[](const T&)
|
const T defaultValue,
|
||||||
{
|
std::function<void(const T&)> callback =
|
||||||
}):
|
[](const T&)
|
||||||
Flag(names, helptext),
|
{
|
||||||
_defaultValue(defaultValue),
|
}):
|
||||||
_value(defaultValue),
|
Flag(names, helptext),
|
||||||
_callback(callback)
|
_defaultValue(defaultValue),
|
||||||
{
|
_value(defaultValue),
|
||||||
}
|
_callback(callback)
|
||||||
|
{
|
||||||
const T& get() const
|
}
|
||||||
{
|
|
||||||
checkInitialised();
|
const T& get() const
|
||||||
return _value;
|
{
|
||||||
}
|
checkInitialised();
|
||||||
|
return _value;
|
||||||
operator const T&() const
|
}
|
||||||
{
|
|
||||||
return get();
|
operator const T&() const
|
||||||
}
|
{
|
||||||
|
return get();
|
||||||
bool isSet() const
|
}
|
||||||
{
|
|
||||||
return _isSet;
|
bool isSet() const
|
||||||
}
|
{
|
||||||
|
return _isSet;
|
||||||
void setDefaultValue(T value)
|
}
|
||||||
{
|
|
||||||
_value = _defaultValue = value;
|
void setDefaultValue(T value)
|
||||||
}
|
{
|
||||||
|
_value = _defaultValue = value;
|
||||||
bool hasArgument() const
|
}
|
||||||
{
|
|
||||||
return true;
|
bool hasArgument() const
|
||||||
}
|
{
|
||||||
|
return true;
|
||||||
protected:
|
}
|
||||||
T _defaultValue;
|
|
||||||
T _value;
|
protected:
|
||||||
bool _isSet = false;
|
T _defaultValue;
|
||||||
std::function<void(const T&)> _callback;
|
T _value;
|
||||||
};
|
bool _isSet = false;
|
||||||
|
std::function<void(const T&)> _callback;
|
||||||
class StringFlag : public ValueFlag<std::string>
|
};
|
||||||
{
|
|
||||||
public:
|
class StringFlag : public ValueFlag<std::string>
|
||||||
StringFlag(
|
{
|
||||||
const std::vector<std::string>& names,
|
public:
|
||||||
const std::string helptext,
|
StringFlag(
|
||||||
const std::string defaultValue = "",
|
const std::vector<std::string>& names,
|
||||||
std::function<void(const std::string&)> callback =
|
const std::string helptext,
|
||||||
[](const std::string&)
|
const std::string defaultValue = "",
|
||||||
{
|
std::function<void(const std::string&)> callback =
|
||||||
}):
|
[](const std::string&)
|
||||||
ValueFlag(names, helptext, defaultValue, callback)
|
{
|
||||||
{
|
}):
|
||||||
}
|
ValueFlag(names, helptext, defaultValue, callback)
|
||||||
|
{
|
||||||
const std::string defaultValueAsString() const
|
}
|
||||||
{
|
|
||||||
return _defaultValue;
|
const std::string defaultValueAsString() const
|
||||||
}
|
{
|
||||||
void set(const std::string& value)
|
return _defaultValue;
|
||||||
{
|
}
|
||||||
_value = value;
|
void set(const std::string& value)
|
||||||
_callback(_value);
|
{
|
||||||
_isSet = true;
|
_value = value;
|
||||||
}
|
_callback(_value);
|
||||||
};
|
_isSet = true;
|
||||||
|
}
|
||||||
class IntFlag : public ValueFlag<int>
|
};
|
||||||
{
|
|
||||||
public:
|
class IntFlag : public ValueFlag<int>
|
||||||
IntFlag(
|
{
|
||||||
const std::vector<std::string>& names,
|
public:
|
||||||
const std::string helptext,
|
IntFlag(
|
||||||
int defaultValue = 0,
|
const std::vector<std::string>& names,
|
||||||
std::function<void(const int&)> callback =
|
const std::string helptext,
|
||||||
[](const int&)
|
int defaultValue = 0,
|
||||||
{
|
std::function<void(const int&)> callback =
|
||||||
}):
|
[](const int&)
|
||||||
ValueFlag(names, helptext, defaultValue, callback)
|
{
|
||||||
{
|
}):
|
||||||
}
|
ValueFlag(names, helptext, defaultValue, callback)
|
||||||
|
{
|
||||||
const std::string defaultValueAsString() const
|
}
|
||||||
{
|
|
||||||
return std::to_string(_defaultValue);
|
const std::string defaultValueAsString() const
|
||||||
}
|
{
|
||||||
void set(const std::string& value)
|
return std::to_string(_defaultValue);
|
||||||
{
|
}
|
||||||
_value = std::stoi(value);
|
void set(const std::string& value)
|
||||||
_callback(_value);
|
{
|
||||||
_isSet = true;
|
_value = std::stoi(value);
|
||||||
}
|
_callback(_value);
|
||||||
};
|
_isSet = true;
|
||||||
|
}
|
||||||
class HexIntFlag : public IntFlag
|
};
|
||||||
{
|
|
||||||
public:
|
class HexIntFlag : public IntFlag
|
||||||
HexIntFlag(
|
{
|
||||||
const std::vector<std::string>& names,
|
public:
|
||||||
const std::string helptext,
|
HexIntFlag(
|
||||||
int defaultValue = 0,
|
const std::vector<std::string>& names,
|
||||||
std::function<void(const int&)> callback =
|
const std::string helptext,
|
||||||
[](const int&)
|
int defaultValue = 0,
|
||||||
{
|
std::function<void(const int&)> callback =
|
||||||
}):
|
[](const int&)
|
||||||
IntFlag(names, helptext, defaultValue, callback)
|
{
|
||||||
{
|
}):
|
||||||
}
|
IntFlag(names, helptext, defaultValue, callback)
|
||||||
|
{
|
||||||
const std::string defaultValueAsString() const;
|
}
|
||||||
};
|
|
||||||
|
const std::string defaultValueAsString() const;
|
||||||
class DoubleFlag : public ValueFlag<double>
|
};
|
||||||
{
|
|
||||||
public:
|
class DoubleFlag : public ValueFlag<double>
|
||||||
DoubleFlag(
|
{
|
||||||
const std::vector<std::string>& names,
|
public:
|
||||||
const std::string helptext,
|
DoubleFlag(
|
||||||
double defaultValue = 1.0,
|
const std::vector<std::string>& names,
|
||||||
std::function<void(const double&)> callback =
|
const std::string helptext,
|
||||||
[](const double&)
|
double defaultValue = 1.0,
|
||||||
{
|
std::function<void(const double&)> callback =
|
||||||
}):
|
[](const double&)
|
||||||
ValueFlag(names, helptext, defaultValue, callback)
|
{
|
||||||
{
|
}):
|
||||||
}
|
ValueFlag(names, helptext, defaultValue, callback)
|
||||||
|
{
|
||||||
const std::string defaultValueAsString() const
|
}
|
||||||
{
|
|
||||||
return std::to_string(_defaultValue);
|
const std::string defaultValueAsString() const
|
||||||
}
|
{
|
||||||
void set(const std::string& value)
|
return std::to_string(_defaultValue);
|
||||||
{
|
}
|
||||||
_value = std::stod(value);
|
void set(const std::string& value)
|
||||||
_callback(_value);
|
{
|
||||||
_isSet = true;
|
_value = std::stod(value);
|
||||||
}
|
_callback(_value);
|
||||||
};
|
_isSet = true;
|
||||||
|
}
|
||||||
class BoolFlag : public ValueFlag<bool>
|
};
|
||||||
{
|
|
||||||
public:
|
class BoolFlag : public ValueFlag<bool>
|
||||||
BoolFlag(
|
{
|
||||||
const std::vector<std::string>& names,
|
public:
|
||||||
const std::string helptext,
|
BoolFlag(
|
||||||
bool defaultValue = false,
|
const std::vector<std::string>& names,
|
||||||
std::function<void(const bool&)> callback =
|
const std::string helptext,
|
||||||
[](const bool&)
|
bool defaultValue = false,
|
||||||
{
|
std::function<void(const bool&)> callback =
|
||||||
}):
|
[](const bool&)
|
||||||
ValueFlag(names, helptext, defaultValue, callback)
|
{
|
||||||
{
|
}):
|
||||||
}
|
ValueFlag(names, helptext, defaultValue, callback)
|
||||||
|
{
|
||||||
const std::string defaultValueAsString() const
|
}
|
||||||
{
|
|
||||||
return _defaultValue ? "true" : "false";
|
const std::string defaultValueAsString() const
|
||||||
}
|
{
|
||||||
void set(const std::string& value);
|
return _defaultValue ? "true" : "false";
|
||||||
};
|
}
|
||||||
|
void set(const std::string& value);
|
||||||
#endif
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
200
lib/vfs/lif.cc
Normal file
200
lib/vfs/lif.cc
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#include "lib/globals.h"
|
||||||
|
#include "lib/vfs/vfs.h"
|
||||||
|
#include "lib/config.pb.h"
|
||||||
|
#include "lib/utils.h"
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
/* See https://www.hp9845.net/9845/projects/hpdir/#lif_filesystem for
|
||||||
|
* a description. */
|
||||||
|
|
||||||
|
static void trimZeros(std::string s)
|
||||||
|
{
|
||||||
|
s.erase(std::remove(s.begin(), s.end(), 0), s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
class LifFilesystem : public Filesystem
|
||||||
|
{
|
||||||
|
class LifDirent : public Dirent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LifDirent(const LifProto& config, Bytes& bytes)
|
||||||
|
{
|
||||||
|
file_type = TYPE_FILE;
|
||||||
|
|
||||||
|
ByteReader br(bytes);
|
||||||
|
filename = trimWhitespace(br.read(10));
|
||||||
|
uint16_t type = br.read_be16();
|
||||||
|
location = br.read_be32();
|
||||||
|
length = br.read_be32() * config.block_size();
|
||||||
|
|
||||||
|
mode = fmt::format("{:04x}", type);
|
||||||
|
path = {filename};
|
||||||
|
|
||||||
|
attributes[Filesystem::FILENAME] = filename;
|
||||||
|
attributes[Filesystem::LENGTH] = std::to_string(length);
|
||||||
|
attributes[Filesystem::FILE_TYPE] = "file";
|
||||||
|
attributes[Filesystem::MODE] = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t location;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
LifFilesystem(
|
||||||
|
const LifProto& config, std::shared_ptr<SectorInterface> sectors):
|
||||||
|
Filesystem(sectors),
|
||||||
|
_config(config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t capabilities() const
|
||||||
|
{
|
||||||
|
return OP_GETFSDATA | OP_LIST | OP_GETFILE | OP_GETDIRENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilesystemStatus check() override
|
||||||
|
{
|
||||||
|
return FS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> getMetadata() override
|
||||||
|
{
|
||||||
|
mount();
|
||||||
|
|
||||||
|
std::map<std::string, std::string> attributes;
|
||||||
|
|
||||||
|
attributes[VOLUME_NAME] = _volumeLabel;
|
||||||
|
attributes[TOTAL_BLOCKS] = std::to_string(_totalBlocks);
|
||||||
|
attributes[USED_BLOCKS] = std::to_string(_usedBlocks);
|
||||||
|
attributes[BLOCK_SIZE] = std::to_string(_config.block_size());
|
||||||
|
attributes["lif.directory_block"] = std::to_string(_directoryBlock);
|
||||||
|
attributes["lif.directory_size"] = std::to_string(_directorySize);
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Dirent> getDirent(const Path& path) override
|
||||||
|
{
|
||||||
|
mount();
|
||||||
|
if (path.size() != 1)
|
||||||
|
throw BadPathException();
|
||||||
|
|
||||||
|
return findFile(path.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Dirent>> list(const Path& path) override
|
||||||
|
{
|
||||||
|
mount();
|
||||||
|
if (!path.empty())
|
||||||
|
throw FileNotFoundException();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Dirent>> result;
|
||||||
|
for (auto& de : _dirents)
|
||||||
|
result.push_back(de);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bytes getFile(const Path& path) override
|
||||||
|
{
|
||||||
|
mount();
|
||||||
|
if (path.size() != 1)
|
||||||
|
throw BadPathException();
|
||||||
|
|
||||||
|
auto dirent = findFile(path.front());
|
||||||
|
|
||||||
|
return getLifBlock(
|
||||||
|
dirent->location, dirent->length / _config.block_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void mount()
|
||||||
|
{
|
||||||
|
_sectorSize = getLogicalSectorSize();
|
||||||
|
_sectorsPerBlock = _sectorSize / _config.block_size();
|
||||||
|
|
||||||
|
_rootBlock = getLifBlock(0);
|
||||||
|
|
||||||
|
ByteReader rbr(_rootBlock);
|
||||||
|
if (rbr.read_be16() != 0x8000)
|
||||||
|
throw BadFilesystemException();
|
||||||
|
_volumeLabel = trimWhitespace(rbr.read(6));
|
||||||
|
_directoryBlock = rbr.read_be32();
|
||||||
|
rbr.skip(4);
|
||||||
|
_directorySize = rbr.read_be32();
|
||||||
|
unsigned tracks = rbr.read_be32();
|
||||||
|
unsigned heads = rbr.read_be32();
|
||||||
|
unsigned sectors = rbr.read_be32();
|
||||||
|
_usedBlocks = 1 + _directorySize;
|
||||||
|
|
||||||
|
Bytes directory = getLifBlock(_directoryBlock, _directorySize);
|
||||||
|
|
||||||
|
_dirents.clear();
|
||||||
|
ByteReader br(directory);
|
||||||
|
while (!br.eof())
|
||||||
|
{
|
||||||
|
Bytes direntBytes = br.read(32);
|
||||||
|
if (direntBytes[0] != 0xff)
|
||||||
|
{
|
||||||
|
auto dirent = std::make_unique<LifDirent>(_config, direntBytes);
|
||||||
|
_usedBlocks += dirent->length / _config.block_size();
|
||||||
|
_dirents.push_back(std::move(dirent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_totalBlocks = std::max(tracks * heads * sectors, _usedBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<LifDirent> findFile(const std::string filename)
|
||||||
|
{
|
||||||
|
for (const auto& dirent : _dirents)
|
||||||
|
{
|
||||||
|
if (dirent->filename == filename)
|
||||||
|
return dirent;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FileNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bytes getLifBlock(uint32_t number, uint32_t count)
|
||||||
|
{
|
||||||
|
Bytes b;
|
||||||
|
ByteWriter bw(b);
|
||||||
|
|
||||||
|
while (count)
|
||||||
|
{
|
||||||
|
bw += getLifBlock(number);
|
||||||
|
number++;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bytes getLifBlock(uint32_t number)
|
||||||
|
{
|
||||||
|
/* LIF uses 256-byte blocks, but the underlying format can have much
|
||||||
|
* bigger sectors. */
|
||||||
|
|
||||||
|
Bytes sector = getLogicalSector(number / _sectorsPerBlock);
|
||||||
|
unsigned offset = number % _sectorsPerBlock;
|
||||||
|
return sector.slice(
|
||||||
|
offset * _config.block_size(), _config.block_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const LifProto& _config;
|
||||||
|
int _sectorSize;
|
||||||
|
int _sectorsPerBlock;
|
||||||
|
Bytes _rootBlock;
|
||||||
|
std::string _volumeLabel;
|
||||||
|
unsigned _directoryBlock;
|
||||||
|
unsigned _directorySize;
|
||||||
|
unsigned _totalBlocks;
|
||||||
|
unsigned _usedBlocks;
|
||||||
|
std::vector<std::shared_ptr<LifDirent>> _dirents;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Filesystem> Filesystem::createLifFilesystem(
|
||||||
|
const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors)
|
||||||
|
{
|
||||||
|
return std::make_unique<LifFilesystem>(config.lif(), sectors);
|
||||||
|
}
|
||||||
@@ -233,8 +233,8 @@ private:
|
|||||||
_rootBlock = getPsosBlock(2, 1);
|
_rootBlock = getPsosBlock(2, 1);
|
||||||
_bitmapBlockNumber = _rootBlock.reader().seek(0x1c).read_be16();
|
_bitmapBlockNumber = _rootBlock.reader().seek(0x1c).read_be16();
|
||||||
_filedesBlockNumber = _rootBlock.reader().seek(0x1e).read_be16();
|
_filedesBlockNumber = _rootBlock.reader().seek(0x1e).read_be16();
|
||||||
_filedesLength =
|
_filedesLength = _rootBlock.reader().seek(0x20).read_be16() -
|
||||||
_rootBlock.reader().seek(0x20).read_be16() - _filedesBlockNumber + 1;
|
_filedesBlockNumber + 1;
|
||||||
_totalBlocks = _rootBlock.reader().seek(0x18).read_be16();
|
_totalBlocks = _rootBlock.reader().seek(0x18).read_be16();
|
||||||
|
|
||||||
Bytes directoryBlock = getPsosBlock(3, 1);
|
Bytes directoryBlock = getPsosBlock(3, 1);
|
||||||
|
|||||||
@@ -212,6 +212,9 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystem(
|
|||||||
case FilesystemProto::PHILE:
|
case FilesystemProto::PHILE:
|
||||||
return Filesystem::createPhileFilesystem(config, image);
|
return Filesystem::createPhileFilesystem(config, image);
|
||||||
|
|
||||||
|
case FilesystemProto::LIF:
|
||||||
|
return Filesystem::createLifFilesystem(config, image);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Error() << "no filesystem configured";
|
Error() << "no filesystem configured";
|
||||||
return std::unique_ptr<Filesystem>();
|
return std::unique_ptr<Filesystem>();
|
||||||
|
|||||||
@@ -254,6 +254,8 @@ public:
|
|||||||
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
||||||
static std::unique_ptr<Filesystem> createPhileFilesystem(
|
static std::unique_ptr<Filesystem> createPhileFilesystem(
|
||||||
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
||||||
|
static std::unique_ptr<Filesystem> createLifFilesystem(
|
||||||
|
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
||||||
|
|
||||||
static std::unique_ptr<Filesystem> createFilesystem(
|
static std::unique_ptr<Filesystem> createFilesystem(
|
||||||
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
|
||||||
|
|||||||
@@ -59,26 +59,33 @@ message CbmfsProto
|
|||||||
|
|
||||||
message ProdosProto {}
|
message ProdosProto {}
|
||||||
|
|
||||||
message AppledosProto {
|
message AppledosProto
|
||||||
optional uint32 filesystem_offset_sectors = 1 [
|
{
|
||||||
default = 0,
|
optional uint32 filesystem_offset_sectors = 1 [
|
||||||
(help) = "offset the entire offset up the disk this many sectors"
|
default = 0,
|
||||||
];
|
(help) = "offset the entire offset up the disk this many sectors"
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
message Smaky6FsProto {}
|
message Smaky6FsProto {}
|
||||||
|
|
||||||
message PhileProto {
|
message PhileProto
|
||||||
optional uint32 block_size = 1 [
|
{
|
||||||
default = 1024,
|
optional uint32 block_size = 1
|
||||||
(help) = "Phile filesystem block size"
|
[ default = 1024, (help) = "Phile filesystem block size" ];
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEXT_TAG: 14
|
message LifProto
|
||||||
|
{
|
||||||
|
optional uint32 block_size = 1
|
||||||
|
[ default = 256, (help) = "LIF filesystem block size" ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// NEXT_TAG: 15
|
||||||
message FilesystemProto
|
message FilesystemProto
|
||||||
{
|
{
|
||||||
enum FilesystemType {
|
enum FilesystemType
|
||||||
|
{
|
||||||
NOT_SET = 0;
|
NOT_SET = 0;
|
||||||
ACORNDFS = 1;
|
ACORNDFS = 1;
|
||||||
BROTHER120 = 2;
|
BROTHER120 = 2;
|
||||||
@@ -88,12 +95,14 @@ message FilesystemProto
|
|||||||
MACHFS = 6;
|
MACHFS = 6;
|
||||||
CBMFS = 7;
|
CBMFS = 7;
|
||||||
PRODOS = 8;
|
PRODOS = 8;
|
||||||
SMAKY6 = 9;
|
SMAKY6 = 9;
|
||||||
APPLEDOS = 10;
|
APPLEDOS = 10;
|
||||||
PHILE = 11;
|
PHILE = 11;
|
||||||
|
LIF = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional FilesystemType type = 10 [default = NOT_SET, (help) = "filesystem type"];
|
optional FilesystemType type = 10
|
||||||
|
[ default = NOT_SET, (help) = "filesystem type" ];
|
||||||
|
|
||||||
optional AcornDfsProto acorndfs = 1;
|
optional AcornDfsProto acorndfs = 1;
|
||||||
optional Brother120FsProto brother120 = 2;
|
optional Brother120FsProto brother120 = 2;
|
||||||
@@ -103,9 +112,11 @@ message FilesystemProto
|
|||||||
optional MacHfsProto machfs = 6;
|
optional MacHfsProto machfs = 6;
|
||||||
optional CbmfsProto cbmfs = 7;
|
optional CbmfsProto cbmfs = 7;
|
||||||
optional ProdosProto prodos = 8;
|
optional ProdosProto prodos = 8;
|
||||||
optional AppledosProto appledos = 12;
|
optional AppledosProto appledos = 12;
|
||||||
optional Smaky6FsProto smaky6 = 11;
|
optional Smaky6FsProto smaky6 = 11;
|
||||||
optional PhileProto phile = 13;
|
optional PhileProto phile = 13;
|
||||||
|
optional LifProto lif = 14;
|
||||||
optional SectorListProto sector_order = 9 [(help) = "specify the filesystem order of sectors"];
|
|
||||||
|
optional SectorListProto sector_order = 9
|
||||||
|
[ (help) = "specify the filesystem order of sectors" ];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
comment: 'Acorn ADFS generic settings (32-bit formats)'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "acornadfs.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 1024
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
ignore_side_byte: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Acorn ADFS generic settings (8-bit formats)'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "acornadfs.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
ignore_side_byte: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
comment: 'Apple II generic settings'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: false
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
apple2 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
apple2 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
option {
|
|
||||||
name: "nofs"
|
|
||||||
comment: "use physical CHS sector order and no file system"
|
|
||||||
exclusivity_group: "format"
|
|
||||||
}
|
|
||||||
|
|
||||||
option {
|
|
||||||
name: "appledos"
|
|
||||||
comment: "use AppleDOS soft sector skew and file system"
|
|
||||||
message: "compensating for AppleDOS soft sector skew"
|
|
||||||
exclusivity_group: "format"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image_reader {
|
|
||||||
filesystem_sector_order: true
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filesystem_sector_order: true
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: APPLEDOS
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
filesystem {
|
|
||||||
sector: 0
|
|
||||||
sector: 13
|
|
||||||
sector: 11
|
|
||||||
sector: 9
|
|
||||||
sector: 7
|
|
||||||
sector: 5
|
|
||||||
sector: 3
|
|
||||||
sector: 1
|
|
||||||
sector: 14
|
|
||||||
sector: 12
|
|
||||||
sector: 10
|
|
||||||
sector: 8
|
|
||||||
sector: 6
|
|
||||||
sector: 4
|
|
||||||
sector: 2
|
|
||||||
sector: 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
option {
|
|
||||||
name: "prodos"
|
|
||||||
comment: "use ProDOS soft sector skew and filesystem"
|
|
||||||
message: "compensating for ProDOS soft sector skew"
|
|
||||||
exclusivity_group: "format"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image_reader {
|
|
||||||
filesystem_sector_order: true
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filesystem_sector_order: true
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: PRODOS
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
filesystem {
|
|
||||||
sector: 0
|
|
||||||
sector: 2
|
|
||||||
sector: 4
|
|
||||||
sector: 6
|
|
||||||
sector: 8
|
|
||||||
sector: 10
|
|
||||||
sector: 12
|
|
||||||
sector: 14
|
|
||||||
sector: 1
|
|
||||||
sector: 3
|
|
||||||
sector: 5
|
|
||||||
sector: 7
|
|
||||||
sector: 9
|
|
||||||
sector: 11
|
|
||||||
sector: 13
|
|
||||||
sector: 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
option {
|
|
||||||
name: "cpm"
|
|
||||||
comment: "use CP/M soft sector skew and filesystem"
|
|
||||||
message: "compensating for CP/M soft sector skew"
|
|
||||||
exclusivity_group: "format"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image_reader {
|
|
||||||
filesystem_sector_order: true
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filesystem_sector_order: true
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: CPMFS
|
|
||||||
cpmfs {
|
|
||||||
filesystem_start {
|
|
||||||
track: 3
|
|
||||||
}
|
|
||||||
block_size: 4096
|
|
||||||
dir_entries: 128
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
apple2 {
|
|
||||||
side_one_track_offset: 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
apple2 {
|
|
||||||
side_one_track_offset: 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
# The boot tracks use ProDOS translation.
|
|
||||||
|
|
||||||
track: 0
|
|
||||||
up_to_track: 2
|
|
||||||
filesystem {
|
|
||||||
sector: 0
|
|
||||||
sector: 2
|
|
||||||
sector: 4
|
|
||||||
sector: 6
|
|
||||||
sector: 8
|
|
||||||
sector: 10
|
|
||||||
sector: 12
|
|
||||||
sector: 14
|
|
||||||
sector: 1
|
|
||||||
sector: 3
|
|
||||||
sector: 5
|
|
||||||
sector: 7
|
|
||||||
sector: 9
|
|
||||||
sector: 11
|
|
||||||
sector: 13
|
|
||||||
sector: 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutdata {
|
|
||||||
# The data tracks use their own, special translation.
|
|
||||||
|
|
||||||
track: 3
|
|
||||||
up_to_track: 79
|
|
||||||
filesystem {
|
|
||||||
sector: 0
|
|
||||||
sector: 3
|
|
||||||
sector: 6
|
|
||||||
sector: 9
|
|
||||||
sector: 12
|
|
||||||
sector: 15
|
|
||||||
sector: 2
|
|
||||||
sector: 5
|
|
||||||
sector: 8
|
|
||||||
sector: 11
|
|
||||||
sector: 14
|
|
||||||
sector: 1
|
|
||||||
sector: 4
|
|
||||||
sector: 7
|
|
||||||
sector: 10
|
|
||||||
sector: 13
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
comment: 'Common Atari definitions'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 200
|
|
||||||
target_clock_period_us: 4
|
|
||||||
emit_iam: false
|
|
||||||
gap0: 80
|
|
||||||
gap2: 22
|
|
||||||
gap3: 34
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
ignore_sector: 66
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
comment: 'Common Micropolis definitions'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
drive {
|
|
||||||
hard_sector_count: 16
|
|
||||||
}
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "micropolis.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "micropolis.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
micropolis {}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
micropolis {}
|
|
||||||
}
|
|
||||||
|
|
||||||
option {
|
|
||||||
name: "vgi"
|
|
||||||
comment: "Read/write VGI format images"
|
|
||||||
message: "using VGI format"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image_reader {
|
|
||||||
filename: "micropolis.vgi"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "micropolis.vgi"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 275
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
micropolis {
|
|
||||||
sector_output_size: 275
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
comment: 'DVK MX common settings'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "mx.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
mx {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
comment: 'Northstar generic settings'
|
|
||||||
is_extension: true
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "northstar.nsi"
|
|
||||||
type: NSI
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "northstar.nsi"
|
|
||||||
type: NSI
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
hard_sector_count: 10
|
|
||||||
sync_with_index: true
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
northstar {}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
northstar {}
|
|
||||||
}
|
|
||||||
|
|
||||||
121
src/formats/acornadfs.textpb
Normal file
121
src/formats/acornadfs.textpb
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
comment: 'Acorn ADFS family (ro)'
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "acornadfs.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
ignore_side_byte: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "160"
|
||||||
|
comment: '160kB 3.5" or 5.25" 40-track SSDD; S format'
|
||||||
|
|
||||||
|
config {
|
||||||
|
tpi: 48
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "320"
|
||||||
|
comment: '320kB 3.5" or 5.25" 80-track SSDD; M format'
|
||||||
|
|
||||||
|
config {
|
||||||
|
tpi: 96
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "640"
|
||||||
|
comment: '640kB 3.5" or 5.25" 80-track DSDD; L format'
|
||||||
|
|
||||||
|
config {
|
||||||
|
tpi: 96
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "800"
|
||||||
|
comment: '800kB 3.5" 80-track DSDD; D and E formats'
|
||||||
|
|
||||||
|
config {
|
||||||
|
tpi: 96
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 1024
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "1600"
|
||||||
|
comment: '1600kB 3.5" 80-track DSHD; F formats'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
tpi: 96
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 1024
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
comment: 'Acorn ADFS S-format 160kB 3.5" or 5.25" 40-track SS'
|
|
||||||
include: '_acornadfs8'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
comment: 'Acorn ADFS F-format 1600kB 3.5" 80-track DS'
|
|
||||||
include: '_acornadfs32'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
physical {
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
comment: 'Acorn ADFS M-format 320kB 3.5" or 5.25" 80-track SS'
|
|
||||||
include: '_acornadfs8'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
comment: 'Acorn ADFS L-format 640kB 3.5" or 5.25" 80-track DS'
|
|
||||||
include: '_acornadfs8'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
comment: 'Acorn ADFS D and E-format 800kB 3.5" 80-track DS'
|
|
||||||
include: '_acornadfs32'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
layoutdata {
|
|
||||||
physical {
|
|
||||||
count: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
comment: 'Acorn DFS 100kB/200kB 3.5" or 5.25" 40- or 80-track SS (ro)'
|
comment: 'Acorn DFS fmaily'
|
||||||
|
|
||||||
image_reader {
|
image_reader {
|
||||||
filename: "acorndfs.img"
|
filename: "acorndfs.img"
|
||||||
@@ -11,7 +11,6 @@ image_writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
layout {
|
layout {
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
sides: 1
|
||||||
layoutdata {
|
layoutdata {
|
||||||
sector_size: 256
|
sector_size: 256
|
||||||
@@ -47,3 +46,30 @@ filesystem {
|
|||||||
type: ACORNDFS
|
type: ACORNDFS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "100"
|
||||||
|
comment: '100kB 40-track SSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "200"
|
||||||
|
comment: '200kB 80-track SSSD'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
58
src/formats/ampro.textpb
Normal file
58
src/formats/ampro.textpb
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
comment: 'Ampro 5.25" family'
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "ampro.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 1024
|
||||||
|
physical {
|
||||||
|
start_sector: 17
|
||||||
|
count: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
ibm {}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: CPMFS
|
||||||
|
cpmfs {
|
||||||
|
filesystem_start {
|
||||||
|
track: 1
|
||||||
|
}
|
||||||
|
block_size: 2048
|
||||||
|
dir_entries: 128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "400"
|
||||||
|
comment: "400kB 40-track DSDD"
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "800"
|
||||||
|
comment: "800kB 80-track DSDD"
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
comment: 'Ampro 400kB/800kB 5.25" 40/80 track SSDD/DSDD (ro)'
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ampro.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 1024
|
|
||||||
physical {
|
|
||||||
start_sector: 17
|
|
||||||
count: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
comment: 'Ampro 400kB/800kB 5.25" 40/80 track SSDD/DSDD (ro)'
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ampro.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 1024
|
|
||||||
physical {
|
|
||||||
start_sector: 17
|
|
||||||
count: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
254
src/formats/apple2.textpb
Normal file
254
src/formats/apple2.textpb
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
comment: 'Apple II family'
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
apple2 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
apple2 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "140"
|
||||||
|
comment: '140kB 5.25" 35-track SS'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 35
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tpi: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "640"
|
||||||
|
comment: '640kB 5.25" 80-track DS'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
order: HCS
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tpi: 96
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "side1"
|
||||||
|
comment: "for AppleDOS file system access, read the volume on side 1 of a disk"
|
||||||
|
|
||||||
|
config {
|
||||||
|
filesystem {
|
||||||
|
appledos {
|
||||||
|
filesystem_offset_sectors: 0x500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Filesystem and sector skew"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "nofs"
|
||||||
|
comment: "use physical CHS sector order and no file system"
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "appledos"
|
||||||
|
comment: "use AppleDOS soft sector skew and file system"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image_reader {
|
||||||
|
filesystem_sector_order: true
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filesystem_sector_order: true
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: APPLEDOS
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
filesystem {
|
||||||
|
sector: 0
|
||||||
|
sector: 13
|
||||||
|
sector: 11
|
||||||
|
sector: 9
|
||||||
|
sector: 7
|
||||||
|
sector: 5
|
||||||
|
sector: 3
|
||||||
|
sector: 1
|
||||||
|
sector: 14
|
||||||
|
sector: 12
|
||||||
|
sector: 10
|
||||||
|
sector: 8
|
||||||
|
sector: 6
|
||||||
|
sector: 4
|
||||||
|
sector: 2
|
||||||
|
sector: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "prodos"
|
||||||
|
comment: "use ProDOS soft sector skew and filesystem"
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
image_reader {
|
||||||
|
filesystem_sector_order: true
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filesystem_sector_order: true
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: PRODOS
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
filesystem {
|
||||||
|
sector: 0
|
||||||
|
sector: 2
|
||||||
|
sector: 4
|
||||||
|
sector: 6
|
||||||
|
sector: 8
|
||||||
|
sector: 10
|
||||||
|
sector: 12
|
||||||
|
sector: 14
|
||||||
|
sector: 1
|
||||||
|
sector: 3
|
||||||
|
sector: 5
|
||||||
|
sector: 7
|
||||||
|
sector: 9
|
||||||
|
sector: 11
|
||||||
|
sector: 13
|
||||||
|
sector: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "cpm"
|
||||||
|
comment: "use CP/M soft sector skew and filesystem"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image_reader {
|
||||||
|
filesystem_sector_order: true
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filesystem_sector_order: true
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: CPMFS
|
||||||
|
cpmfs {
|
||||||
|
filesystem_start {
|
||||||
|
track: 3
|
||||||
|
}
|
||||||
|
block_size: 4096
|
||||||
|
dir_entries: 128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
apple2 {
|
||||||
|
side_one_track_offset: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
apple2 {
|
||||||
|
side_one_track_offset: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
# The boot tracks use ProDOS translation.
|
||||||
|
|
||||||
|
track: 0
|
||||||
|
up_to_track: 2
|
||||||
|
filesystem {
|
||||||
|
sector: 0
|
||||||
|
sector: 2
|
||||||
|
sector: 4
|
||||||
|
sector: 6
|
||||||
|
sector: 8
|
||||||
|
sector: 10
|
||||||
|
sector: 12
|
||||||
|
sector: 14
|
||||||
|
sector: 1
|
||||||
|
sector: 3
|
||||||
|
sector: 5
|
||||||
|
sector: 7
|
||||||
|
sector: 9
|
||||||
|
sector: 11
|
||||||
|
sector: 13
|
||||||
|
sector: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutdata {
|
||||||
|
# The data tracks use their own, special translation.
|
||||||
|
|
||||||
|
track: 3
|
||||||
|
up_to_track: 79
|
||||||
|
filesystem {
|
||||||
|
sector: 0
|
||||||
|
sector: 3
|
||||||
|
sector: 6
|
||||||
|
sector: 9
|
||||||
|
sector: 12
|
||||||
|
sector: 15
|
||||||
|
sector: 2
|
||||||
|
sector: 5
|
||||||
|
sector: 8
|
||||||
|
sector: 11
|
||||||
|
sector: 14
|
||||||
|
sector: 1
|
||||||
|
sector: 4
|
||||||
|
sector: 7
|
||||||
|
sector: 10
|
||||||
|
sector: 13
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
comment: 'Apple II 140kB 5.25" 35 track SSDD'
|
|
||||||
include: '_apple2'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "appleii140.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "appleii140.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 35
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
comment: 'Apple II 640kB 5.25" 80 track DSDD'
|
|
||||||
include: '_apple2'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "appleii640.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "appleii640.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
order: HCS
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 96
|
|
||||||
|
|
||||||
option {
|
|
||||||
name: "side1"
|
|
||||||
comment: "read the volume on side 1 of a disk (AppleDOS only)"
|
|
||||||
message: "accessing volume on side 1"
|
|
||||||
|
|
||||||
config {
|
|
||||||
filesystem {
|
|
||||||
appledos {
|
|
||||||
filesystem_offset_sectors: 0x500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
180
src/formats/atarist.textpb
Normal file
180
src/formats/atarist.textpb
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
comment: 'Atari ST family'
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 200
|
||||||
|
target_clock_period_us: 4
|
||||||
|
emit_iam: false
|
||||||
|
gap0: 80
|
||||||
|
gap2: 22
|
||||||
|
gap3: 34
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
ignore_sector: 66
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "360"
|
||||||
|
comment: '360kB 3.5" 80-track 9-sector SSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "370"
|
||||||
|
comment: '370kB 3.5" 82-track 9-sector SSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 82
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "400"
|
||||||
|
comment: '400kB 3.5" 80-track 10-sector SSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "410"
|
||||||
|
comment: '410kB 3.5" 82-track 10-sector SSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 82
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "720"
|
||||||
|
comment: '720kB 3.5" 80-track 9-sector DSDD'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "740"
|
||||||
|
comment: '740kB 3.5" 82-track 9-sector DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 82
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "800"
|
||||||
|
comment: '800kB 3.5" 80-track 10-sector DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "820"
|
||||||
|
comment: '820kB 3.5" 82-track 10-sector DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 82
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Atari ST 360kB 3.5" 80-track 9-sector SSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist360.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist360.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Atari ST 370kB 3.5" 82-track 9-sector SSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist370.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist370.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 82
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Atari ST 400kB 3.5" 80-track 10-sector SSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist400.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist400.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Atari ST 410kB 3.5" 82-track 10-sector SSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist410.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist410.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 82
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Atari ST 720kB 3.5" 80-track 9-sector DSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist720.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist720.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
comment: 'Atari ST 740kB 3.5" 82-track 9-sector DSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist740.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist740.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 82
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
comment: 'Atari ST 800kB 3.5" 80-track 10-sector DSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist800.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist800.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
comment: 'Atari ST 820kB 3.5" 82-track 10-sector DSDD'
|
|
||||||
|
|
||||||
include: '_atari'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "atarist820.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "atarist820.st"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 82
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
91
src/formats/brother.textpb
Normal file
91
src/formats/brother.textpb
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
comment: 'Brother GCR family'
|
||||||
|
|
||||||
|
image_reader {
|
||||||
|
filename: "brother.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "brother.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
brother {}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
brother {}
|
||||||
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "120"
|
||||||
|
comment: '120kB 3.5" 39-track SS GCR'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 39
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 12
|
||||||
|
skew: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
brother {
|
||||||
|
format: BROTHER120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drive {
|
||||||
|
head_bias: 0
|
||||||
|
group_offset: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: BROTHER120
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "240"
|
||||||
|
comment: '240kB 3.5" 78-track SS GCR'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 78
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 12
|
||||||
|
skew: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drive {
|
||||||
|
head_bias: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: FATFS
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 96
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
comment: 'Brother 120kB 3.5" 39-track SS GCR'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "brother120.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "brother120.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 39
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 12
|
|
||||||
skew: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
brother {
|
|
||||||
format: BROTHER120
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
brother {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
head_bias: 0
|
|
||||||
group_offset: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: BROTHER120
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
comment: 'Brother 240kB 3.5" 78-track SS GCR'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "brother240.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "brother240.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 78
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
count: 12
|
|
||||||
skew: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
brother {}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
brother {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
head_bias: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,37 +1,16 @@
|
|||||||
FORMATS = \
|
FORMATS = \
|
||||||
_acornadfs8 \
|
|
||||||
_acornadfs32 \
|
|
||||||
_apple2 \
|
|
||||||
_atari \
|
|
||||||
_micropolis \
|
|
||||||
_northstar \
|
|
||||||
_mx \
|
|
||||||
40track_drive \
|
40track_drive \
|
||||||
acornadfs160 \
|
acornadfs \
|
||||||
acornadfs320 \
|
|
||||||
acornadfs640 \
|
|
||||||
acornadfs800 \
|
|
||||||
acornadfs1600 \
|
|
||||||
acorndfs \
|
acorndfs \
|
||||||
aeslanier \
|
aeslanier \
|
||||||
agat840 \
|
agat840 \
|
||||||
amiga \
|
amiga \
|
||||||
ampro400 \
|
ampro \
|
||||||
ampro800 \
|
|
||||||
apple2_drive \
|
apple2_drive \
|
||||||
appleii140 \
|
apple2 \
|
||||||
appleii640 \
|
atarist \
|
||||||
atarist360 \
|
|
||||||
atarist370 \
|
|
||||||
atarist400 \
|
|
||||||
atarist410 \
|
|
||||||
atarist720 \
|
|
||||||
atarist740 \
|
|
||||||
atarist800 \
|
|
||||||
atarist820 \
|
|
||||||
bk800 \
|
bk800 \
|
||||||
brother120 \
|
brother \
|
||||||
brother240 \
|
|
||||||
commodore1541 \
|
commodore1541 \
|
||||||
commodore1581 \
|
commodore1581 \
|
||||||
cmd_fd2000 \
|
cmd_fd2000 \
|
||||||
@@ -39,44 +18,22 @@ FORMATS = \
|
|||||||
epsonpf10 \
|
epsonpf10 \
|
||||||
f85 \
|
f85 \
|
||||||
fb100 \
|
fb100 \
|
||||||
hp9121 \
|
hplif \
|
||||||
hplif770 \
|
|
||||||
ibm \
|
ibm \
|
||||||
ibm1200 \
|
|
||||||
ibm1232 \
|
|
||||||
ibm1440 \
|
|
||||||
ibm180 \
|
|
||||||
ibm160 \
|
|
||||||
ibm360 \
|
|
||||||
ibm320 \
|
|
||||||
ibm720 \
|
|
||||||
icl30 \
|
icl30 \
|
||||||
mac400 \
|
mac \
|
||||||
mac800 \
|
micropolis \
|
||||||
micropolis143 \
|
mx \
|
||||||
micropolis287 \
|
|
||||||
micropolis315 \
|
|
||||||
micropolis630 \
|
|
||||||
mx110 \
|
|
||||||
mx220_ds \
|
|
||||||
mx220_ss \
|
|
||||||
mx440 \
|
|
||||||
n88basic \
|
n88basic \
|
||||||
northstar175 \
|
northstar \
|
||||||
northstar350 \
|
|
||||||
northstar87 \
|
|
||||||
psos800 \
|
psos800 \
|
||||||
rolandd20 \
|
rolandd20 \
|
||||||
rx50 \
|
rx50 \
|
||||||
shugart_drive \
|
shugart_drive \
|
||||||
smaky6 \
|
smaky6 \
|
||||||
tids990 \
|
tids990 \
|
||||||
tiki90 \
|
tiki \
|
||||||
tiki200 \
|
victor9k \
|
||||||
tiki400 \
|
|
||||||
tiki800 \
|
|
||||||
victor9k_ds \
|
|
||||||
victor9k_ss \
|
|
||||||
zilogmcz \
|
zilogmcz \
|
||||||
|
|
||||||
$(OBJDIR)/src/formats/format_%.o: $(OBJDIR)/src/formats/format_%.cc
|
$(OBJDIR)/src/formats/format_%.o: $(OBJDIR)/src/formats/format_%.cc
|
||||||
|
|||||||
@@ -64,27 +64,30 @@ filesystem {
|
|||||||
type: CBMFS
|
type: CBMFS
|
||||||
}
|
}
|
||||||
|
|
||||||
option {
|
option_group {
|
||||||
name: "35"
|
comment: "Format family"
|
||||||
comment: "35-track variant (default)"
|
|
||||||
message: "using 35-track variant"
|
option {
|
||||||
|
name: "171"
|
||||||
config {
|
comment: "35-track variant"
|
||||||
layout {
|
set_by_default: true
|
||||||
tracks: 35
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 35
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "192"
|
||||||
|
comment: "40-track variant"
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
option {
|
|
||||||
name: "40"
|
|
||||||
comment: "40-track variant"
|
|
||||||
message: "using 40-track variant"
|
|
||||||
|
|
||||||
config {
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
comment: 'Hewlett-Packard 9121 264kB 3.5" SSDD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "hp9121.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 66
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
physical {
|
|
||||||
sector: 0
|
|
||||||
sector: 4
|
|
||||||
sector: 8
|
|
||||||
sector: 12
|
|
||||||
sector: 1
|
|
||||||
sector: 5
|
|
||||||
sector: 9
|
|
||||||
sector: 13
|
|
||||||
sector: 2
|
|
||||||
sector: 6
|
|
||||||
sector: 10
|
|
||||||
sector: 14
|
|
||||||
sector: 3
|
|
||||||
sector: 7
|
|
||||||
sector: 11
|
|
||||||
sector: 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
emit_iam: false
|
|
||||||
target_rotational_period_ms: 200
|
|
||||||
target_clock_period_us: 4
|
|
||||||
gap0: 80
|
|
||||||
gap2: 22
|
|
||||||
gap3: 44
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
143
src/formats/hplif.textpb
Normal file
143
src/formats/hplif.textpb
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
comment: 'Hewlett-Packard LIF family'
|
||||||
|
|
||||||
|
drive {
|
||||||
|
high_density: false
|
||||||
|
}
|
||||||
|
|
||||||
|
image_reader {
|
||||||
|
filename: "hplif.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "hplif.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
ibm {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: LIF
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 96
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format family"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "264"
|
||||||
|
comment: '264kB 3.5" 66-track SSDD; HP9121 format'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 66
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
sector: 0
|
||||||
|
sector: 4
|
||||||
|
sector: 8
|
||||||
|
sector: 12
|
||||||
|
sector: 1
|
||||||
|
sector: 5
|
||||||
|
sector: 9
|
||||||
|
sector: 13
|
||||||
|
sector: 2
|
||||||
|
sector: 6
|
||||||
|
sector: 10
|
||||||
|
sector: 14
|
||||||
|
sector: 3
|
||||||
|
sector: 7
|
||||||
|
sector: 11
|
||||||
|
sector: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
emit_iam: false
|
||||||
|
target_rotational_period_ms: 200
|
||||||
|
target_clock_period_us: 4
|
||||||
|
gap0: 80
|
||||||
|
gap2: 22
|
||||||
|
gap3: 44
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "616"
|
||||||
|
comment: '616kB 3.5" 77-track DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 77
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 200
|
||||||
|
target_clock_period_us: 4
|
||||||
|
emit_iam: false
|
||||||
|
gap0: 80
|
||||||
|
gap2: 22
|
||||||
|
gap3: 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "770"
|
||||||
|
comment: '770kB 3.5" 77-track DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 77
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 1024
|
||||||
|
physical {
|
||||||
|
sector: 1
|
||||||
|
sector: 2
|
||||||
|
sector: 3
|
||||||
|
sector: 4
|
||||||
|
sector: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 200
|
||||||
|
target_clock_period_us: 4
|
||||||
|
gap0: 80
|
||||||
|
gap2: 22
|
||||||
|
gap3: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
comment: 'Hewlett-Packard LIF 770kB 3.5" DSDD'
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: false
|
|
||||||
rotational_period_ms: 200
|
|
||||||
}
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "hplif770.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "hplif770.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 77
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 1024
|
|
||||||
physical {
|
|
||||||
sector: 1
|
|
||||||
sector: 2
|
|
||||||
sector: 3
|
|
||||||
sector: 4
|
|
||||||
sector: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 200
|
|
||||||
target_clock_period_us: 4
|
|
||||||
gap0: 80
|
|
||||||
gap2: 22
|
|
||||||
gap3: 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
comment: 'PC 3.5"/5.25" autodetect double sided format'
|
comment: 'Generic PC 3.5"/5.25" family'
|
||||||
|
|
||||||
|
image_reader {
|
||||||
|
filename: "ibm.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
image_writer {
|
image_writer {
|
||||||
filename: "ibm.img"
|
filename: "ibm.img"
|
||||||
@@ -9,9 +14,255 @@ decoder {
|
|||||||
ibm {}
|
ibm {}
|
||||||
}
|
}
|
||||||
|
|
||||||
heads {
|
filesystem {
|
||||||
start: 0
|
type: FATFS
|
||||||
end: 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpi: 96
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "auto"
|
||||||
|
comment: 'try to autodetect the format (unreliable)'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "160"
|
||||||
|
comment: '160kB 5.25" 40-track 8-sector SSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 167
|
||||||
|
target_clock_period_us: 3.333
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "180"
|
||||||
|
comment: '180kB 5.25" 40-track 9-sector SSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 167
|
||||||
|
target_clock_period_us: 3.333
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "320"
|
||||||
|
comment: '320kB 5.25" 40-track 8-sector DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 167
|
||||||
|
target_clock_period_us: 3.333
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "360"
|
||||||
|
comment: '360kB 5.25" 40-track 9-sector DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 167
|
||||||
|
target_clock_period_us: 3.333
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "720"
|
||||||
|
comment: '720kB 5.25"/3.5" 80-track 9-sector DSDD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
# This also works on 166ms drives (producing a physical clock of
|
||||||
|
# 3.33us).
|
||||||
|
target_rotational_period_ms: 200
|
||||||
|
target_clock_period_us: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "1200"
|
||||||
|
comment: '1200kB 5.25" 80-track 15-sector DSHD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 167
|
||||||
|
target_clock_period_us: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "1232"
|
||||||
|
comment: '1232kB 5.25"/3.5" 77-track 8-sector DSHD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 77
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 1024
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 167
|
||||||
|
target_clock_period_us: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "1440"
|
||||||
|
comment: '1440kB 3.5" 80-track 18-sector DSHD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
ibm {
|
||||||
|
trackdata {
|
||||||
|
target_rotational_period_ms: 200
|
||||||
|
target_clock_period_us: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
comment: 'PC 1200kB 5.25" 80-track 15-sector DSHD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm1200.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm1200.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 167
|
|
||||||
target_clock_period_us: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: true
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
comment: 'Japanese PC 1232kB 5.25"/3.5" 77-track 8-sector DSHD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm1232.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm1232.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 77
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 1024
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 167
|
|
||||||
target_clock_period_us: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: true
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
comment: 'PC 1440kB 3.5" 80-track 18-sector DSHD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm1440.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm1440.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 18
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 200
|
|
||||||
target_clock_period_us: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
comment: 'PC 160kB 5.25" 40-track 8-sector SSDD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm160.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm160.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 167
|
|
||||||
target_clock_period_us: 3.333
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: false
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
comment: 'PC 180kB 5.25" 40-track 9-sector SSDD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm180.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm180.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 167
|
|
||||||
target_clock_period_us: 3.333
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: false
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
comment: 'PC 320kB 5.25" 40-track 8-sector DSDD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm320.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm320.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 167
|
|
||||||
target_clock_period_us: 3.333
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
comment: 'PC 360kB 5.25" 40-track 9-sector DSDD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm360.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm360.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
target_rotational_period_ms: 167
|
|
||||||
target_clock_period_us: 3.333
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
comment: 'PC 720kB 5.25"/3.5" 80-track 9-sector DSDD'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "ibm720.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "ibm720.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
ibm {
|
|
||||||
trackdata {
|
|
||||||
# This also works on 166ms drives (producing a physical clock of
|
|
||||||
# 3.33us).
|
|
||||||
target_rotational_period_ms: 200
|
|
||||||
target_clock_period_us: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
drive {
|
|
||||||
high_density: false
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: FATFS
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
comment: 'Macintosh 800kB 3.5" DSDD GCR'
|
comment: 'Macintosh GCR family'
|
||||||
|
|
||||||
image_reader {
|
image_reader {
|
||||||
filename: "mac800.dsk"
|
filename: "mac.dsk"
|
||||||
type: IMG
|
type: IMG
|
||||||
}
|
}
|
||||||
|
|
||||||
image_writer {
|
image_writer {
|
||||||
filename: "mac800.dsk"
|
filename: "mac.dsk"
|
||||||
type: IMG
|
type: IMG
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +64,47 @@ decoder {
|
|||||||
macintosh {}
|
macintosh {}
|
||||||
}
|
}
|
||||||
|
|
||||||
filesystem {
|
option_group {
|
||||||
type: MACHFS
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "400"
|
||||||
|
comment: "400kB 80-track SSDD"
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
sides: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "800"
|
||||||
|
comment: "800kB 80-track DSDD"
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
sides: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: MACHFS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "metadata"
|
||||||
|
comment: "read/write 524 byte sectors"
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 524
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
comment: 'Macintosh 400kB 3.5" SSDD GCR'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "mac400.dsk"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "mac400.dsk"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
skew: 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 0
|
|
||||||
up_to_track: 15
|
|
||||||
physical {
|
|
||||||
count: 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 16
|
|
||||||
up_to_track: 31
|
|
||||||
physical {
|
|
||||||
count: 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 32
|
|
||||||
up_to_track: 47
|
|
||||||
physical {
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 48
|
|
||||||
up_to_track: 63
|
|
||||||
physical {
|
|
||||||
count: 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 64
|
|
||||||
up_to_track: 79
|
|
||||||
physical {
|
|
||||||
count: 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
macintosh {}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
macintosh {}
|
|
||||||
}
|
|
||||||
113
src/formats/micropolis.textpb
Normal file
113
src/formats/micropolis.textpb
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
comment: ' Micropolis format family'
|
||||||
|
|
||||||
|
drive {
|
||||||
|
hard_sector_count: 16
|
||||||
|
}
|
||||||
|
|
||||||
|
image_reader {
|
||||||
|
filename: "micropolis.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "micropolis.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
micropolis {}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
micropolis {}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "vgi"
|
||||||
|
comment: "Read/write VGI format images with 275 bytes per sector"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image_reader {
|
||||||
|
filename: "micropolis.vgi"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "micropolis.vgi"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 275
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
micropolis {
|
||||||
|
sector_output_size: 275
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
option {
|
||||||
|
name: "143"
|
||||||
|
comment: '143kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod I'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 35
|
||||||
|
sides: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "287"
|
||||||
|
comment: '287kB 5.25" DSDD hard-sectored; Micropolis MetaFloppy Mod I'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 35
|
||||||
|
sides: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "315"
|
||||||
|
comment: '315kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod II'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 77
|
||||||
|
sides: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "630"
|
||||||
|
comment: '630kB 5.25" DSDD hard-sectored; Micropolis MetaFloppy Mod II'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 77
|
||||||
|
sides: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
comment: 'Micropolis MetaFloppy Mod I 143kB 5.25" SSDD hard-sectored'
|
|
||||||
|
|
||||||
include: '_micropolis'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 35
|
|
||||||
sides: 1
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
comment: 'Micropolis MetaFloppy Mod I 287kB 5.25" DSDD hard-sectored'
|
|
||||||
|
|
||||||
include: '_micropolis'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 35
|
|
||||||
sides: 2
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
comment: 'Micropolis MetaFloppy Mod II 315kB 5.25" SSDD hard-sectored'
|
|
||||||
|
|
||||||
include: '_micropolis'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 77
|
|
||||||
sides: 1
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
comment: 'Micropolis MetaFloppy Mod II 630kB 5.25" DSDD hard-sectored'
|
|
||||||
|
|
||||||
include: '_micropolis'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 77
|
|
||||||
sides: 2
|
|
||||||
}
|
|
||||||
76
src/formats/mx.textpb
Normal file
76
src/formats/mx.textpb
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
comment: 'DVK MX family'
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "mx.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
mx {}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format family"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "110"
|
||||||
|
comment: '110kB 5.25" 40-track SSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "220ds"
|
||||||
|
comment: '220kB 5.25" 40-track DSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "220ss"
|
||||||
|
comment: '220kB 5.25" 80-track SSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "440"
|
||||||
|
comment: '440kB 5.25" 80-track DSSD'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
comment: 'DVK MX 110kB 5.25" (ro)'
|
|
||||||
|
|
||||||
include: '_mx'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
comment: 'DVK MX 220kB DS 40-track 5.25" (ro)'
|
|
||||||
|
|
||||||
include: '_mx'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
comment: 'DVK MX 220kB SS 80-track 5.25" (ro)'
|
|
||||||
|
|
||||||
include: '_mx'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
comment: 'DVK MX 440kB 5.25" (ro)'
|
|
||||||
|
|
||||||
include: '_mx'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
}
|
|
||||||
85
src/formats/northstar.textpb
Normal file
85
src/formats/northstar.textpb
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
comment: 'Northstar family'
|
||||||
|
|
||||||
|
image_reader {
|
||||||
|
filename: "northstar.nsi"
|
||||||
|
type: NSI
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "northstar.nsi"
|
||||||
|
type: NSI
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
layoutdata {
|
||||||
|
physical {
|
||||||
|
start_sector: 0
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drive {
|
||||||
|
hard_sector_count: 10
|
||||||
|
sync_with_index: true
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder {
|
||||||
|
northstar {}
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
northstar {}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "87"
|
||||||
|
comment: '87.5kB 5.25" 35-track SSSD hard-sectored'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "175"
|
||||||
|
comment: '175kB 5.25" 40-track SSDD hard-sectored'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "350"
|
||||||
|
comment: '350kB 5.25" 40-track DSDD hard-sectored'
|
||||||
|
set_by_default: true
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
comment: 'Northstar 175kB 5.25" 35-track SSDD hard-sectored'
|
|
||||||
|
|
||||||
include: '_northstar'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
comment: 'Northstar 350kB 5.25" 35-track SSDD hard-sectored'
|
|
||||||
|
|
||||||
include: '_northstar'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
comment: 'Northstar 87.5kB 5.25" 35-track SSSD hard-sectored'
|
|
||||||
|
|
||||||
include: '_northstar'
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 256
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
144
src/formats/tiki.textpb
Normal file
144
src/formats/tiki.textpb
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
comment: 'Tiki 100 family'
|
||||||
|
|
||||||
|
image_writer {
|
||||||
|
filename: "tiki.img"
|
||||||
|
type: IMG
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder {
|
||||||
|
ibm {}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 48
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format variant"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "90"
|
||||||
|
comment: '90kB 40-track 18-sector SSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
side: 0
|
||||||
|
sector_size: 128
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: CPMFS
|
||||||
|
cpmfs {
|
||||||
|
filesystem_start {
|
||||||
|
track: 3
|
||||||
|
}
|
||||||
|
block_size: 1024
|
||||||
|
dir_entries: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "200"
|
||||||
|
comment: '200kB 40-track 10-sector SSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 1
|
||||||
|
layoutdata {
|
||||||
|
side: 0
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: CPMFS
|
||||||
|
cpmfs {
|
||||||
|
filesystem_start {
|
||||||
|
track: 2
|
||||||
|
}
|
||||||
|
block_size: 1024
|
||||||
|
dir_entries: 64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "400"
|
||||||
|
comment: '400kB 40-track 10-sector DSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 40
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: CPMFS
|
||||||
|
cpmfs {
|
||||||
|
filesystem_start {
|
||||||
|
side: 0
|
||||||
|
track: 1
|
||||||
|
}
|
||||||
|
block_size: 2048
|
||||||
|
dir_entries: 128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "800"
|
||||||
|
comment: '800kB 80-track 10-sector DSSD'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
tracks: 80
|
||||||
|
sides: 2
|
||||||
|
layoutdata {
|
||||||
|
sector_size: 512
|
||||||
|
physical {
|
||||||
|
start_sector: 1
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
type: CPMFS
|
||||||
|
cpmfs {
|
||||||
|
filesystem_start {
|
||||||
|
side: 0
|
||||||
|
track: 1
|
||||||
|
}
|
||||||
|
block_size: 2048
|
||||||
|
dir_entries: 128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpi: 96
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
comment: 'Tiki 100 200kB 40-track 10-sector SSSD (ro)'
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "tiki200.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
side: 0
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: CPMFS
|
|
||||||
cpmfs {
|
|
||||||
filesystem_start {
|
|
||||||
track: 2
|
|
||||||
}
|
|
||||||
block_size: 1024
|
|
||||||
dir_entries: 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
comment: 'Tiki 100 400kB 40-track 10-sector DSSD (ro)'
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "tiki400.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: CPMFS
|
|
||||||
cpmfs {
|
|
||||||
filesystem_start {
|
|
||||||
side: 0
|
|
||||||
track: 1
|
|
||||||
}
|
|
||||||
block_size: 2048
|
|
||||||
dir_entries: 128
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
comment: 'Tiki 100 800kB 80-track 10-sector DSSD (ro)'
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "tiki900.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: CPMFS
|
|
||||||
cpmfs {
|
|
||||||
filesystem_start {
|
|
||||||
side: 0
|
|
||||||
track: 1
|
|
||||||
}
|
|
||||||
block_size: 2048
|
|
||||||
dir_entries: 128
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 96
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
comment: 'Tiki 100 90kB 40-track 18-sector SSSD (ro)'
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "tiki90.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
side: 0
|
|
||||||
sector_size: 128
|
|
||||||
physical {
|
|
||||||
start_sector: 1
|
|
||||||
count: 18
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
ibm {}
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
type: CPMFS
|
|
||||||
cpmfs {
|
|
||||||
filesystem_start {
|
|
||||||
track: 3
|
|
||||||
}
|
|
||||||
block_size: 1024
|
|
||||||
dir_entries: 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tpi: 48
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
comment: 'Victor 9000 / Sirius One 1224kB DSHD GCR variable sector)'
|
comment: 'Victor 9000 / Sirius One family'
|
||||||
|
|
||||||
image_reader {
|
image_reader {
|
||||||
filename: "victor9k_ds.img"
|
filename: "victor9k.img"
|
||||||
type: IMG
|
type: IMG
|
||||||
}
|
}
|
||||||
|
|
||||||
image_writer {
|
image_writer {
|
||||||
filename: "victor9k_ds.img"
|
filename: "victor9k.img"
|
||||||
type: IMG
|
type: IMG
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,3 +261,30 @@ encoder {
|
|||||||
decoder {
|
decoder {
|
||||||
victor9k {}
|
victor9k {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
option_group {
|
||||||
|
comment: "Format family"
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "612"
|
||||||
|
comment: '612kB 80-track DSHD GCR'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
sides: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
name: "1224"
|
||||||
|
comment: '1224kB 80-track DSHD GCR'
|
||||||
|
|
||||||
|
config {
|
||||||
|
layout {
|
||||||
|
sides: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
comment: 'Victor 9000 / Sirius One 612kB SSHD GCR variable sector)'
|
|
||||||
|
|
||||||
image_reader {
|
|
||||||
filename: "victor9k.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
image_writer {
|
|
||||||
filename: "victor9k.img"
|
|
||||||
type: IMG
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
layoutdata {
|
|
||||||
sector_size: 512
|
|
||||||
physical {
|
|
||||||
start_sector: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 0
|
|
||||||
up_to_track: 3
|
|
||||||
physical {
|
|
||||||
count: 19
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 4
|
|
||||||
up_to_track: 15
|
|
||||||
physical {
|
|
||||||
count: 18
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 18
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 16
|
|
||||||
up_to_track: 26
|
|
||||||
physical {
|
|
||||||
count: 17
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 17
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 27
|
|
||||||
up_to_track: 37
|
|
||||||
physical {
|
|
||||||
count: 16
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 16
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 38
|
|
||||||
up_to_track: 47
|
|
||||||
physical {
|
|
||||||
count: 15
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 15
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 48
|
|
||||||
up_to_track: 59
|
|
||||||
physical {
|
|
||||||
count: 14
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 14
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 60
|
|
||||||
up_to_track: 70
|
|
||||||
physical {
|
|
||||||
count: 13
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 13
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutdata {
|
|
||||||
track: 71
|
|
||||||
up_to_track: 79
|
|
||||||
physical {
|
|
||||||
count: 12
|
|
||||||
}
|
|
||||||
filesystem {
|
|
||||||
start_sector: 0
|
|
||||||
count: 12
|
|
||||||
skew: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder {
|
|
||||||
victor9k {
|
|
||||||
trackdata {
|
|
||||||
clock_period_us: 2.1367 # 468kHz
|
|
||||||
post_index_gap_us: 500.0
|
|
||||||
pre_header_sync_bits: 150
|
|
||||||
post_header_gap_bits: 60
|
|
||||||
pre_data_sync_bits: 40
|
|
||||||
post_data_gap_bits: 300
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 0
|
|
||||||
max_track: 3
|
|
||||||
rotational_period_ms: 237.9
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 4
|
|
||||||
max_track: 15
|
|
||||||
rotational_period_ms: 224.5
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 16
|
|
||||||
max_track: 26
|
|
||||||
rotational_period_ms: 212.2
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 27
|
|
||||||
max_track: 37
|
|
||||||
rotational_period_ms: 199.9
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 38
|
|
||||||
max_track: 47
|
|
||||||
rotational_period_ms: 187.6
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 48
|
|
||||||
max_track: 59
|
|
||||||
rotational_period_ms: 175.3
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 60
|
|
||||||
max_track: 70
|
|
||||||
rotational_period_ms: 163.0
|
|
||||||
}
|
|
||||||
trackdata {
|
|
||||||
head: 0
|
|
||||||
min_track: 71
|
|
||||||
max_track: 79
|
|
||||||
rotational_period_ms: 149.6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder {
|
|
||||||
victor9k {}
|
|
||||||
}
|
|
||||||
|
|
||||||
filesystem {
|
|
||||||
cpmfs {
|
|
||||||
filesystem_start {
|
|
||||||
track: 5
|
|
||||||
}
|
|
||||||
block_size: 2048
|
|
||||||
dir_entries: 128
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -577,89 +577,85 @@ private:
|
|||||||
_formatNames[formatChoice->GetSelection()];
|
_formatNames[formatChoice->GetSelection()];
|
||||||
FlagGroup::parseConfigFile(formatName, formats);
|
FlagGroup::parseConfigFile(formatName, formats);
|
||||||
|
|
||||||
std::set<std::string> exclusivityGroups;
|
for (auto& group : config.option_group())
|
||||||
for (auto& option : config.option())
|
|
||||||
{
|
{
|
||||||
if (option.has_exclusivity_group())
|
|
||||||
exclusivityGroups.insert(option.exclusivity_group());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.option().empty())
|
|
||||||
sizer->Add(new wxStaticText(formatOptionsContainer,
|
sizer->Add(new wxStaticText(formatOptionsContainer,
|
||||||
wxID_ANY,
|
wxID_ANY,
|
||||||
"(no options for this format)"));
|
group.comment() + ":"));
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Add grouped radiobuttons for anything in an exclusivity
|
|
||||||
* group. */
|
|
||||||
|
|
||||||
for (auto& group : exclusivityGroups)
|
bool first = true;
|
||||||
|
bool valueSet = false;
|
||||||
|
wxRadioButton* defaultButton = nullptr;
|
||||||
|
for (auto& option : group.option())
|
||||||
{
|
{
|
||||||
bool first = true;
|
auto* rb = new wxRadioButton(formatOptionsContainer,
|
||||||
for (auto& option : config.option())
|
wxID_ANY,
|
||||||
{
|
option.comment(),
|
||||||
if (option.exclusivity_group() != group)
|
wxDefaultPosition,
|
||||||
continue;
|
wxDefaultSize,
|
||||||
|
first ? wxRB_GROUP : 0);
|
||||||
auto* rb = new wxRadioButton(formatOptionsContainer,
|
|
||||||
wxID_ANY,
|
|
||||||
option.comment());
|
|
||||||
auto key =
|
|
||||||
std::make_pair(formatName, option.name());
|
|
||||||
sizer->Add(rb);
|
|
||||||
|
|
||||||
rb->Bind(wxEVT_RADIOBUTTON,
|
|
||||||
[=](wxCommandEvent& e)
|
|
||||||
{
|
|
||||||
for (auto& option : config.option())
|
|
||||||
{
|
|
||||||
if (option.exclusivity_group() == group)
|
|
||||||
_formatOptions.erase(std::make_pair(
|
|
||||||
formatName, option.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
_formatOptions.insert(key);
|
|
||||||
|
|
||||||
OnControlsChanged(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (_formatOptions.find(key) !=
|
|
||||||
_formatOptions.end())
|
|
||||||
rb->SetValue(true);
|
|
||||||
|
|
||||||
if (first)
|
|
||||||
rb->SetExtraStyle(wxRB_GROUP);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Anything that's _not_ in a group gets a checkbox. */
|
|
||||||
|
|
||||||
for (auto& option : config.option())
|
|
||||||
{
|
|
||||||
if (option.has_exclusivity_group())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto* choice = new wxCheckBox(
|
|
||||||
formatOptionsContainer, wxID_ANY, option.comment());
|
|
||||||
auto key = std::make_pair(formatName, option.name());
|
auto key = std::make_pair(formatName, option.name());
|
||||||
sizer->Add(choice);
|
sizer->Add(rb);
|
||||||
|
|
||||||
if (_formatOptions.find(key) != _formatOptions.end())
|
rb->Bind(wxEVT_RADIOBUTTON,
|
||||||
choice->SetValue(true);
|
|
||||||
|
|
||||||
choice->Bind(wxEVT_CHECKBOX,
|
|
||||||
[=](wxCommandEvent& e)
|
[=](wxCommandEvent& e)
|
||||||
{
|
{
|
||||||
if (choice->GetValue())
|
for (auto& option : group.option())
|
||||||
_formatOptions.insert(key);
|
{
|
||||||
else
|
_formatOptions.erase(std::make_pair(
|
||||||
_formatOptions.erase(key);
|
formatName, option.name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
_formatOptions.insert(key);
|
||||||
|
|
||||||
OnControlsChanged(e);
|
OnControlsChanged(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_formatOptions.find(key) != _formatOptions.end())
|
||||||
|
{
|
||||||
|
rb->SetValue(true);
|
||||||
|
valueSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.set_by_default() || !defaultButton)
|
||||||
|
defaultButton = rb;
|
||||||
|
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!valueSet && defaultButton)
|
||||||
|
defaultButton->SetValue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Anything that's _not_ in a group gets a checkbox. */
|
||||||
|
|
||||||
|
for (auto& option : config.option())
|
||||||
|
{
|
||||||
|
auto* choice = new wxCheckBox(
|
||||||
|
formatOptionsContainer, wxID_ANY, option.comment());
|
||||||
|
auto key = std::make_pair(formatName, option.name());
|
||||||
|
sizer->Add(choice);
|
||||||
|
|
||||||
|
choice->SetValue(
|
||||||
|
(_formatOptions.find(key) != _formatOptions.end()) ||
|
||||||
|
option.set_by_default());
|
||||||
|
|
||||||
|
choice->Bind(wxEVT_CHECKBOX,
|
||||||
|
[=](wxCommandEvent& e)
|
||||||
|
{
|
||||||
|
if (choice->GetValue())
|
||||||
|
_formatOptions.insert(key);
|
||||||
|
else
|
||||||
|
_formatOptions.erase(key);
|
||||||
|
|
||||||
|
OnControlsChanged(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.option().empty() && config.option_group().empty())
|
||||||
|
sizer->Add(new wxStaticText(formatOptionsContainer,
|
||||||
|
wxID_ANY,
|
||||||
|
"(no options for this format)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
formatOptionsContainer->SetSizerAndFit(sizer);
|
formatOptionsContainer->SetSizerAndFit(sizer);
|
||||||
|
|||||||
Reference in New Issue
Block a user