diff --git a/echo/echo.rs b/echo/echo.rs new file mode 100644 index 0000000..e0ebe81 --- /dev/null +++ b/echo/echo.rs @@ -0,0 +1,10 @@ +use std::env::args; + +fn main() { // cannot do non UTF-8 strings as far as I know + if args().collect::>().len() >= 2 { + for argument in args().skip(1) { + print!("{} ", argument); + } + } + print!("\n"); +} diff --git a/false/false.rs b/false/false.rs new file mode 100644 index 0000000..31bcdc5 --- /dev/null +++ b/false/false.rs @@ -0,0 +1,5 @@ +use std::process::ExitCode; + +fn main() -> ExitCode { + ExitCode::from(1) +} diff --git a/homepage/homepage b/homepage/homepage index a30ab25..3e86202 100755 --- a/homepage/homepage +++ b/homepage/homepage @@ -1925,6 +1925,843 @@ If I don't, escalate the issue to the host of this site (this can also be found +/blah/2023-10-31.html + +: trinity writes a rust hello world + +Where I now find myself living (though to say I live here would be a lie) I am +surrounded by a couple of the smartest people I know, and through some days of +wearing me down I am donning the programmer socks and writing a Rust Hello +World program. + +I am now actually wearing thigh highs. +# apk add rust + +I don't actually know how to get the Rust build system going but this seems +like the best option so I'll go with this which is already packaged for +Chimera. + +Oh, I'll need cargo(1) too. +# apk add cargo + +One of my friends built the Rust book PDF for me which is nice because I can +consult it on my tablet while programming on the laptop. + +>Foreword +>It wasn't always so clear, but the Rust programming language is fundamentally +>about *empowerment*... + +Okay, I get why so many chan-types are so against Rust. But seeing how people +who know Rust use Rust I am sort of starting to get it. It's a high level +language that can be used well for systems programming, basically? + +>To check whether you have Rust installed correctly, open a shell and enter +>this line: +$ rustc --version +Okay. +rustc 1.73.0 (cc66ad468 2023-10-03) (Chimera Linux) +Awesome! + +I don't have rustup so I can't read the Rust docs but I'll probably be around a +web browser when programming so I think it's fine? + +Rust wants me to make a Hello, World! to start, but that's not super practical +code for me. I think I'm gonna start smaller and make a true(1) implementation. + +```rs +fn main() { +} +``` + +Works. + +```rs +``` + +Does not work; there's no `main` function so the program doesn't know how to +execute: + +error[E0601]: `main` function not found in crate `r#true` + | + = note: consider adding a `main` function to `true.rs` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0601`. + +I really like the `rustc --explain` thing, this reminds me of Shellcheck. +Compare to the clang error message when compiling the same file: + +ld: error: undefined symbol: main +>>> referenced by crt1.c:18 (../crt/crt1.c:18) +>>> /lib/Scrt1.o:(_start_c) +>>> referenced by crt1.c:18 (../crt/crt1.c:18) +>>> /lib/Scrt1.o:(_start_c) +clang-16: error: linker command failed with exit code 1 (use -v to see invocati +on) + +There's a lot going on here that the beginner (or even proficient C programmer) +doesn't know and doesn't know how to start to know. + +Alright, what about this: + +```rs +fn main(); +``` + +error: free function without a body + --> true.rs:1:1 + | +1 | fn main(); + | ^^^^^^^^^- + | | + | help: provide a definition for the function: `{ }` + +error: aborting due to previous error + +Okay, so `fn main() { }` seems to be the simplest way to do this. How do I +return an exit code explicitly, though, so I can make a false(1) +implementation? + +It was at this point one of the people I know who knows Rust came by and I told +them how I was coming along and they were really supportive of my very meager +progress. + +I found some stuff here: +https://doc.rust-lang.org/std/process/struct.ExitCode.html + +So instead of understanding everything that's happening I'll try just plugging +some code in, StackOverflow style: + +```rs +use std::process::ExitCode; + +fn main() -> ExitCode { + ExitCode::from(0) +} +``` + +TRIN: Can I name you in my blog? Or should I keep saying "it was at this point + one of the people with which I'm staying walked through on its pacing + route"? +MARS: You can say Mars, that's fine. + +TRIN: So you can put a constant on the last line of a function + without a trailing semicolon to return that value? +MARS [paraphrased]: Yeah. It's less to say, "return that value" than it is to + say "this function has this value". Rust is a functional + language disguised as a procedural language. + +Okay, that fucks. ExitCode has a SUCCESS constant I could also use, meaning the +equivalent to C's `E_OK` or whatever the constant provided by stdio.h is, but +I'm wary about using a library-defined constant less it changes because POSIX +does not change (much). So I think this is a good Rust true(1) implementation. +It can be found in src/true/true.rs. And src/false/false.rs: + +```rs +use std::process::ExitCode; + +fn main() -> ExitCode { + ExitCode::from(1) +} +``` + +I just had supper which was delicious, vegan hot dogs and some macaroni my +hosts had left over. They are really delightful. + +Now I wanna make echo(1). This will serve as my HelloWorld as it uses stdout +printing and, beyond the usual HelloWorld, very light argument handling. The +book mentions cargo(1) which I will be using but for now I'll stick to single +.rs files because echo(1) shouldn't have any dependencies. + +It looks like std::env will give me stuff relating to arguments, std::env::args +or std::env::args_os. According to StackOverflow the difference is in typing. +I've heard docs.rs has some documentation but looking at the site it looks like +it only documents third party cargo crates, which are like C libraries but (I +think) included per-project so as to not muck up the system (I hope). I looked +up "rust std env" and found docs.rust-lang.org which has /std/env which was +what I needed. + +The Rust documentation summarizes more thoroughly but, basically, an OsString, +the type instances of which are iterated through by (oh my god this sentence is +a prepositional mess I give up) an OsString is a fat pointer or whatever the +Rust equivalent is while a String is probably just a nul-terminated sequence of +bytes. Implementation-defined of course but Rust documentation notes that +OsString should be converted to a CStr before being used in UNIX system calls. +A nice detail I'm happy to know! I shouldn't have to do any string conversion; +echo(1) should spit out *exactly* what it's given (opinion; implementations +differ) just with space delimiting and newline ending. Hopefully there's a way +for me to print out an OsString without conversion or anything. I need to `use +std::ffi::{OsStr, OsString};` or something like that I think but I'm gonna try +with just `use std::env;` at first. + +The use of echo(1) is defined for argc<2 (print a newline alone; argc can be +zero without consequence here) and argc>=2, so it won't be necessary to return +a value from main(), Rust can just use the default successful value. + +It looks like OsStr and OsString are from std::ffi which provides tools for FFI +bindings. This also notes that the Rust String is also fat and not nul +-terminated. It looks like the difference is that OsString represents an "owned +platform string" and an OsStr represents a "borrowed reference to a platform +string". This, I think, relates to memory management and a Borrow Checker +(spooky) about which I haven't gotten around to learning. Rust's std::ffi is +fascinating but while learning Rust I wanna be doing things oxidatiously or +whatever and not doing a thin Rust wrapper and then my usual C bullshit. One of +the things about Rust that excites me is that it seems to be able to make +guarantees about project stability C can't but I don't know much about that +except the stuff Mars has shown me that I don't quite understand. + +So how do I iterate through env::args_os? According to its reference page, +```rs +use std::env; + +fn main() { + for argument in env::args_os() { + println!("{argument:?}"); + } +} +``` +Wow! What the fuck is a println!? According to the Rust book all we need to +know is that the `!` suffix is some Hungarian notation esque marker that +println!() is a macro. The Rust documentation provides a definition, I think, +of println: +```rs +macro_rules! println { + () => { ... }; + ($($arg:tt)*) => { ... }; +} +``` +I think the `{ ... }` notes abridged portions and the [...]` => { ... };` +indicates that one case is triggered by println receiving no arguments and the +other case is triggered by println receiving any other amount of arguments. I +don't know if this is actual code or anything but yeah uh... Rust macros. Cool. +What I was actually interested in is how to print without a newline. I think +there's a macro for that too. +```rs +macro_rules! print { + ($($arg:tt)*) => { ... }; +} +``` +Interesting. The documentation notes: +>Prints to the standard output. +> +>Equivalent to the `println!` macro except that a newline is not printed at the +>end of the message. +>Note that stdout is frequently line-buffered by default so it may be necessary +>to use `io::stdout().flush()` to ensure the output is emitted immediately. +I like the note that `fflush(stdout);` is needed because this bites C beginners +a lot when writing stuff that does something like `printf("> "); +fgets([...]);`. + +I see stuff in here about `.unwrap()` and `stdout().lock()` but I hope I don't +need that because I don't understand it yet. I'm just gonna use print!. So how +do I print! an OsString? And how do I handle argc<2? + +The book chapter 12 actually touches on a lot of this and I stumbled upon it +looking at std::env stuff. Here's a test I can run from the book: +```rs +use std::env; + +fn main() { + let args: Vec = env::args().collect(); + dbg!(args); +} +``` + +I'll modify that a little: +```rs +use std::env; + +fn main() { + let args: Vec = env::args().collect(); + dbg!(args); +} +``` +$ rustc echo.rs +error[E0412]: cannot find type `OsString` in this scope + --> echo.rs:4:19 + | +4 | let args: Vec = env::args().collect(); + | ^^^^^^^^ + --> /builddir/rust-1.73.0/library/alloc/src/string.rs:365:1 + | + = note: similarly named struct `String` defined here + | +help: a struct with a similar name exists + | +4 | let args: Vec = env::args().collect(); + | ~~~~~~ +help: consider importing this struct + | +1 + use std::ffi::OsString; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. + +Okay. +$ sed -e '1a use std::ffi::OsString' echo.2.rs +$ rustc echo.2.rs +error[E0277]: a value of type `Vec` cannot be built from an iterator over elements of type `String` + --> echo.rs:5:43 + | +5 | let args: Vec = env::args().collect(); + | ^^^^^^^ value of type `Vec` cannot be built from `std::iter::Iterator` + | + = help: the trait `FromIterator` is not implemented for `Vec` + = help: the trait `FromIterator` is implemented for `Vec` +note: required by a bound in `collect` + --> /builddir/rust-1.73.0/library/core/src/iter/traits/iterator.rs:2049:5 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277` + +Oh shit, I forgot to change env::args to env::os_args. +$ sed -e '5s.args.os_args.' echo.rs +$ rustc echo.rs +error[E0425]: cannot find function `os_args` in module `env` + --> echo.rs:5:36 + | +5 | let args: Vec = env::os_args().collect(); + | ^^^^^^^ help: a function with a similar name exists: `args_os` + --> /builddir/rust-1.73.0/library/std/src/env.rs:793:1 + | + = note: similarly named function `args_os` defined here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. + +Oops. +$ sed -e '5s.os_args.args_os.' echo.2.rs +$ rustc echo.2.rs +$ + +So presumably it compiled. +$ ./echo +[echo.rs:6] args = [ + "./echo", +] + +Okay, that debug macro is kinda awesome. The 500K binary makes me kinda weirded +out, what's the size of the actual echo.c (which is the complete program) when +compiled for arm64 (my current architecture)? + +.rwxr-xr-x trinity trinity 9.8 KB Tue Oct 31 21:01:27 2023 🏗 a.out + +This output is prettier than usual because I'm using lsd(1), a reimplementation +of the standard POSIX ls(1). My girlfriend in Florida uses it and it's really +pleasant and color codes some stuff in a way that's very useful. + +10K is a lot less than half a meg. I wonder if Rust is statically compiling +versus relying on system library stuff. I don't wanna bother looking this up so +I'll go ask Mars. + +Its door is closed so I'll look this up. "why are rust binaries so big" popped +up a StackOverflow post that started with "Rust uses static linking" so that +answers my question. I would assume a statically linked C executable would be +about that big, from memory I think this is true but don't wanna bother testing +because I don't have the energy to look up clang arguments. + +$ cc -static echo.c +ld: error: unable to find library -l:libunwind.a +ld: error: unable to find library -latomic +ld: error: unable to find library -lc +clang-16: error: linker command failed with exit code 1 (use -v to see invocati +on) + +Yeah, I'm not sorting that out, I'm not building C stuff on here to distribute. + +I think vec.len() will tell me how many arguments I've received? + +```rs +use std::env; +use std::ffi::OsString; + +fn main() { + let args: Vec = env::args_os().collect(); + dbg!(args); + dbg!(args.len()); +} +``` +$ rm echo.2.rs +$ rustc echo.rs +error[E0382]: borrow of moved value: `args` + --> echo.rs:7:10 + | +5 | let args: Vec = env::args_os().collect(); + | ---- move occurs because `args` has type `Vec`, which doe +s not implement the `Copy` trait +6 | dbg!(args); + | ---------- value moved here +7 | dbg!(args.len()); + | ^^^^ value borrowed here after move + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. + +Okay, so now I'm talking to the borrow checker. Maybe if I assign the length to +a variable it'll work? I don't know what I'm doing. + +```rs +use std::env::args_os; +use std::ffi::OsString; + +fn main() { + let args: Vec = args_os().collect(); + let argc = args.len(); + dbg!(args); + dbg!(argc); +} +``` +$ rustc echo.rs +$ ./echo +[echo.rs:7] args = [ + "./echo", +] +[echo.rs:8] argc = 1 + +Okay. I don't know why that works but it does. Something to do with memory +management. That's not a big deal to me because I understand when I do fucky +wucks like +```py +try: print("c = " + str( + (float(input("a = ")) ** 2 + + float(input("b = ")) ** 2) + ** 0.5)) +except ValueError: print("input must be a number") +except: pass +``` +there's a lot of memory shit happening behind the scenes I don't have to worry +about, unlike in the equivalent C where I would have to handle buffer overflows +(I personally would toss the excess and skip to the newline) and string to +float conversion. Rust requiring some steps Python wouldn't makes sense to me +because while Rust is less pedantic it doesn't lie to me (much). + +Let me try something now: +```rs +use std::env::args_os; +use std::ffi::OsString; + +fn main() { + let argv: Vec = args_os.collect(); + let argc = argv.len(); + + if argc < 2 { + println!(); + } else { + dbg!(argv); + } +} +``` +$ rustc echo.rs +$ ./echo | hexdump -C +00000000 0a |.| +00000001 +$ ./echo piss shit +[echo.rs:11] argv = [ + "./echo", + "piss", + "shit", +] + +Cool stuff. I don't think Rust has ternaries so I'm not gonna be able to do +language tricks to make the code really compact like my C implementation: +```c +#include /* NULL, fprintf(3), putc(3) */ +#include /* stdout */ +#include /* EX_OK */ + +int main(int argc, char **argv){ + + if(*argv == NULL || *++argv == NULL){ + argc = 1; + putc('\n', stdout); + } + + while(--argc) + fprintf(stdout, "%s%c", *(argv++), argc > 1 ? ' ' : '\n'); + + return EX_OK; +} +``` +Something I really like is that whereas in C I note what I use from headers in +comments like a total tool, Rust lets me bring individual structures and +functions in so I can keep track of my dependencies in code alone. + +I wonder if I can +```rs +use std::env::args_os; + +fn main() { + let argc = args_os().collect().len(); + dbg!(argc); +} +``` +$ rustc echo.rs +error[E0282]: type annotations needed + --> echo.rs:5:26 + | +4 | let argc = args_os().collect().len(); + | ^^^^^^^ cannot infer type of the type parameter `B +` declared on the method `collect` + | +help: consider specifying the generic argument + | +4 | let argc = args_os().collect::>().len(); + | ++++++++++ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0282`. + +Okay, how about +```rs +use std::env::args_os; +use std::ffi::OsString; + +fn main() { + let argc = args_os().collect::Vec().len(); + dbg!(argc); +} +``` +I guess function::type() specifies the type of which function should be +returning. That sort of makes sense? C doesn't have generic functions like that +but I think I understand some of what's happening there. +$ rustc echo.rs +error: generic parameters without surrounding angle brackets + --> echo.rs:5:35 + | +5 | let argc = args_os().collect::Vec().len(); + | ^^^^^^^^^^^^^ + | +help: surround the type parameters with angle brackets + | +5 | let argc = args_os().collect::>().len(); + | + + + +error: aborting due to previous error + +Okay. I'm changing that without copying my code because I'm not motivated to do +so. Also the actual errors are probably not byte-for-byte if for whatever +reason you're following along at home (why would you? I don't know what I'm +doing) because my code actually has a ton of snippets commented out so I don't +need to retype everything. + +I made the changes it suggested and the program works. Neat. But do I need that +local variable? +```rs +use std::env::args_os; +use std::ffi::OsString; + +fn main() { + if args_os().collect::>().len() < 2 { + println!(); + } else { + } +} +``` +$ rustc echo.c +$ + +No I don't! Only if I'm using it more than once, which makes sense. I'd like to +forego println!() though because I have a feeling this prelude-provided macro +will do platform-specific things and differ on NT vs UNIX due to line ending +conventions. I don't like that for a program that's supposed to follow POSIX. +It looks like std::io::Stdout exists so I'm gonna use that and put a lock on +std::stdout so I can write to it. I think this works? +```rs +use std::env::args_os; +use std::io::{Write, stdout}; +use std::ffi::OsString; + +fn main() { + let mut stdout = stdout().lock(); + if args_os().collect::>().len() < 2 { + stdout.write(b"\n"); // Rust wants a 'b' prefix + } else { + } +} +``` +$ rustc echo.rs +warning: unused `Result` that must be used + --> echo.rs:8:9 + | +8 | stdout.write(b"\n"); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled + = note: `#[warn(unused_must_use)]` on by default +help: use `let _ = ...` to ignore the resulting value + | +8 | let _ = stdout.write(b"\n"); + | +++++++ + +warning: 1 warning emitted + +Okay, a note that I should handle the possibility of an error. I don't know how +to do that so I won't, like a true in-the-field professional. + +I guess b"\n" is a Rust byte string. I don't think it's super important just +yet for me to know what that is so I'm gonna assume I'm fine. + +I'm feeling devious. +```rs +use std::env::args_os; +use std::io::{Write, stdout}; +use std::ffi::OsString; + +fn main() { + let mut stdout = stdout().lock(); + if args_os().collect::>().len() >= 2 { + for argument in args_os() { + stdout.write(argument); + stdout.write(b" "); + } + } + stdout.write(b"\n") +} +``` +$ rustc echo.c +error[E0308]: mismatched types + --> echo.rs:9:26 + | +9 | stdout.write(argument); + | ----- ^^^^^^^^ expected `&[u8]`, found `OsString` + | | + | arguments to this method are incorrect + | +note: method defined here + --> /builddir/rust-1.73.0/library/std/src/io/mod.rs:1461:8 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. + +So I could look up how to turn an OsString into a `&[u8]` but I need to know +what that is because echo(1) shouldn't be dependent on "proper input" (UTF-1 +should work as well as UTF-8). I checked the std::ffi::OsString methods but +none of them really told me anything I think I can use so I'm gonna look at +std::io. + +Looking at the primitive u8, it's an 8-bit unsigned integer which should be +fine for my uses. The method into_os_str_bytes() should work to convert +std::ffi::OsString into a Vec but the documentation notes that this is +"a nightly-only experimental API". Whatever, probably fine. + +```rs +use std::env::args_os; +use std::io::{Write, stdout}; +use std::ffi::OsString; + +fn main() { + let mut stdout = stdout().lock(); + if args_os().collect::>().len() >= 2 { + for argument in args_os() { + stdout.write(argument.into_os_str_bytes()); + stdout.write(b" "); + } + } + stdout.write(b"\n"); +} +``` +$ rustc echo.c +error[E0658]: use of unstable library feature 'os_str_bytes' + --> echo.rs:9:35 + | +9 | stdout.write(argument.into_os_str_bytes()); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #111544 f +or more information + +error[E0308]: mismatched types + --> echo.rs:9:26 + | +9 | stdout.write(argument.into_os_str_bytes()); + | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&[u8]`, fou +nd `Vec` + | | + | arguments to this method are incorrect + | + = note: expected reference `&[u8]` + found struct `Vec` +note: method defined here + --> /builddir/rust-1.73.0/library/std/src/io/mod.rs:1461:8 +help: consider borrowing here + | +9 | stdout.write(&argument.into_os_str_bytes()); + | + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. + +Okay, I'll add that ampersand the borrow checker desires. I'm not sure how this +works still. +$ rustc echo.rs +error[E0658]: use of unstable library feature 'os_str_bytes' + --> echo.rs:9:36 + | +9 | stdout.write(&argument.into_os_str_bytes()); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #111544 f +or more information + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. + +So how do I use an unstable library feature? I'll use the rustc facilities. + +$ rustc --explain E0658 + +This brought me into a manual snippet shown in my configured pager (I think) +with instructions on how to add a feature flag. I then did what it said and +wasn't anywhere better so I wonder if there's another way to turn an OsString +into a &[u8]. + +Then Mars came into the room and greeted me and I asked it how to make this +shit work. Apparently an issue is I'm running stable rustc and in order to use +nightly rustc stuff I need nightly rustc provided by using rustup instead of +the packaged rust toolchain. I don't really wanna do that but I also don't +really wanna give up so I think I'm just gonna make this a shitty echo(1) +implementation that limits input to UTF-8. But first I wanna see how someone +else has done this already. + +https://github.com/uutils/coreutils.git src/uu/echo/src/echo.rs L119: +>pub fn uumain(args: impl uucore::Args) -> UResult<()> { +> let args = args.collect_lossy(); +> let matches = uu_app().get_matches_from(args); +> +> let no_newline = matches.get_flag(options::NO_NEWLINE); +> let escaped = matches.get_flag(options::ENABLE_BACKSLASH_ESCAPE); +> let values: Vec = match matches.get_many::(options::STRING +) { +> Some(s) => s.map(|s| s.to_string()).collect(), +> None => vec![String::new()], +> }; +> +> execute(no_newline, escaped, &values) +> .map_err_context(|| "could not write to stdout".to_string()) +>} + +Those rat bastards did std::env::args.collect_lossy()! Those utter tools! I +imagine this doesn't work for binary data but I don't know and I'm not building +this because I don't wanna figure out how to right now. + +Everyone is going to sleep now except me so I now feel like I need to get an +echo(1) implementation working on this, the first day I've actually started to +learn Rust. I'm just gonna go with std::env::args and Strings. + +Mars also mentioned some Rust types stuff, namely &[u8] being a borrowed slice +of u8s or something. I sort of got it and sort of didn't, I did at the time I +just forgot. Sorry! + +Also it came back out after I wrote that to greet me and then promptly +disappeared. + +This spits out a lot of warnings: +```rs +use std::env::args; +use std::io::{Write, stdout}; + +fn main() { + let mut stdout = stdout().lock(); + if args().collect::>().len() >= 2 { + for argument in args() { + stdout.write(&argument.as_bytes()); + stdout.write(b" "); + } + } + stdout.write(b"\n"); +} +``` + +This is nice but print!() handles errors I think so I'm just going back to +that. + +```rs +use std::env::args; + +fn main() { + if args().collect::>().len() >= 2 { + for argument in args() { + print!(argument); + print!(" "); + } + } + print!("\n"); +} +``` +$ rustc echo.c +error: format argument must be a string literal + --> echo.rs:6:20 + | +6 | print!(argument); + | ^^^^^^^^ + | +help: you might be missing a string literal to format with + | +6 | print!("{}", argument); + | +++++ + +error: aborting due to previous error + +Okay. + +```rs +use std::env::args; + +fn main() { + if args().collect::>().len() >= 2 { + for argument in args() { + print!("{}", argument); + print!(" "); + } + } + print!("\n"); +} +``` +$ rustc echo.c +$ ./echo hello world +./echo hello world + +The issue is the first argument is coming along for the ride in that for loop. +How do I skip the first iteration of an iterator? + +[trial and error with .rs files and rustc omitted] + +Oh. + +```rs +use std::env::args; + +fn main() { + if args().collect::>().len() >= 2 { + for argument in args().skip(1) { + print!("{} ", argument); + } + } + print!("\n"); +} +``` +$ rustc echo.c +$ ./echo Hello, world! +Hello, world! +$ ./echo Happy Halloween! +Happy Halloween! + +That's where I'm leaving my Rust education today. And this is day 1. Pretty +good! + + /blah/2023-10-29.html Another journal, in its entirety diff --git a/true/true.rs b/true/true.rs new file mode 100644 index 0000000..9e15d4a --- /dev/null +++ b/true/true.rs @@ -0,0 +1,5 @@ +use std::process::ExitCode; + +fn main() -> ExitCode { + ExitCode::from(0) +}