Introduce poor man's hash.
[cascardo/libreceita.git] / decfile.c
1 /*
2  *  Copyright (C) 2012-2013  Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #define _GNU_SOURCE
20 #include "decfile.h"
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26
27 struct rnet_decfile {
28         char *filename;
29         FILE *file;
30         char **lines;
31         int lines_len;
32 };
33
34 /*
35  * line should be an allocated buffer given to append_line
36  * this means, free(line) will be called when decfile is released
37  */
38 static int append_line(struct rnet_decfile *decfile, char *line)
39 {
40         size_t len;
41         char **old_lines;
42         decfile->lines_len += 1;
43         len = sizeof(*decfile->lines) * decfile->lines_len;
44         old_lines = decfile->lines;
45         decfile->lines = realloc(decfile->lines, len);
46         if (!decfile->lines) {
47                 decfile->lines = old_lines;
48                 goto out;
49         }
50         decfile->lines[decfile->lines_len - 1] = line;
51         return 0;
52 out:
53         decfile->lines_len -= 1;
54         return -1;
55 }
56
57 static void decfile_release_lines(struct rnet_decfile *decfile)
58 {
59         int i;
60         for (i = 0; i < decfile->lines_len; i++)
61                 free(decfile->lines[i]);
62         free(decfile->lines);
63         decfile->lines = NULL;
64 }
65
66 static int decfile_parse(struct rnet_decfile *decfile)
67 {
68         char *buffer = NULL;
69         size_t len = 0;
70         int r;
71         while ((r = getline(&buffer, &len, decfile->file)) > 0) {
72                 r = append_line(decfile, buffer);
73                 if (r) {
74                         free(buffer);
75                         goto out;
76                 }
77                 buffer = NULL;
78                 len = 0;
79         }
80         return 0;
81 out:
82         decfile_release_lines(decfile);
83         return -1;
84 }
85
86 struct rnet_decfile * rnet_decfile_open(char *filename)
87 {
88         struct rnet_decfile *decfile;
89         decfile = malloc(sizeof(*decfile));
90         if (!decfile)
91                 return NULL;
92         decfile->filename = strdup(filename);
93         if (!decfile->filename)
94                 goto out_filename;
95         decfile->file = fopen(filename, "r");
96         if (!decfile->file)
97                 goto out_file;
98         decfile->lines_len = 0;
99         decfile->lines = NULL;
100         if (decfile_parse(decfile))
101                 goto out_parse;
102         return decfile;
103 out_parse:
104         fclose(decfile->file);
105 out_file:
106         free(decfile->filename);
107 out_filename:
108         free(decfile);
109         return NULL;
110 }
111
112 void rnet_decfile_close(struct rnet_decfile *decfile)
113 {
114         decfile_release_lines(decfile);
115         fclose(decfile->file);
116         free(decfile->filename);
117         free(decfile);
118 }