+ write_int (w, docs->n);
+ for (i = 0; i < docs->n; i++)
+ {
+ char *s = recode_string (enc, "UTF-8", docs->strings[i], -1);
+ size_t s_len = strlen (s);
+ size_t write_len = MIN (s_len, DOC_LINE_LENGTH);
+
+ write_bytes (w, s, write_len);
+ write_spaces (w, DOC_LINE_LENGTH - write_len);
+ free (s);
+ }
+}
+
+static void
+put_attrset (struct string *string, const struct attrset *attrs)
+{
+ const struct attribute *attr;
+ struct attrset_iterator i;
+
+ for (attr = attrset_first (attrs, &i); attr != NULL;
+ attr = attrset_next (attrs, &i))
+ {
+ size_t n_values = attribute_get_n_values (attr);
+ size_t j;
+
+ ds_put_cstr (string, attribute_get_name (attr));
+ ds_put_byte (string, '(');
+ for (j = 0; j < n_values; j++)
+ ds_put_format (string, "'%s'\n", attribute_get_value (attr, j));
+ ds_put_byte (string, ')');
+ }
+}
+
+static void
+write_data_file_attributes (struct sfm_writer *w,
+ const struct dictionary *d)
+{
+ struct string s = DS_EMPTY_INITIALIZER;
+ put_attrset (&s, dict_get_attributes (d));
+ write_utf8_record (w, dict_get_encoding (d), &s, 17);
+ ds_destroy (&s);
+}
+
+static void
+add_role_attribute (enum var_role role, struct attrset *attrs)
+{
+ struct attribute *attr;
+ const char *s;
+
+ switch (role)
+ {
+ case ROLE_NONE:
+ default:
+ s = "0";
+ break;
+
+ case ROLE_INPUT:
+ s = "1";
+ break;
+
+ case ROLE_OUTPUT:
+ s = "2";
+ break;
+
+ case ROLE_BOTH:
+ s = "3";
+ break;
+
+ case ROLE_PARTITION:
+ s = "4";
+ break;
+
+ case ROLE_SPLIT:
+ s = "5";
+ break;
+ }
+ attrset_delete (attrs, "$@Role");
+
+ attr = attribute_create ("$@Role");
+ attribute_add_value (attr, s);
+ attrset_add (attrs, attr);
+}
+
+static void
+write_variable_attributes (struct sfm_writer *w, const struct dictionary *d)
+{
+ struct string s = DS_EMPTY_INITIALIZER;
+ size_t n_vars = dict_get_var_cnt (d);
+ size_t n_attrsets = 0;
+ size_t i;
+
+ for (i = 0; i < n_vars; i++)
+ {
+ struct variable *v = dict_get_var (d, i);
+ struct attrset attrs;
+
+ attrset_clone (&attrs, var_get_attributes (v));
+
+ add_role_attribute (var_get_role (v), &attrs);
+ if (n_attrsets++)
+ ds_put_byte (&s, '/');
+ ds_put_format (&s, "%s:", var_get_name (v));
+ put_attrset (&s, &attrs);
+ attrset_destroy (&attrs);
+ }
+ if (n_attrsets)
+ write_utf8_record (w, dict_get_encoding (d), &s, 18);
+ ds_destroy (&s);
+}
+
+/* Write multiple response sets. If PRE_V14 is true, writes sets supported by
+ SPSS before release 14, otherwise writes sets supported only by later
+ versions. */
+static void
+write_mrsets (struct sfm_writer *w, const struct dictionary *dict,
+ bool pre_v14)
+{
+ const char *encoding = dict_get_encoding (dict);
+ struct string s = DS_EMPTY_INITIALIZER;
+ size_t n_mrsets;
+ size_t i;
+
+ if (is_encoding_ebcdic_compatible (encoding))
+ {
+ /* FIXME. */
+ return;
+ }
+
+ n_mrsets = dict_get_n_mrsets (dict);
+ if (n_mrsets == 0)
+ return;
+
+ for (i = 0; i < n_mrsets; i++)
+ {
+ const struct mrset *mrset = dict_get_mrset (dict, i);
+ char *name;
+ size_t j;
+
+ if ((mrset->type != MRSET_MD || mrset->cat_source != MRSET_COUNTEDVALUES)
+ != pre_v14)
+ continue;
+
+ name = recode_string (encoding, "UTF-8", mrset->name, -1);
+ ds_put_format (&s, "%s=", name);
+ free (name);
+
+ if (mrset->type == MRSET_MD)
+ {
+ char *counted;
+
+ if (mrset->cat_source == MRSET_COUNTEDVALUES)
+ ds_put_format (&s, "E %d ", mrset->label_from_var_label ? 11 : 1);
+ else
+ ds_put_byte (&s, 'D');
+
+ if (mrset->width == 0)
+ counted = xasprintf ("%.0f", mrset->counted.f);
+ else
+ counted = xmemdup0 (value_str (&mrset->counted, mrset->width),
+ mrset->width);
+ ds_put_format (&s, "%zu %s", strlen (counted), counted);
+ free (counted);
+ }
+ else
+ ds_put_byte (&s, 'C');
+ ds_put_byte (&s, ' ');
+
+ if (mrset->label && !mrset->label_from_var_label)
+ {
+ char *label = recode_string (encoding, "UTF-8", mrset->label, -1);
+ ds_put_format (&s, "%zu %s", strlen (label), label);
+ free (label);
+ }
+ else
+ ds_put_cstr (&s, "0 ");
+
+ for (j = 0; j < mrset->n_vars; j++)
+ {
+ const char *short_name_utf8 = var_get_short_name (mrset->vars[j], 0);
+ char *lower_name_utf8 = utf8_to_lower (short_name_utf8);
+ char *short_name = recode_string (encoding, "UTF-8",
+ lower_name_utf8, -1);
+ ds_put_format (&s, " %s", short_name);
+ free (short_name);
+ free (lower_name_utf8);
+ }
+ ds_put_byte (&s, '\n');
+ }
+
+ if (!ds_is_empty (&s))
+ write_string_record (w, ds_ss (&s), pre_v14 ? 7 : 19);
+ ds_destroy (&s);