Code style

Toybox source is formatted to be read with 4-space tab stops. Each file starts with a special comment telling vi to set the tab stop to 4. Note that one of the bugs in Ubuntu 7.10 broke vi's ability to parse these comments; you must either rebuild vim from source, or go ":ts=4" yourself each time you load the file.

Gotos are allowed for error handling, and for breaking out of nested loops. In general, a goto should only jump forward (not back), and should either jump to the end of an outer loop, or to error handling code at the end of the function. Goto labels are never indented: they override the block structure of the file. Putting them at the left edge makes them easy to spot as overrides to the normal flow of control, which they are.

The primary goal of toybox is _simple_ code. Small is second, speed and lots of features come in somewhere after that. Note that environmental dependencies are a type of complexity, so needing other packages to build or run is a downside. For example, don't use curses when you can output ansi escape sequences instead.

Infrastructure:

The toybox source code is in following directories:

Adding a new command

To add a new command to toybox, add a C file implementing that command to the toys directory. No other files need to be modified; the build extracts all the information it needs (such as command line arguments) from specially formatted comments and macros in the C file. (See the description of the generated directory for details.)

An easy way to start a new command is copy the file "hello.c" to the name of the new command, and modify this copy to implement the new command. This file is an example command meant to be used as a "skeleton" for new commands (more or less by turning every instance of "hello" into the name of your command, updating the command line arguments, globals, and help data, and then filling out its "main" function with code that does something interesting). It provides examples of all the build infrastructure (including optional elements like command line argument parsing and global variables that a "hello world" program doesn't strictly need).

Here's a checklist of steps to turn hello.c into another command:

Top level directory.

This directory contains global infrastructure.

main.c

Contains the main() function where execution starts, plus common infrastructure to initialize global variables and select which command to run. The "toybox" multiplexer command also lives here. (This is the only command defined outside of the toys directory.)

Execution starts in main() which trims any path off of the first command name and calls toybox_main(), which calls toy_exec(), which calls toy_find() and toy_init() before calling the appropriate command's function from toy_list. If the command is "toybox", execution recurses into toybox_main(), otherwise the call goes to the appropriate commandname_main() from a C file in the toys directory.

The following global variables are defined in main.c:

The following functions are defined in main.c:

Config.in

Top level configuration file in a stylized variant of kconfig format. Includes generated/Config.in.

These files are directly used by "make menuconfig" to select which commands to build into toybox (thus generating a .config file), and by scripts/config2help.py to create generated/help.h.

Temporary files:

There is one temporary file in the top level source directory:

The "generated/" directory contains files generated from other source code in toybox. All of these files can be recreated by the build system, although some (such as generated/help.h) are shipped in release versions to reduce environmental dependencies (I.E. so you don't need python on your build system).

Directory toys/

toys/Config.in

Included from the top level Config.in, contains one or more configuration entries for each command.

Each command has a configuration entry matching the command name (although configuration symbols are uppercase and command names are lower case). Options to commands start with the command name followed by an underscore and the option name. Global options are attachd to the "toybox" command, and thus use the prefix "TOYBOX_". This organization is used by scripts/cfg2files to select which toys/*.c files to compile for a given .config.

A commands with multiple names (or multiple similar commands implemented in the same .c file) should have config symbols prefixed with the name of their C file. I.E. config symbol prefixes are NEWTOY() names. If OLDTOY() names have config symbols they're options (symbols with an underscore and suffix) to the NEWTOY() name. (See toys/toylist.h)

toys/toylist.h

The first half of this file prototypes all the structures to hold global variables for each command, and puts them in toy_union. These prototypes are only included if the macro NEWTOY isn't defined (in which case NEWTOY is defined to a default value that produces function prototypes).

The second half of this file lists all the commands in alphabetical order, along with their command line arguments and install location. Each command has an appropriate configuration guard so only the commands that are enabled wind up in the list.

The first time this header is #included, it defines structures and produces function prototypes for the commands in the toys directory.

The first time it's included, it defines structures and produces function prototypes. This is used to initialize toy_list in main.c, and later in that file to initialize NEED_OPTIONS (to figure out whether the command like parsing logic is needed), and to put the help entries in the right order in toys/help.c.

toys/help.h

#defines two help text strings for each command: a single line command_help and an additinal command_help_long. This is used by help_main() in toys/help.c to display help for commands.

Although this file is generated from Config.in help entries by scripts/config2help.py, it's shipped in release tarballs so you don't need python on the build system. (If you check code out of source control, or modify Config.in, then you'll need python installed to rebuild it.)

This file contains help for all commands, regardless of current configuration, but only the currently enabled ones are entered into help_data[] in toys/help.c.

Directory lib/

lib: llist, getmountlist(), error_msg/error_exit, xmalloc(), strlcpy(), xexec(), xopen()/xread(), xgetcwd(), xabspath(), find_in_path(), itoa().

Directory scripts/

scripts/cfg2files.sh

Run .config through this filter to get a list of enabled commands, which is turned into a list of files in toys via a sed invocation in the top level Makefile.

Directory kconfig/

Menuconfig infrastructure copied from the Linux kernel. See the Linux kernel's Documentation/kbuild/kconfig-language.txt