Compare commits
	
		
			3 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7c9f640ee1 | |||
| 3910c341bd | |||
| cfef7aec1d | 
							
								
								
									
										16
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Makefile
									
									
									
									
									
								
							| @ -28,7 +28,7 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \ | |||||||
| CFLAGS += -I$(SYSEXITS) | CFLAGS += -I$(SYSEXITS) | ||||||
| 
 | 
 | ||||||
| .PHONY: all | .PHONY: all | ||||||
| all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true | all: dj false fop hru intcmp mm npc rpn scrut strcmp stris swab true | ||||||
| 
 | 
 | ||||||
| build: | build: | ||||||
| 	# keep build/include until bindgen(1) has stdin support | 	# keep build/include until bindgen(1) has stdin support | ||||||
| @ -118,10 +118,13 @@ scrut: build/bin/scrut | |||||||
| build/bin/scrut: src/scrut.c build | build/bin/scrut: src/scrut.c build | ||||||
| 	$(CC) $(CFLAGS) -o $@ src/scrut.c | 	$(CC) $(CFLAGS) -o $@ src/scrut.c | ||||||
| 
 | 
 | ||||||
| .PHONY: str | .PHONY: stris | ||||||
| str: build/bin/str | stris: build/bin/stris | ||||||
| build/bin/str: src/str.c build | build/bin/stris: src/stris.rs build build/o/libgetopt.rlib \ | ||||||
| 	$(CC) $(CFLAGS) -o $@ src/str.c | 		build/o/libsysexits.rlib | ||||||
|  | 	$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
 | ||||||
|  | 		--extern sysexits=build/o/libsysexits.rlib \
 | ||||||
|  | 		-o $@ src/stris.rs | ||||||
| 
 | 
 | ||||||
| .PHONY: strcmp | .PHONY: strcmp | ||||||
| strcmp: build/bin/strcmp | strcmp: build/bin/strcmp | ||||||
| @ -130,7 +133,8 @@ build/bin/strcmp: src/strcmp.c build | |||||||
| 
 | 
 | ||||||
| .PHONY: swab | .PHONY: swab | ||||||
| swab: build/bin/swab | swab: build/bin/swab | ||||||
| build/bin/swab: src/swab.rs build build/o/libsysexits.rlib | build/bin/swab: src/swab.rs build build/o/libgetopt.rlib \ | ||||||
|  | 		build/o/libsysexits.rlib | ||||||
| 	$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
 | 	$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
 | ||||||
| 		--extern sysexits=build/o/libsysexits.rlib \
 | 		--extern sysexits=build/o/libsysexits.rlib \
 | ||||||
| 		-o $@ src/swab.rs | 		-o $@ src/swab.rs | ||||||
|  | |||||||
							
								
								
									
										58
									
								
								docs/str.1
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								docs/str.1
									
									
									
									
									
								
							| @ -1,58 +0,0 @@ | |||||||
| .\" Copyright (c) 2023–2024 DTB <trinity@trinity.moe> |  | ||||||
| .\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> |  | ||||||
| .\" |  | ||||||
| .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, |  | ||||||
| .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. |  | ||||||
| 
 |  | ||||||
| .TH STR 1 |  | ||||||
| 
 |  | ||||||
| .SH NAME |  | ||||||
| 
 |  | ||||||
