4 * Date: Sat Dec 26 22:47:16 2009
6 * GNU recutils - Writer
10 /* Copyright (C) 2009-2019 Jose E. Marchesi */
12 /* This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include <rec-utils.h>
37 * Static functions defined in this file
39 static bool rec_writer_putc (rec_writer_t writer
, char c
);
40 static bool rec_writer_puts (rec_writer_t writer
, const char *s
);
42 /* Writer Data Structure
47 FILE *file_out
; /* File stream used by the writer. */
48 rec_buf_t buf_out
; /* Growable buffer used by the writer. */
51 int line
; /* Current line number. */
53 /* The following flags and options can be accesssed using the
54 corresponding rec_writer_(get/set)_FLAG function. */
56 bool collapse_p
; /* If true the writer won't introduce
57 separators between records. */
58 bool skip_comments_p
; /* If true the writer won't print out
60 enum rec_writer_mode_e mode
; /* The mode in which the writer operates.
61 See the definition of the enumerated type
62 in rec.h for a list of allowed modes. */
67 rec_writer_new_common (rec_writer_t writer
)
69 writer
->file_out
= NULL
;
70 writer
->buf_out
= NULL
;
73 writer
->collapse_p
= false;
74 writer
->skip_comments_p
= false;
75 writer
->mode
= REC_WRITER_NORMAL
;
79 rec_writer_new (FILE *file_out
)
83 new = malloc (sizeof(struct rec_writer_s
));
86 rec_writer_new_common (new);
87 new->file_out
= file_out
;
94 rec_writer_new_str (char **str
, size_t *str_size
)
98 new = malloc (sizeof(struct rec_writer_s
));
101 rec_writer_new_common (new);
102 new->buf_out
= rec_buf_new (str
, str_size
);
109 rec_writer_destroy (rec_writer_t writer
)
113 if (writer
->file_out
)
115 fflush (writer
->file_out
);
119 rec_buf_close (writer
->buf_out
);
127 rec_write_comment (rec_writer_t writer
,
128 rec_comment_t comment
)
135 if (writer
->mode
== REC_WRITER_SEXP
)
137 if (!rec_writer_puts (writer
, "(comment "))
141 if (!rec_writer_putc (writer
, '"'))
146 str
= rec_comment_text (comment
);
147 for (i
= 0; i
< strlen (str
); i
++)
151 if (!rec_writer_puts (writer
, "\\n"))
158 if (!rec_writer_putc (writer
, str
[i
]))
165 if (!rec_writer_puts (writer
, "\")"))
172 /* Every line in the comment is written preceded by a '#'
173 character. The lines composing the comments are separated by
174 newline characters. */
178 str
= strdup (rec_comment_text (comment
));
179 orig_str
= str
; /* Save a pointer to str to deallocate it later,
180 since strsep will modify the str
182 line
= strsep (&str
, "\n");
187 if (!rec_writer_putc (writer
, '\n'))
193 if (!rec_writer_putc (writer
, '#')
194 || !rec_writer_puts (writer
, line
))
201 while ((line
= strsep (&str
, "\n")));
210 rec_write_field (rec_writer_t writer
,
216 enum rec_writer_mode_e mode
= writer
->mode
;
218 if (mode
== REC_WRITER_SEXP
)
220 if (!rec_writer_puts (writer
, "(field "))
224 if (!rec_writer_puts (writer
, rec_field_char_location_str (field
)))
228 if (!rec_writer_putc (writer
, ' '))
234 if ((mode
!= REC_WRITER_VALUES
) && (mode
!= REC_WRITER_VALUES_ROW
))
236 fname
= rec_field_name (field
);
237 if (!rec_write_field_name (writer
, fname
))
243 /* Write the field value */
244 if (mode
== REC_WRITER_SEXP
)
246 if (!rec_writer_putc (writer
, ' '))
251 if (!rec_writer_putc (writer
, '"'))
257 fvalue
= rec_field_value (field
);
259 if ((strlen (fvalue
) > 0) && (mode
== REC_WRITER_NORMAL
))
261 if (!rec_writer_putc (writer
, ' '))
267 for (pos
= 0; pos
< strlen (fvalue
); pos
++)
269 if (fvalue
[pos
] == '\n')
271 if (mode
== REC_WRITER_SEXP
)
273 if (!rec_writer_puts (writer
, "\\n"))
278 else if (mode
== REC_WRITER_NORMAL
)
280 if (!rec_writer_puts (writer
, "\n+ "))
287 if (!rec_writer_putc (writer
, '\n'))
293 else if (((fvalue
[pos
] == '"') || (fvalue
[pos
] == '\\')) && (mode
== REC_WRITER_SEXP
))
295 if ((!rec_writer_putc (writer
, '\\'))
296 || (!rec_writer_putc (writer
, fvalue
[pos
])))
303 if (!rec_writer_putc (writer
, fvalue
[pos
]))
311 if (mode
== REC_WRITER_SEXP
)
313 if (!rec_writer_putc (writer
, '"'))
319 if (mode
== REC_WRITER_SEXP
)
321 if (!rec_writer_puts (writer
, ")"))
331 rec_write_field_name (rec_writer_t writer
,
332 const char *field_name
)
334 /* Field names can be written in several formats, according to the
338 * The field name is written in rec format. i.e. NP:
340 * The field name is a string: "NP"
343 enum rec_writer_mode_e mode
= writer
->mode
;
345 if (mode
== REC_WRITER_SEXP
)
347 if (!rec_writer_putc (writer
, '"'))
353 if (!rec_writer_puts (writer
, field_name
))
358 if (mode
== REC_WRITER_SEXP
)
360 if (!rec_writer_putc (writer
, '"'))
367 if (!rec_writer_putc (writer
, ':'))
377 rec_write_record (rec_writer_t writer
,
381 rec_mset_iterator_t iter
;
382 rec_mset_elem_t elem
;
384 size_t num_field
, num_elem
, num_fields
, num_elems
;
385 enum rec_writer_mode_e mode
= writer
->mode
;
389 if (mode
== REC_WRITER_SEXP
)
391 if (!rec_writer_puts (writer
, "(record "))
393 if (!rec_writer_puts (writer
, rec_record_char_location_str (record
)))
395 if (!rec_writer_puts (writer
, " (\n"))
399 num_elems
= rec_record_num_elems (record
);
400 num_fields
= rec_record_num_fields (record
);
403 iter
= rec_mset_iterator (rec_record_mset (record
));
404 while (rec_mset_iterator_next (&iter
, MSET_ANY
, (const void **) &data
, &elem
))
406 if (rec_mset_elem_type (elem
) == MSET_FIELD
)
409 rec_field_t field
= (rec_field_t
) data
;
411 if (!rec_write_field (writer
, field
))
417 /* Include a field separator. */
419 if ((mode
== REC_WRITER_VALUES_ROW
)
420 && (num_field
!= (num_fields
- 1)))
422 if(mode
== REC_WRITER_VALUES_ROW
)
424 if (!rec_writer_putc (writer
, ' '))
428 else if ((writer
->skip_comments_p
&& (num_field
!= (num_fields
- 1)))
429 || (!writer
->skip_comments_p
&& (num_elem
!= (num_elems
- 1))))
431 if (!rec_writer_putc (writer
, '\n'))
437 else if (!writer
->skip_comments_p
)
439 /* Write a comment. */
441 rec_comment_t comment
= (rec_comment_t
) data
;
443 if ((mode
!= REC_WRITER_VALUES
) && (mode
!= REC_WRITER_VALUES_ROW
))
445 if (!rec_write_comment (writer
, comment
))
451 if (num_elem
!= (num_elems
- 1))
453 if (!rec_writer_putc (writer
, '\n'))
462 rec_mset_iterator_free (&iter
);
464 if (mode
== REC_WRITER_SEXP
)
466 if (!rec_writer_puts (writer
, "))"))
476 rec_write_rset (rec_writer_t writer
,
480 rec_record_t descriptor
;
481 bool wrote_descriptor
;
483 size_t descriptor_pos
;
484 rec_mset_iterator_t iter
;
485 rec_mset_elem_t elem
;
487 enum rec_writer_mode_e mode
= writer
->mode
;
490 wrote_descriptor
= false;
492 descriptor_pos
= rec_rset_descriptor_pos (rset
);
493 descriptor
= rec_rset_descriptor (rset
);
495 /* Special case: record set containing just the record
497 if ((rec_rset_num_elems (rset
) == 0) && descriptor
)
499 rec_write_record (writer
,
500 rec_rset_descriptor (rset
));
501 rec_writer_putc (writer
, '\n');
506 iter
= rec_mset_iterator (rec_rset_mset (rset
));
507 while (rec_mset_iterator_next (&iter
, MSET_ANY
, (const void **) &data
, &elem
))
511 if (!rec_writer_putc (writer
, '\n'))
517 if (position
== descriptor_pos
)
520 && (!(wrote_descriptor
= rec_write_record (writer
,
521 rec_rset_descriptor (rset
)))))
527 if (wrote_descriptor
)
529 if (!rec_writer_puts (writer
, "\n\n"))
537 if (rec_mset_elem_type (elem
) == MSET_RECORD
)
539 ret
= rec_write_record (writer
, (rec_record_t
) data
);
541 else if (!writer
->skip_comments_p
)
543 ret
= rec_write_comment (writer
, (rec_comment_t
) data
);
546 if (!writer
->collapse_p
|| (position
== (rec_rset_num_elems (rset
) - 1)))
548 if (!rec_writer_putc (writer
, '\n'))
562 rec_mset_iterator_free (&iter
);
572 if (!wrote_descriptor
573 && (descriptor_pos
>= rec_rset_num_elems (rset
))
574 && rec_rset_descriptor (rset
))
576 if (!rec_writer_putc (writer
, '\n'))
580 if (!rec_write_record (writer
, rec_rset_descriptor (rset
)))
584 if (!rec_writer_putc (writer
, '\n'))
594 rec_write_db (rec_writer_t writer
,
601 for (i
= 0; i
< rec_db_size (db
); i
++)
603 rec_rset_t rset
= rec_db_get_rset (db
, i
);
607 if (!rec_writer_putc (writer
, '\n'))
614 if (!rec_write_rset (writer
, rset
))
625 rec_write_field_str (rec_field_t field
,
626 rec_writer_mode_t mode
)
633 writer
= rec_writer_new_str (&result
, &result_size
);
636 rec_writer_set_mode (writer
, mode
);
637 rec_write_field (writer
, field
);
638 rec_writer_destroy (writer
);
645 rec_write_field_name_str (const char *field_name
,
646 rec_writer_mode_t mode
)
653 writer
= rec_writer_new_str (&result
, &result_size
);
656 rec_writer_set_mode (writer
, mode
);
657 rec_write_field_name (writer
, field_name
);
658 rec_writer_destroy (writer
);
665 rec_write_comment_str (rec_comment_t comment
,
666 rec_writer_mode_t mode
)
673 writer
= rec_writer_new_str (&result
, &result_size
);
676 rec_writer_set_mode (writer
, mode
);
677 rec_write_comment (writer
, comment
);
678 rec_writer_destroy (writer
);
685 rec_write_string (rec_writer_t writer
,
688 return rec_writer_puts (writer
, str
);
692 rec_writer_set_collapse (rec_writer_t writer
,
695 writer
->collapse_p
= value
;
699 rec_writer_set_skip_comments (rec_writer_t writer
,
702 writer
->skip_comments_p
= value
;
706 rec_writer_set_mode (rec_writer_t writer
,
707 enum rec_writer_mode_e mode
)
717 rec_writer_putc (rec_writer_t writer
, char c
)
722 if (writer
->file_out
)
724 ret
= (fputc (c
, writer
->file_out
) != EOF
);
728 ret
= (rec_buf_putc (c
, writer
->buf_out
) != EOF
);
735 rec_writer_puts (rec_writer_t writer
, const char *s
)
740 if (writer
->file_out
)
742 ret
= (fputs (s
, writer
->file_out
) != EOF
);
746 ret
= (rec_buf_puts (s
, writer
->buf_out
) != EOF
);
752 /* End of rec-writer.c */