configure.ac: Add subheaders to Input/Sticker/Autodiscovery/Metadata and Misc.
[mpd-mk.git] / src / directory_save.c
blob18472db98659d94e0c32c95dd731c51646ce62f0
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "directory_save.h"
22 #include "directory.h"
23 #include "song.h"
24 #include "text_file.h"
25 #include "song_save.h"
27 #include <assert.h>
28 #include <string.h>
30 #define DIRECTORY_MTIME "mtime: "
31 #define DIRECTORY_BEGIN "begin: "
32 #define DIRECTORY_END "end: "
34 /**
35 * The quark used for GError.domain.
37 static inline GQuark
38 directory_quark(void)
40 return g_quark_from_static_string("directory");
43 void
44 directory_save(FILE *fp, struct directory *directory)
46 struct dirvec *children = &directory->children;
47 size_t i;
49 if (!directory_is_root(directory)) {
50 fprintf(fp, DIRECTORY_MTIME "%lu\n",
51 (unsigned long)directory->mtime);
53 fprintf(fp, "%s%s\n", DIRECTORY_BEGIN,
54 directory_get_path(directory));
57 for (i = 0; i < children->nr; ++i) {
58 struct directory *cur = children->base[i];
59 char *base = g_path_get_basename(cur->path);
61 fprintf(fp, DIRECTORY_DIR "%s\n", base);
62 g_free(base);
64 directory_save(fp, cur);
66 if (ferror(fp))
67 return;
70 songvec_save(fp, &directory->songs);
72 if (!directory_is_root(directory))
73 fprintf(fp, DIRECTORY_END "%s\n",
74 directory_get_path(directory));
77 static struct directory *
78 directory_load_subdir(FILE *fp, struct directory *parent, const char *name,
79 GString *buffer, GError **error_r)
81 struct directory *directory;
82 const char *line;
83 bool success;
85 if (directory_get_child(parent, name) != NULL) {
86 g_set_error(error_r, directory_quark(), 0,
87 "Duplicate subdirectory '%s'", name);
88 return NULL;
91 if (directory_is_root(parent)) {
92 directory = directory_new(name, parent);
93 } else {
94 char *path = g_strconcat(directory_get_path(parent), "/",
95 name, NULL);
96 directory = directory_new(path, parent);
97 g_free(path);
100 line = read_text_line(fp, buffer);
101 if (line == NULL) {
102 g_set_error(error_r, directory_quark(), 0,
103 "Unexpected end of file");
104 directory_free(directory);
105 return NULL;
108 if (g_str_has_prefix(line, DIRECTORY_MTIME)) {
109 directory->mtime =
110 g_ascii_strtoull(line + sizeof(DIRECTORY_MTIME) - 1,
111 NULL, 10);
113 line = read_text_line(fp, buffer);
114 if (line == NULL) {
115 g_set_error(error_r, directory_quark(), 0,
116 "Unexpected end of file");
117 directory_free(directory);
118 return NULL;
122 if (!g_str_has_prefix(line, DIRECTORY_BEGIN)) {
123 g_set_error(error_r, directory_quark(), 0,
124 "Malformed line: %s", line);
125 directory_free(directory);
126 return NULL;
129 success = directory_load(fp, directory, buffer, error_r);
130 if (!success) {
131 directory_free(directory);
132 return NULL;
135 return directory;
138 bool
139 directory_load(FILE *fp, struct directory *directory,
140 GString *buffer, GError **error)
142 const char *line;
144 while ((line = read_text_line(fp, buffer)) != NULL &&
145 !g_str_has_prefix(line, DIRECTORY_END)) {
146 if (g_str_has_prefix(line, DIRECTORY_DIR)) {
147 struct directory *subdir =
148 directory_load_subdir(fp, directory,
149 line + sizeof(DIRECTORY_DIR) - 1,
150 buffer, error);
151 if (subdir == NULL)
152 return false;
154 dirvec_add(&directory->children, subdir);
155 } else if (g_str_has_prefix(line, SONG_BEGIN)) {
156 const char *name = line + sizeof(SONG_BEGIN) - 1;
157 struct song *song;
159 if (songvec_find(&directory->songs, name) != NULL) {
160 g_set_error(error, directory_quark(), 0,
161 "Duplicate song '%s'", name);
162 return NULL;
165 song = song_load(fp, directory, name,
166 buffer, error);
167 if (song == NULL)
168 return false;
170 songvec_add(&directory->songs, song);
171 } else {
172 g_set_error(error, directory_quark(), 0,
173 "Malformed line: %s", line);
174 return false;
178 return true;