rofi 1.7.5
history.c
Go to the documentation of this file.
1/*
2 * rofi
3 *
4 * MIT/X11 License
5 * Copyright © 2013-2022 Qball Cow <qball@gmpclient.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28#include "history.h"
29#include "rofi.h"
30#include "settings.h"
31#include <errno.h>
32#include <glib.h>
33#include <glib/gstdio.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/types.h>
38#include <unistd.h>
39
43typedef struct __element {
45 long int index;
47 char *name;
49
50static int __element_sort_func(const void *ea, const void *eb,
51 void *data __attribute__((unused))) {
52 _element *a = *(_element **)ea;
53 _element *b = *(_element **)eb;
54 return b->index - a->index;
55}
56
57static void __history_write_element_list(FILE *fd, _element **list,
58 unsigned int length) {
59 if (list == NULL || length == 0) {
60 return;
61 }
62 // Sort the list before writing out.
63 g_qsort_with_data(list, length, sizeof(_element *), __element_sort_func,
64 NULL);
65
66 // Get minimum index.
67 int min_value = list[length - 1]->index;
68
69 // Set the max length of the list.
70 length =
71 (length > config.max_history_size) ? config.max_history_size : length;
72
73 // Write out entries.
74 for (unsigned int iter = 0; iter < length; iter++) {
75 fprintf(fd, "%ld %s\n", list[iter]->index - min_value, list[iter]->name);
76 }
77}
78
79static char **__history_get_element_list_fields(FILE *fd,
80 unsigned int *length) {
81 unsigned int real_length = 0;
82 char **retv = NULL;
83 ;
84 if (length == NULL) {
85 return NULL;
86 }
87 *length = 0;
88
89 if (fd == NULL) {
90 return NULL;
91 }
92 char *buffer = NULL;
93 size_t buffer_length = 0;
94 ssize_t l = 0;
95 while ((l = getline(&buffer, &buffer_length, fd)) > 0) {
96 // Jump to the first space.
97 const char *start = strchr(buffer, ' ');
98 // not found, skip.
99 if (start == NULL) {
100 continue;
101 }
102 start++;
103 // remove trailing \n
104 buffer[l - 1] = '\0';
105 if (real_length < (*length + 2)) {
106 real_length += 15;
107 // Resize and check.
108 retv = g_realloc(retv, (real_length) * sizeof(char *));
109 }
110 // Parse the number of times.
111 retv[(*length)] = g_strndup(start, l - 1 - (start - buffer));
112 // Force trailing '\0'
113 retv[(*length) + 1] = NULL;
114
115 (*length)++;
116 }
117 if (buffer_length > 0) {
118 g_free(buffer);
119 }
120 return retv;
121}
122
123static _element **__history_get_element_list(FILE *fd, unsigned int *length) {
124 unsigned int real_length = 0;
125 _element **retv = NULL;
126
127 if (length == NULL) {
128 return NULL;
129 }
130 *length = 0;
131
132 if (fd == NULL) {
133 return NULL;
134 }
135 char *buffer = NULL;
136 size_t buffer_length = 0;
137 ssize_t l = 0;
138 while ((l = getline(&buffer, &buffer_length, fd)) > 0) {
139 char *start = NULL;
140 // Skip empty lines.
141 if (l <= 1) {
142 continue;
143 }
144
145 long int index = strtol(buffer, &start, 10);
146 if (start == buffer || *start == '\0') {
147 continue;
148 }
149 start++;
150 if ((l - (start - buffer)) < 2) {
151 continue;
152 }
153 if (real_length < (*length + 2)) {
154 real_length += 15;
155 // Resize and check.
156 retv = g_realloc(retv, (real_length) * sizeof(_element *));
157 }
158
159 retv[(*length)] = g_malloc(sizeof(_element));
160
161 // remove trailing \n
162 buffer[l - 1] = '\0';
163 // Parse the number of times.
164 retv[(*length)]->index = index;
165 retv[(*length)]->name = g_strndup(start, l - 1 - (start - buffer));
166 // Force trailing '\0'
167 retv[(*length) + 1] = NULL;
168
169 (*length)++;
170 }
171 if (buffer != NULL) {
172 free(buffer);
173 buffer = NULL;
174 }
175 return retv;
176}
177
178void history_set(const char *filename, const char *entry) {
180 return;
181 }
182
183 // Check if program should be ignored
184 for (char *checked_prefix = strtok(config.ignored_prefixes, ";");
185 checked_prefix != NULL; checked_prefix = strtok(NULL, ";")) {
186 // For each ignored prefix
187
188 while (g_unichar_isspace(g_utf8_get_char(checked_prefix))) {
189 checked_prefix = g_utf8_next_char(
190 checked_prefix); // Some users will probably want "; " as their
191 // separator for aesthetics.
192 }
193
194 if (g_str_has_prefix(entry, checked_prefix)) {
195 return;
196 }
197 }
198
199 int found = 0;
200 unsigned int curr = 0;
201 unsigned int length = 0;
202 _element **list = NULL;
203 // Open file for reading and writing.
204 FILE *fd = g_fopen(filename, "r");
205 if (fd != NULL) {
206 // Get list.
207 list = __history_get_element_list(fd, &length);
208 // Close file, if fails let user know on stderr.
209 if (fclose(fd) != 0) {
210 g_warning("Failed to close history file: %s", g_strerror(errno));
211 }
212 }
213 // Look if the entry exists.
214 for (unsigned int iter = 0; !found && iter < length; iter++) {
215 if (strcmp(list[iter]->name, entry) == 0) {
216 curr = iter;
217 found = 1;
218 }
219 }
220
221 if (found) {
222 // If exists, increment list index number
223 list[curr]->index++;
224 } else {
225 // If not exists, add it.
226 // Increase list by one
227 list = g_realloc(list, (length + 2) * sizeof(_element *));
228 list[length] = g_malloc(sizeof(_element));
229 // Copy name
230 if (list[length] != NULL) {
231 list[length]->name = g_strdup(entry);
232 // set # hits
233 list[length]->index = 1;
234
235 length++;
236 list[length] = NULL;
237 }
238 }
239
240 fd = fopen(filename, "w");
241 if (fd == NULL) {
242 g_warning("Failed to open file: %s", g_strerror(errno));
243 } else {
244 // Write list.
245 __history_write_element_list(fd, list, length);
246 // Close file, if fails let user know on stderr.
247 if (fclose(fd) != 0) {
248 g_warning("Failed to close history file: %s", g_strerror(errno));
249 }
250 }
251 // Free the list.
252 for (unsigned int iter = 0; iter < length; iter++) {
253 g_free(list[iter]->name);
254 g_free(list[iter]);
255 }
256 g_free(list);
257}
258
259void history_remove(const char *filename, const char *entry) {
261 return;
262 }
263 _element **list = NULL;
264 int found = 0;
265 unsigned int curr = 0;
266 unsigned int length = 0;
267 // Open file for reading and writing.
268 FILE *fd = g_fopen(filename, "r");
269 if (fd == NULL) {
270 g_warning("Failed to open file: %s", g_strerror(errno));
271 return;
272 }
273 // Get list.
274 list = __history_get_element_list(fd, &length);
275
276 // Close file, if fails let user know on stderr.
277 if (fclose(fd) != 0) {
278 g_warning("Failed to close history file: %s", g_strerror(errno));
279 }
280 // Find entry.
281 for (unsigned int iter = 0; !found && iter < length; iter++) {
282 if (strcmp(list[iter]->name, entry) == 0) {
283 curr = iter;
284 found = 1;
285 }
286 }
287
288 // If found, remove it and write out new file.
289 if (found) {
290 // Remove the entry.
291 g_free(list[curr]->name);
292 g_free(list[curr]);
293 // Swap last to here (if list is size 1, we just swap empty sets).
294 list[curr] = list[length - 1];
295 // Empty last.
296 list[length - 1] = NULL;
297 length--;
298
299 fd = g_fopen(filename, "w");
300 // Clear list.
301 if (fd != NULL) {
302 // Write list.
303 __history_write_element_list(fd, list, length);
304 // Close file, if fails let user know on stderr.
305 if (fclose(fd) != 0) {
306 g_warning("Failed to close history file: %s", g_strerror(errno));
307 }
308 } else {
309 g_warning("Failed to open file: %s", g_strerror(errno));
310 }
311 }
312
313 // Free the list.
314 for (unsigned int iter = 0; iter < length; iter++) {
315 g_free(list[iter]->name);
316 g_free(list[iter]);
317 }
318 if (list != NULL) {
319 g_free(list);
320 }
321}
322
323char **history_get_list(const char *filename, unsigned int *length) {
324 *length = 0;
325
327 return NULL;
328 }
329 char **retv = NULL;
330 // Open file.
331 FILE *fd = g_fopen(filename, "r");
332 if (fd == NULL) {
333 // File that does not exists is not an error, so ignore it.
334 // Everything else? panic.
335 if (errno != ENOENT) {
336 g_warning("Failed to open file: %s", g_strerror(errno));
337 }
338 return NULL;
339 }
340 // Get list.
341 retv = __history_get_element_list_fields(fd, length);
342
343 // Close file, if fails let user know on stderr.
344 if (fclose(fd) != 0) {
345 g_warning("Failed to close history file: %s", g_strerror(errno));
346 }
347 return retv;
348}
void history_set(const char *filename, const char *entry)
Definition history.c:178
void history_remove(const char *filename, const char *entry)
Definition history.c:259
char ** history_get_list(const char *filename, unsigned int *length)
Definition history.c:323
struct __element _element
static char ** __history_get_element_list_fields(FILE *fd, unsigned int *length)
Definition history.c:79
static void __history_write_element_list(FILE *fd, _element **list, unsigned int length)
Definition history.c:57
static _element ** __history_get_element_list(FILE *fd, unsigned int *length)
Definition history.c:123
static int __element_sort_func(const void *ea, const void *eb, void *data __attribute__((unused)))
Definition history.c:50
Settings config
unsigned int disable_history
Definition settings.h:92
char * ignored_prefixes
Definition settings.h:94
unsigned int max_history_size
Definition settings.h:155
char * name
Definition history.c:47
long int index
Definition history.c:45