Fixup prev commit (LV2 X11 UI) -- #7837
[ardour.git] / libs / ardour / recent_sessions.cc
1 /*
2  * Copyright (C) 2005-2016 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
4  * Copyright (C) 2006-2012 Tim Mayberry <mojofunk@gmail.com>
5  * Copyright (C) 2008-2012 David Robillard <d@drobilla.net>
6  * Copyright (C) 2015 John Emmas <john@creativepost.co.uk>
7  * Copyright (C) 2015 Robin Gareus <robin@gareus.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include <cstring>
25 #include <cerrno>
26 #include <sstream>
27 #include <algorithm>
28
29 #include "pbd/gstdio_compat.h"
30 #include <glibmm/miscutils.h>
31
32 #include "pbd/error.h"
33
34 #include "ardour/rc_configuration.h"
35 #include "ardour/filesystem_paths.h"
36 #include "ardour/recent_sessions.h"
37
38 #include "pbd/i18n.h"
39
40 using namespace std;
41 using namespace ARDOUR;
42 using namespace PBD;
43
44 namespace {
45
46         const char * const recent_file_name = "recent";
47         const char * const recent_templates_file_name = "recent_templates";
48
49 } // anonymous
50
51 int
52 ARDOUR::read_recent_sessions (RecentSessions& rs)
53 {
54         std::string path = Glib::build_filename (user_config_directory(), recent_file_name);
55         FILE* fin = g_fopen (path.c_str(), "rb");
56
57         if (!fin) {
58                 if (errno != ENOENT) {
59                         error << string_compose (_("cannot open recent session file %1 (%2)"), path, strerror (errno)) << endmsg;
60                         return -1;
61                 } else {
62                         return 1;
63                 }
64         }
65
66         // Read the file into a std::string
67         std::stringstream recent;
68         while (!feof (fin)) {
69                 char buf[1024];
70                 size_t charsRead = fread (buf, sizeof(char), 1024, fin);
71                 if (ferror (fin)) {
72                         error << string_compose (_("Error reading recent session file %1 (%2)"), path, strerror (errno)) << endmsg;
73                         fclose(fin);
74                         return -1;
75                 }
76                 if (charsRead == 0) {
77                         break;
78                 }
79                 recent.write (buf, charsRead);
80         }
81
82         while (true) {
83
84                 pair<string,string> newpair;
85
86                 getline(recent, newpair.first);
87
88                 if (!recent.good()) {
89                         break;
90                 }
91
92                 getline(recent, newpair.second);
93
94                 if (!recent.good()) {
95                         break;
96                 }
97
98                 rs.push_back (newpair);
99         }
100
101         /* display sorting should be done in the GUI, otherwise the
102          * natural order will be broken
103          */
104
105         fclose (fin);
106         return 0;
107 }
108
109 int
110 ARDOUR::read_recent_templates (std::deque<std::string>& rt)
111 {
112         std::string path = Glib::build_filename (user_config_directory(), recent_templates_file_name);
113         FILE* fin = g_fopen (path.c_str(), "rb");
114
115         if (!fin) {
116                 if (errno != ENOENT) {
117                         error << string_compose (_("Cannot open recent template file %1 (%2)"), path, strerror (errno)) << endmsg;
118                         return -1;
119                 } else {
120                         return 1;
121                 }
122         }
123
124         // Copy the file contents into a std::stringstream
125         std::stringstream recent;
126         while (!feof (fin)) {
127                 char buf[1024];
128                 size_t charsRead = fread (buf, sizeof(char), 1024, fin);
129                 if (ferror (fin)) {
130                         error << string_compose (_("Error reading recent session file %1 (%2)"), path, strerror (errno)) << endmsg;
131                         fclose(fin);
132                         return -1;
133                 }
134                 if (charsRead == 0) {
135                         break;
136                 }
137                 recent.write (buf, charsRead);
138         }
139
140         while (true) {
141
142                 std::string session_template_full_name;
143
144                 getline(recent, session_template_full_name);
145
146                 if (!recent.good()) {
147                         break;
148                 }
149
150                 rt.push_back (session_template_full_name);
151         }
152
153         fclose (fin);
154         return 0;
155 }
156
157 int
158 ARDOUR::write_recent_sessions (RecentSessions& rs)
159 {
160         FILE* fout = g_fopen (Glib::build_filename (user_config_directory(), recent_file_name).c_str(), "wb");
161
162         if (!fout) {
163                 return -1;
164         }
165
166         {
167                 stringstream recent;
168
169                 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
170                         recent << (*i).first << '\n' << (*i).second << endl;
171                 }
172
173                 string recentString = recent.str();
174                 size_t writeSize = recentString.length();
175
176                 fwrite(recentString.c_str(), sizeof(char), writeSize, fout);
177
178                 if (ferror(fout))
179                 {
180                         error << string_compose (_("Error writing recent sessions file %1 (%2)"), recent_file_name, strerror (errno)) << endmsg;
181                         fclose(fout);
182                         return -1;
183                 }
184         }
185
186
187
188         fclose (fout);
189
190         return 0;
191 }
192
193 int
194 ARDOUR::write_recent_templates (std::deque<std::string>& rt)
195 {
196         FILE* fout = g_fopen (Glib::build_filename (user_config_directory(), recent_templates_file_name).c_str(), "wb");
197
198         if (!fout) {
199                 return -1;
200         }
201
202         stringstream recent;
203
204         for (std::deque<std::string>::const_iterator i = rt.begin(); i != rt.end(); ++i) {
205                 recent << (*i) << std::endl;
206         }
207
208         string recentString = recent.str();
209         size_t writeSize = recentString.length();
210
211         fwrite(recentString.c_str(), sizeof(char), writeSize, fout);
212
213         if (ferror(fout))
214         {
215                 error << string_compose (_("Error writing saved template file %1 (%2)"), recent_templates_file_name, strerror (errno)) << endmsg;
216                 fclose(fout);
217                 return -1;
218         }
219
220         fclose (fout);
221
222         return 0;
223 }
224
225 int
226 ARDOUR::store_recent_sessions (string name, string path)
227 {
228         RecentSessions rs;
229
230         if (ARDOUR::read_recent_sessions (rs) < 0) {
231                 return -1;
232         }
233
234         pair<string,string> newpair;
235
236         newpair.first = name;
237         newpair.second = path;
238
239         rs.erase(remove(rs.begin(), rs.end(), newpair), rs.end());
240
241         rs.push_front (newpair);
242
243         uint32_t max_recent_sessions = Config->get_max_recent_sessions();
244
245         if (rs.size() > max_recent_sessions) {
246                 rs.erase(rs.begin()+max_recent_sessions, rs.end());
247         }
248
249         return ARDOUR::write_recent_sessions (rs);
250 }
251
252 int
253 ARDOUR::store_recent_templates (const std::string& session_template_full_name)
254 {
255         std::deque<std::string> rt;
256
257         if (ARDOUR::read_recent_templates (rt) < 0) {
258                 return -1;
259         }
260
261         rt.erase(remove (rt.begin(), rt.end(), session_template_full_name), rt.end());
262
263         rt.push_front (session_template_full_name);
264
265         uint32_t max_recent_templates = Config->get_max_recent_templates ();
266
267         if (rt.size() > max_recent_templates) {
268                 rt.erase( rt.begin() + max_recent_templates, rt.end ());
269         }
270
271         return ARDOUR::write_recent_templates (rt);
272 }
273
274 int
275 ARDOUR::remove_recent_sessions (const string& path)
276 {
277         RecentSessions rs;
278         bool write = false;
279
280         if (ARDOUR::read_recent_sessions (rs) < 0) {
281                 return -1;
282         }
283
284         for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
285                 if (i->second == path) {
286                         rs.erase (i);
287                         write = true;
288                         break;
289                 }
290         }
291
292         if (write) {
293                 return ARDOUR::write_recent_sessions (rs);
294         } else {
295                 return 1;
296         }
297 }