config: add configuration file for unknown compilers
[nasm.git] / nasmlib / file.c
blob57cbc9cd1c5886aa620f1d079b0da83727870e46
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2016 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
34 #include "compiler.h"
35 #include "nasmlib.h"
37 #include <errno.h>
39 #ifdef HAVE_TYPES_H
40 # include <types.h>
41 #endif
42 #ifdef HAVE_SYS_TYPES_H
43 # include <sys/types.h>
44 #endif
45 #ifdef HAVE_FCNTL_H
46 # include <fcntl.h>
47 #endif
48 #ifdef HAVE_SYS_STAT_H
49 # include <sys/stat.h>
50 #endif
51 #ifdef HAVE_IO_H
52 # include <io.h>
53 #endif
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
57 #ifdef HAVE_SYS_MMAN_H
58 # include <sys/mman.h>
59 #endif
61 #if !defined(HAVE_FILENO) && defined(HAVE__FILENO)
62 # define HAVE_FILENO 1
63 # define fileno _fileno
64 #endif
66 #if !defined(HAVE_ACCESS) && defined(HAVE__ACCESS)
67 # define HAVE_ACCESS 1
68 # define access _access
69 #endif
70 #ifndef R_OK
71 # define R_OK 4 /* Classic Unix constant, same on Windows */
72 #endif
74 /* Can we adjust the file size without actually writing all the bytes? */
75 #ifdef HAVE_FILENO /* Useless without fileno() */
76 # ifdef HAVE__CHSIZE_S
77 # define nasm_ftruncate(fd,size) _chsize_s(fd,size)
78 # elif defined(HAVE__CHSIZE)
79 # define nasm_ftruncate(fd,size) _chsize(fd,size)
80 # elif defined(HAVE_FTRUNCATE)
81 # define nasm_ftruncate(fd,size) ftruncate(fd,size)
82 # endif
83 #endif
85 #ifdef HAVE__STATI64
86 # define HAVE_STAT 1
87 # define stat _stati64
88 #endif
90 void nasm_write(const void *ptr, size_t size, FILE *f)
92 size_t n = fwrite(ptr, 1, size, f);
93 if (n != size || ferror(f) || feof(f))
94 nasm_fatal(0, "unable to write output: %s", strerror(errno));
97 #ifdef WORDS_LITTLEENDIAN
99 void fwriteint16_t(uint16_t data, FILE * fp)
101 nasm_write(&data, 2, fp);
104 void fwriteint32_t(uint32_t data, FILE * fp)
106 nasm_write(&data, 4, fp);
109 void fwriteint64_t(uint64_t data, FILE * fp)
111 nasm_write(&data, 8, fp);
114 void fwriteaddr(uint64_t data, int size, FILE * fp)
116 nasm_write(&data, size, fp);
119 #else /* not WORDS_LITTLEENDIAN */
121 void fwriteint16_t(uint16_t data, FILE * fp)
123 char buffer[2], *p = buffer;
124 WRITESHORT(p, data);
125 nasm_write(buffer, 2, fp);
128 void fwriteint32_t(uint32_t data, FILE * fp)
130 char buffer[4], *p = buffer;
131 WRITELONG(p, data);
132 nasm_write(buffer, 4, fp);
135 void fwriteint64_t(uint64_t data, FILE * fp)
137 char buffer[8], *p = buffer;
138 WRITEDLONG(p, data);
139 nasm_write(buffer, 8, fp);
142 void fwriteaddr(uint64_t data, int size, FILE * fp)
144 char buffer[8], *p = buffer;
145 WRITEADDR(p, data, size);
146 nasm_write(buffer, size, fp);
149 #endif
152 void fwritezero(off_t bytes, FILE *fp)
154 size_t blksize;
156 #ifdef nasm_ftruncate
157 if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
158 off_t pos = ftello(fp);
159 if (pos >= 0) {
160 pos += bytes;
161 if (!fflush(fp) &&
162 !nasm_ftruncate(fileno(fp), pos) &&
163 !fseeko(fp, pos, SEEK_SET))
164 return;
167 #endif
169 while (bytes > 0) {
170 blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
172 nasm_write(zero_buffer, blksize, fp);
173 bytes -= blksize;
177 FILE *nasm_open_read(const char *filename, enum file_flags flags)
179 FILE *f;
180 bool again = true;
182 #ifdef __GLIBC__
184 * Try to open this file with memory mapping for speed, unless we are
185 * going to do it "manually" with nasm_map_file()
187 if (!(flags & NF_FORMAP)) {
188 f = fopen(filename, (flags & NF_TEXT) ? "rtm" : "rbm");
189 again = (!f) && (errno == EINVAL); /* Not supported, try without m */
191 #endif
193 if (again)
194 f = fopen(filename, (flags & NF_TEXT) ? "rt" : "rb");
196 if (!f && (flags & NF_FATAL))
197 nasm_fatal(ERR_NOFILE, "unable to open input file: `%s': %s",
198 filename, strerror(errno));
200 return f;
203 FILE *nasm_open_write(const char *filename, enum file_flags flags)
205 FILE *f;
207 f = fopen(filename, (flags & NF_TEXT) ? "wt" : "wb");
209 if (!f && (flags & NF_FATAL))
210 nasm_fatal(ERR_NOFILE, "unable to open output file: `%s': %s",
211 filename, strerror(errno));
213 return f;
217 * Report the existence of a file
219 bool nasm_file_exists(const char *filename)
221 #if defined(HAVE_FACCESSAT) && defined(AT_EACCESS)
222 return faccessat(AT_FDCWD, filename, R_OK, AT_EACCESS) == 0;
223 #elif defined(HAVE_ACCESS)
224 return access(filename, R_OK) == 0;
225 #else
226 FILE *f;
228 f = fopen(filename, "rb");
229 if (f) {
230 fclose(f);
231 return true;
232 } else {
233 return false;
235 #endif
239 * Report file size. This MAY move the file pointer.
241 off_t nasm_file_size(FILE *f)
243 #if defined(HAVE_FILENO) && defined(HAVE__FILELENGTHI64)
244 return _filelengthi64(fileno(f));
245 #elif defined(HAVE_FILENO) && defined(HAVE_FSTAT)
246 struct stat st;
248 if (fstat(fileno(f), &st))
249 return (off_t)-1;
251 return st.st_size;
252 #else
253 if (fseeko(f, 0, SEEK_END))
254 return (off_t)-1;
256 return ftello(f);
257 #endif
261 * Report file size given pathname
263 off_t nasm_file_size_by_path(const char *pathname)
265 #ifdef HAVE_STAT
266 struct stat st;
268 if (stat(pathname, &st))
269 return (off_t)-1;
271 return st.st_size;
272 #else
273 FILE *fp;
274 off_t len;
276 fp = nasm_open_read(pathname, NF_BINARY);
277 if (!fp)
278 return (off_t)-1;
280 len = nasm_file_size(fp);
281 fclose(fp);
283 return len;
284 #endif
288 * System page size
291 /* File scope since not all compilers like static data in inline functions */
292 static size_t nasm_pagemask;
294 static size_t get_pagemask(void)
296 size_t ps = 0;
298 # if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
299 ps = sysconf(_SC_PAGESIZE);
300 # elif defined(HAVE_GETPAGESIZE)
301 ps = getpagesize();
302 # endif
304 nasm_pagemask = ps = is_power2(ps) ? (ps - 1) : 0;
305 return ps;
308 static inline size_t pagemask(void)
310 size_t pm = nasm_pagemask;
312 if (unlikely(!pm))
313 return get_pagemask();
315 return pm;
319 * Try to map an input file into memory
321 const void *nasm_map_file(FILE *fp, off_t start, off_t len)
323 #if defined(HAVE_FILENO) && defined(HAVE_MMAP)
324 const char *p;
325 off_t astart; /* Aligned start */
326 size_t salign; /* Amount of start adjustment */
327 size_t alen; /* Aligned length */
328 const size_t page_mask = pagemask();
330 if (unlikely(!page_mask))
331 return NULL; /* Page size undefined? */
333 if (unlikely(!len))
334 return NULL; /* Mapping nothing... */
336 if (unlikely(len != (off_t)(size_t)len))
337 return NULL; /* Address space insufficient */
339 astart = start & ~(off_t)page_mask;
340 salign = start - astart;
341 alen = (len + salign + page_mask) & ~page_mask;
343 p = mmap(NULL, alen, PROT_READ, MAP_SHARED, fileno(fp), astart);
344 return unlikely(p == MAP_FAILED) ? NULL : p + salign;
345 #else
346 /* XXX: add Windows support? */
347 return NULL;
348 #endif
352 * Unmap an input file
354 void nasm_unmap_file(const void *p, size_t len)
356 #if defined(HAVE_FILENO) && defined(HAVE_MMAP)
357 const size_t page_mask = pagemask();
358 uintptr_t astart;
359 size_t salign;
360 size_t alen;
362 if (unlikely(!page_mask))
363 return;
365 astart = (uintptr_t)p & ~(uintptr_t)page_mask;
366 salign = (uintptr_t)p - astart;
367 alen = (len + salign + page_mask) & ~page_mask;
369 munmap((void *)astart, alen);
370 #endif