• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html><head><title>The design of toybox</title></head>
2<!--#include file="header.html" -->
3
4<a name="goals"><b><h2><a href="#goals">Design goals</a></h2></b>
5
6<p>Toybox should be simple, small, fast, and full featured. In that order.</p>
7
8<p>When these goals need to be balanced off against each other, keeping the code
9as simple as it can be to do what it does is the most important (and hardest)
10goal. Then keeping it small is slightly more important than making it fast.
11Features are the reason we write code in the first place but this has all
12been implemented before so if we can't do a better job why bother?</p>
13
14<p>It should be possible to get 80% of the way to each goal
15before they really start to fight. Here they are in reverse order
16of importance:</p>
17
18<b><h3>Features</h3></b>
19
20<p>These days toybox is the command line of Android, so anything the android
21guys say to do gets at the very least closely listened to.</p>
22
23<p>Toybox should provide the command line utilities of a build
24environment capable of recompiling itself under itself from source code.
25This minimal build system conceptually consists of 4 parts: toybox,
26a C library, a compiler, and a kernel. Toybox needs to provide all the
27commands (with all the behavior) necessary to run the configure/make/install
28of each package and boot the resulting system into a usable state.</p>
29
30<p>In addition, it should be possible to bootstrap up to arbitrary complexity
31under the result by compiling and installing additional packages into this
32minimal system, as measured by building both Linux From Scratch and the
33Android Open Source Project under the result. Any "circular dependencies"
34should be solved by toybox including the missing dependencies itself
35(see "Shared Libraries" below).</p>
36
37<p>Finally, toybox may provide some "convenience" utilties
38like top and vi that aren't necessarily used in a build but which turn
39the minimal build environment into a minimal development environment
40(supporting edit/compile/test cycles in a text console), configure
41network infrastructure for communication with other systems (in a build
42cluster), and so on.</p>
43
44<p>The hard part is deciding what NOT to include.
45A project without boundaries will bloat itself
46to death. One of the hardest but most important things a project must
47do is draw a line and say "no, this is somebody else's problem, not
48something we should do."
49Some things are simply outside the scope of the project: even though
50posix defines commands for compiling and linking, we're not going to include
51a compiler or linker (and support for a potentially infinite number of hardware
52targets). And until somebody comes up with a ~30k ssh implementation (with
53a crypto algorithm that won't need replacing every 5 years), we're
54going to point you at dropbear or bearssl.</p>
55
56<p>The <a href=roadmap.html>roadmap</a> has the list of features we're
57trying to implement, and the reasons why we decided to include those
58features. After the 1.0 release some of that material may get moved here,
59but for now it needs its own page. The <a href=status.html>status</a>
60page shows the project's progress against the roadmap.</p>
61
62<p>There are potential features (such as a screen/tmux implementation)
63that might be worth adding after 1.0, in part because they could share
64infrastructure with things like "less" and "vi" so might be less work for
65us to do than for an external from scratch implementation. But for now, major
66new features outside posix, android's existing commands, and the needs of
67development systems, are a distraction from the 1.0 release.</p>
68
69<b><h3>Speed</h3></b>
70
71<p>It's easy to say lots about optimizing for speed (which is why this section
72is so long), but at the same time it's the optimization we care the least about.
73The essence of speed is being as efficient as possible, which means doing as
74little work as possible.  A design that's small and simple gets you 90% of the
75way there, and most of the rest is either fine-tuning or more trouble than
76it's worth (and often actually counterproductive).  Still, here's some
77advice:</p>
78
79<p>First, understand the darn problem you're trying to solve.  You'd think
80I wouldn't have to say this, but I do.  Trying to find a faster sorting
81algorithm is no substitute for figuring out a way to skip the sorting step
82entirely.  The fastest way to do anything is not to have to do it at all,
83and _all_ optimization boils down to avoiding unnecessary work.</p>
84
85<p>Speed is easy to measure; there are dozens of profiling tools for Linux
86(although personally I find the "time" command a good starting place).
87Don't waste too much time trying to optimize something you can't measure,
88and there's no much point speeding up things you don't spend much time doing
89anyway.</p>
90
91<p>Understand the difference between throughput and latency.  Faster
92processors improve throughput, but don't always do much for latency.
93After 30 years of Moore's Law, most of the remaining problems are latency,
94not throughput.  (There are of course a few exceptions, like data compression
95code, encryption, rsync...)  Worry about throughput inside long-running
96loops, and worry about latency everywhere else.  (And don't worry too much
97about avoiding system calls or function calls or anything else in the name
98of speed unless you are in the middle of a tight loop that's you've already
99proven isn't running fast enough.)</p>
100
101<p>"Locality of reference" is generally nice, in all sorts of contexts.
102It's obvious that waiting for disk access is 1000x slower than doing stuff in
103RAM (and making the disk seek is 10x slower than sequential reads/writes),
104but it's just as true that a loop which stays in L1 cache is many times faster
105than a loop that has to wait for a DRAM fetch on each iteration.  Don't worry
106about whether "&" is faster than "%" until your executable loop stays in L1
107cache and the data access is fetching cache lines intelligently.  (To
108understand DRAM, L1, and L2 cache, read Hannibal's marvelous ram guide at Ars
109Technica:
110<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part1-2.html>part one</a>,
111<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part2-1.html>part two</a>,
112<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part3-1.html>part three</a>,
113plus this
114<a href=http://arstechnica.com/articles/paedia/cpu/caching.ars/1>article on
115cacheing</a>, and this one on
116<a href=http://arstechnica.com/articles/paedia/cpu/bandwidth-latency.ars>bandwidth
117and latency</a>.
118And there's <a href=http://arstechnica.com/paedia/index.html>more where that came from</a>.)
119Running out of L1 cache can execute one instruction per clock cycle, going
120to L2 cache costs a dozen or so clock cycles, and waiting for a worst case dram
121fetch (round trip latency with a bank switch) can cost thousands of
122clock cycles.  (Historically, this disparity has gotten worse with time,
123just like the speed hit for swapping to disk.  These days, a _big_ L1 cache
124is 128k and a big L2 cache is a couple of megabytes.  A cheap low-power
125embedded processor may have 8k of L1 cache and no L2.)</p>
126
127<p>Learn how <a href=http://nommu.org/memory-faq.txt>virtual memory and
128memory managment units work</a>.  Don't touch
129memory you don't have to.  Even just reading memory evicts stuff from L1 and L2
130cache, which may have to be read back in later.  Writing memory can force the
131operating system to break copy-on-write, which allocates more memory.  (The
132memory returned by malloc() is only a virtual allocation, filled with lots of
133copy-on-write mappings of the zero page.  Actual physical pages get allocated
134when the copy-on-write gets broken by writing to the virtual page.  This
135is why checking the return value of malloc() isn't very useful anymore, it
136only detects running out of virtual memory, not physical memory.  Unless
137you're using a <a href=http://nommu.org>NOMMU system</a>, where all bets
138are off.)</p>
139
140<p>Don't think that just because you don't have a swap file the system can't
141start swap thrashing: any file backed page (ala mmap) can be evicted, and
142there's a reason all running programs require an executable file (they're
143mmaped, and can be flushed back to disk when memory is short).  And long
144before that, disk cache gets reclaimed and has to be read back in.  When the
145operating system really can't free up any more pages it triggers the out of
146memory killer to free up pages by killing processes (the alternative is the
147entire OS freezing solid).  Modern operating systems seldom run out of
148memory gracefully.</p>
149
150<p>Also, it's better to be simple than clever.  Many people think that mmap()
151is faster than read() because it avoids a copy, but twiddling with the memory
152management is itself slow, and can cause unnecessary CPU cache flushes.  And
153if a read faults in dozens of pages sequentially, but your mmap iterates
154backwards through a file (causing lots of seeks, each of which your program
155blocks waiting for), the read can be many times faster.  On the other hand, the
156mmap can sometimes use less memory, since the memory provided by mmap
157comes from the page cache (allocated anyway), and it can be faster if you're
158doing a lot of different updates to the same area.  The moral?  Measure, then
159try to speed things up, and measure again to confirm it actually _did_ speed
160things up rather than made them worse.  (And understanding what's really going
161on underneath is a big help to making it happen faster.)</p>
162
163<p>In general, being simple is better than being clever.  Optimization
164strategies change with time.  For example, decades ago precalculating a table
165of results (for things like isdigit() or cosine(int degrees)) was clearly
166faster because processors were so slow.  Then processors got faster and grew
167math coprocessors, and calculating the value each time became faster than
168the table lookup (because the calculation fit in L1 cache but the lookup
169had to go out to DRAM).  Then cache sizes got bigger (the Pentium M has
1702 megabytes of L2 cache) and the table fit in cache, so the table became
171fast again...  Predicting how changes in hardware will affect your algorithm
172is difficult, and using ten year old optimization advice and produce
173laughably bad results.  But being simple and efficient is always going to
174give at least a reasonable result.</p>
175
176<p>The famous quote from Ken Thompson, "When in doubt, use brute force",
177applies to toybox.  Do the simple thing first, do as little of it as possible,
178and make sure it's right.  You can always speed it up later.</p>
179
180<b><h3>Size</h3></b>
181<p>Again, being simple gives you most of this. An algorithm that does less work
182is generally smaller.  Understand the problem, treat size as a cost, and
183get a good bang for the byte.</p>
184
185<p>Understand the difference between binary size, heap size, and stack size.
186Your binary is the executable file on disk, your heap is where malloc() memory
187lives, and your stack is where local variables (and function call return
188addresses) live.  Optimizing for binary size is generally good: executing
189fewer instructions makes your program run faster (and fits more of it in
190cache).  On embedded systems, binary size is especially precious because
191flash is expensive (and its successor, MRAM, even more so).  Small stack size
192is important for nommu systems because they have to preallocate their stack
193and can't make it bigger via page fault.  And everybody likes a small heap.</p>
194
195<p>Measure the right things.  Especially with modern optimizers, expecting
196something to be smaller is no guarantee it will be after the compiler's done
197with it.  Binary size isn't the most accurate indicator of the impact of a
198given change, because lots of things get combined and rounded during
199compilation and linking.  Matt Mackall's bloat-o-meter is a python script
200which compares two versions of a program, and shows size changes in each
201symbol (using the "nm" command behind the scenes).  To use this, run
202"make baseline" to build a baseline version to compare against, and
203then "make bloatometer" to compare that baseline version against the current
204code.</p>
205
206<p>Avoid special cases.  Whenever you see similar chunks of code in more than
207one place, it might be possible to combine them and have the users call shared
208code. (This is the most commonly cited trick, which doesn't make it easy. If
209seeing two lines of code do the same thing makes you slightly uncomfortable,
210you've got the right mindset.)</p>
211
212<p>Some specific advice: Using a char in place of an int when doing math
213produces significantly larger code on some platforms (notably arm),
214because each time the compiler has to emit code to convert it to int, do the
215math, and convert it back.  Bitfields have this problem on most platforms.
216Because of this, using char to index a for() loop is probably not a net win,
217although using char (or a bitfield) to store a value in a structure that's
218repeated hundreds of times can be a good tradeoff of binary size for heap
219space.</p>
220
221<b><h3>Simplicity</h3></b>
222
223<p>Complexity is a cost, just like code size or runtime speed. Treat it as
224a cost, and spend your complexity budget wisely. (Sometimes this means you
225can't afford a feature because it complicates the code too much to be
226worth it.)</p>
227
228<p>Simplicity has lots of benefits.  Simple code is easy to maintain, easy to
229port to new processors, easy to audit for security holes, and easy to
230understand.</p>
231
232<p>Simplicity itself can have subtle non-obvious aspects requiring a tradeoff
233between one kind of simplicity and another: simple for the computer to
234execute and simple for a human reader to understand aren't always the
235same thing. A compact and clever algorithm that does very little work may
236not be as easy to explain or understand as a larger more explicit version
237requiring more code, memory, and CPU time. When balancing these, err on the
238side of doing less work, but add comments describing how you
239could be more explicit.</p>
240
241<p>In general, comments are not a substitute for good code (or well chosen
242variable or function names). Commenting "x += y;" with "/* add y to x */"
243can actually detract from the program's readability. If you need to describe
244what the code is doing (rather than _why_ it's doing it), that means the
245code itself isn't very clear.</p>
246
247<p>Environmental dependencies are another type of complexity, so needing other
248packages to build or run is a big downside. For example, we don't use curses
249when we can simply output ansi escape sequences and trust all terminal
250programs written in the past 30 years to be able to support them. Regularly
251testing that we work with C libraries which support static linking (musl does,
252glibc doesn't) is another way to be self-contained with known boundaries:
253it doesn't have to be the only way to build the project, but should be regularly
254tested and supported.</p>
255
256<p>Prioritizing simplicity tends to serve our other goals: simplifying code
257generally reduces its size (both in terms of binary size and runtime memory
258usage), and avoiding unnecessary work makes code run faster. Smaller code
259also tends to run faster on modern hardware due to CPU cacheing: fitting your
260code into L1 cache is great, and staying in L2 cache is still pretty good.</p>
261
262<p>But a simple implementation is not always the smallest or fastest, and
263balancing simplicity vs the other goals can be difficult. For example, the
264atolx_range() function in lib/lib.c always uses the 64 bit "long long" type,
265which produces larger and slower code on 32 bit platforms and
266often assigned into smaller interger types. Although libc has parallel
267implementations for different data sizes (atoi, atol, atoll) we chose a
268common codepath which can cover all cases (every user goes through the
269same codepath, with the maximum amount of testing and minimum and avoids
270surprising variations in behavior).</p>
271
272<p>On the other hand, the "tail" command has two codepaths, one for seekable
273files and one for nonseekable files. Although the nonseekable case can handle
274all inputs (and is required when input comes from a pipe or similar, so cannot
275be removed), reading through multiple gigabytes of data to reach the end of
276seekable files was both a common case and hugely penalized by a nonseekable
277approach (half-minute wait vs instant results). This is one example
278where performance did outweigh simplicity of implementation.</p>
279
280<p><a href=http://www.joelonsoftware.com/articles/fog0000000069.html>Joel
281Spolsky argues against throwing code out and starting over</a>, and he has
282good points: an existing debugged codebase contains a huge amount of baked
283in knowledge about strange real-world use cases that the designers didn't
284know about until users hit the bugs, and most of this knowledge is never
285explicitly stated anywhere except in the source code.</p>
286
287<p>That said, the Mythical Man-Month's "build one to throw away" advice points
288out that until you've solved the problem you don't properly understand it, and
289about the time you finish your first version is when you've finally figured
290out what you _should_ have done.  (The corrolary is that if you build one
291expecting to throw it away, you'll actually wind up throwing away two.  You
292don't understand the problem until you _have_ solved it.)</p>
293
294<p>Joel is talking about what closed source software can afford to do: Code
295that works and has been paid for is a corporate asset not lightly abandoned.
296Open source software can afford to re-implement code that works, over and
297over from scratch, for incremental gains.  Before toybox, the unix command line
298has already been reimplemented from scratch several times (the
299original AT&amp;T Unix command line in assembly and then in C, the BSD
300versions, Coherent was the first full from-scratch Unix clone in 1980,
301Minix was another clone which Linux was inspired by and developed under,
302the GNU tools were yet another rewrite intended for use in the stillborn
303"Hurd" project, BusyBox was still another rewrite, and more versions
304were written in Plan 9, uclinux, klibc, sash, sbase, s6, and of course
305android toolbox...). But maybe toybox can do a better job. :)</p>
306
307<p>As Antoine de St. Exupery (author of "The Little Prince" and an early
308aircraft designer) said, "Perfection is achieved, not when there
309is nothing left to add, but when there is nothing left to take away."
310And Ken Thompson (creator of Unix) said "One of my most productive
311days was throwing away 1000 lines of code." It's always possible to
312come up with a better way to do it.</p>
313
314<p>P.S. How could I resist linking to an article about
315<a href=http://blog.outer-court.com/archive/2005-08-24-n14.html>why
316programmers should strive to be lazy and dumb</a>?</p>
317
318<a name="portability"><b><h2><a href="#portability">Portability issues</a></h2></b>
319
320<b><h3>Platforms</h3></b>
321<p>Toybox should run on Android (all commands with musl-libc, as large a subset
322as practical with bionic), and every other hardware platform Linux runs on.
323Other posix/susv4 environments (perhaps MacOS X or newlib+libgloss) are vaguely
324interesting but only if they're easy to support; I'm not going to spend much
325effort on them.</p>
326
327<p>I don't do windows.</p>
328
329<p>We depend on C99 and posix-2008 libc features such as the openat() family of
330functions. We also root around in the linux /proc directory a lot (no other
331way to implement "ps" at the moment), and assume certain "modern" linux kernel
332behavior such as large environment sizes (<a href=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318>linux commit b6a2fea39318</a>, went into 2.6.22
333released <a href=faq.html#support_horizon>July 2007</a>, expanding the 128k
334limit to 2 gigabytes. But it was then
335trimmed back down to 10 megabytes, and when I asked for a way to query the
336actual value from the kernel if it was going to keep changing
337like that, <a href=https://lkml.org/lkml/2017/11/5/204>Linus declined</a>).
338In theory this shouldn't prevent us from working on
339older kernels or other implementations (ala BSD), but we don't police their
340corner cases.</p>
341
342<a name="bits" />
343<b><h3>32/64 bit</h3></b>
344<p>Toybox should work on both 32 bit and 64 bit systems. 64 bit desktop
345hardware went mainstream in <a href=https://web.archive.org/web/20040307000108mp_/http://developer.intel.com/technology/64bitextensions/faq.htm>in 2005</a>
346and was essentially ubiquitous <a href=faq.html#support_horizon>by 2012</a>,
347but 32 bit hardware will continue to be important in embedded devices for years to come.</p>
348
349<p>Toybox relies on the
350<a href=http://archive.opengroup.org/public/tech/aspen/lp64_wp.htm>LP64 standard</a>
351which Linux, MacOS X, and BSD all implement, and which modern 64 bit processors such as
352x86-64 were <a href=http://www.pagetable.com/?p=6>explicitly designed to
353support</a>. (Here's the original <a href=https://web.archive.org/web/20020905181545/http://www.unix.org/whitepapers/64bit.html>LP64 white paper</a>.)</p>
354
355<p>LP64 defines explicit sizes for all the basic C integer types, and
356guarantees that on any Unix-like platform "long" and "pointer" types
357are always the same size. This means it's safe to assign pointers into
358longs and vice versa without losing data: on 32 bit systems both are 32 bit,
359on 64 bit systems both are 64 bit.</p>
360
361<table border=1 cellpadding=10 cellspacing=2>
362<tr><td>C type</td><td>32 bit<br />sizeof</td><td>64 bit<br />sizeof</td></tr>
363<tr><td>char</td><td>1 byte</td><td>1 byte</td></tr>
364<tr><td>short</td><td>2 bytes</td><td>2 bytes</td></tr>
365<tr><td>int</td><td>4 bytes</td><td>4 bytes</td></tr>
366<tr><td>long</td><td>4 bytes</td><td>8 bytes</td></tr>
367<tr><td>long long</td><td>8 bytes</td><td>8 bytes</td></tr>
368</table>
369
370<p>LP64 eliminates the need to use c99 "uint32_t" and friends: the basic
371C types all have known size/behavior, and the only type whose
372size varies is "long", which is the natural register size of the processor.</p>
373
374<p>Note that Windows doesn't work like this, and I don't care, but if you're
375curious here are <a href=https://devblogs.microsoft.com/oldnewthing/20050131-00/?p=36563>the insane legacy reasons why this is broken on Windows</a>.</a></p>
376
377<b><h3>Signedness of char</h3></b>
378<p>On platforms like x86, variables of type char default to unsigned.  On
379platforms like arm, char defaults to signed.  This difference can lead to
380subtle portability bugs, and to avoid them we specify which one we want by
381feeding the compiler -funsigned-char.</p>
382
383<p>The reason to pick "unsigned" is that way char strings are 8-bit clean by
384default, which makes UTF-8 support easier.</p>
385
386<p><h3>Error messages and internationalization:</h3></p>
387
388<p>Error messages are extremely terse not just to save bytes, but because we
389don't use any sort of _("string") translation infrastructure. (We're not
390translating the command names themselves, so we must expect a minimum amount of
391english knowledge from our users, but let's keep it to a minimum.)</p>
392
393<p>Thus "bad -A '%c'" is
394preferable to "Unrecognized address base '%c'", because a non-english speaker
395can see that -A was the problem (giving back the command line argument they
396supplied). A user with a ~20 word english vocabulary is
397more likely to know (or guess) "bad" than the longer message, and you can
398use "bad" in place of "invalid", "inappropriate", "unrecognized"...
399Similarly when atolx_range() complains about range constraints with
400"4 < 17" or "12 > 5", it's intentional: those don't need to be translated.</p>
401
402<p>The strerror() messages produced by perror_exit() and friends should be
403localized by libc, and our error functions also prepend the command name
404(which non-english speakers can presumably recognize already). Keep the
405explanation in between to a minimum, and where possible feed back the values
406they passed in to identify _what_ we couldn't process.
407If you say perror_exit("setsockopt"), you've identified the action you
408were trying to take, and the perror gives a translated error message (from libc)
409explaining _why_ it couldn't do it, so you probably don't need to add english
410words like "failed" or "couldn't assign".</p>
411
412<p>All commands should be 8-bit clean, with explicit
413<a href=http://yarchive.net/comp/linux/utf8.html>UTF-8</a> support where
414necessary. Assume all input data might be utf8, and at least preserve
415it and pass it through. (For this reason, our build is -funsigned-char on
416all architectures; "char" is unsigned unless you stick "signed" in front
417of it.)</p>
418
419<p>Locale support isn't currently a goal; that's a presentation layer issue
420(I.E. a GUI problem).</p>
421
422<p>Someday we should probably have translated --help text, but that's a
423post-1.0 issue.</p>
424
425<p><h3>Shared Libraries</h3></p>
426
427<p>Toybox's policy on shared libraries is that they should never be
428required, but can optionally be used to improve performance.</p>
429
430<p>Toybox should provide the command line utilities for
431<a href=roadmap.html#dev_env>self-hosting development envirionments</a>,
432and an easy way to set up "hermetic builds" (I.E. builds which provide
433their own dependencies, isolating the build logic from host command version
434skew with a simple known build environment). In both cases, external
435dependencies defeat the purpose.</p>
436
437<p>This means toybox should provide full functionality without relying
438on any external dependencies (other than libc). But toybox may optionally use
439libraries such as zlib and openssl to improve performance for things like
440deflate and sha1sum, which lets the corresponding built-in implementations
441be simple (and thus slow). But the built-in implementations need to exist and
442work.</p>
443
444<p>(This is why we use an external https wrapper program, because depending on
445openssl or similar to be linked in would change the behavior of toybox.)</p>
446
447<a name="license" />
448<h2>License</h2>
449
450<p>Toybox is licensed <a href=license.html>0BSD</a>, which is a public domain
451equivalent license approved by <a href=https://spdx.org/licenses/0BSD.html>SPDX</a>. This works like other BSD licenses except that it doesn't
452require copying specific license text into the resulting project when
453you copy code. (We care about attribution, not ownership, and the internet's
454really good at pointing out plagiarism.)</p>
455
456<p>This means toybox usually can't use external code contributions, and must
457implement new versions of everything unless the external code's original
458author (and any additional contributors) grants permission to relicense.
459Just as a GPLv2 project can't incorporate GPLv3 code and a BSD-licensed
460project can't incorporate either kind of GPL code, we can't incorporate
461most BSD or Apache licensed code without changing our license terms.</p>
462
463<p>The exception to this is code under an existing public domain equivalent
464license, such as the xz decompressor or
465<a href=https://github.com/mkj/dropbear/blob/master/libtommath/LICENSE>libtommath</a> and <a href=https://github.com/mkj/dropbear/blob/master/libtomcrypt/LICENSE>libtomcrypt</a>.</p>
466
467<a name="codestyle" />
468<h2>Coding style</h2>
469
470<p>The real coding style holy wars are over things that don't matter
471(whitespace, indentation, curly bracket placement...) and thus have no
472obviously correct answer. As in academia, "the fighting is so vicious because
473the stakes are so small". That said, being consistent makes the code readable,
474so here's how to make toybox code look like other toybox code.</p>
475
476<p>Toybox source uses two spaces per indentation level, and wraps at 80
477columns. (Indentation of continuation lines is awkward no matter what
478you do, sometimes two spaces looks better, sometimes indenting to the
479contents of a parentheses looks better.)</p>
480
481<p>I'm aware this indentation style creeps some people out, so here's
482the sed invocation to convert groups of two leading spaces to tabs:</p>
483<blockquote><pre>
484sed -i ':loop;s/^\( *\)  /\1\t/;t loop' filename
485</pre></blockquote>
486
487<p>And here's the sed invocation to convert leading tabs to two spaces each:</p>
488<blockquote><pre>
489sed -i ':loop;s/^\( *\)\t/\1  /;t loop' filename
490</pre></blockquote>
491
492<p>There's a space after C flow control statements that look like functions, so
493"if (blah)" instead of "if(blah)". (Note that sizeof is actually an
494operator, so we don't give it a space for the same reason ++ doesn't get
495one. Yeah, it doesn't need the parentheses either, but it gets them.
496These rules are mostly to make the code look consistent, and thus easier
497to read.) We also put a space around assignment operators (on both sides),
498so "int x = 0;".</p>
499
500<p>Blank lines (vertical whitespace) go between thoughts. "We were doing that,
501now we're doing this." (Not a hard and fast rule about _where_ it goes,
502but there should be some for the same reason writing has paragraph breaks.)</p>
503
504<p>Variable declarations go at the start of blocks, with a blank line between
505them and other code. Yes, c99 allows you to put them anywhere, but they're
506harder to find if you do that. If there's a large enough distance between
507the declaration and the code using it to make you uncomfortable, maybe the
508function's too big, or is there an if statement or something you can
509use as an excuse to start a new closer block? Use a longer variable name
510that's easier to search for perhaps?</p>
511
512<p>An * binds to a variable name not a type name, so space it that way.
513(In C "char *a, b;" and "char* a, b;" mean the same thing: "a" is a pointer
514but "b" is not. Spacing it the second way is not how C works.)</p>
515
516<p>If statements with a single line body go on the same line if the result
517fits in 80 columns, on a second line if it doesn't. We usually only use
518curly brackets if we need to, either because the body is multiple lines or
519because we need to distinguish which if an else binds to. Curly brackets go
520on the same line as the test/loop statement. The exception to both cases is
521if the test part of an if statement is long enough to split into multiple
522lines, then we put the curly bracket on its own line afterwards (so it doesn't
523get lost in the multple line variably indented mess), and we put it there
524even if it's only grouping one line (because the indentation level is not
525providing clear information in that case).</p>
526
527<p>I.E.</p>
528
529<blockquote>
530<pre>
531if (thingy) thingy;
532else thingy;
533
534if (thingy) {
535  thingy;
536  thingy;
537} else thingy;
538
539if (blah blah blah...
540    && blah blah blah)
541{
542  thingy;
543}
544</pre></blockquote>
545
546<p>Gotos are allowed for error handling, and for breaking out of
547nested loops. In general, a goto should only jump forward (not back), and
548should either jump to the end of an outer loop, or to error handling code
549at the end of the function. Goto labels are never indented: they override the
550block structure of the file. Putting them at the left edge makes them easy
551to spot as overrides to the normal flow of control, which they are.</p>
552
553<p>When there's a shorter way to say something, we tend to do that for
554consistency. For example, we tend to say "*blah" instead of "blah[0]" unless
555we're referring to more than one element of blah. Similarly, NULL is
556really just 0 (and C will automatically typecast 0 to anything, except in
557varargs), "if (function() != NULL)" is the same as "if (function())",
558"x = (blah == NULL);" is "x = !blah;", and so on.</p>
559
560<p>The goal is to be
561concise, not cryptic: if you're worried about the code being hard to
562understand, splitting it to multiple steps on multiple lines is
563better than a NOP operation like "!= NULL". A common sign of trying too
564hard is nesting ? : three levels deep, sometimes if/else and a temporary
565variable is just plain easier to read. If you think you need a comment,
566you may be right.</p>
567
568<p>Comments are nice, but don't overdo it. Comments should explain _why_,
569not how. If the code doesn't make the how part obvious, that's a problem with
570the code. Sometimes choosing a better variable name is more revealing than a
571comment. Comments on their own line are better than comments on the end of
572lines, and they usually have a blank line before them. Most of toybox's
573comments are c99 style // single line comments, even when there's more than
574one of them. The /* multiline */ style is used at the start for the metadata,
575but not so much in the code itself. They don't nest cleanly, are easy to leave
576accidentally unterminated, need extra nonfunctional * to look right, and if
577you need _that_ much explanation maybe what you really need is a URL citation
578linking to a standards document? Long comments can fall out of sync with what
579the code is doing. Comments do not get regression tested. There's no such
580thing as self-documenting code (if nothing else, code with _no_ comments
581is a bit unfriendly to new readers), but "chocolate sauce isn't the answer
582to bad cooking" either. Don't use comments as a crutch to explain unclear
583code if the code can be fixed.</p>
584
585<!--#include file="footer.html" -->
586