www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - print ubyte[] as (ascii) string

reply eugene <dee0xeed gmail.com> writes:
I suspect the question was asked somewhere before.
If so just give a link.

Anyway:

```d

class IoContext {
     ...
     ubyte[] buf;
     ...
     this(uint bufSize) {
         buf = new ubyte[bufSize];
     }
}

```

The buffer contains (ascii) string terminated with '\n'.
In order to print it not as an array of numbers (buf is 1024 
bytes long),
but as usual string I do

```d
char[] s = cast(char[])ioCtx.buf[0 .. 
strlen(cast(char*)ioCtx.buf.ptr) - 1];
// -1 is to eliminate terminating '\n'
writefln("got '%s' from '%s:%d'", s, client.addr, client.port);
```

Is there some more concise/elegant way to do that?

Of course, I could use old good printf() instead:
```d
printf(
     "got '%s' from '%s:%d'\n",
     ioCtx.buf.ptr,            // '\n' still there
     toStringz(client.addr),
     client.port
);
```

but I want to use D stdlib, not libc.
Dec 30 2021
next sibling parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Thursday, 30 December 2021 at 09:34:27 UTC, eugene wrote:
 The buffer contains (ascii) string terminated with '\n'. In 
 order to print it not as an array of numbers (buf is 1024 bytes 
 long), but as usual string I do
Few years ago i asked a similar question, not to do UTF-8 but to do Ascii. I was working on a tool for Morrowind after determining the strings were not variable in length and instead much like ascii fixed at 256 combinations. The answer i ended up with was a quick conversion to a UTF in order to print it. Seems you might have to convert to Latin-1. Here's the old thread. https://forum.dlang.org/thread/lehgyzmwewgvkdgraizv forum.dlang.org
Dec 30 2021
parent eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 16:00:59 UTC, Era Scarecrow 
wrote:
  The answer i ended up with was a quick conversion to a UTF in 
 order to print it. Seems you might have to convert to Latin-1.
For a moment I only have symbols from the lower half of ASCII table. I meant - can that be done as simple as in C, i.e: ```c u8 *buf; ... printf("%s", (char*)buf); ``` without any twists and turns.
Dec 30 2021
prev sibling next sibling parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 30 December 2021 at 09:34:27 UTC, eugene wrote:
 I suspect the question was asked somewhere before.
 If so just give a link.

 Anyway:

 ```d

 class IoContext {
     ...
     ubyte[] buf;
     ...
     this(uint bufSize) {
         buf = new ubyte[bufSize];
     }
 }

 ```
```d class IoContext { ... ubyte[] buf; ... this(uint bufSize) { buf.length = bufSize; //this should do the same thing, I believe } } ```
 The buffer contains (ascii) string terminated with '\n'.
 In order to print it not as an array of numbers (buf is 1024 
 bytes long),
 but as usual string I do

 ```d
 char[] s = cast(char[])ioCtx.buf[0 .. 
 strlen(cast(char*)ioCtx.buf.ptr) - 1];
 // -1 is to eliminate terminating '\n'
 writefln("got '%s' from '%s:%d'", s, client.addr, client.port);
 ```
```d char[] s = cast(char[])ioCtx.buf[0 .. $];// please remember that in `[0 .. $]` last index is automatically `length - 1` but just buf[$] will be an error since there the actual `length` will be used ``` I _think_ the above code is correct, please verify
Dec 30 2021
next sibling parent reply eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 16:49:17 UTC, Tejas wrote:
 ```d
 char[] s = cast(char[])ioCtx.buf[0 .. $];// please remember 
 that in `[0 .. $]` last index is automatically `length - 1` but 
 just buf[$] will be an error since there the actual `length` 
 will be used
 ```

 I _think_ the above code is correct, please verify
