mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2026-10-24 23:02:27 +00:00
Merge pull request #318 from AppleCommander/prep-for-15.0
Prep for 15.0
This commit is contained in:
12 files changed
+146
-116
No files matched your search
@@ -25,6 +25,7 @@ import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk;
|
||||
import io.github.applecommander.acx.base.ReusableCommandOptions;
|
||||
import io.github.applecommander.acx.converter.IntegerTypeConverter;
|
||||
import org.applecommander.source.Source;
|
||||
import org.applecommander.util.GlobGenerator;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
@@ -45,9 +46,9 @@ import static picocli.CommandLine.*;
|
||||
will (essentially) search for likely HGR candidates. Note that size is the only
|
||||
optional allowed to repeat due to ANDing of the criteria.
|
||||
|
||||
For filename comparisons, the '%%' can be used similar to the SQL 'LIKE' operator.
|
||||
For filename comparisons, simple 'glob' patterns are allowed of '*' or '?'.
|
||||
There is no keyword and it is implicitly case insensitive. An example using this is:
|
||||
--name='%%myname%%'
|
||||
--name='*myname*'
|
||||
which will match 'MYNAME', 'myname.txt', and 'Zmyname'.
|
||||
|
||||
Number value support allows the '$' or '0x' prefix for hex numbers.
|
||||
@@ -64,14 +65,8 @@ public class SearchCommand extends ReusableCommandOptions {
|
||||
@Option(names = "--name", description = "Filename (case insensitive).", paramLabel = "FILENAME")
|
||||
private void applyNameFilter(String filename) {
|
||||
Objects.requireNonNull(filename);
|
||||
if (filename.contains("%")) {
|
||||
// This is a one-off for the LIKE operation
|
||||
Pattern pattern = Pattern.compile("(?i)" + filename.replace("%", ".*"));
|
||||
criteria = criteria.and(fileEntry -> pattern.matcher(fileEntry.getFilename()).matches());
|
||||
}
|
||||
else {
|
||||
addCriteria(String.CASE_INSENSITIVE_ORDER, filename, s -> s, FileEntry::getFilename);
|
||||
}
|
||||
Pattern pattern = Pattern.compile(GlobGenerator.globToRegex(filename, false));
|
||||
criteria = criteria.and(fileEntry -> pattern.matcher(fileEntry.getFilename()).matches());
|
||||
}
|
||||
@Option(names = "--size", description = "File size.", paramLabel = "SIZE")
|
||||
private void applySizeFilter(String[] filesizes) {
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
# - Naming JAR file.
|
||||
# - The build will insert this into a file that is read at run time as well.
|
||||
# - Use SNAPSHOT for development and remove for a release.
|
||||
version=15.0-SNAPSHOT
|
||||
version=15.0
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
package com.webcodepro.applecommander.util.filestreamer;
|
||||
|
||||
import com.webcodepro.applecommander.storage.*;
|
||||
import com.webcodepro.applecommander.util.GlobGenerator;
|
||||
import org.applecommander.util.GlobGenerator;
|
||||
import org.applecommander.source.Source;
|
||||
|
||||
import java.io.File;
|
||||
@@ -140,7 +140,7 @@ public class FileStreamer {
|
||||
String filePath = tuple.fileEntry.getFilename();
|
||||
String fullPath = tuple.fullPath();
|
||||
for (String glob : this.globs) {
|
||||
String regex = GlobGenerator.globToRegex(glob, tuple.formattedDisk);
|
||||
String regex = GlobGenerator.globToRegex(glob, tuple.formattedDisk.canHaveDirectories());
|
||||
if (filePath.matches(regex) || fullPath.matches(regex)) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
Yet to do
|
||||
==========
|
||||
1. Need some logging capability to capture messages (instead of a single exception) across an entire "file store".
|
||||
2. There are coded assertions that likely should be actual logging.
|
||||
3. Review exceptions and see if there should be some structure; now defaulting to runtime exceptions.
|
||||
@@ -0,0 +1,25 @@
|
||||
/// Contains most of the device interfaces and implementation.
|
||||
///
|
||||
/// Some creational patterns for `TrackSectorDevice`:
|
||||
///
|
||||
/// * 140K DOS-ordered sectors:
|
||||
/// ```
|
||||
/// Source source = DataBufferSource.create(DiskConstants.APPLE_140KB_DISK, "filename.do").get();
|
||||
/// TrackSectorDevice device = new DosOrderedTrackSectorDevice(source);
|
||||
/// ```
|
||||
///
|
||||
/// * 140K ProDOS-ordered sectors:
|
||||
/// ```
|
||||
/// Source source = DataBufferSource.create(DiskConstants.APPLE_140KB_DISK, "filename.po").get();
|
||||
/// TrackSectorDevice device = new BlockToTrackSectorAdapter(new ProdosOrderedBlockDevice(source,
|
||||
/// BlockDevice.STANDARD_BLOCK_SIZE), new ProdosBlockToTrackSectorAdapterStrategy());
|
||||
/// ```
|
||||
///
|
||||
/// * 140K Nibble-ordered sectors:
|
||||
/// ```
|
||||
/// Source source = DataBufferSource.create(DiskConstants.APPLE_140KB_NIBBLE_DISK, "filename.nib").get();
|
||||
/// TrackSectorDevice device = SkewedTrackSectorDevice.physicalToDosSkew(
|
||||
/// TrackSectorNibbleDevice.create(new NibbleImage(source), 16));
|
||||
/// ```
|
||||
///
|
||||
package org.applecommander.device;
|
||||
@@ -0,0 +1,35 @@
|
||||
/// GameDOS, Written by usotsuki.
|
||||
///
|
||||
/// This is a single-load read-only program launcher that does not require DOS.
|
||||
/// It only resides on track 0, freeing up the rest of the disk for ... games.
|
||||
/// There dos not appear to be any presence on the internet, but the source and
|
||||
/// some example disks do exist in the Asimov archives.
|
||||
///
|
||||
/// GameDOS requires a DOS-ordered 140K disk.
|
||||
///
|
||||
/// There is a readme that gives information on the disk format and (expected)
|
||||
/// file types:
|
||||
///
|
||||
/// ```c
|
||||
/// struct gd_dirent {
|
||||
/// char type; /* 'A' = Applesoft, 'B' = Binary */
|
||||
/// unsigned char track1;
|
||||
/// unsigned char sector1;
|
||||
/// unsigned short int meta; /* load addr for Binary,
|
||||
/// end of code addr for Applesoft */
|
||||
/// char filename[26]; /* space-padded */
|
||||
/// unsigned char len; /* in sectors; file must be contiguous */
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// There are 16 directory entries, stored from $BE00 up (track 00 sectors E and F).
|
||||
///
|
||||
/// The following types are defined but not yet implemented:
|
||||
///
|
||||
/// * T - Text
|
||||
/// * S - System, loads at $0800 (NOT $2000 as ProDOS!)
|
||||
/// * P - Picture, loads at $2000
|
||||
/// * I - Integer Basic
|
||||
///
|
||||
/// The AppleCommander implementation assumes all types are currently valid.
|
||||
package org.applecommander.os.gamedos;
|
||||
@@ -27,14 +27,18 @@ import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A DataBuffer is a bunch of bytes with Apple II knowledge.
|
||||
* This shares the technical details as well as the actual image data
|
||||
* across all components in the application. There are two sets of
|
||||
* accessors get/put the index the buffer and read/write that
|
||||
* navigate via position. Note that read and write can overrun
|
||||
* the buffer and generate an error.
|
||||
*/
|
||||
/// A `DataBuffer` is a bunch of bytes with Apple II knowledge.
|
||||
/// This shares the technical details as well as the actual image data
|
||||
/// across all components in the application.
|
||||
///
|
||||
/// There are two sets of accessors:
|
||||
///
|
||||
/// * `get`/`put` access the buffer via an index (explicit positioning); and
|
||||
/// * `read`/`write` that navigate via position. Note that read and write
|
||||
/// can overrun the buffer and generate an error.
|
||||
///
|
||||
/// Creational patterns are via the `wrap` methods for existing data
|
||||
/// or via the `create` method.
|
||||
public class DataBuffer {
|
||||
private static final int[] BIT_MASKS = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/// `FileExtensions` is the one place that holds all possible file extensions.
|
||||
/// It can be used in a user-interface context by using the description in
|
||||
/// conjunction with the glob-pattern file extensions or just by utilizing
|
||||
/// all the file extensions.
|
||||
///
|
||||
/// There are no accessors, just the static variables.
|
||||
public class FileExtensions {
|
||||
public static final List<FileExtension> FILE_FILTERS;
|
||||
public static final List<String> DISK_IMAGE_EXTENSIONS;
|
||||
|
||||
+16
-21
@@ -17,30 +17,25 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.util;
|
||||
|
||||
import com.webcodepro.applecommander.storage.FormattedDisk;
|
||||
package org.applecommander.util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility methods to support glob-style patterns with Apple file names.
|
||||
* <br>
|
||||
* Glob patterns supported:<ul>
|
||||
* <li><code>*</code> = matches zero or more characters</li>
|
||||
* <li><code>?</code> = matches exactly one character</li>
|
||||
* <li><code>**</code> = match any number of directories</li>
|
||||
* <li><code>\x</code> = escape character</li>
|
||||
* </ul>
|
||||
*/
|
||||
/// Utility methods to support glob-style patterns with Apple file names.
|
||||
///
|
||||
/// Glob patterns supported:
|
||||
///
|
||||
/// - `*` = matches zero or more characters
|
||||
/// - `?` = matches exactly one character
|
||||
/// - `**` = match any number of directories
|
||||
/// - `\x` = escape character
|
||||
public class GlobGenerator {
|
||||
/**
|
||||
* Transform glob pattern into a regex expression. This needs to take into effect the "valid"
|
||||
* character set used in the filesystem as well as if directories are supported.
|
||||
*/
|
||||
public static String globToRegex(String glob, FormattedDisk disk) {
|
||||
private static final Set<Character> REGEX_SPECIAL_CHARS = Set.of('?', '*', '^', '$');
|
||||
|
||||
/// Transform glob pattern into a regex expression. This needs to take into effect the "valid"
|
||||
/// character set used in the filesystem as well as if directories are supported.
|
||||
public static String globToRegex(String glob, boolean supportsDirectories) {
|
||||
StringBuilder regex = new StringBuilder();
|
||||
Set<Character> regexSpecialChars = Set.of('?', '*', '^', '$');
|
||||
regex.append("(?i)^");
|
||||
for (int i = 0; i < glob.length(); i++) {
|
||||
char c = glob.charAt(i);
|
||||
@@ -54,7 +49,7 @@ public class GlobGenerator {
|
||||
i++;
|
||||
}
|
||||
// if we have directories (currently just ProDOS) exclude the separator '/'
|
||||
else if (disk.canHaveDirectories()) {
|
||||
else if (supportsDirectories) {
|
||||
regex.append("[^/]*");
|
||||
}
|
||||
// otherwise we want everything
|
||||
@@ -66,7 +61,7 @@ public class GlobGenerator {
|
||||
case '?' -> regex.append(".");
|
||||
case '\\' -> {
|
||||
if (nextc != 0) {
|
||||
if (regexSpecialChars.contains(nextc)) regex.append("\\\\");
|
||||
if (REGEX_SPECIAL_CHARS.contains(nextc)) regex.append("\\\\");
|
||||
regex.append(nextc);
|
||||
i++;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2026 by Robert Greene and others
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.util;
|
||||
|
||||
import com.webcodepro.applecommander.storage.DiskConstants;
|
||||
import com.webcodepro.applecommander.storage.os.dos33.DosFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk;
|
||||
import org.applecommander.device.BlockDevice;
|
||||
import org.applecommander.device.DosOrderedTrackSectorDevice;
|
||||
import org.applecommander.device.ProdosOrderedBlockDevice;
|
||||
import org.applecommander.device.TrackSectorDevice;
|
||||
import org.applecommander.hint.Hint;
|
||||
import org.applecommander.source.DataBufferSource;
|
||||
import org.applecommander.source.Source;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class GlobGeneratorTest {
|
||||
public static final ProdosFormatDisk prodosFormatDisk;
|
||||
static {
|
||||
Source source = DataBufferSource.create(DiskConstants.APPLE_140KB_DISK, "new-disk").get();
|
||||
BlockDevice blockDevice = new ProdosOrderedBlockDevice(source, BlockDevice.STANDARD_BLOCK_SIZE);
|
||||
ProdosFormatDisk[] disks = ProdosFormatDisk.create("deleteme.po", "nothere", blockDevice);
|
||||
prodosFormatDisk = disks[0];
|
||||
}
|
||||
public static final DosFormatDisk dosFormatDisk;
|
||||
static {
|
||||
Source source = DataBufferSource.create(DiskConstants.APPLE_140KB_DISK, "new-disk").get();
|
||||
TrackSectorDevice device = new DosOrderedTrackSectorDevice(source, Hint.DOS_SECTOR_ORDER);
|
||||
DosFormatDisk[] disks = DosFormatDisk.create("deleteme.do", device);
|
||||
dosFormatDisk = disks[0];
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoDirectories() {
|
||||
assertEquals("(?i)^.*$", GlobGenerator.globToRegex("*", dosFormatDisk));
|
||||
assertEquals("(?i)^.*\\.txt$", GlobGenerator.globToRegex("*.txt", dosFormatDisk));
|
||||
assertEquals("(?i)^file.\\.txt$", GlobGenerator.globToRegex("file?.txt", dosFormatDisk));
|
||||
assertEquals("(?i)^asterisks\\\\*$", GlobGenerator.globToRegex("asterisks\\*", dosFormatDisk));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithDirectories() {
|
||||
assertEquals("(?i)^[^/]*$", GlobGenerator.globToRegex("*", prodosFormatDisk));
|
||||
assertEquals("(?i)^[^/]*\\.txt$", GlobGenerator.globToRegex("*.txt", prodosFormatDisk));
|
||||
assertEquals("(?i)^.*/[^/]*\\.txt$", GlobGenerator.globToRegex("**/*.txt", prodosFormatDisk));
|
||||
assertEquals("(?i)^file.\\.txt$", GlobGenerator.globToRegex("file?.txt", prodosFormatDisk));
|
||||
assertEquals("(?i)^asterisks\\\\*$", GlobGenerator.globToRegex("asterisks\\*", prodosFormatDisk));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2026 by Robert Greene and others
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package org.applecommander.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class GlobGeneratorTest {
|
||||
@Test
|
||||
public void testNoDirectories() {
|
||||
assertEquals("(?i)^.*$", GlobGenerator.globToRegex("*", false));
|
||||
assertEquals("(?i)^.*\\.txt$", GlobGenerator.globToRegex("*.txt", false));
|
||||
assertEquals("(?i)^file.\\.txt$", GlobGenerator.globToRegex("file?.txt", false));
|
||||
assertEquals("(?i)^asterisks\\\\*$", GlobGenerator.globToRegex("asterisks\\*", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithDirectories() {
|
||||
assertEquals("(?i)^[^/]*$", GlobGenerator.globToRegex("*", true));
|
||||
assertEquals("(?i)^[^/]*\\.txt$", GlobGenerator.globToRegex("*.txt", true));
|
||||
assertEquals("(?i)^.*/[^/]*\\.txt$", GlobGenerator.globToRegex("**/*.txt", true));
|
||||
assertEquals("(?i)^file.\\.txt$", GlobGenerator.globToRegex("file?.txt", true));
|
||||
assertEquals("(?i)^asterisks\\\\*$", GlobGenerator.globToRegex("asterisks\\*", true));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
find . -name "*.java" -not -name "Sleak.java" -not -name module-info.java | xargs grep -L "GNU General Public License"
|
||||
find . -name "*.java" -not -name "Sleak.java" -not -name module-info.java -not -name package-info.java | xargs grep -L "GNU General Public License"
|
||||
Reference in new issue
Block a user