+ struct resize_datasheet_value_aux *aux = aux_;
+
+ memcpy (value_to_data (&aux->src_value, aux->src_width),
+ (uint8_t *) src + aux->src_ofs,
+ width_to_n_bytes (aux->src_width));
+
+ aux->resize_cb (&aux->src_value, &aux->dst_value, aux->resize_cb_aux);
+
+ memcpy ((uint8_t *) dst + aux->dst_ofs,
+ value_to_data (&aux->dst_value, aux->dst_width),
+ width_to_n_bytes (aux->dst_width));
+
+ return true;
+}
+
+bool
+datasheet_resize_column (struct datasheet *ds, size_t column, int new_width,
+ void (*resize_cb) (const union value *,
+ union value *, void *aux),
+ void *resize_cb_aux)
+{
+ struct column old_col;
+ struct column *col;
+ int old_width;
+
+ assert (column < datasheet_get_n_columns (ds));
+
+ col = &ds->columns[column];
+ old_col = *col;
+ old_width = old_col.width;
+
+ if (new_width == -1)
+ {
+ if (old_width != -1)
+ {
+ datasheet_delete_columns (ds, column, 1);
+ datasheet_insert_column (ds, NULL, -1, column);
+ }
+ }
+ else if (old_width == -1)
+ {
+ union value value;
+ value_init (&value, new_width);
+ value_set_missing (&value, new_width);
+ if (resize_cb != NULL)
+ resize_cb (NULL, &value, resize_cb_aux);
+ datasheet_delete_columns (ds, column, 1);
+ datasheet_insert_column (ds, &value, new_width, column);
+ value_destroy (&value, new_width);
+ }
+ else if (source_has_backing (col->source))
+ {
+ unsigned long int n_rows = axis_get_size (ds->rows);
+ unsigned long int lrow;
+ union value src, dst;
+
+ source_release_column (col->source, col->byte_ofs, col->width);
+ allocate_column (ds, new_width, col);
+
+ value_init (&src, old_width);
+ value_init (&dst, new_width);
+ for (lrow = 0; lrow < n_rows; lrow++)
+ {
+ unsigned long int prow = axis_map (ds->rows, lrow);
+ if (!source_read (&old_col, prow, &src))
+ {
+ /* FIXME: back out col changes. */
+ return false;
+ }
+ resize_cb (&src, &dst, resize_cb_aux);
+ if (!source_write (col, prow, &dst))
+ {
+ /* FIXME: back out col changes. */
+ return false;
+ }
+ }
+
+ release_source (ds, old_col.source);
+ }
+ else
+ {
+ struct resize_datasheet_value_aux aux;
+
+ source_release_column (col->source, col->byte_ofs, col->width);
+ allocate_column (ds, new_width, col);
+
+ value_init (&aux.src_value, old_col.width);
+ aux.src_ofs = old_col.byte_ofs;
+ aux.src_width = old_col.width;
+ aux.resize_cb = resize_cb;
+ aux.resize_cb_aux = resize_cb_aux;
+ value_init (&aux.dst_value, new_width);
+ aux.dst_ofs = col->byte_ofs;
+ aux.dst_width = new_width;
+ sparse_xarray_copy (old_col.source->data, col->source->data,
+ resize_datasheet_value, &aux);
+ value_destroy (&aux.src_value, old_width);
+ value_destroy (&aux.dst_value, new_width);
+
+ release_source (ds, old_col.source);
+ }
+ return true;