There is one pecularity: ```d char[] s = fromStringz(cast(char*)ioCtx.buf.ptr); writefln("got '%s' from '%s:%d'", s.strip, client.addr, client.port); // strip works :) ``` ```d char[] s = cast(char[])ioCtx.buf[0 .. $]; writefln("got '%s' from '%s:%d'", s.strip, client.addr, client.port); // strip does not work :( ```
Dec 30 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 30 December 2021 at 17:07:20 UTC, eugene wrote:
 On Thursday, 30 December 2021 at 16:49:17 UTC, Tejas wrote:
 ```d
 char[] s = cast(char[])ioCtx.buf[0 .. $];// please remember 
 that in `[0 .. $]` last index is automatically `length - 1` 
 but just buf[$] will be an error since there the actual 
 `length` will be used
 ```

 I _think_ the above code is correct, please verify
There is one pecularity: ```d char[] s = fromStringz(cast(char*)ioCtx.buf.ptr); writefln("got '%s' from '%s:%d'", s.strip, client.addr, client.port); // strip works :) ``` ```d char[] s = cast(char[])ioCtx.buf[0 .. $]; writefln("got '%s' from '%s:%d'", s.strip, client.addr, client.port); // strip does not work :( ```
I'll need to know the error message, because the following works: ```d import std; void main() { ubyte[] c ; c.length = 100; char[] arr = cast(char[])c[0 .. $]; foreach(ref elem; arr) elem = 'a'; writeln(arr.strip); } ```
Dec 30 2021
parent eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 17:16:10 UTC, Tejas wrote:
 I'll need to know the error message
There is none, see example in my prev message
 because the following works:
 ```d
 import std;
 void main()
 {
     ubyte[] c ;
     c.length = 100;
     char[] arr = cast(char[])c[0 .. $];
     foreach(ref elem; arr)
         elem = 'a';
     writeln(arr.strip);
 }
 ```
There is nothing to strip here (spaces, new lines...).
Dec 30 2021
prev sibling parent reply eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 16:49:17 UTC, Tejas wrote:
 I _think_ the above code is correct, please verify
Self-contained example: ```d import std.stdio; import std.string; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ char[] s = fromStringz(cast(char*)b.ptr); writefln("'%s, world'", s.strip); s = cast(char[])b[0 .. $]; writefln("'%s, world'", s.strip); } ``` Output: ``` mono:~/2-coding/d-lang/misc$ ./p 'hello, world' 'hello , world' ```
Dec 30 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 30 December 2021 at 17:31:27 UTC, eugene wrote:
 On Thursday, 30 December 2021 at 16:49:17 UTC, Tejas wrote:
 I _think_ the above code is correct, please verify
Self-contained example: ```d import std.stdio; import std.string; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ char[] s = fromStringz(cast(char*)b.ptr); writefln("'%s, world'", s.strip); s = cast(char[])b[0 .. $]; writefln("'%s, world'", s.strip); } ``` Output: ``` mono:~/2-coding/d-lang/misc$ ./p 'hello, world' 'hello , world' ```
I'm not at my computer anymore, could you please replace the `0x00` with `0x0A` and tell me if `strip` still doesn't work for my solution? I think the `fromstringz` is trimming the null bytes for you, making the `\n` the last character, allowing `strip` to work.
Dec 30 2021
parent reply eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 17:43:14 UTC, Tejas wrote:
 I'm not at my computer anymore, could you please replace the 
 `0x00` with `0x0A` and tell me if `strip` still doesn't work 
 for my solution?
Ok.
 I think the `fromstringz` is trimming the null bytes for you, 
 making the `\n` the last character, allowing `strip` to work.
Yes, you are right: ```d import std.stdio; import std.string; void main() { ubyte[8] b1 = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; ubyte[8] b2 = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x0A, 0x0A]; /* "hello\n\0\0" */ char[] s1 = fromStringz(cast(char*)b1.ptr); writefln("'%s, world'", s1.strip); char[] s2 = cast(char[])b2[0 .. $]; writefln("'%s, world'", s2.strip); } ``` output: ``` mono:~/2-coding/d-lang/misc$ ./p 'hello, world' 'hello, world' ``` everything as needed. thanks.
Dec 30 2021
parent reply eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 17:52:20 UTC, eugene wrote:
 everything as needed.
