flac: Saner EOF handling
[cmus.git] / file.c
blob9553e0564b70304276211eed96d8837a8edda57d
1 /*
2 * Copyright 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 "file.h"
21 #include "xmalloc.h"
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/mman.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <errno.h>
31 ssize_t read_all(int fd, void *buf, size_t count)
33 char *buffer = buf;
34 int pos = 0;
36 do {
37 int rc;
39 rc = read(fd, buffer + pos, count - pos);
40 if (rc == -1) {
41 if (errno == EINTR || errno == EAGAIN)
42 continue;
43 return -1;
45 if (rc == 0) {
46 /* eof */
47 break;
49 pos += rc;
50 } while (count - pos > 0);
51 return pos;
54 ssize_t write_all(int fd, const void *buf, size_t count)
56 const char *buffer = buf;
57 int count_save = count;
59 do {
60 int rc;
62 rc = write(fd, buffer, count);
63 if (rc == -1) {
64 if (errno == EINTR || errno == EAGAIN)
65 continue;
66 return -1;
68 buffer += rc;
69 count -= rc;
70 } while (count > 0);
71 return count_save;
74 char *mmap_file(const char *filename, int *size)
76 struct stat st;
77 char *buf;
78 int fd;
80 fd = open(filename, O_RDONLY);
81 if (fd == -1)
82 goto err;
84 if (fstat(fd, &st) == -1)
85 goto close_err;
87 /* can't mmap empty files */
88 buf = NULL;
89 if (st.st_size) {
90 buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
91 if (buf == MAP_FAILED)
92 goto close_err;
95 close(fd);
96 *size = st.st_size;
97 return buf;
99 close_err:
100 close(fd);
101 err:
102 *size = -1;
103 return NULL;
106 void buffer_for_each_line(const char *buf, int size,
107 int (*cb)(void *data, const char *line),
108 void *data)
110 char *line = NULL;
111 int line_size = 0, pos = 0;
113 while (pos < size) {
114 int end, len;
116 end = pos;
117 while (end < size && buf[end] != '\n')
118 end++;
120 len = end - pos;
121 if (end > pos && buf[end - 1] == '\r')
122 len--;
124 if (len >= line_size) {
125 line_size = len + 1;
126 line = xrenew(char, line, line_size);
128 memcpy(line, buf + pos, len);
129 line[len] = 0;
130 pos = end + 1;
132 if (cb(data, line))
133 break;
135 free(line);
138 void buffer_for_each_line_reverse(const char *buf, int size,
139 int (*cb)(void *data, const char *line),
140 void *data)
142 char *line = NULL;
143 int line_size = 0, end = size - 1;
145 while (end >= 0) {
146 int pos, len;
148 if (end > 1 && buf[end] == '\n' && buf[end - 1] == '\r')
149 end--;
151 pos = end;
152 while (pos > 0 && buf[pos - 1] != '\n')
153 pos--;
155 len = end - pos;
156 if (len >= line_size) {
157 line_size = len + 1;
158 line = xrenew(char, line, line_size);
160 memcpy(line, buf + pos, len);
161 line[len] = 0;
162 end = pos - 1;
164 if (cb(data, line))
165 break;
167 free(line);
170 int file_for_each_line(const char *filename,
171 int (*cb)(void *data, const char *line),
172 void *data)
174 char *buf;
175 int size;
177 buf = mmap_file(filename, &size);
178 if (size == -1)
179 return -1;
181 if (buf) {
182 buffer_for_each_line(buf, size, cb, data);
183 munmap(buf, size);
185 return 0;