diff --git a/usr/src/mei/printf/Cargo.toml b/usr/src/mei/printf/Cargo.toml index ac4961b..57fe821 100644 --- a/usr/src/mei/printf/Cargo.toml +++ b/usr/src/mei/printf/Cargo.toml @@ -10,3 +10,4 @@ path = "src/printf.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.4.8", features = ["derive"] } diff --git a/usr/src/mei/printf/src/printf.rs b/usr/src/mei/printf/src/printf.rs index e7a11a9..7591734 100644 --- a/usr/src/mei/printf/src/printf.rs +++ b/usr/src/mei/printf/src/printf.rs @@ -1,3 +1,92 @@ -fn main() { - println!("Hello, world!"); +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2023 Ren Kararou All rights reserved. + * Use is subject to license terms. + */ + +// man page is printf(1) [https://illumos.org/man/1/printf] +// man page refs formats(7) [https://illumos.org/man/7/formats] +// +// returns 0 on success. Any positive int return code is an error. +// negative return codes are UB. +// +// must handle both escape sequences and format strings as defined primarily in formats(7) and +// additionally in printf(1). We will only be following the sections pertinent to /usr/bin/printf. + +use std::process::ExitCode; + +use clap::Parser; + +#[derive(Parser)] +#[clap(disable_help_flag = true)] +#[command(name = "printf")] +struct Args { + format: Option, + argument: Option>, +} + +#[inline] +fn usage() { + eprintln!("usage: printf format [arguments ...]"); +} + +fn escape(escstr: String) -> String { + let escmap = vec![ + ("\\\\", "\\"), + //("\\a", "\a"), + //("\\b", "\b"), + //("\\f", "\f"), + ("\\n", "\n"), + ("\\r", "\r"), + ("\\t", "\t"), + //("\\v", "\v"), + ]; + let mut im = escstr; + for esc in escmap { + im = str::replace(im.as_str(), esc.0, esc.1); + } + // TODO: Handle octal esc + + im.clone() +} + +fn fmt(fmtstr: String) -> String { + fmtstr.clone() +} + +fn main() -> ExitCode { + let args = Args::parse(); + + if args.format.clone().is_none() && args.argument.clone().is_none() { + usage(); + return ExitCode::FAILURE; + } + + if let Some(fmtstr) = args.format { + let fmtstr = escape(fmtstr.clone()); + print!("{fmtstr}"); + } + + ExitCode::SUCCESS }