Nevertheless, I do have zeroes in the buffer, so: ```d import std.stdio; import std.string; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ char[] s = cast(char[])b[0 .. $]; writefln("'%s, world'", s.strip("\n\x00")); } ``` much better than my initial ```d char[] s = cast(char[])ioCtx.buf[0 .. strlen(cast(char*)ioCtx.buf.ptr) - 1]; ```
Dec 30 2021
parent reply Jack Applegame <japplegame gmail.com> writes:
On Thursday, 30 December 2021 at 18:07:15 UTC, eugene wrote:
 On Thursday, 30 December 2021 at 17:52:20 UTC, eugene wrote:
 much better than my initial
You can also write ```d auto s = cast(string)b; // or cast(string)(b) ``` instead of ```d char[] s = cast(char[])b[0 .. $]; ```
Jan 01 2022
parent eugene <dee0xeed gmail.com> writes:
On Saturday, 1 January 2022 at 09:34:10 UTC, Jack Applegame wrote:
 On Thursday, 30 December 2021 at 18:07:15 UTC, eugene wrote:
 On Thursday, 30 December 2021 at 17:52:20 UTC, eugene wrote:
 much better than my initial
You can also write ```d auto s = cast(string)b; // or cast(string)(b) ``` instead of ```d char[] s = cast(char[])b[0 .. $]; ```
```d import std.stdio; import std.string; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ auto s = cast(string)b; writefln("'%s, world'", s); writefln("'%s, world'", s.strip("\n\x00")); } ``` ``` mono:~/2-coding/d-lang/misc$ ./p2 'hello , world' 'hello, world' ```
Jan 02 2022
prev sibling next sibling parent eugene <dee0xeed gmail.com> writes:
On Thursday, 30 December 2021 at 09:34:27 UTC, eugene wrote:
 ```d
 char[] s = cast(char[])ioCtx.buf[0 .. 
 strlen(cast(char*)ioCtx.buf.ptr) - 1];
 // -1 is to eliminate terminating '\n'
 writefln("got '%s' from '%s:%d'", s, client.addr, client.port);
 ```
 Is there some more concise/elegant way to do that?
```d char[] s = fromStringz(cast(char*)ioCtx.buf.ptr).strip; writefln("got '%s' from '%s:%d'", s, client.addr, client.port); ``` Well, this will do:)
Dec 30 2021
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Thursday, 30 December 2021 at 09:34:27 UTC, eugene wrote:
 I suspect the question was asked somewhere before.
 If so just give a link.

 Anyway:

 ```d

 class IoContext {
     ...
     ubyte[] buf;
     ...
     this(uint bufSize) {
         buf = new ubyte[bufSize];
     }
 }

 ```

 The buffer contains (ascii) string terminated with '\n'.
 In order to print it not as an array of numbers (buf is 1024 
 bytes long),
 but as usual string I do

 ```d
 char[] s = cast(char[])ioCtx.buf[0 .. 
 strlen(cast(char*)ioCtx.buf.ptr) - 1];
 // -1 is to eliminate terminating '\n'
 writefln("got '%s' from '%s:%d'", s, client.addr, client.port);
 ```

 Is there some more concise/elegant way to do that?

 Of course, I could use old good printf() instead:
 ```d
 printf(
     "got '%s' from '%s:%d'\n",
     ioCtx.buf.ptr,            // '\n' still there
     toStringz(client.addr),
     client.port
 );
 ```

 but I want to use D stdlib, not libc.
Unless I'm misunderstanding: ```d import std.algorithm : until; writefln("got '%s' from '%s:%d'", (cast(char[])ioCtx.buf[]).until('\n'), client.addr, client.port); ``` Note that this does not save the "sliced" version of the buffer, so if you wanted to just search for the `\n` once, and keep using it, then you may want to use an algorithm that slices off everything until the character. -Steve
Dec 31 2021
parent reply eugene <dee0xeed gmail.com> writes:
On Friday, 31 December 2021 at 14:45:41 UTC, Steven Schveighoffer 
wrote:
 Unless I'm misunderstanding:

 ```d
 import std.algorithm  : until;
 writefln("got '%s' from '%s:%d'", 
 (cast(char[])ioCtx.buf[]).until('\n'), client.addr, 
 client.port);
 ```
