www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how do you append arrays?

reply asdf <a b.c> writes:
I'm trying to make a terminal input preprocessor with 
alias/shortcuts and history.


import std.stdio;

void main() {
     string line;
     string[] history;

     line = readln();
     foreach(int i; 0..100) history = history + [""]; // XXX

     while(!stdin.eof) {
         writeln(line);
         if(line != history[0]) {
             history[1..100] = history[0..99];
             history[0] = line;
         }
         line = readln();
     }
}
Feb 25 2016
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 25 February 2016 at 12:53:37 UTC, asdf wrote:
 I'm trying to make a terminal input preprocessor with 
 alias/shortcuts and history.


 import std.stdio;

 void main() {
     string line;
     string[] history;

     line = readln();
     foreach(int i; 0..100) history = history + [""]; // XXX

     while(!stdin.eof) {
         writeln(line);
         if(line != history[0]) {
             history[1..100] = history[0..99];
             history[0] = line;
         }
         line = readln();
     }
 }
In D the binary operator "~" is used to concatenate both strings (arrays of characters) and arrays. (also the ~= operator is equivalent to lhs = lhs ~ rhs Nic
Feb 25 2016
next sibling parent asdf <a b.c> writes:
On Thursday, 25 February 2016 at 12:58:54 UTC, Nicholas Wilson 
wrote:
 In D the binary operator "~"  is used to concatenate both 
 strings (arrays of characters) and arrays. (also the ~= 
 operator is equivalent to lhs = lhs ~ rhs

 Nic
It worked! A link from someone else's question suggested `new string[101]` also. Now on to other problems, it never ends...
Feb 25 2016
prev sibling parent reply cym13 <cpicard openmailbox.org> writes:
On Thursday, 25 February 2016 at 12:58:54 UTC, Nicholas Wilson 
wrote:
 On Thursday, 25 February 2016 at 12:53:37 UTC, asdf wrote:
 I'm trying to make a terminal input preprocessor with 
 alias/shortcuts and history.


 import std.stdio;

 void main() {
     string line;
     string[] history;

     line = readln();
     foreach(int i; 0..100) history = history + [""]; // XXX

     while(!stdin.eof) {
         writeln(line);
         if(line != history[0]) {
             history[1..100] = history[0..99];
             history[0] = line;
         }
         line = readln();
     }
 }
In D the binary operator "~" is used to concatenate both strings (arrays of characters) and arrays. (also the ~= operator is equivalent to lhs = lhs ~ rhs Nic
Just a precision: "lhs ~= rhs" isn't exactly equivalent to "lhs = lhs ~ rhs", those are two distinct operators that may deal with memory etc in different ways. For arrays doing "lhs = lhs ~ rhs" will first create (and allocate) the array corresponding to "lhs ~ rhs" and then assign this new array to lhs. On the other hand "lhs ~= rhs" realises in-place append.
Feb 25 2016
parent reply asdf <a b.c> writes:
On Thursday, 25 February 2016 at 13:06:10 UTC, cym13 wrote:
 In D the binary operator "~"  is used to concatenate both 
 strings (arrays of characters) and arrays. (also the ~= 
 operator is equivalent to lhs = lhs ~ rhs

 Nic
Just a precision: "lhs ~= rhs" isn't exactly equivalent to "lhs = lhs ~ rhs", those are two distinct operators that may deal with memory etc in different ways. For arrays doing "lhs = lhs ~ rhs" will first create (and allocate) the array corresponding to "lhs ~ rhs" and then assign this new array to lhs. On the other hand "lhs ~= rhs" realises in-place append.
I tried both, the error this time is: object.Exception /data/data/com.termux/files/home/ldc/runtime/druntime/src/l c/arrayinit.d(151): overlapping array copy
Feb 25 2016
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 25 February 2016 at 13:24:09 UTC, asdf wrote:
 On Thursday, 25 February 2016 at 13:06:10 UTC, cym13 wrote:
 In D the binary operator "~"  is used to concatenate both 
 strings (arrays of characters) and arrays. (also the ~= 
 operator is equivalent to lhs = lhs ~ rhs

 Nic
Just a precision: "lhs ~= rhs" isn't exactly equivalent to "lhs = lhs ~ rhs", those are two distinct operators that may deal with memory etc in different ways. For arrays doing "lhs = lhs ~ rhs" will first create (and allocate) the array corresponding to "lhs ~ rhs" and then assign this new array to lhs. On the other hand "lhs ~= rhs" realises in-place append.
I tried both, the error this time is: object.Exception /data/data/com.termux/files/home/ldc/runtime/druntime/src/l c/arrayinit.d(151): overlapping array copy
so you will have to make a copy and then move it Im assuming history[1..100] = history[0..99]; this is the line causing your problem. Note that D has zero based array indexing so assuming your array has 100 elements history[1..100] is going one past the end of the array. also using a circular buffer here will solve this problem. Nic
Feb 25 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 25.02.2016 14:33, Nicholas Wilson wrote:
 Note that D has zero based array indexing
 so assuming your array has 100 elements history[1..100]
 is going one past the end of the array.
No, that's fine. `history[1..100]` gives you 99 elements starting at index 1, i.e. all except the first one.
Feb 25 2016
parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 25 February 2016 at 13:38:56 UTC, ag0aep6g wrote:
 On 25.02.2016 14:33, Nicholas Wilson wrote:
 Note that D has zero based array indexing
 so assuming your array has 100 elements history[1..100]
 is going one past the end of the array.
No, that's fine. `history[1..100]` gives you 99 elements starting at index 1, i.e. all except the first one.
Derp. You are correct, I was thinking about the first index.
Feb 25 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/25/16 8:24 AM, asdf wrote:
 On Thursday, 25 February 2016 at 13:06:10 UTC, cym13 wrote:
 In D the binary operator "~"  is used to concatenate both strings
 (arrays of characters) and arrays. (also the ~= operator is
 equivalent to lhs = lhs ~ rhs

 Nic
Just a precision: "lhs ~= rhs" isn't exactly equivalent to "lhs = lhs ~ rhs", those are two distinct operators that may deal with memory etc in different ways. For arrays doing "lhs = lhs ~ rhs" will first create (and allocate) the array corresponding to "lhs ~ rhs" and then assign this new array to lhs. On the other hand "lhs ~= rhs" realises in-place append.
I tried both, the error this time is: object.Exception /data/data/com.termux/files/home/ldc/runtime/druntime/src/ldc/arrayinit.d(151): overlapping array copy
overlapping copies are not supported. In this case especially, the copying has to be done backwards. I believe you could use std.algorithm.copy, but probably need to do it with retro as well. -Steve
Feb 25 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/25/16 2:12 PM, Steven Schveighoffer wrote:
 I believe you could use std.algorithm.copy, but probably need to do it
 with retro as well.
Heh, or of course use memmove :) -Steve
Feb 25 2016
parent reply asdf <a b.c> writes:
On Thursday, 25 February 2016 at 19:21:31 UTC, Steven 
Schveighoffer wrote:
 On 2/25/16 2:12 PM, Steven Schveighoffer wrote:
 I believe you could use std.algorithm.copy, but probably need 
 to do it
 with retro as well.
Heh, or of course use memmove :) -Steve
I got the history list working this morning but probably not very efficient. You can see: ---- cut ---- debug = 0; import std.stdio; import std.string; void main() { string line; string[] history; char cmd = '/', sep = ';', dot = '.', bak = '\\'; line = readln().chomp; foreach(int i; 0..100) history ~= ""; debug(1) { stderr.writeln(history); } while(!stdin.eof) { string[] emit = line.split(sep); foreach(string e; emit) { /* how to do proper prefix and/or leading word? */ if(e[0] == cmd) { /* ... */ } else if(e[0] == dot) { /* ... */ } else if(e[0] == bak) { /* ... */ } else writeln(e); } if(line != "" && line != history[0]) { string[] x = [line]; foreach(string i; history[0..99]) x ~= i; history = x; } debug(1) { stderr.writeln(history); } line = readln().chomp; } } ---- cut ---- Is there a good way to pick out matching prefixes of a string? Picking out the first word without disrupting whitespace after the second word would be nice =) How do you read chars without waiting for a newline? That would be needed to respond to the ANSI esapes for arrow keys...
Feb 25 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/25/16 4:39 PM, asdf wrote:

          if(line != "" && line != history[0]) {
              string[] x = [line];
              foreach(string i; history[0..99]) x ~= i;
              history = x;
          }
ugh! history = line ~ history[0 .. $ - 1]; What you may want to consider is making history backwards referenced. That is, history[0] is the oldest line. Then you could do: history = history[1 .. $]; history ~= line;
 Is there a good way to pick out matching prefixes of a string? Picking
 out the first word without disrupting whitespace after the second word
 would be nice =)

 How do you read chars without waiting for a newline? That would be
 needed to respond to the ANSI esapes for arrow keys...
If you are only getting characters after a newline, then you aren't interacting directly with the terminal (which requires some terminal access library). The terminal is letting the user edit the line, then when he hits return, it sends the whole line to your program. You won't get arrow key codes. -Steve
Feb 25 2016
parent reply asdf <a b.c> writes:
On Friday, 26 February 2016 at 00:40:40 UTC, Steven Schveighoffer 
wrote:
 ugh!

 history = line ~ history[0 .. $ - 1];
That works alot better =) Trying to uncook the terminal failed however. It can't recognize struct tag-declarations I think: /* copy-paste code from: http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html */ import core.sys.linux.termios; // struct termios oldterm; // struct termios newterm; termios.termios oldterm; termios.termios newterm; void uncook_term() { tcgetattr(stdin.fileno, &oldterm); newterm = oldterm; newterm.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newterm.c_iflag = IGNPAR; newterm.c_oflag = 0; newterm.c_lflag = 0; tcflush(stdin.fileno, TCIFLUSH); tcsetattr(stdin.fileno, TCSANOW, &newterm); } void restore_term() { tcsetattr(stdin.fileno, TCSANOW, &oldterm); } void main() { uncook_term(); char ch = read(); while(ch != 'q' && !stdin.eof) { write(ch); ch = read(); } restore_term(); }
Feb 26 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 02/26/2016 12:47 AM, asdf wrote:

 Trying to uncook the terminal failed however. It can't recognize struct
 tag-declarations I think:
The following compiles and seems to work. I've marked my changes with // Ali: /* copy-paste code from: http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html */ import std.stdio; // Ali import core.sys.linux.termios; // struct termios oldterm; // struct termios newterm; termios oldterm; // Ali termios newterm; // Ali void uncook_term() { tcgetattr(stdin.fileno, &oldterm); newterm = oldterm; newterm.c_cflag = /*BAUDRATE | Ali */ CRTSCTS | CS8 | CLOCAL | CREAD; newterm.c_iflag = IGNPAR; newterm.c_oflag = 0; newterm.c_lflag = 0; tcflush(stdin.fileno, TCIFLUSH); tcsetattr(stdin.fileno, TCSANOW, &newterm); } void restore_term() { tcsetattr(stdin.fileno, TCSANOW, &oldterm); } void main() { uncook_term(); int ch = fgetc(core.stdc.stdio.stdin); //read(); Ali while(ch != 'q' && !stdin.eof) { write(ch); ch = fgetc(core.stdc.stdio.stdin); //read(); Ali } restore_term(); } Ali
Feb 26 2016
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 02/26/2016 01:01 AM, Ali Çehreli wrote:
 On 02/26/2016 12:47 AM, asdf wrote:

 Trying to uncook the terminal failed however. It can't recognize struct
 tag-declarations I think:
I've just found the following code among my collection of D snippets, which uses a different method and supports Ctrl-D: import std.stdio : writef, writeln; import core.stdc.stdio; import core.sys.posix.termios; /* The declaration of cfmakeraw, which is missing from standard D modules. */ extern(C) void cfmakeraw(termios *termios_p); void main() { /* Saving the existing state of tty. */ termios oldState; tcgetattr(1, &oldState); /* Ensuring that it will be restored upon exit. */ scope (exit) tcsetattr(1, TCSADRAIN, &oldState); /* Make a new state and set it to raw mode. */ termios newState; tcgetattr(1, &newState); cfmakeraw(&newState); /* Use the new state in this terminal. */ tcsetattr(1, TCSADRAIN, &newState); /* * We are ready to read characters in this raw mode... */ /* This is Ctrl-D, the EOF character under Linux. */ enum endOfFile = '\4'; for (char c; c != endOfFile; ) { c = cast(char)fgetc(stdin); writef("%02x ", c); } writeln(); } Ali
Feb 26 2016
prev sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 25 February 2016 at 12:53:37 UTC, asdf wrote:
 I'm trying to make a terminal input preprocessor with 
 alias/shortcuts and history.


 import std.stdio;

 void main() {
     string line;
     string[] history;

     line = readln();
     foreach(int i; 0..100) history = history + [""]; // XXX

     while(!stdin.eof) {
         writeln(line);
         if(line != history[0]) {
             history[1..100] = history[0..99];
             history[0] = line;
         }
         line = readln();
     }
 }
Also for this kind of thing you probably want to use a circular buffer. I'm sure there is an implementation of one somewhere. see std.range.cycle
Feb 25 2016