diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/Makefile.in | 77 | ||||
-rw-r--r-- | src/utils/hammer.cc | 414 | ||||
-rw-r--r-- | src/utils/storage.H | 87 | ||||
-rw-r--r-- | src/utils/storage.cc | 175 |
4 files changed, 753 insertions, 0 deletions
diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in new file mode 100644 index 00000000..024af5dc --- /dev/null +++ b/src/utils/Makefile.in @@ -0,0 +1,77 @@ +# Copyright (C) 2010, Gabriel Dos Reis. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# - Neither the name of The Numerical Algorithms Group Ltd. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +subdir = src/utils/ + +bin_PROGRAMS = hammer$(EXEEXT) +hammer_SOURCES = hammer.cc +hammer_OBJECTS = $(hammer_SOURCES:.cc=.lo) +hammer_LDADD = -L. -lOpenAxiom + +libOpenAxiom_HEADERS = storage.H +libOpenAxiom_SOURCES = storage.cc +libOpenAxiom_OBJECTS = $(libOpenAxiom_SOURCES:.cc=.lo) + +.PHONY: all all-ax all-utils +.SUFFIXES: +.SUFFIXES: .cc .H $(OBJEXT) $(LIBEXT) + +all: all-ax + +all-ax all-utils: stamp + +stamp: libOpenAxiom.$(LIBEXT) hammer$(EXEEXT) + -rm -f stamp + $(STAMP) stamp + +.SUFFIXES: +.SUFFIXES: .c .h .lo .$(OBJEXT) +.PRECIOUS: %.lo %.obj + +hammer$(EXEEXT): $(hammer_OBJECTS) libOpenAxiom.$(LIBEXT) + $(CXXLINK) -o $@ $(hammer_OBJECTS) $(hammer_LDADD) $(LDFLAGS) + +libOpenAxiom.$(LIBEXT): $(libOpenAxiom_OBJECTS) + $(CXXLINK) -o $@ $(libOpenAxiom_OBJECTS) + +%.lo: %.cc $(libOpenAxiom_HEADERS) + $(CXXCOMPILE) ${CXXFLAGS} -I. -I$(top_builddir)/config -o $@ $< + + +mostlyclean-local: + @rm -rf .libs + @rm -f $(libOpenAxiom_OBJECTS) + @rm -f *~ core + +clean-local: mostlyclean-local + +distclean-local: clean-local + diff --git a/src/utils/hammer.cc b/src/utils/hammer.cc new file mode 100644 index 00000000..17c5cc73 --- /dev/null +++ b/src/utils/hammer.cc @@ -0,0 +1,414 @@ +// Copyright (C) 2010, Gabriel Dos Reis. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of The Numerical Algorithms Group Ltd. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <string.h> +#include <stdlib.h> +#include <utility> +#include <string> +#include <iostream> +#include <fstream> +#include <iterator> +#include <list> +#include <vector> +#include <map> +#include "storage.H" + +// -- This program implements basic functionalities for untangling +// -- algebra source code from the pamphlets. The syntax is that +// -- of `noweb'. A chunk definition starts with a pattern +// -- <<name>>= on a line by itself, and ends with `@' by itself +// -- on a line. A chunk can refer to another chunk through +// -- a pattern of the form `<<name>>'. + +namespace OpenAxiom { + namespace Hammer { + // ------------- + // -- Element -- + // ------------- + // Base class of document elements. + struct Element { + virtual ~Element() { } + }; + + // --------------- + // -- BasicText -- + // --------------- + // Plain text, with no reference to any chunk. + struct BasicText : Element { + BasicText(const char* f, const char* l) : span(f, l) { } + // Pointer to the start of this basic text element + const char* begin() const { return span.first; } + // Oone-past-the-end of the this basic text element. + const char* end() const { return span.second; } + private: + std::pair<const char*, const char*> span; + }; + + // --------------- + // -- Reference -- + // --------------- + // Reference to a a chunk by name. + struct Reference : Element { + explicit Reference(const std::string& s) : label(s) { } + // Naame of the chunk referenced. + const std::string& name() const { return label; } + private: + const std::string label; + }; + + // ------------------- + // -- CompositeText -- + // ------------------- + // Sequence of basic elements and reference to chunks. + struct CompositeText: private std::vector<const Element*> { + typedef std::vector<const Element*> base; + using base::iterator; + using base::begin; + using base::end; + using base::size; + using base::operator[]; + + // Augment this chunk with a basic text in the open interval + // [f,l). + CompositeText& add_text(const char* f, const char* l) { + texts.push_back(BasicText(f, l)); + push_back(&texts.back()); + return *this; + } + + // Augment this chunk with a reference to another chunk + // named `n'. Note that we don't attempt to check for + // possible circularities. + CompositeText reference_chunk(const char* f, const char* l) { + refs.push_back(Reference(std::string(f, l))); + push_back(&refs.back()); + return *this; + } + + private: + std::list<BasicText> texts; + std::list<Reference> refs; + }; + + // -------------- + // -- Document -- + // -------------- + // A whole document; a sequence of chunks. + struct Document : std::list<CompositeText> { + Document(const Memory::FileMapping& file) + : active_chunk(&prose), text_start(file.begin()) { + parse(file); + } + + // Return a pointer to a document chunk name `n'. + // Otherwise, return null. + CompositeText* lookup_chunk(const std::string& n) const { + ChunkTable::const_iterator i = defs.find(n); + return i == defs.end() ? 0 : i->second; + } + + private: + typedef std::map<std::string, CompositeText*> ChunkTable; + CompositeText prose; // the prose around the chunks. + ChunkTable defs; // chunk definition table. + CompositeText* active_chunk; // chunk under construction. + const char* text_start; // begining of current basic text. + + // Append basic text in the range `[text_start,last)' + // to the current chunk. + void finish_chunk(const char* last) { + if (text_start != last) + active_chunk->add_text(text_start, last); + active_chunk = &prose; + text_start = last; + } + + // Start a new chunk or extend an existing chunk. + void begin_chunk(const std::string& name, const char* start) { + if (CompositeText* chunk = lookup_chunk(name)) + active_chunk = chunk; + else { + push_back(CompositeText()); + defs[name] = active_chunk = &back(); + } + text_start = start; + } + + // Parse a file mapping into this document. + void parse(const Memory::FileMapping&); + }; + + // Return true if the character `c' introduces a newline. + static inline bool + looking_at_newline(char c) { + return c == '\n' or c == '\r'; + } + + // Attempt to advance the cursor past newline marker. + // Return true on sucess. + static bool + saw_newline(const char*& cur, const char* end) { + if (*cur == '\n') { + ++cur; + return true; + } + else if (*cur == '\r') { + if (++cur < end and *cur == '\n') + ++cur; + return true; + } + return false; + } + + // Move `cur' to end of line or `end', whichever comes first. + // Return true if the area swept consisted only of blank characters. + static inline bool + trailing_blank(const char*& cur, const char* end) { + bool result = true; + for (; cur < end and not saw_newline(cur, end); ++cur) + result = isspace(*cur); + return result; + } + + // Attempt to advance `cur' past the double left angle brackets + // starting a chunk name. Returm true on success. + static bool + chunk_name_began(const char*& cur, const char* end) { + if (cur[0] == '<' and cur + 1 < end and cur[1] == '<') { + cur += 2; + return true; + } + return false; + } + + // Attempt to move `cur' past the double right angle brackets + // terminating a chunk name. Returm true on success. + static bool + chunk_name_ended(const char*& cur, const char* end) { + if (cur[0] == '>' and cur + 1 < end and cur[1] == '>') { + cur += 2; + return true; + } + return false; + } + + // We've just seen the start of a chunk reference; skip + // characters till we seen of the chunk's name. + static void + skip_to_end_of_chunk_name(const char*& cur, const char* end) { + while (cur < end) { + if (looking_at_newline(*cur) + or (cur + 1 < end and cur[0] == '>' and cur[1] == '>')) + return; + ++cur; + } + } + + // Move the cursor until end of line. + static void + skip_to_end_of_line(const char*& cur, const char* end) { + while (cur < end) { + if (saw_newline(cur, end)) + break; + ++cur; + } + } + + void + Document::parse(const Memory::FileMapping& file) { + const char* cur = text_start; + const char* last = file.end(); + // Process one line at a time. + while (cur < last) { + // 1. `@' ends previous chunk + if (*cur == '@') { + const char* p = cur; + if (trailing_blank(++cur, last)) + finish_chunk(p); + } + // 2. `<<' introduces a chunk reference or a chunk definition. + else if (chunk_name_began(cur, last)) { + const char* label_start = cur; + skip_to_end_of_chunk_name(cur, last); + if (chunk_name_ended(cur, last)) { + const char* label_end = cur - 2; + if (cur < last and *cur == '=') { + if (trailing_blank(++cur, last)) { + // chunk definition or extension + finish_chunk(label_start - 2); + begin_chunk(std::string(label_start, label_end), cur); + } + } + else if (trailing_blank(cur, last)) { + // This is just a reference to a chunk. + active_chunk->add_text(text_start, label_start - 2); + active_chunk->reference_chunk(label_start, label_end); + text_start = cur; + } + else + skip_to_end_of_line(cur, last); + } + } + else + skip_to_end_of_line(cur, last); + } + finish_chunk(cur); + } + + // Capture chunk resolution in a document. + struct resolve_chunk { + resolve_chunk(const std::string& s, const Document& f) + : name(s), doc(f) { } + const std::string name; // name of the chunk + const Document& doc; // document containing the chunk. + }; + + // Print the resolution of a chunk name onto an output stream. + std::ostream& + operator<<(std::ostream& os, const resolve_chunk& rc) { + // FIXME: no attempt at detecting circularities. + const CompositeText* doc = rc.doc.lookup_chunk(rc.name); + if (doc == 0) { + std::cerr << "chunk " << rc.name << " is undefined" << std::endl; + exit(1); + } + for (std::size_t i = 0; i < doc->size(); ++i) { + const Element* elt = (*doc)[i]; + if (const BasicText* t = dynamic_cast<const BasicText*>(elt)) + std::copy(t->begin(), t->end(), + std::ostream_iterator<char>(os)); + else if (const Reference* r = dynamic_cast<const Reference*>(elt)) + os << resolve_chunk(r->name(), rc.doc); + else { + std::cerr << "unknown document element" << std::endl; + exit(1); + } + } + + return os; + } + + // Return true if the `arg' is the option named`opt'. + static inline bool + is_option(const char* arg, const char* opt) { + return strcmp(arg, opt) == 0; + } + + // `arg' is a argument on the command line. If `arg' + // does not match option name `opt', return null. Otherwise, + // return a pointer to the terminating NUL character if there + // is no specified value for that option, or a pointer to the + // start of the value. + static const char* + is_named_arg(const char* arg, const char* opt) { + const int n = strlen(opt); + int i = 0; + // Get out if argion name does not match. + // Note: Ideally, we could use strncmp(). However, that + // function is not available in C++98, so we cannot depend on it. + for (; i < n ; ++i) + if (arg[i] != opt[i]) + return 0; + + if (arg[i] == '\0') + return arg + i; // no value for the option. + return arg + n + 1; // being of the value. + } + } +} + + +int +main(int argc, char* argv[]) { + using namespace OpenAxiom::Hammer; + int error_count = 0; + const char* chunk = 0; // chunck to tangle + const char* output_path = 0; // path to the output file + const char* input_path = 0; // path to the input file. + // 1. Process command line arguments. + for (int pos = 1; error_count == 0 and pos < argc; ++pos) { + if (const char* val = is_named_arg(argv[pos], "--tangle")) { + if (chunk != 0) { + std::cerr << "cannot tangle more than one chunk"; + ++error_count; + } + else + chunk = *val == 0 ? "*" : val; + } + else if (const char* val = is_named_arg(argv[pos], "--output")) { + if (*val == 0) { + std::cerr << "missing output file name" << std::endl; + ++error_count; + } + else + output_path = val; + } + else if (argv[pos][0] == '-' and argv[pos][1] == '-') { + std::cerr << "unknown option " << argv[pos] << std::endl; + ++error_count; + } + else if (input_path != 0) { + std::cerr << "there must be exactly one input file" << std::endl; + ++error_count; + } + else + input_path = argv[pos]; + } + + // 2. Basic sanity check. + if (input_path == 0) { + std::cerr << "missing input file" << std::endl; + return 1; + } + if (output_path == 0) { + std::cerr << "missing output file" << std::endl; + return 1; + } + if (chunk == 0) { + std::cerr << "missing chunk name" << std::endl; + return 1; + } + + if (error_count != 0) + return 1; + + // 3. Attempt to extract the chunk. + try { + OpenAxiom::Memory::FileMapping file(input_path); + std::ofstream os(output_path); + os << resolve_chunk(chunk, Document(file)); + } + catch(const OpenAxiom::SystemError& e) { + std::cerr << e.message() << std::endl; + exit(1); + } + return 0; +} diff --git a/src/utils/storage.H b/src/utils/storage.H new file mode 100644 index 00000000..ba14ec97 --- /dev/null +++ b/src/utils/storage.H @@ -0,0 +1,87 @@ +// Copyright (C) 2010, Gabriel Dos Reis. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of The Numerical Algorithms Group Ltd. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <stddef.h> +#include <string> + +namespace OpenAxiom { + // ----------------- + // -- SystemError -- + // ----------------- + // Objects of (type derived from) this type are used to report + // error orignating from the OpenAxiom core system. + struct SystemError { + explicit SystemError(std::string); + virtual ~SystemError(); + // Return the text of the diagnostic message. + virtual const std::string& message() const; + protected: + const std::string text; + }; + + // Report a file system erro + void filesystem_error(std::string); + + namespace Memory { + // Datatype for pointers to data. + typedef void* Pointer; + + // Precision of the host OS storage page unit in byte count + size_t page_size(); + + // Acquire raw memory from the host OS in multiple + // of storage page nits. + Pointer os_acquire_raw_memory(size_t); + + // Release raw storage to the hosting OS. The first operand must + // be a pointer value previous returned by `os_acquire_raw_memory'. + // Otherwise, the result is undefined. + void os_release_raw_memory(Pointer, size_t); + + // ----------------- + // -- FileMapping -- + // ----------------- + struct FileMapping { + explicit FileMapping(std::string); + ~FileMapping(); + const char* begin() const { return static_cast<const char*>(start); } + const char* end() const { return begin() + extent; } + std::size_t size() const { return extent; } + protected: + Pointer start; // address at the mapped storage + size_t extent; // length (in bytes) of the storage + private: + FileMapping(const FileMapping&); // not implemented + FileMapping& operator=(const FileMapping&); // idem + }; + + } +} diff --git a/src/utils/storage.cc b/src/utils/storage.cc new file mode 100644 index 00000000..4db7f302 --- /dev/null +++ b/src/utils/storage.cc @@ -0,0 +1,175 @@ +// Copyright (C) 2010, Gabriel Dos Reis. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of The Numerical Algorithms Group Ltd. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "openaxiom-c-macros.h" + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#include <sys/types.h> +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif +#ifdef OPENAXIOM_MS_WINDOWS_HOST +# include <windows.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "storage.H" + +namespace OpenAxiom { + // ---------------- + // -- SystemError -- + // ---------------- + SystemError::SystemError(std::string s) : text(s) { } + + SystemError::~SystemError() { } + + const std::string& + SystemError::message() const { + return text; + } + + void + filesystem_error(std::string s) { + throw SystemError(s); + } + + namespace Memory { + // Return storage page allocation unit in byte count. + size_t page_size() { +#if defined(OPENAXIOM_MS_WINDOWS_HOST) + SYSTEM_INFO si = { }; + GetSystemInfo(&si); + return si.dwPageSize; +#elif defined(HAVE_UNISTD_H) + return sysconf(_SC_PAGESIZE); +#else + // Well, we have to return a number. + return 4096; +#endif + } + + // Subroutine of os_acquire_raw_memory. Attempt to acquire + // storage from the host OS. Return null on failure. + static inline Pointer + os_allocate_read_write_raw_memory(size_t nbytes) { +#if defined(OPENAXIOM_MS_WINDOWS_HOST) + return VirtualAlloc(Pointer(), nbytes, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +#elif defined(HAVE_SYS_MMAN_H) + Pointer p = mmap(Pointer(), nbytes, PROT_READ | PROT_WRITE, + MAP_PRIVATE | OPENAXIOM_MM_ANONYMOUS_MAP_FLAG, + -1, 0); + return p == MAP_FAILED ? Pointer() : p; +#else + return malloc(byte_count); +#endif + } + + Pointer + os_acquire_raw_memory(size_t nbytes) { + Pointer p = os_allocate_read_write_raw_memory(nbytes); + if (p == 0) + throw SystemError("cannot acquire more memory"); + return memset(p, nbytes, 0); + } + + void + os_release_raw_memory(Pointer p, size_t n) { +#if defined(OPENAXIOM_MS_WINDOWS_HOST) + VirtualFree(p, 0, MEM_RELEASE); +#elif defined(HAVE_SYS_MMAN_H) + munmap(p, n); +#else + free(p); +#endif + } + + // ----------------- + // -- FileMapping -- + // ----------------- + FileMapping::FileMapping(std::string path) + : start(), extent() { +#if defined(OPENAXIOM_MS_WINDOWS_HOST) + HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + filesystem_error("could not access file " + path); + HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0); + if (mapping == 0) + filesystem_error("could not map file " + path); + start = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); + extent = GetFileSize(file, 0); + CloseHandle(mapping); + CloseHandle(file); +#elif defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_FCNTL_H) + struct stat s; + errno = 0; + if (stat(path.c_str(), &s) < 0) + filesystem_error("could not access file " + path); + else if (!S_ISREG(s.st_mode)) + filesystem_error(path + " is not a regular file"); + int fd = open(path.c_str(), O_RDONLY); + if (fd < 0) + filesystem_error("could not open " + path); + start = mmap(Pointer(), s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (start == MAP_FAILED) + filesystem_error("could not map file " + path); + extent = s.st_size; +#else +# error "Don't know how to map a file on this platform" +#endif // OPENAXIOM_MS_WINDOWS_HOST + } + + FileMapping::~FileMapping() { +#if defined(OPENAXIOM_MS_WINDOWS_HOST) + UnmapViewOfFile(start); +#elif defined(HAVE_SYS_MMAN_H) + munmap(start, extent); +#else +# error "Don't know how to unmap a file on this platform" +#endif + } + } +} |