```d import std.stdio; import std.string; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ writefln("'%s, world'", cast(char[])b[].until('\n')); } ``` ``` mono:~/2-coding/d-lang/misc$ dmd p1.d p1.d(8): Error: no property `until` for type `ubyte[]` ``` ``` mono:~/2-coding/d-lang/misc$ dmd --version DMD64 D Compiler v2.098.1 ```
Jan 02 2022
parent reply eugene <dee0xeed gmail.com> writes:
On Sunday, 2 January 2022 at 08:39:57 UTC, eugene wrote:
 ```d
 import std.stdio;
 import std.string;
 ```
oops... ```d import std.stdio; import std.string; import std.algorithm : until; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ writefln("'%s, world'", cast(char[])b[].until('\n')); } ``` ``` p1.d(9): Error: cannot cast expression `until(b[], '\x0a', Flag.yes)` of type `Until!("a == b", ubyte[], char)` to `char[]` ```
Jan 02 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 2 January 2022 at 09:15:32 UTC, eugene wrote:
 ```
 p1.d(9): Error: cannot cast expression `until(b[], '\x0a', 
 Flag.yes)` of type `Until!("a == b", ubyte[], char)` to `char[]`

 ```
Here's a working version: ```d import std.stdio; import std.string; import std.algorithm : until, map; import std.conv : to; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ writefln("'%-(%s%), world'", b[].until('\n').map!(to!char)); } ``` This code uses `map!(to!char)` to convert the elements of the range from `ubyte` to `char`, then uses a `%-(...%)` format specifier to print out each element of the range using the format string inside the parentheses (in this case, `%s`).
Jan 02 2022
parent eugene <dee0xeed gmail.com> writes:
On Sunday, 2 January 2022 at 15:13:06 UTC, Paul Backus wrote:
 On Sunday, 2 January 2022 at 09:15:32 UTC, eugene wrote:
 ```
 p1.d(9): Error: cannot cast expression `until(b[], '\x0a', 
 Flag.yes)` of type `Until!("a == b", ubyte[], char)` to 
 `char[]`

 ```
Here's a working version: ```d import std.stdio; import std.string; import std.algorithm : until, map; import std.conv : to; void main() { ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00]; /* "hello\n\0\0" */ writefln("'%-(%s%), world'", b[].until('\n').map!(to!char)); } ``` This code uses `map!(to!char)` to convert the elements of the range from `ubyte` to `char`, then uses a `%-(...%)` format specifier to print out each element of the range using the format string inside the parentheses (in this case, `%s`).
Well, just a Gross! But I am not a fun of functional programming style :) (sorry for replying late)
Jan 07 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 1/2/22 4:15 AM, eugene wrote:
 On Sunday, 2 January 2022 at 08:39:57 UTC, eugene wrote:
 ```d
 import std.stdio;
 import std.string;
 ```
oops... ```d import std.stdio; import std.string; import std.algorithm : until; void main() {     ubyte[8] b = [0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00];     /* "hello\n\0\0" */     writefln("'%s, world'", cast(char[])b[].until('\n')); } ``` ``` p1.d(9): Error: cannot cast expression `until(b[], '\x0a', Flag.yes)` of type `Until!("a == b", ubyte[], char)` to `char[]` ```
Thanks for posting the entire example, that always helps to diagnose unexpected errors. You missed a set of parentheses. `cast` is quite low for operator precedence. What is happening in your code is: `b[].until('\n')` is being evaluated *first*, which returns an `Until!...` struct, which then cannot be cast into char[]. But if you run my code, I do `(cast(char[])b[]).until('\n')`, which *first* casts the ubyte array into a char array, and *then* runs `until` on it. -Steve
Jan 02 2022
parent reply eugene <dee0xeed gmail.com> writes:
On Monday, 3 January 2022 at 02:50:46 UTC, Steven Schveighoffer 
wrote:
 On 1/2/22 4:15 AM, eugene wrote:
 On Sunday, 2 January 2022 at 08:39:57 UTC, eugene wrote:
 ```d
      writefln("'%s, world'", cast(char[])b[].until('\n'));
 }
 ```
 You missed a set of parentheses.
