From 4cb5ea78d71e564939d1c5ab464a85bea8de9ba0 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 5 Sep 2024 12:44:14 -0600 Subject: [PATCH] STYLE: improves clarity, focus, distribution of items, adds more gripes, includes usage text style --- STYLE | 198 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 127 insertions(+), 71 deletions(-) diff --git a/STYLE b/STYLE index aa233a2..1aeb1b1 100644 --- a/STYLE +++ b/STYLE @@ -1,26 +1,33 @@ +“Everyone knows that debugging is twice as hard as writing a program in the +first place. So if you’re as clever as you can be when you write it, how +will you ever debug it?” + – Brian Kernighan, The Elements of Programming Style + + The following guidelines are conducive to clear and readable code that is consistent with the style of the rest of the Bonsai Computer System. -0. Use: - - a single line for control flow statements short enough to be easily -understood at a glance: + +Use +=== + + 0. A single line for control flow statements short enough to be easily + understood at a glance: if !(argc < 0) { usage(program_name); } -This applies to C switch cases, as well. + This applies to C switch cases, as well: switch (value) { /* aligning stuff to make it easier to read is fine */ case possibility: variable = foo; break; default: variable = NULL; break; } - - as little nested logic as possible (within reason). - - braces in control flow, when their inclusion is left optional by a -programming language (in, for example, C). + 1. Braces in control flow where their inclusion is left optional in C: if (condition) { statement; } - - empty lines between different kinds of statements: + 2. Empty lines between different kinds of statements: int t; @@ -40,66 +47,59 @@ programming language (in, for example, C). return io; - - compiler options that yield the most useful warnings, such as -Wpedantic in -a lot of C compilers. Fix the warnings, too. See [0]. - - fixed bounds for loops; see [0]. - - one more level of indentation and one line per argument, when a function -call or statement header is too long to fit on one line: + 3. Compiler options that yield the most useful warnings, such as -Wpedantic in + a lot of C compilers. Fix the warnings, too [0]. + + 4. Fixed bounds for loops [0]. + + 5. One more level of indentation and one argument per line when a function + call or statement header is too long to fit on one line: let usage = format!( "Usage: {} [-d delimiter] index command [args...]", argv[0], ); - - one more level of indentation than the keyword that initiated a block. + 6. One more level of indentation than the keyword that initiated a multi-line + block. if (condition) { statement; statement; } - - the return value of all non-void functions, or explicitly ignore them (like -casting to void in C): + 7. The return value of all non-void functions, or explicitly ignore them (like + casting to void in C) [0]: if ((a = malloc(sizeof char)) == NULL) { /* handle this error */ (void)fprintf(stderr, "oh noes!"); /* explicitly ignore this one */ return EX_OSERR; /* ...because the program is exiting anyway */ } -See [0]. + 8. The smallest possible scope for data [0]. - - the smallest possible scope for data; see [0]. - - (C) comments noting all the symbols and macros used from a header, next to -its include macro: + 9. Comments noting all the symbols and macros used from a C header file, next + to its include macro: #include /* close(2), getopt(3), lseek(2), read(2), write(2), (space-aligned) * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ - - (C) one more level of indentation within switch cases. - - switch (value) { - case possibility: - statement; - default: - statement; - } - - - (C) spaces in control flow statements, after the keyword and before the -opening brace: + 10. Spaces in control flow statements, after the keyword and before the + opening brace: for (i = 2; i < argc; ++i) { - - (Cpp) as little of the preprocessor as possible; see [0]. - - (Rust) a trailing comma on all arguments or fields that are on their own -lines: + + 11. In Rust, a trailing comma on all arguments or fields that are on their own + lines: return Err(EvaluationError { message: format!("{}: Invalid token", i), code: EX_DATAERR, }) - - (Rust) extern statements after use statements that include standard library -crates. Group like statements: + 12. In Rust, place extern statements after use statements that include standard + library crates. Group like statements: use std::fs::Path; @@ -109,17 +109,29 @@ crates. Group like statements: use strerror::StrError; use sysexits::{ EX_OSERR, EX_USAGE }; - - (Rust) if text is on the same line as a brace, spaces after an opening curly -brace and before a closing one: + 13. If text is on the same line as a brace, spaces after an opening brace and + before a closing one: use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; - - (Rust) one more level of indentation within match arms. + 14. One more level of indentation for match arms and switch cases. -1. Avoid: - - function pointers; see [0]. - - heap memory allocation; see [0]. - - too many levels of dereferences; see [0]. + 15. Alphabetic sorting, where applicable: + + use std::io::{ BufWriter, Read, Write, stderr, stdin, stdout } + + 16. In Rust, use the to_owned() method on string types (str, OsStr, CStr, etc.) + and the to_string() method on other types. + + +Avoid +===== + + 0. Heap memory allocation [0]. + + 1. Using too much nested logic (within reason). + + 2. Too many levels of dereferences [0]: /* do not do this */ for (size_t i = 0; i < sizeof a / sizeof *a; ++i) { @@ -131,48 +143,92 @@ brace and before a closing one: if (s->id == MATCH) { s->val = 0; } } -2. Do not use: - - more than the length of one printed page for a function; see [0]. - - recursion, as it's complex and can unexpectedly overflow the stack; see [0] -and section 2 of this document. - - (C) any language features not in C99. - - (C) do-while loops, as they're unique to the language and confusing for -casual C programmers. - - (C) gotos; use sensible flow control, see [0]. - - (C) pointer arithmetic, as it tends to be confusing and unnecessary; use -index-reference patterns like &p[1] instead of p + 1. &p[n] is the address at -p + sizeof p * n, not p + n, like pointer arithmetic suggests. - - (C) struct bitfields in unions, to access certain bits of bigger data types, -as it's poorly defined in the C standards; use bit arithmetic. - - (C) trigraphs. - - (Cpp) inclusions in C header files, to prevent multiple file inclusions. - - (Cpp) variables to prevent multiple inclusions of the same file, such as: + 3. Using C preprocessor macros; the fewer, the better [0]. + + 4. The exit(3p) and std::process::exit() functions; returning from the main + function skips a system call. + + +Do Not Use +========== + + 0. Function pointers [0]. + + 1. More than the length of one printed page for a function [0]. + + 2. Recursion, as it’s complex and can unexpectedly overflow the stack [0]. + + 3. Any functionality not in the POSIX C specification and language features not + in C99. + + 4. Do-while loops, as they’re unique to C and confusing for casual programmers. + + 5. Labels and goto statements; use sensible flow control [0]. + + 6. Pointer arithmetic, as it tends to be confusing and unnecessary; use + index-reference patterns like &p[1] instead of p + 1. &p[n] is the address at + p + sizeof p * n, not p + n, like pointer arithmetic suggests. + + 7. C struct bitfields in unions, to access certain bits of bigger data types, + as it’s poorly defined in the C standards; use bit arithmetic. + + 8. C trigraphs. + + 9. Inclusions in C header files, to prevent multiple file inclusions. + + 10. C preprocessor variables to prevent multiple inclusions of the same file, + such as: #ifdef _FILE #define _FILE /* file body */ #endif /* ifdef _FILE */ -Instead, take the time to ensure other files aren't including the any files -twice. + Instead, take the time to ensure other files aren’t including the any files + twice. - - (libc) any functionality not in the latest POSIX or C99. - - (libc) gets(3p) from , as it's impossible to prevent buffer -overflows when it's used; use fgets(3p) from . - - (libc) scanf(3p) from ; see [1]. - - (Make) any functionality not described in make(1p) from the latest POSIX. + 11. The gets(3p) function from , as it’s impossible to prevent buffer + overflows when it's used; use fgets(3p) from . + + 12. The scanf(3p) function from [1]. + + 13. Any functionality not described in the latest POSIX make(1) specification. + + 14. Macros which panic on failure in Rust (such as the print!() and println!() + macros). Use a function and handle any errors. However, do use the eprintln!() + macro for error messages. Handling an error for writing an error message is + redundant. + + +Usage Text +========== + +This section is adapted from the NetBSD style guide [2]. + +When programs are invoked incorrectly and in the synopsis of manual pages, uasge +text should be provided to the user. The following is the format used by this +project for this purpose: + +All optional arguments are to be placed in square brackets (U+005B, U+005D). +Mutually exclusive arguments can be separated by a vertical line (U+007C). +Groups of arguments should be specified in alphabetical order in most cases. The +order of arguments and an example of these rules follows: + + 0. Options with no option arguments. + 1. Options with option arguments. Arguments should be specified inside the same + square brackets as the options. + 3. Non-option arguments. + + "usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n" + "usage: f [-a | -b] [-c [-de] [-n number]]\n" -2. Keep the following in mind: - - Everyone knows that debugging is twice as hard as writing a program in the -first place. So if you're as clever as you can be when you write it, how will -you ever debug it? - -- Brian Kernighan, in The Elements of Programming Style References ========== [0] [1] +[2] -- Copyright © 2024 Emma Tebibyte