From: Ian Jackson Date: Tue, 6 Apr 2021 18:56:26 +0000 (+0100) Subject: shapelib: Add "extra fields" feature X-Git-Tag: otter-0.5.0~148 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=f3887e5592104e3b7de87cb7e317a50793e91367;p=otter.git shapelib: Add "extra fields" feature We'll define one of these in a moment. Signed-off-by: Ian Jackson --- diff --git a/media-scraper b/media-scraper index ab6d39d8..b1db5f40 100755 --- a/media-scraper +++ b/media-scraper @@ -223,7 +223,7 @@ foreach my $groupname (sort keys %$groups) { my $method_impl = $method_fn->($scraper, $method); foreach (split(/\n/, $gcfg->('files'))) { s/^\s+//; - next if m/^\#/ || m/^$/; + next if m/^\#/ || m/^$/ || m/^\:/; m/^(\S+)\s+(\S+)/ or die "bad line in files: \`$_'"; my $lministem = $1; my $rministem = $2; diff --git a/src/shapelib-toml.rs b/src/shapelib-toml.rs index b5736292..99e180b2 100644 --- a/src/shapelib-toml.rs +++ b/src/shapelib-toml.rs @@ -54,9 +54,10 @@ pub struct LibraryTomlFile { // `GroupDefn` is processed. #[derive(Debug,Deserialize)] pub struct GroupDefn { - /// `files` is a multi-line string, each line of which has three - /// fields (the first two terminated by whitespace). The fields - /// are those in [`FileData`]. `#` comments are supported. + /// `files` is a multi-line string, each line of which has + /// (normally) three fields (the leading ones terminated by + /// whitespace). The fields are those in [`FileData`]. `#` + /// comments are supported. /// /// Each non-empty non-comment line in `files` specifies a single /// SVG to be made aavailable as a piece. @@ -73,6 +74,16 @@ pub struct GroupDefn { /// Item names are conventionally structured using a hierarchical /// name with `-` between the components. Do not put `/` or `_` in /// item names. + /// + /// It is also possible to specify additional data for each item by + /// adding fields to each line. This is done by adding a line at + /// the start starting with `:` and then additing one additional + /// whitespace separated value on each data line. Unknown + /// `fieldname` values are ignored. + /// + /// The values for these extra fields come just before the + /// dwscription, after the other whitespace-delimited fields, in the + /// same order as specified in the `:` heading line. pub files: FileList, /// See the discussioin of the item name. @@ -202,7 +213,7 @@ pub struct FileList(pub Vec); /// Contents of each line in [`files`](GroupDefn::files) /// -/// This is not a key value list. The first two fields are found by +/// This is not a key value list. The leading fields are found by /// splitting on whitespace, and the final field is the rest of the /// line. #[derive(Deserialize,Debug)] @@ -219,6 +230,9 @@ pub struct FileData { #[cfg(doc)] pub r_file_spec: String, #[cfg(not(doc))] pub r_file_spec: (), + /// Extra fields, normally not present. + pub extra_fields: HashMap, + /// Desscription. (Shown hn the game log, for example.) /// Will be HTML-escaped. pub desc: String, diff --git a/src/shapelib.rs b/src/shapelib.rs index c07d0f35..1f0443d1 100644 --- a/src/shapelib.rs +++ b/src/shapelib.rs @@ -105,6 +105,8 @@ pub enum LibraryLoadError { #[error("{:?}",&self)] FilesListLineMissingWhitespace(usize), #[error("{:?}",&self)] + FilesListFieldsMustBeAtStart(usize), + #[error("{:?}",&self)] MissingSubstituionToken(&'static str), #[error("{:?}",&self)] RepeatedSubstituionToken(&'static str), @@ -885,9 +887,20 @@ impl TryFrom for FileList { // #[throws(LLE)] fn try_from(s: String) -> Result { let mut o = Vec::new(); + let mut xfields = Vec::new(); for (lno,l) in s.lines().enumerate() { let l = l.trim(); if l=="" || l.starts_with("#") { continue } + if let Some(xfields_spec) = l.strip_prefix(':') { + if ! (o.is_empty() && xfields.is_empty()) { + throw!(LLE::FilesListFieldsMustBeAtStart(lno)); + } + xfields = xfields_spec.split_ascii_whitespace() + .filter(|s| !s.is_empty()) + .map(|s| s.to_owned()) + .collect::>(); + continue; + } let mut remain = &*l; let mut n = ||{ let ws = remain.find(char::is_whitespace) @@ -898,8 +911,11 @@ impl TryFrom for FileList { }; let item_spec = n()?; let _r_file_spec = n()?; + let extra_fields = xfields.iter() + .map(|field| Ok::<_,LLE>((field.to_owned(), n()?.to_owned()))) + .collect::>()?; let desc = remain.to_owned(); - o.push(FileData{ item_spec, r_file_spec: (), desc }); + o.push(FileData{ item_spec, r_file_spec: (), extra_fields, desc }); } Ok(FileList(o)) }