That was lack of attention from my side, sorry :) A couple of impressions... * Does .until() make a copy of original string? And GC then will take care of it? * So many ways to do simple C printf("%s", (char*)buf)... I am feeling like Buridan's ass
Jan 07 2022
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Jan 07, 2022 at 07:54:28PM +0000, eugene via Digitalmars-d-learn wrote:
[...]
 * Does .until() make a copy of original string? And GC then will take
 care of it?
No, it's one of the lazy range functions that lazily evaluates the string and does not allocate.
 * So many ways to do simple C printf("%s", (char*)buf)... I am feeling
 like Buridan's ass
D strings are different from C strings. Although D *can* handle C strings, it should not be surprising there's a bit of friction. The simplest way to handle a C string from D is just to use .fromStringz: import std.string : fromStringz; char *buf = some_c_function(); writeln(buf.fromStringz); Note that fromStringz is nogc, since it only takes a slice of the C string and does not copy anything. So it should be good even for GC-phobic code. T -- What do you get if you drop a piano down a mineshaft? A flat minor.
Jan 07 2022
next sibling parent eugene <dee0xeed gmail.com> writes:
On Friday, 7 January 2022 at 20:08:00 UTC, H. S. Teoh wrote:
 The simplest way to handle a C string from D is just to use 
 .fromStringz:
yes, this approach was used in some my previous traival
Jan 07 2022
prev sibling parent reply eugene <dee0xeed gmail.com> writes:
On Friday, 7 January 2022 at 20:08:00 UTC, H. S. Teoh wrote:
 So it should be good even for GC-phobic code.
Nice term - "GC-phobic" :) But looking from my cave - it's not a phobia, it's an observation. We've got a huge and complex project at my job, and... * python guys have memory leaks * js guys have memory leaks Both "systems" (I mean python and javascript) are GC-systems. And? Should I trust D with GC or accurate C-programmers? :)
Jan 07 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Friday, 7 January 2022 at 20:33:05 UTC, eugene wrote:
 * python guys have memory leaks
 * js guys have memory leaks
GC isn't actually there to prevent memory leaks. Its main job is to guard against use-after-free memory corruption bugs. Actually, technically, the paradigm is "infinite lifetime" and the garbage collection is just there as a practical matter because computers don't have infinite memory. They do a reasonably good job on memory leaks too, but that's not the main goal so they'd rather let memory leak than risk a use after free. That's why D lets you do a hybrid approach easily: where the lifetime is trivial, you can easily do it yourself to optimize memory use. But when it isn't so obvious, you can use the GC to play it safe at the cost of a lil more memory use.
Jan 07 2022
parent eugene <dee0xeed gmail.com> writes:
On Friday, 7 January 2022 at 20:40:02 UTC, Adam D Ruppe wrote:
 On Friday, 7 January 2022 at 20:33:05 UTC, eugene wrote:
 * python guys have memory leaks
 * js guys have memory leaks
GC isn't actually there to prevent memory leaks.
Aha, unless you'll build GC into OS core :)
 Its main job is to guard against use-after-free memory 
 corruption bugs
```c if (ptr) { free(ptr); ptr = NULL; } ... if (NULL == someptr) BUG()/PANIC()/WHATEVER() ```
 because computers don't have infinite memory
first time I've heard this ))) tell that to py/js super-coders :)
 where the lifetime is trivial, you can easily do it yourself to 
 optimize memory use. But when it isn't so obvious, you can use 
 the GC to play it safe at the cost of a lil more memory use.
other way around * when the lifetime is trivial (whithin a function, including thread function) - trust GC * when the lifetime is not trivial (ptr goes through or a self-pipe or similar) - GC has no info about that
Jan 07 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 1/7/22 2:54 PM, eugene wrote:

 A couple of impressions...
 
 * Does .until() make a copy of original string? And GC then will take 
 care of it?