| str \(en test the character types of string arguments |  | ||||||
| 
 |  | ||||||
| .SH SYNOPSIS |  | ||||||
| 
 |  | ||||||
| str |  | ||||||
| .RB [ type ] |  | ||||||
| .RB [ string... ] |  | ||||||
| 
 |  | ||||||
| .SH DESCRIPTION |  | ||||||
| 
 |  | ||||||
| Str tests each character in an arbitrary quantity of string arguments against |  | ||||||
| the function of the same name within ctype(3). |  | ||||||
| 
 |  | ||||||
| .SH DIAGNOSTICS |  | ||||||
| 
 |  | ||||||
| Str exits successfully if all tests pass and unsuccessfully if a test failed. |  | ||||||
| .PP |  | ||||||
| Str will exit unsuccessfully if a string is empty, as none of its contents |  | ||||||
| passed the test. |  | ||||||
| .PP |  | ||||||
| Str will print a message to standard error and exit unsuccessfully if used |  | ||||||
| improperly. |  | ||||||
| 
 |  | ||||||
| .SH DEPRECATED FEATURES |  | ||||||
| 
 |  | ||||||
| Str used to have an "isvalue" type as an extension to ctype(3). This was |  | ||||||
| removed in favor of using strcmp(1) to compare strings against the empty string |  | ||||||
| (''). |  | ||||||
| 
 |  | ||||||
| .SH BUGS |  | ||||||
| 
 |  | ||||||
| There's no way of knowing which argument failed the test without re-testing |  | ||||||
| arguments individually. |  | ||||||
| .PP |  | ||||||
| If a character in a string isn't valid ASCII str will exit unsuccessfully. |  | ||||||
| 
 |  | ||||||
| .SH AUTHOR |  | ||||||
| 
 |  | ||||||
| Written by DTB <trinity@trinity.moe>. |  | ||||||
| 
 |  | ||||||
| .SH COPYRIGHT |  | ||||||
| 
 |  | ||||||
| Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later |  | ||||||
| <https://gnu.org/licenses/gpl.html>. |  | ||||||
| 
 |  | ||||||
| .SH SEE ALSO |  | ||||||
| 
 |  | ||||||
| ctype(3p), strcmp(1), ascii(7) |  | ||||||
							
								
								
									
										118
									
								
								docs/stris.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								docs/stris.1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | .\" Copyright (c) 2023–2024 DTB <trinity@trinity.moe> | ||||||
|  | .\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> | ||||||
|  | .\" | ||||||
|  | .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, | ||||||
|  | .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. | ||||||
|  | 
 | ||||||
|  | .TH STRIS 1 | ||||||
|  | 
 | ||||||
|  | .SH NAME | ||||||
|  | 
 | ||||||
|  | stris \(en test the character types of string arguments | ||||||
|  | 
 | ||||||
|  | .SH SYNOPSIS | ||||||
|  | 
 | ||||||
|  | stris | ||||||
|  | .RB ( -7bcdlu ) | ||||||
|  | .RB ( -i [ inclusions ]) | ||||||
|  | .RB [ strings... ] | ||||||
|  | 
 | ||||||
|  | .SH DESCRIPTION | ||||||
|  | 
 | ||||||
|  | Stris tests each rune in an arbitrary quantity of string arguments, ensuring | ||||||
|  | each meets any of the parameters specified in the program options. | ||||||
|  | 
 | ||||||
|  | .SH OPTIONS | ||||||
|  | 
 | ||||||
|  | .B -7 | ||||||
|  | .RS | ||||||
|  | Tests to see if runes are fit within seven bits; that is, that they are encoded | ||||||
|  | with ASCII. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .B -b | ||||||
|  | .RS | ||||||
|  | Tests to see if runes are blank or "whitespace"; characters that do not print | ||||||
|  | but fill a predictable amount of space. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .B -c | ||||||
|  | .RS | ||||||
|  | Tests to see if runes are control characters; characters that are not printing | ||||||
|  | or graphical. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .B -d | ||||||
|  | .RS | ||||||
|  | Tests to see if runes are numeric. This test does not only allow the ASCII | ||||||
|  | digits but any numeric symbol. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .B -i | ||||||
|  | .RS | ||||||
|  | Permits, in addition to the given specified parameters, all of the runes | ||||||
|  | supplied in its option argument. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .B -l | ||||||
|  | .RS | ||||||
|  | Tests to see if runes are in their lower case. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .B -u | ||||||
|  | .RS | ||||||
|  | Tests to see if runes are in their upper case, or capitalized. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .SH DIAGNOSTICS | ||||||
|  | 
 | ||||||
|  | Stris exits successfully if all runes in all given strings meet any of the | ||||||
|  | specified parameters, or if no parameters were specified but all given strings | ||||||
|  | were legibly encoded. It exits unsuccessfully if the previous is untrue, and if | ||||||
|  | invalid options were given, or if no strings were given, a usage synopsis will | ||||||
|  | be printed to the standard error. | ||||||
|  | 
 | ||||||
|  | .SH BUGS | ||||||
|  | 
 | ||||||
|  | There's no way of knowing which argument failed the test without re-testing | ||||||
|  | arguments individually. | ||||||
|  | 
 | ||||||
|  | Some runes that can losslessly be encoded into ASCII from UTF-8 but in an | ||||||
|  | "overlong encoding", where the rune was encoded with unnecessary leading | ||||||
|  | zeroes causing it to span multiple bytes, won't be detected as ASCII. | ||||||
|  | 
 | ||||||
|  | .SH EXAMPLES | ||||||
|  | 
 | ||||||
|  | This is an sh(1p) snippet that checks to see if an environment variable is an | ||||||
|  | ASCII digit. | ||||||
|  | 
 | ||||||
|  | .RS | ||||||
|  | .R stris -7 "$v" && stris -d "$v" && echo ASCII digit. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | This is an sh(1p) snippet that checks to see if an environment variable is a | ||||||
|  | hexadecimal number. | ||||||
|  | 
 | ||||||
|  | .RS | ||||||
|  | .R stris -7 "$v" && stris -di ABCDEFabcdef "$v" && echo Hexadecimal number. | ||||||
|  | .RE | ||||||
|  | 
 | ||||||
|  | .SH AUTHOR | ||||||
|  | 
 | ||||||
|  | Written by DTB <trinity@trinity.moe>. | ||||||
|  | 
 | ||||||
|  | .SH HISTORY | ||||||
|  | 
 | ||||||
|  | Stris replaces the former str(1) which took the name of a function from | ||||||
|  | ctype(3) as its first argument and checked the following strings against it; | ||||||
|  | str(1) exited unsuccessfully when it encountered any non-ASCII runes and could | ||||||
|  | only have one parameter specified. | ||||||
|  | 
 | ||||||
|  | .SH COPYRIGHT | ||||||
|  | 
 | ||||||
|  | Copyright © 2023–2024 DTB. License AGPLv3+: GNU AGPL version 3 or later | ||||||
|  | <https://gnu.org/licenses/gpl.html>. | ||||||
|  | 
 | ||||||
|  | .SH SEE ALSO | ||||||
|  | 
 | ||||||
|  | ascii(7), ctype(3p), strcmp(1) | ||||||
							
								
								
									
										75
									
								
								src/str.c
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								src/str.c
									
									
									
									
									
								
							| @ -1,75 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * Copyright (c) 2023 DTB <trinity@trinity.moe> |  | ||||||
|  * Copyright (c) 2023 Marceline Cramer <mars@tebibyte.media> |  | ||||||
|  * SPDX-License-Identifier: AGPL-3.0-or-later |  | ||||||
|  * |  | ||||||
|  * This program is free software: you can redistribute it and/or modify it under |  | ||||||
|  * the terms of the GNU Affero General Public License as published by the Free |  | ||||||
|  * Software Foundation, either version 3 of the License, or (at your option) any |  | ||||||
|  * later version. |  | ||||||
|  *  |  | ||||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT |  | ||||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |  | ||||||
|  * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |  | ||||||
|  * details. |  | ||||||
|  * |  | ||||||
|  * You should have received a copy of the GNU Affero General Public License |  | ||||||
|  * along with this program. If not, see https://www.gnu.org/licenses/.
 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <stddef.h> /* NULL */ |  | ||||||
| #include <stdio.h> /* fprintf(3) */ |  | ||||||
| #include <stdlib.h> /* EXIT_FAILURE */ |  | ||||||
| #include <string.h> /* strcmp(3) */ |  | ||||||
| #include <sysexits.h> |  | ||||||
| 
 |  | ||||||
| static char *program_name = "str"; |  | ||||||
| 
 |  | ||||||
| static struct { |  | ||||||
| 	char *name; |  | ||||||
| 	int (*f)(int); |  | ||||||
| }ctypes[] = { |  | ||||||
| 	{ "isalnum", isalnum }, |  | ||||||
| 	{ "isalpha", isalpha }, |  | ||||||
| 	{ "isblank", isblank }, |  | ||||||
| 	{ "iscntrl", iscntrl }, |  | ||||||
| 	{ "isdigit", isdigit }, |  | ||||||
| 	{ "isxdigit", isxdigit }, |  | ||||||
| 	{ "isgraph", isgraph }, |  | ||||||
| 	{ "islower", islower }, |  | ||||||
| 	{ "isprint", isprint }, |  | ||||||
| 	{ "ispunct", ispunct }, |  | ||||||
| 	{ "isspace", isspace }, |  | ||||||
| 	{ "isupper", isupper } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| int main(int argc, char *argv[]){ |  | ||||||
| 	int ctype; |  | ||||||
| 	int i; |  | ||||||
| 	int r; |  | ||||||
| 
 |  | ||||||
| 	if(argc >= 3){ |  | ||||||
| 		for(ctype = 0; ctype < (sizeof ctypes) / (sizeof *ctypes); |  | ||||||
| 				++ctype) |  | ||||||
| 			if(strcmp(argv[1], ctypes[ctype].name) == 0) |  | ||||||
| 				goto pass; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fprintf(stderr, "Usage: %s [type] [string...]\n", |  | ||||||
| 		argv[0] == NULL ? program_name : argv[0]); |  | ||||||
| 
 |  | ||||||
| 	return EX_USAGE; |  | ||||||
| 
 |  | ||||||
| pass:	for(argv += 2, r = 1; *argv != NULL; ++argv) |  | ||||||
| 		for(i = 0; argv[0][i] != '\0'; ++i) |  | ||||||
| 			/* First checks if argv[0][i] is valid ASCII; ctypes(3)
 |  | ||||||
| 			 * don't handle non-ASCII. |  | ||||||
| 			 * This is bad. */ |  | ||||||
| 			if((unsigned char)argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i])) |  | ||||||
| 				return 1; |  | ||||||
| 			else |  | ||||||
| 				r = 0; |  | ||||||
| 
 |  | ||||||
| 	return r; |  | ||||||
| } |  | ||||||
							
								
								
									
										93
									
								
								src/stris.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/stris.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2023–2024 DTB <trinity@trinity.moe> | ||||||
|  |  * Copyright (c) 2023 Marceline Cramer <mars@tebibyte.media> | ||||||
|  |  * SPDX-License-Identifier: AGPL-3.0-or-later | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify it under | ||||||
|  |  * the terms of the GNU Affero General Public License as published by the Free | ||||||
|  |  * Software Foundation, either version 3 of the License, or (at your option) any | ||||||
|  |  * later version. | ||||||
|  |  * 
 | ||||||
|  |  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||||
|  |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||||
|  |  * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | ||||||
|  |  * details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see https://www.gnu.org/licenses/.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | use std::{ | ||||||
|  | 	env::args, | ||||||
|  | 	process::ExitCode | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | extern crate getopt; | ||||||
|  | use getopt::{ Opt, Parser }; | ||||||
|  | 
 | ||||||
|  | extern crate sysexits; | ||||||
|  | use sysexits::EX_USAGE; | ||||||
|  | 
 | ||||||
|  | struct Reqs { | ||||||
|  | 	ascii: bool, blank: bool, cntrl: bool, digit: bool, lower: bool, | ||||||
|  | 	upper: bool, inuse: bool, extra: String | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn usage(s: &str) -> ExitCode { | ||||||
|  | 	eprintln!("Usage: {} (-7bcdlu) (-i [inclusions]) [strings...]", s); | ||||||
|  | 	ExitCode::from(EX_USAGE as u8) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> ExitCode { | ||||||
|  | 	let argv = args().collect::<Vec<String>>(); | ||||||
|  | 	let mut opts = Parser::new(&argv, "7bcdi:lu"); | ||||||
|  | 	let mut reqs = Reqs { | ||||||
|  | 		ascii: false, blank: false, cntrl: false, digit: false, lower: false, | ||||||
|  | 		upper: false, inuse: false, extra: String::new() | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	loop { | ||||||
|  | 		match opts.next() { | ||||||
|  | 			None => break, | ||||||
|  | 			Some(opt) => { | ||||||
|  | 				match opt { | ||||||
|  | 					Ok(Opt('7', None)) => reqs.ascii = true, | ||||||
|  | 					Ok(Opt('b', None)) => reqs.blank = true, | ||||||
|  | 					Ok(Opt('c', None)) => reqs.cntrl = true, | ||||||
|  | 					Ok(Opt('d', None)) => reqs.digit = true, | ||||||
|  | 					Ok(Opt('i', Some(arg))) => reqs.extra = arg, | ||||||
|  | 					Ok(Opt('l', None)) => reqs.lower = true, | ||||||
|  | 					Ok(Opt('u', None)) => reqs.upper = true, | ||||||
|  | 					_ => { return usage(&argv[0]); } | ||||||
|  | 				} | ||||||
|  | 				reqs.inuse = true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if argv.len() == opts.index() { | ||||||
|  | 		return usage(&argv[0]); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	drop(argv); | ||||||
|  | 
 | ||||||
|  | 	if reqs.inuse { | ||||||
|  | 		for arg in args().skip(opts.index()) { | ||||||
|  | 			for c in arg.chars() { | ||||||
|  | 				if (reqs.ascii && c.is_ascii()) | ||||||
|  | 						|| (reqs.blank && c.is_whitespace()) | ||||||
|  | 						|| (reqs.cntrl && c.is_control()) | ||||||
|  | 						|| (reqs.digit && c.is_numeric()) | ||||||
|  | 						|| (reqs.lower && c.is_lowercase()) | ||||||
|  | 						|| (reqs.upper && c.is_uppercase()) | ||||||
|  | 						|| reqs.extra.contains(c) { | ||||||
|  | 					continue; | ||||||
|  | 				} else { | ||||||
|  | 					return ExitCode::FAILURE; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ExitCode::SUCCESS | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user