1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
5 * Copyright (C) 2003 Sven Neumann <sven@gimp.org>
7 * This library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <https://www.gnu.org/licenses/>.
29 #include <gio/gwin32outputstream.h>
31 #include <gio/gunixoutputstream.h>
34 #include "libgimpbase/gimpbase.h"
36 #include "gimpconfigtypes.h"
38 #include "gimpconfigwriter.h"
39 #include "gimpconfig-iface.h"
40 #include "gimpconfig-error.h"
41 #include "gimpconfig-serialize.h"
42 #include "gimpconfig-utils.h"
44 #include "libgimp/libgimp-intl.h"
48 * SECTION: gimpconfigwriter
49 * @title: GimpConfigWriter
50 * @short_description: Functions for writing config info to a file for
53 * Functions for writing config info to a file for libgimpconfig.
57 struct _GimpConfigWriter
59 GOutputStream
*output
;
69 static inline void gimp_config_writer_flush (GimpConfigWriter
*writer
);
70 static inline void gimp_config_writer_newline (GimpConfigWriter
*writer
);
71 static gboolean
gimp_config_writer_close_output (GimpConfigWriter
*writer
,
75 gimp_config_writer_flush (GimpConfigWriter
*writer
)
82 if (! g_output_stream_write_all (writer
->output
,
87 g_set_error (&writer
->error
, GIMP_CONFIG_ERROR
, GIMP_CONFIG_ERROR_WRITE
,
88 _("Error writing to '%s': %s"),
90 gimp_file_get_utf8_name (writer
->file
) : "output stream",
92 g_clear_error (&error
);
95 g_string_truncate (writer
->buffer
, 0);
99 gimp_config_writer_newline (GimpConfigWriter
*writer
)
103 g_string_append_c (writer
->buffer
, '\n');
106 g_string_append_len (writer
->buffer
, "# ", 2);
108 for (i
= 0; i
< writer
->depth
; i
++)
109 g_string_append_len (writer
->buffer
, " ", 4);
113 * gimp_config_writer_new_file:
114 * @filename: a filename
115 * @atomic: if %TRUE the file is written atomically
116 * @header: text to include as comment at the top of the file
117 * @error: return location for errors
119 * Creates a new #GimpConfigWriter and sets it up to write to
120 * @filename. If @atomic is %TRUE, a temporary file is used to avoid
121 * possible race conditions. The temporary file is then moved to
122 * @filename when the writer is closed.
124 * Return value: a new #GimpConfigWriter or %NULL in case of an error
129 gimp_config_writer_new_file (const gchar
*filename
,
134 GimpConfigWriter
*writer
;
137 g_return_val_if_fail (filename
!= NULL
, NULL
);
138 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
140 file
= g_file_new_for_path (filename
);
142 writer
= gimp_config_writer_new_gfile (file
, atomic
, header
, error
);
144 g_object_unref (file
);
150 * gimp_config_writer_new_gfile:
152 * @atomic: if %TRUE the file is written atomically
153 * @header: text to include as comment at the top of the file
154 * @error: return location for errors
156 * Creates a new #GimpConfigWriter and sets it up to write to
157 * @file. If @atomic is %TRUE, a temporary file is used to avoid
158 * possible race conditions. The temporary file is then moved to @file
159 * when the writer is closed.
161 * Return value: a new #GimpConfigWriter or %NULL in case of an error
166 gimp_config_writer_new_gfile (GFile
*file
,
171 GimpConfigWriter
*writer
;
172 GOutputStream
*output
;
175 g_return_val_if_fail (G_IS_FILE (file
), NULL
);
176 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
178 dir
= g_file_get_parent (file
);
179 if (dir
&& ! g_file_query_exists (dir
, NULL
))
181 if (! g_file_make_directory_with_parents (dir
, NULL
, error
))
182 g_prefix_error (error
,
183 _("Could not create directory '%s' for '%s': "),
184 gimp_file_get_utf8_name (dir
),
185 gimp_file_get_utf8_name (file
));
187 g_object_unref (dir
);
194 output
= G_OUTPUT_STREAM (g_file_replace (file
,
195 NULL
, FALSE
, G_FILE_CREATE_NONE
,
198 g_prefix_error (error
,
199 _("Could not create temporary file for '%s': "),
200 gimp_file_get_utf8_name (file
));
204 output
= G_OUTPUT_STREAM (g_file_replace (file
,
206 G_FILE_CREATE_REPLACE_DESTINATION
,
213 writer
= g_slice_new0 (GimpConfigWriter
);
215 writer
->output
= output
;
216 writer
->file
= g_object_ref (file
);
217 writer
->buffer
= g_string_new (NULL
);
221 gimp_config_writer_comment (writer
, header
);
222 gimp_config_writer_linefeed (writer
);
229 * gimp_config_writer_new_stream:
230 * @output: a #GOutputStream
231 * @header: text to include as comment at the top of the file
232 * @error: return location for errors
234 * Creates a new #GimpConfigWriter and sets it up to write to
237 * Return value: a new #GimpConfigWriter or %NULL in case of an error
242 gimp_config_writer_new_stream (GOutputStream
*output
,
246 GimpConfigWriter
*writer
;
248 g_return_val_if_fail (G_IS_OUTPUT_STREAM (output
), NULL
);
249 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
251 writer
= g_slice_new0 (GimpConfigWriter
);
253 writer
->output
= g_object_ref (output
);
254 writer
->buffer
= g_string_new (NULL
);
258 gimp_config_writer_comment (writer
, header
);
259 gimp_config_writer_linefeed (writer
);
266 * gimp_config_writer_new_fd:
269 * Return value: a new #GimpConfigWriter or %NULL in case of an error
274 gimp_config_writer_new_fd (gint fd
)
276 GimpConfigWriter
*writer
;
278 g_return_val_if_fail (fd
> 0, NULL
);
280 writer
= g_slice_new0 (GimpConfigWriter
);
283 writer
->output
= g_win32_output_stream_new ((gpointer
) fd
, FALSE
);
285 writer
->output
= g_unix_output_stream_new (fd
, FALSE
);
288 writer
->buffer
= g_string_new (NULL
);
294 * gimp_config_writer_new_string:
297 * Return value: a new #GimpConfigWriter or %NULL in case of an error
302 gimp_config_writer_new_string (GString
*string
)
304 GimpConfigWriter
*writer
;
306 g_return_val_if_fail (string
!= NULL
, NULL
);
308 writer
= g_slice_new0 (GimpConfigWriter
);
310 writer
->buffer
= string
;
316 * gimp_config_writer_comment_mode:
317 * @writer: a #GimpConfigWriter
318 * @enable: %TRUE to enable comment mode, %FALSE to disable it
320 * This function toggles whether the @writer should create commented
321 * or uncommented output. This feature is used to generate the
322 * system-wide installed gimprc that documents the default settings.
324 * Since comments have to start at the beginning of a line, this
325 * function will insert a newline if necessary.
330 gimp_config_writer_comment_mode (GimpConfigWriter
*writer
,
333 g_return_if_fail (writer
!= NULL
);
338 enable
= (enable
? TRUE
: FALSE
);
340 if (writer
->comment
== enable
)
343 writer
->comment
= enable
;
347 if (writer
->buffer
->len
== 0)
348 g_string_append_len (writer
->buffer
, "# ", 2);
350 gimp_config_writer_newline (writer
);
356 * gimp_config_writer_open:
357 * @writer: a #GimpConfigWriter
358 * @name: name of the element to open
360 * This function writes the opening parenthesis followed by @name.
361 * It also increases the indentation level and sets a mark that
362 * can be used by gimp_config_writer_revert().
367 gimp_config_writer_open (GimpConfigWriter
*writer
,
370 g_return_if_fail (writer
!= NULL
);
371 g_return_if_fail (name
!= NULL
);
376 /* store the current buffer length so we can revert to this state */
377 writer
->marker
= writer
->buffer
->len
;
379 if (writer
->depth
> 0)
380 gimp_config_writer_newline (writer
);
384 g_string_append_printf (writer
->buffer
, "(%s", name
);
388 * gimp_config_writer_print:
389 * @writer: a #GimpConfigWriter
390 * @string: a string to write
391 * @len: number of bytes from @string or -1 if @string is NUL-terminated.
393 * Appends a space followed by @string to the @writer. Note that string
394 * must not contain any special characters that might need to be escaped.
399 gimp_config_writer_print (GimpConfigWriter
*writer
,
403 g_return_if_fail (writer
!= NULL
);
404 g_return_if_fail (len
== 0 || string
!= NULL
);
410 len
= strlen (string
);
414 g_string_append_c (writer
->buffer
, ' ');
415 g_string_append_len (writer
->buffer
, string
, len
);
420 * gimp_config_writer_printf:
421 * @writer: a #GimpConfigWriter
422 * @format: a format string as described for g_strdup_printf().
423 * @...: list of arguments according to @format
425 * A printf-like function for #GimpConfigWriter.
430 gimp_config_writer_printf (GimpConfigWriter
*writer
,
437 g_return_if_fail (writer
!= NULL
);
438 g_return_if_fail (format
!= NULL
);
443 va_start (args
, format
);
444 buffer
= g_strdup_vprintf (format
, args
);
447 g_string_append_c (writer
->buffer
, ' ');
448 g_string_append (writer
->buffer
, buffer
);
454 * gimp_config_writer_string:
455 * @writer: a #GimpConfigWriter
456 * @string: a NUL-terminated string
458 * Writes a string value to @writer. The @string is quoted and special
459 * characters are escaped.
464 gimp_config_writer_string (GimpConfigWriter
*writer
,
467 g_return_if_fail (writer
!= NULL
);
472 g_string_append_c (writer
->buffer
, ' ');
473 gimp_config_string_append_escaped (writer
->buffer
, string
);
477 * gimp_config_writer_identifier:
478 * @writer: a #GimpConfigWriter
479 * @identifier: a NUL-terminated string
481 * Writes an identifier to @writer. The @string is *not* quoted and special
482 * characters are *not* escaped.
487 gimp_config_writer_identifier (GimpConfigWriter
*writer
,
488 const gchar
*identifier
)
490 g_return_if_fail (writer
!= NULL
);
491 g_return_if_fail (identifier
!= NULL
);
496 g_string_append_printf (writer
->buffer
, " %s", identifier
);
501 * gimp_config_writer_data:
502 * @writer: a #GimpConfigWriter
509 gimp_config_writer_data (GimpConfigWriter
*writer
,
515 g_return_if_fail (writer
!= NULL
);
516 g_return_if_fail (length
>= 0);
517 g_return_if_fail (data
!= NULL
|| length
== 0);
522 g_string_append (writer
->buffer
, " \"");
524 for (i
= 0; i
< length
; i
++)
526 if (g_ascii_isalpha (data
[i
]))
527 g_string_append_c (writer
->buffer
, data
[i
]);
529 g_string_append_printf (writer
->buffer
, "\\%o", data
[i
]);
532 g_string_append (writer
->buffer
, "\"");
536 * gimp_config_writer_revert:
537 * @writer: a #GimpConfigWriter
539 * Reverts all changes to @writer that were done since the last call
540 * to gimp_config_writer_open(). This can only work if you didn't call
541 * gimp_config_writer_close() yet.
546 gimp_config_writer_revert (GimpConfigWriter
*writer
)
548 g_return_if_fail (writer
!= NULL
);
553 g_return_if_fail (writer
->depth
> 0);
554 g_return_if_fail (writer
->marker
!= -1);
556 g_string_truncate (writer
->buffer
, writer
->marker
);
563 * gimp_config_writer_close:
564 * @writer: a #GimpConfigWriter
566 * Closes an element opened with gimp_config_writer_open().
571 gimp_config_writer_close (GimpConfigWriter
*writer
)
573 g_return_if_fail (writer
!= NULL
);
578 g_return_if_fail (writer
->depth
> 0);
580 g_string_append_c (writer
->buffer
, ')');
582 if (--writer
->depth
== 0)
584 g_string_append_c (writer
->buffer
, '\n');
586 gimp_config_writer_flush (writer
);
591 * gimp_config_writer_finish:
592 * @writer: a #GimpConfigWriter
593 * @footer: text to include as comment at the bottom of the file
594 * @error: return location for possible errors
596 * This function finishes the work of @writer and frees it afterwards.
597 * It closes all open elements, appends an optional comment and
598 * releases all resources allocated by @writer. You must not access
599 * the @writer afterwards.
601 * Return value: %TRUE if everything could be successfully written,
607 gimp_config_writer_finish (GimpConfigWriter
*writer
,
611 gboolean success
= TRUE
;
613 g_return_val_if_fail (writer
!= NULL
, FALSE
);
614 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
616 if (writer
->depth
< 0)
618 g_warning ("gimp_config_writer_finish: depth < 0 !!");
622 while (writer
->depth
)
623 gimp_config_writer_close (writer
);
628 gimp_config_writer_linefeed (writer
);
629 gimp_config_writer_comment (writer
, footer
);
634 success
= gimp_config_writer_close_output (writer
, error
);
637 g_object_unref (writer
->file
);
639 g_string_free (writer
->buffer
, TRUE
);
644 if (error
&& *error
== NULL
)
645 g_propagate_error (error
, writer
->error
);
647 g_clear_error (&writer
->error
);
652 g_slice_free (GimpConfigWriter
, writer
);
658 gimp_config_writer_linefeed (GimpConfigWriter
*writer
)
660 g_return_if_fail (writer
!= NULL
);
665 if (writer
->output
&& writer
->buffer
->len
== 0 && !writer
->comment
)
667 GError
*error
= NULL
;
669 if (! g_output_stream_write_all (writer
->output
, "\n", 1,
672 g_set_error (&writer
->error
, GIMP_CONFIG_ERROR
, GIMP_CONFIG_ERROR_WRITE
,
673 _("Error writing to '%s': %s"),
675 gimp_file_get_utf8_name (writer
->file
) : "output stream",
677 g_clear_error (&error
);
682 gimp_config_writer_newline (writer
);
687 * gimp_config_writer_comment:
688 * @writer: a #GimpConfigWriter
689 * @comment: the comment to write (ASCII only)
691 * Appends the @comment to @str and inserts linebreaks and hash-marks to
692 * format it as a comment. Note that this function does not handle non-ASCII
698 gimp_config_writer_comment (GimpConfigWriter
*writer
,
699 const gchar
*comment
)
702 gboolean comment_mode
;
705 #define LINE_LENGTH 75
707 g_return_if_fail (writer
!= NULL
);
712 g_return_if_fail (writer
->depth
== 0);
717 comment_mode
= writer
->comment
;
718 gimp_config_writer_comment_mode (writer
, TRUE
);
720 len
= strlen (comment
);
724 for (s
= comment
, i
= 0, space
= 0;
725 *s
!= '\n' && (i
<= LINE_LENGTH
|| space
== 0) && i
< len
;
728 if (g_ascii_isspace (*s
))
732 if (i
> LINE_LENGTH
&& space
&& *s
!= '\n')
735 g_string_append_len (writer
->buffer
, comment
, i
);
743 gimp_config_writer_newline (writer
);
746 gimp_config_writer_comment_mode (writer
, comment_mode
);
747 gimp_config_writer_newline (writer
);
749 if (writer
->depth
== 0)
750 gimp_config_writer_flush (writer
);
756 gimp_config_writer_close_output (GimpConfigWriter
*writer
,
759 g_return_val_if_fail (writer
->output
!= NULL
, FALSE
);
763 g_object_unref (writer
->output
);
764 writer
->output
= NULL
;
771 GError
*my_error
= NULL
;
773 if (! g_output_stream_close (writer
->output
, NULL
, &my_error
))
775 g_set_error (error
, GIMP_CONFIG_ERROR
, GIMP_CONFIG_ERROR_WRITE
,
776 _("Error writing '%s': %s"),
777 gimp_file_get_utf8_name (writer
->file
),
779 g_clear_error (&my_error
);
781 g_object_unref (writer
->output
);
782 writer
->output
= NULL
;
788 g_object_unref (writer
->output
);
789 writer
->output
= NULL
;