Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 8 commits
  • 4 files changed
  • 0 commit comments
  • 3 contributors
View
91 c_src/emmap.cpp
@@ -9,6 +9,11 @@
static ErlNifResourceType* MMAP_RESOURCE;
+#ifndef MAP_NOCACHE
+/* No MAP_NOCACHE on Linux - just bypass this option */
+#define MAP_NOCACHE (0)
+#endif
+
typedef struct
{
size_t position;
@@ -73,6 +78,7 @@ static ERL_NIF_TERM ATOM_EOF;
static ERL_NIF_TERM emmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_read(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM emmap_read_line(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_pread(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_pwrite(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -88,6 +94,7 @@ extern "C" {
{"pwrite_nif", 3, emmap_pwrite},
{"position_nif", 3, emmap_position},
{"read_nif", 2, emmap_read},
+ {"read_line_nif", 1, emmap_read_line},
};
ERL_NIF_INIT(emmap, nif_funcs, &on_load, NULL, NULL, NULL);
@@ -311,9 +318,12 @@ static ERL_NIF_TERM emmap_pread(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
&& enif_get_ulong(env, argv[2], &bytes)
&& pos >= 0
&& bytes >= 0
- && (pos + bytes) <= handle->len
+ && pos <= handle->len
)
{
+ // Adjust bytes to behave like original file:pread/3
+ if (pos + bytes > handle->len) bytes = handle->len - pos;
+
ErlNifBinary bin;
if ((handle->prot & PROT_READ) == 0) {
@@ -437,6 +447,85 @@ static ERL_NIF_TERM emmap_read(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
}
}
+static ERL_NIF_TERM emmap_read_line(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ mhandle *handle;
+
+ if (enif_get_resource(env, argv[0], MMAP_RESOURCE, (void**)&handle)) {
+
+ RW_LOCK;
+
+ if (handle->position == handle->len) {
+ RW_UNLOCK;
+ return ATOM_EOF;
+ }
+
+ long start = handle->position;
+ char *current = ((char*)handle->mem) + handle->position;
+ long linelen = 0; // Length of line without trailing \n
+ long no_crlf_len = 0;
+ bool have_cr = false;
+ bool got_eof = false;
+
+ // Read buffer until \n or EOF is reached
+ while (*current != '\n') {
+ handle->position ++;
+ current ++;
+ if (handle->position == handle->len) {
+ got_eof = true;
+ break;
+ }
+ }
+ // Step to next byte if EOF is not reached
+ if (not got_eof) {
+ handle->position ++;
+ }
+
+ no_crlf_len = linelen = handle->position - start;
+
+ if (not got_eof) {
+ // Found LF -- exclude it from line
+ no_crlf_len --;
+ // If line length before \n is non-zero check if we have \r before \n
+ if ((no_crlf_len > 0) && (*(current - 1) == '\r')) {
+ have_cr = true;
+ no_crlf_len --;
+ }
+ }
+
+ RW_UNLOCK;
+
+ // We must not include CR before LF in result, so use direct only without CR
+ if ((handle->direct) && (not have_cr)) {
+
+ // Include trailing LF if we have it
+ ERL_NIF_TERM res = enif_make_resource_binary
+ (env, handle, (void*) (((char*)handle->mem) + start), linelen);
+
+ return enif_make_tuple2(env, ATOM_OK, res);
+
+ } else {
+ if (not got_eof) linelen = no_crlf_len + 1;
+
+ ErlNifBinary bin;
+ // When it is non-direct, we have to allocate the binary
+ if (!enif_alloc_binary((size_t) linelen, &bin)) {
+ return make_error_tuple(env, ENOMEM);
+ }
+
+ memcpy(bin.data, (void*) (((char*)handle->mem) + start), no_crlf_len);
+ // Set trailing \n if needed
+ if (not got_eof) *(((char*)bin.data) + no_crlf_len) = '\n';
+
+ ERL_NIF_TERM res = enif_make_binary(env, &bin);
+ return enif_make_tuple2(env, ATOM_OK, res);
+ }
+
+ } else {
+ return enif_make_badarg(env);
+ }
+}
+
static ERL_NIF_TERM emmap_position(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
mhandle *handle;
View
BIN  rebar
Binary file not shown
View
5 rebar.config
@@ -1,7 +1,6 @@
-{port_sources, ["c_src/*.cpp"]}.
-{so_name, "emmap_nifs.so"}.
+{port_specs, [{"priv/emmap_nifs.so", ["c_src/*.cpp"]}]}.
-{port_envs, [
+{port_env, [
%% Make sure to link -lstdc++
{"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin)",
"LDFLAGS", "$LDFLAGS -lstdc++"},
View
15 src/emmap.erl
@@ -1,6 +1,6 @@
-module(emmap).
--export([open/2, open/4, close/1, pread/3, pwrite/3, read/2, position/2]).
+-export([open/2, open/4, close/1, pread/3, pwrite/3, read/2, read_line/1, position/2]).
-on_load(init/0).
-ifdef(TEST).
@@ -86,6 +86,16 @@ read_nif(_,_) ->
{ok, <<>>}.
+-spec read_line(File::mmap_file()) ->
+ {ok, binary()} | {error, term()} | eof.
+
+read_line(#file_descriptor{ module=?MODULE, data=Mem }) ->
+ read_line_nif(Mem).
+
+read_line_nif(_) ->
+ {ok, <<>>}.
+
+
-spec pwrite(File::mmap_file(), Position::pos_integer(), Data::binary()) ->
ok | {error, term()}.
@@ -101,6 +111,9 @@ pwrite_nif(_,_,_) ->
position(#file_descriptor{ module=?MODULE, data=Mem}, At)
when is_integer(At) ->
position_nif(Mem, bof, At);
+position(#file_descriptor{ module=?MODULE, data=Mem}, From)
+ when From == 'bof'; From == 'cur'; From == 'eof' ->
+ position_nif(Mem, From, 0);
position(#file_descriptor{ module=?MODULE, data=Mem}, {From, Off})
when From == 'bof'; From == 'cur'; From == 'eof' ->
position_nif(Mem, From, Off).

No commit comments for this range

Something went wrong with that request. Please try again.