No, `until` will iterate the string one character at a time until it sees that character (excluding it). It doesn't make a copy of the data. In effect, it's doing the "trim" and the iteration to print in one step. In your chosen solution earlier, you were doing it 3 times -- once to find the end of the null-terminated string (via `fromStringz`), once to strip the newline (well, this isn't too bad, since it goes from both ends), and once to actually print it.
 * So many ways to do simple C printf("%s", (char*)buf)... I am feeling 
 like Buridan's ass
There are a million ways to get what you want. I like to go for ones that: 1. don't allocate needlessly (I hate allocating a string just to print it, and then throw it away, regardless of whether it's GC or not) 2. read concisely and clearly. 3. Are as efficient as possible. The one wart here is the cast, but that's impossible to avoid unless you want to allocate. Adhering to 2 and 3 above sometimes are in conflict. But rule 1 is essential for performance. In C you have one choice (printf), but that choice may not fit your needs. -Steve
Jan 07 2022
parent reply eugene <dee0xeed gmail.com> writes:
On Friday, 7 January 2022 at 21:17:33 UTC, Steven Schveighoffer 
wrote:
 In C you have one choice (printf), but that choice may not fit 
 your needs.
There are 2 buffers (RX one and TX one, both of 'reasonable' size) (it's the effing echo-server, nothing more) * print content of RX-buffer, ommiting terminating '\n' ('\n' is the 'end of request') to (log/journal file)/stdout/ * ouptut received 'message' back to client, _with_ terminating '\n'
Jan 07 2022
next sibling parent frame <frame86 live.com> writes:
On Friday, 7 January 2022 at 22:04:28 UTC, eugene wrote:

 There are 2 buffers (RX one and TX one, both of 'reasonable' 
 size)
 (it's the effing echo-server, nothing more)

 * print content of RX-buffer, ommiting terminating '\n' ('\n' 
 is the 'end of request') to (log/journal file)/stdout/

 * ouptut received 'message' back to client, _with_ terminating 
 '\n'
However, you should not rely on a terminating '\n' even you are the source. You determine the length of string trough '\n' but maybe your buffer doesn't contain it (yet) if the connection wasn't blocking or the message is longer as the buffer size or you received just error data. Then, accessing the ubyte[] data directly via `.ptr`/ casting it to char* without knowing the possible content seems not a good idea - if you are using any function that returns bytes till it finds a needle or terminating '\0'. I know it's a little bit off topic but if the question is about the best concise way, the solution you choose should respect that too.
Jan 07 2022
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 1/7/22 5:04 PM, eugene wrote:
 On Friday, 7 January 2022 at 21:17:33 UTC, Steven Schveighoffer wrote:
 In C you have one choice (printf), but that choice may not fit your 
 needs.
There are 2 buffers (RX one and TX one, both of 'reasonable' size) (it's the effing echo-server, nothing more)
Irrelevant to how you log the data.
 * print content of RX-buffer, ommiting terminating '\n' ('\n' is the 
 'end of request') to (log/journal file)/stdout/
 
 * ouptut received 'message' back to client, _with_ terminating '\n'
Since the data is unmodified, then you can do this too after logging it without the `\n`. Two separate needs, both well handled by using ranges and algorithms. Or if they don't suit you well enough, just write your own. Writing a wrapping range isn't hard. -Steve
Jan 07 2022
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Thursday, 30 December 2021 at 09:34:27 UTC, eugene wrote:
 ```d
 char[] s = cast(char[])ioCtx.buf[0 .. 
 strlen(cast(char*)ioCtx.buf.ptr) - 1];
 // -1 is to eliminate terminating '\n'
 writefln("got '%s' from '%s:%d'", s, client.addr, client.port);
 ```

 Is there some more concise/elegant way to do that?
Try `auto s = fromStringz(cast(char*)ioCtx.buf.ptr)`.
Jan 07 2022