Self(BTreeMap::new())
}
+ pub fn contains_name(&self, name: &Identifier) -> bool {
+ self.0.contains_key(name)
+ }
+
+ pub fn insert(&mut self, name: Identifier, values: Vec<String>) {
+ self.0.insert(name, values);
+ }
+
pub fn append(&mut self, other: &mut Self) {
self.0.append(&mut other.0)
}
endian: EndianSettings,
datum: &'a Datum,
encoding: &'static Encoding,
+
+ /// If true, the output will remove leading and trailing spaces from numeric
+ /// values, and trailing spaces from string values. (This might make the
+ /// output narrower than the requested width.)
+ trim_spaces: bool,
+
+ /// If true, the output will include a double quote before and after string
+ /// values.
+ quote_strings: bool,
}
#[cfg(test)]
write!(f, "{byte:02x}")?;
}
} else {
- write!(
- f,
- "{}",
- self.encoding.decode_without_bom_handling(&string.0).0
- )?;
+ let quote = if self.quote_strings { "\"" } else { "" };
+ let s = self.encoding.decode_without_bom_handling(&string.0).0;
+ let s = if self.trim_spaces {
+ s.trim_end_matches(' ')
+ } else {
+ &s
+ };
+ write!(f, "{quote}{s}{quote}")?;
}
return Ok(());
}
encoding,
settings: &settings.formats,
endian: settings.endian,
+ trim_spaces: false,
+ quote_strings: false,
}
}
pub fn with_settings(self, settings: &'b Settings) -> Self {
pub fn with_endian(self, endian: EndianSettings) -> Self {
Self { endian, ..self }
}
+ pub fn with_trimming(self) -> Self {
+ Self {
+ trim_spaces: true,
+ ..self
+ }
+ }
+ pub fn with_quoted_string(self) -> Self {
+ Self {
+ quote_strings: true,
+ ..self
+ }
+ }
fn fmt_binary(&self, f: &mut Formatter) -> FmtResult {
let output = self.to_binary().unwrap();
for b in output {
} else {
"Unknown"
};
- let w = self.format.w();
+ let w = if self.trim_spaces { 0 } else { self.format.w() };
write!(f, "{s:>0$.*}", w)
} else {
self.overflow(f)
_ => (),
}
+ if self.trim_spaces {
+ return write!(f, ".");
+ }
+
let w = self.format.w() as isize;
let d = self.format.d() as isize;
let dot_position = match self.format.type_ {
}
fn overflow(&self, f: &mut Formatter<'_>) -> FmtResult {
- for _ in 0..self.format.w {
+ if self.trim_spaces {
write!(f, "*")?;
+ } else {
+ for _ in 0..self.format.w {
+ write!(f, "*")?;
+ }
}
Ok(())
}
// Assemble number.
let magnitude = rounder.format(decimals as usize);
let mut output = SmallString::<[u8; 40]>::new();
- for _ in width..self.format.w() {
- output.push(' ');
+ if !self.trim_spaces {
+ for _ in width..self.format.w() {
+ output.push(' ');
+ }
}
if negative {
output.push_str(&style.neg_prefix.s);
}
}
- debug_assert!(output.len() >= self.format.w());
+ debug_assert!(self.trim_spaces || output.len() >= self.format.w());
debug_assert!(output.len() <= self.format.w() + style.extra_bytes);
f.write_str(&output)?;
return Ok(true);
width += fraction_width;
let mut output = SmallString::<[u8; 40]>::new();
- for _ in width..self.format.w() {
- output.push(' ');
+ if !self.trim_spaces {
+ for _ in width..self.format.w() {
+ output.push(' ');
+ }
}
if number < 0.0 {
output.push_str(&style.neg_prefix.s);
"{} for {number} width={width} fraction_width={fraction_width}: {output:?}",
self.format
);
- debug_assert!(output.len() >= self.format.w());
+ debug_assert!(self.trim_spaces || output.len() >= self.format.w());
debug_assert!(output.len() <= self.format.w() + style.extra_bytes);
f.write_str(&output)?;
Ok(true)
_ => unreachable!(),
}
}
- write!(f, "{:>1$}", &output, self.format.w())
+ if !self.trim_spaces {
+ write!(f, "{:>1$}", &output, self.format.w())
+ } else {
+ f.write_str(&output)
+ }
}
fn month(&self, f: &mut Formatter<'_>, number: f64) -> FmtResult {
if let Some(month) = month_name(number as u32) {
- write!(f, "{month:.*}", self.format.w())
+ if !self.trim_spaces {
+ write!(f, "{month:.*}", self.format.w())
+ } else {
+ f.write_str(month)
+ }
} else {
self.missing(f)
}
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use encoding_rs::Encoding;
use indexmap::set::MutableValues;
+use itertools::Itertools;
use thiserror::Error as ThisError;
pub use crate::sys::raw::{CategoryLabels, Compression};
},
#[error(
- "At offsets {:#x}...{:#x}, record types 3 and 4 may not add value labels to one or more long string variables: {variables:?}", .offsets.start, .offsets.end
+ "At offsets {:#x}...{:#x}, record types 3 and 4 may not add value labels to one or more long string variables: {}", .offsets.start, .offsets.end, variables.iter().join(", ")
)]
InvalidLongStringValueLabels {
offsets: Range<u64>,
string_var: Identifier,
},
+ #[error("{variable} has duplicate value labels for the following value(s): {}", values.iter().join(", "))]
+ DuplicateValueLabels {
+ variable: Identifier,
+ values: Vec<String>,
+ },
+
#[error("Invalid multiple response set name. {0}")]
InvalidMrSetName(IdError),
len: usize,
},
+ #[error("Variable with short name {short_name} listed in very long string record with width {width} has segment {index} of width {actual} (expected {expected}).")]
+ VeryLongStringInvalidSegmentWidth {
+ short_name: Identifier,
+ width: u16,
+ index: usize,
+ actual: usize,
+ expected: usize,
+ },
+
#[error("Invalid variable name in long string value label record. {0}")]
InvalidLongStringValueLabelName(IdError),
});
}
+ let written_by_readstat = headers.header.eye_catcher.contains("ReadStat");
for dict_index in dict_indexes {
let variable = dictionary.variables.get_index_mut2(dict_index).unwrap();
+ let mut duplicates = Vec::new();
for ValueLabel {
datum: value,
label,
} in record.labels.iter().cloned()
{
- let value = value.decode(variable.width);
- variable.value_labels.insert(value, label);
+ let datum = value.decode(variable.width);
+ if variable.value_labels.insert(datum, label).is_some() {
+ duplicates.push(value);
+ }
+ }
+ if written_by_readstat {
+ // Ignore any possible duplicates. ReadStat is buggy and emits
+ // value labels whose values are longer than string variables'
+ // widths, that are identical in the actual width of the
+ // variable, e.g. both values "ABC123" and "ABC456" for a string
+ // variable with width 3.
+ } else if !duplicates.is_empty() {
+ warn(Error::DuplicateValueLabels {
+ variable: variable.name.clone(),
+ values: duplicates
+ .iter()
+ .map(|value| {
+ value
+ .decode(variable.width)
+ .display(variable.print_format, variable.encoding)
+ .with_trimming()
+ .with_quoted_string()
+ .to_string()
+ })
+ .collect(),
+ });
}
}
}
short_names.push(segment.short_names[0].clone());
let segment_width = segment.width.as_string_width().unwrap_or(0);
if segment_width.next_multiple_of(8) != alloc_width.next_multiple_of(8) {
- warn(dbg!(Error::TBD));
+ warn(Error::VeryLongStringInvalidSegmentWidth {
+ short_name: record.short_name.clone(),
+ width: record.length,
+ index: i,
+ actual: segment_width,
+ expected: alloc_width,
+ });
continue 'outer;
}
}
}
}
}
+
+/*
+trait Quoted {
+ fn quoted(self) -> WithQuotes<Self>
+ where
+ Self: Display + Sized;
+}
+
+impl<T> Quoted for T
+where
+ T: Display,
+{
+ fn quoted(self) -> WithQuotes<Self> {
+ WithQuotes(self)
+ }
+}
+
+struct WithQuotes<T>(T)
+where
+ T: Display;
+
+impl<T> Display for WithQuotes<T>
+where
+ T: Display,
+{
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "\"{}\"", &self.0)
+ }
+}
+*/
use encoding_rs::{mem::decode_latin1, Encoding};
use flate2::read::ZlibDecoder;
+use itertools::Itertools;
use num::Integer;
use std::{
borrow::{Borrow, Cow},
#[error("Attribute record missing left parenthesis, in {0:?}.")]
AttributeMissingLParen(String),
- #[error("Attribute record missing new-line, in {0:?}.")]
- AttributeMissingNewline(String),
+ #[error("Attribute for {name}[{}] lacks value.", index + 1)]
+ AttributeMissingValue { name: Identifier, index: usize },
- #[error("Attribute record missing quotations, in {0:?}.")]
- AttributeMissingQuotes(String),
+ #[error("Attribute for {name}[{}] missing quotations.", index + 1)]
+ AttributeMissingQuotes { name: Identifier, index: usize },
+
+ #[error("Duplicate attributes for variable {variable}: {}.", attributes.iter().join(", "))]
+ DuplicateVariableAttributes {
+ variable: Identifier,
+ attributes: Vec<Identifier>,
+ },
+
+ #[error("Duplicate dataset attributes with names: {}.", attributes.iter().join(", "))]
+ DuplicateFileAttributes { attributes: Vec<Identifier> },
#[error("Compression bias is {0} instead of the usual values of 0 or 100.")]
UnexpectedBias(f64),
max: Self::MAX_INDEXES,
});
} else if n == 0 {
+ dbg!();
warn(Warning::NoVarIndexes {
offset: index_offset,
});
let mut values = Vec::new();
loop {
let Some((value, rest)) = input.split_once('\n') else {
- return Err(Warning::AttributeMissingNewline(input.into()));
+ return Err(Warning::AttributeMissingValue {
+ name: name.clone(),
+ index: values.len(),
+ });
};
if let Some(stripped) = value
.strip_prefix('\'')
{
values.push(stripped.into());
} else {
- decoder.warn(Warning::AttributeMissingQuotes(value.into()));
+ decoder.warn(Warning::AttributeMissingQuotes {
+ name: name.clone(),
+ index: values.len(),
+ });
values.push(value.into());
}
if let Some(rest) = rest.strip_prefix(')') {
decoder: &mut Decoder,
mut input: &'a str,
sentinel: Option<char>,
- ) -> Result<(Attributes, &'a str), Warning> {
+ ) -> Result<(Attributes, &'a str, Vec<Identifier>), Warning> {
let mut attributes = BTreeMap::new();
+ let mut duplicates = Vec::new();
let rest = loop {
match input.chars().next() {
None => break input,
c if c == sentinel => break &input[1..],
_ => {
let (attribute, rest) = Attribute::parse(decoder, input)?;
- // XXX report duplicate name
+ if attributes.contains_key(&attribute.name) {
+ duplicates.push(attribute.name.clone());
+ }
attributes.insert(attribute.name, attribute.values);
input = rest;
}
}
};
- Ok((Attributes(attributes), rest))
+ Ok((Attributes(attributes), rest, duplicates))
}
}
fn decode(self, decoder: &mut Decoder) -> FileAttributesRecord {
let input = decoder.decode(&self.0.text);
match Attributes::parse(decoder, &input, None).issue_warning(&mut decoder.warn) {
- Some((set, rest)) => {
+ Some((set, rest, duplicates)) => {
+ if !duplicates.is_empty() {
+ decoder.warn(Warning::DuplicateFileAttributes {
+ attributes: duplicates,
+ });
+ }
if !rest.is_empty() {
decoder.warn(dbg!(Warning::TBD));
}
.new_identifier(long_var_name)
.and_then(Identifier::must_be_ordinary)
.map_err(Warning::InvalidAttributeVariableName)?;
- let (attributes, rest) = Attributes::parse(decoder, rest, Some('/'))?;
+ let (attributes, rest, duplicates) = Attributes::parse(decoder, rest, Some('/'))?;
+ if !duplicates.is_empty() {
+ decoder.warn(Warning::DuplicateVariableAttributes {
+ variable: long_var_name.clone(),
+ attributes: duplicates,
+ });
+ }
let var_attribute = VarAttributes {
long_var_name,
attributes,
+File header claims 1 variable positions but 34 were read from file.
+
+Variable with short name STR1 listed in very long string record with width 256 has segment 1 of width 9 (expected 4).
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭──────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├──────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1 │ 1│ │Nominal │Input│ 32│Left │A255 │A255 │ │
+│str1_a│ 2│ │Nominal │Input│ 9│Left │A9 │A9 │ │
+╰──────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+Duplicate dataset attributes with names: Attr1.
+
+Duplicate attributes for variable FIRSTVAR: fred.
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│firstvar│ 1│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭───────────────────────┬─────╮
+│Variable and Name │Value│
+├───────────────────────┼─────┤
+│(dataset) Attr1│value│
+├───────────────────────┼─────┤
+│firstvar fred │23 │
+╰───────────────────────┴─────╯
+STR1 has duplicate value labels for the following value(s): "xyzzy"
+
+NUM1 has duplicate value labels for the following value(s): 1
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│ 1│ │Nominal │Input│ 6│Left │A6 │A6 │ │
+│num1│ 2│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭─────────────────────┬───╮
+│Variable Value │ │
+├─────────────────────┼───┤
+│str1 xyzzy │one│
+├─────────────────────┼───┤
+│num1 1 │one│
+╰─────────────────────┴───╯
+Attribute for Attr1[1] lacks value.
+
+Attribute for fred[2] lacks value.
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│firstvar│ 1│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+At offset 0xe8, following value label record, found record type 7 instead of expected type 4 for variable index record
+At offset 0xd4, number of value labels (2147483647) is greater than the maximum number 536870911.
+At offsets 0xf4...0x114, record types 3 and 4 may not add value labels to one or more long string variables: STR1
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│ 1│ │Nominal │Input│ 9│Left │A9 │A9 │ │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+Attribute for Attr1[1] missing quotations.
+
+Attribute for fred[1] missing quotations.
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│firstvar│ 1│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭───────────────────────┬─────╮
+│Variable and Name │Value│
+├───────────────────────┼─────┤
+│(dataset) Attr1│value│
+├───────────────────────┼─────┤
+│firstvar fred │23 │
+╰───────────────────────┴─────╯
+At offset 0x110, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [3, 4]
+
+At offset 0x138, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [5, 6]
+
+At offset 0x160, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [7, 8]
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│ 1│ │Nominal │Input│ 6│Left │A6 │A6 │ │
+│num1│ 2│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+At offset 0x110, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [2]
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│ 1│ │Nominal │Input│ 9│Left │A9 │A9 │ │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+At offset 0xe8, at least one valid variable index for value labels is required but none were specified.
+
+This system file does not indicate its own character encoding. For best results, specify an encoding explicitly. Use SYSFILE INFO with ENCODING="DETECT" to analyze the possible encodings.
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│num1│ 1│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
# Value label with no variables.
3; 1; 1.0; i8 3; s7 "one"; 4; >>0<<;
+
+# End of dictionary.
+>>999; 0<<;
+At offset 0x110, the first variable index is for a string variable but the following variable indexes are for numeric variables: [2]
+
+╭──────────────────────┬────────────────────────╮
+│ Created │ 01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│ Compression │SAV │
+│ Number of Cases│Unknown │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│ │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│ 1│ │Nominal │Input│ 6│Left │A6 │A6 │ │
+│num1│ 2│ │ │Input│ 8│Right │F8.0 │F8.0 │ │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭─────────────────────┬───╮
+│Variable Value │ │
+├─────────────────────┼───┤
+│str1 xyzzy │one│
+╰─────────────────────┴───╯
7; 14; 1; COUNT (
"STR1=00256"; i8 0; i8 9;
);
-
+
dnl Character encoding record.
7; 20; 1; 12; "windows-1252";