Handle streams separately in tree_add_track()
[cmus.git] / history.c
blobc73af958ef59c2e497453cc022a641898d36a19f
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "history.h"
21 #include "xmalloc.h"
22 #include "file.h"
23 #include "uchar.h"
24 #include "list.h"
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <unistd.h>
30 struct history_entry {
31 struct list_head node;
32 char text[0];
35 static struct history_entry *history_entry_new(const char *text)
37 struct history_entry *new;
38 int size = strlen(text) + 1;
40 new = xmalloc(sizeof(struct history_entry) + size);
41 memcpy(new->text, text, size);
42 return new;
45 static int history_add_tail(void *data, const char *line)
47 struct history *history = data;
49 if (history->lines < history->max_lines) {
50 struct history_entry *new;
52 new = history_entry_new(line);
53 list_add_tail(&new->node, &history->head);
54 history->lines++;
56 return 0;
59 void history_load(struct history *history, char *filename, int max_lines)
61 list_init(&history->head);
62 history->max_lines = max_lines;
63 history->lines = 0;
64 history->search_pos = NULL;
65 history->filename = filename;
66 file_for_each_line(filename, history_add_tail, history);
69 void history_save(struct history *history)
71 struct list_head *item;
72 int fd;
74 fd = open(history->filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
75 if (fd == -1)
76 return;
77 list_for_each(item, &history->head) {
78 struct history_entry *history_entry;
79 const char nl = '\n';
81 history_entry = list_entry(item, struct history_entry, node);
82 write(fd, history_entry->text, strlen(history_entry->text));
83 write(fd, &nl, 1);
85 close(fd);
88 void history_add_line(struct history *history, const char *line)
90 struct history_entry *new;
91 struct list_head *item;
93 new = history_entry_new(line);
94 list_add(&new->node, &history->head);
95 history->lines++;
97 /* remove identical */
98 item = history->head.next->next;
99 while (item != &history->head) {
100 struct list_head *next = item->next;
101 struct history_entry *hentry;
103 hentry = container_of(item, struct history_entry, node);
104 if (strcmp(hentry->text, new->text) == 0) {
105 list_del(item);
106 free(hentry);
107 history->lines--;
109 item = next;
112 /* remove oldest if history is 'full' */
113 if (history->lines > history->max_lines) {
114 struct list_head *node;
115 struct history_entry *hentry;
117 node = history->head.prev;
118 list_del(node);
119 hentry = list_entry(node, struct history_entry, node);
120 free(hentry);
121 history->lines--;
125 void history_reset_search(struct history *history)
127 history->search_pos = NULL;
130 const char *history_search_forward(struct history *history, const char *text)
132 struct list_head *item;
133 int search_len;
135 if (history->search_pos == NULL) {
136 /* first time to search. set search */
137 item = history->head.next;
138 } else {
139 item = history->search_pos->next;
141 search_len = strlen(text);
142 while (item != &history->head) {
143 struct history_entry *hentry;
145 hentry = list_entry(item, struct history_entry, node);
146 if (strncmp(text, hentry->text, search_len) == 0) {
147 history->search_pos = item;
148 return hentry->text;
150 item = item->next;
152 return NULL;
155 const char *history_search_backward(struct history *history, const char *text)
157 struct list_head *item;
158 int search_len;
160 if (history->search_pos == NULL)
161 return NULL;
162 item = history->search_pos->prev;
163 search_len = strlen(text);
164 while (item != &history->head) {
165 struct history_entry *hentry;
167 hentry = list_entry(item, struct history_entry, node);
168 if (strncmp(text, hentry->text, search_len) == 0) {
169 history->search_pos = item;
170 return hentry->text;
172 item = item->prev;
174 history->search_pos = NULL;
175 return NULL;