]> git.neil.brown.name Git - wiggle.git/blob - load.c
Makefile: ensure "make lib" sees changes to wiggle.h
[wiggle.git] / load.c
1 /*
2  * wiggle - apply rejected patches
3  *
4  * Copyright (C) 2003 Neil Brown <neilb@cse.unsw.edu.au>
5  * Copyright (C) 2013 Neil Brown <neilb@suse.de>
6  * Copyright (C) 2014-2020 Neil Brown <neil@brown.name>
7  *
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
20  *    along with this program.
21  *
22  *    Author: Neil Brown
23  *    Email: <neil@brown.name>
24  */
25
26 /*
27  * read in files
28  *
29  * Files are read in whole and stored in a
30  * struct stream {char*, len}
31  *
32  *
33  * loading the file "-" reads from stdin which might require
34  * reading into several buffers
35  */
36
37 #include        "wiggle.h"
38 #include        <sys/types.h>
39 #include        <sys/stat.h>
40 #include        <unistd.h>
41 #include        <fcntl.h>
42 #include        <stdlib.h>
43
44 static void join_streams(struct stream list[], int cnt)
45 {
46         /* join all the streams in the list (upto body=NULL)
47          * into one by re-allocing list[0].body and copying
48          */
49         int len = 0;
50         int i;
51         char *c;
52
53         for (i = 0; i < cnt ; i++)
54                 len += list[i].len;
55
56         c = realloc(list[0].body, len+1);
57         if (c == NULL)
58                 wiggle_die("memory allocation");
59
60         list[0].body = c;
61         c  += list[0].len;
62         list[0].len = len;
63         for (i = 1; i < cnt; i++) {
64                 memcpy(c, list[i].body, list[i].len);
65                 c += list[i].len;
66                 list[i].len = 0;
67                 free(list[i].body);
68         }
69         c[0] = 0;
70 }
71
72 static struct stream wiggle_load_regular(int fd)
73 {
74         struct stat stb;
75         struct stream s;
76         fstat(fd, &stb);
77
78         s.len = stb.st_size;
79         s.body = wiggle_xmalloc(s.len+1);
80         if (read(fd, s.body, s.len) != s.len)
81                 wiggle_die("file read");
82
83         s.body[s.len] = 0;
84         return s;
85 }
86
87 static struct stream wiggle_load_other(int fd)
88 {
89
90         struct stream list[10];
91         int i = 0;
92
93         while (1) {
94                 list[i].body = wiggle_xmalloc(8192);
95                 list[i].len = read(fd, list[i].body, 8192);
96                 if (list[i].len < 0)
97                         wiggle_die("file read");
98                 if (list[i].len == 0)
99                         break;
100                 i++;
101                 if (i == 10) {
102                         join_streams(list, i);
103                         i = 1;
104                 }
105         }
106         join_streams(list, i);
107         return list[0];
108 }
109
110 struct stream wiggle_load_segment(FILE *f,
111                            unsigned int start, unsigned int end)
112 {
113         struct stream s;
114         s.len = end - start;
115         s.body = wiggle_xmalloc(s.len+1);
116         fseek(f, start, 0);
117         if (fread(s.body, 1, s.len, f) != (size_t)s.len)
118                 wiggle_die("file read");
119         /* ensure string is 'nul' terminated - for sscanf */
120         s.body[s.len] = 0;
121         return s;
122 }
123
124 struct stream wiggle_load_file(char *name)
125 {
126         struct stream s;
127         struct stat stb;
128         int fd;
129         int start, end;
130         int prefix_len = 0;
131
132         s.body = NULL;
133         s.len = 0;
134         if (sscanf(name, "_wiggle_:%d:%d:%n", &start, &end,
135                    &prefix_len) >= 2 && prefix_len > 0) {
136                 FILE *f = fopen(name + prefix_len, "r");
137                 if (f) {
138                         s = wiggle_load_segment(f, start, end);
139                         fclose(f);
140                 } else {
141                         s.body = NULL;
142                         s.len = 0;
143                 }
144         } else {
145                 if (strcmp(name, "-") == 0)
146                         fd = 0;
147                 else {
148                         fd = open(name, O_RDONLY);
149                         if (fd < 0)
150                                 return s;
151                 }
152                 wiggle_check_dir(name, fd);
153                 if (fstat(fd, &stb) == 0) {
154
155                         if (S_ISREG(stb.st_mode))
156                                 s = wiggle_load_regular(fd);
157                         else
158                                 s = wiggle_load_other(fd);
159                 }
160                 close(fd);
161         }
162         return s;
163 }
164