Crate gpp[][src]

Expand description

gpp is a Generic PreProcessor written in Rust.

It supports:

  • Simple macros, no function macros
  • #include
  • #define and #undef
  • #ifdef, #ifndef, #elifdef, #elifndef, #else and #endif
  • #exec for running commands
  • #in and #endin for giving input to commands

#includes work differently from C, as they do not require (and do not work with) quotes or <>, so #include file.txt is the correct syntax. It does not support #if or #elif, and recursive macros will cause the library to get stuck.


The hash in any command may be succeeded by optional whitespace, so for example # undef Macro is valid, but # undef Macro is not.

#define and #undef

#define works similar to C: #define [name] [value], and #undef too: #undef [name]. Be careful though, because unlike C macro expansion is recursive: if you #define A A and then use A, gpp will run forever. If #define is not given a value, then it will default to an empty string.


Includes, unlike C, do not require quotes or angle brackets, so this: #include "file.txt" or this: #include <file.txt> will not work; you must write #include file.txt.

Also, unlike C the directory does not change when you #include; otherwise, gpp would change its current directory and wouldn’t be thread safe. This means that if you #include dir/file.txt and in dir/file.txt it says #include other_file.txt, that would refer to other_file.txt, not dir/other_file.txt.


The #ifdef, #ifndef, #elifdef, #elifndef, #else and #endif commands work exactly as you expect. I did not add generic #if commands to gpp, as it would make it much more complex and require a lot of parsing, and most of the time these are all you need anyway.

#exec, #in and #endin

The exec command executes the given command with cmd /C for Windows and sh -c for everything else, and captures the command’s standard output. For example, #exec echo Hi! will output Hi!. It does not capture the command’s standard error, and parsing stops if the command exits with a nonzero status.

Due to the security risk enabling #exec causes, by default exec is disabled, however you can enable it by changing the allow_exec flag in your context. If the input tries to #exec when exec is disabled, it will cause an error.

The in command is similar to exec, but all text until the endin command is passed into the program’s standard input. For example,

#in sed 's/tree/three/g'
One, two, tree.

Would output One, two, three.. Note that you shouldn’t do this, just using #define tree three would be much faster and less platform-dependent. You can also place more commands in the in block, including other in blocks. For a useful example:

#in sassc -s

This compiles your scss file into css using Sassc and includes in the HTML every time you generate your webpage with gpp.

Literal hashes

In order to insert literal hash symbols at the start of the line, simply use two hashes. ##some text will convert into #some text, while #some text will throw an error as some is not a command.


// Create a context for preprocessing
let mut context = gpp::Context::new();

// Add a macro to that context manually (context.macros is a HashMap)
context.macros.insert("my_macro".to_owned(), "my_value".to_owned());

// Process some text using that
assert_eq!(gpp::process_str("My macro is my_macro\n", &mut context).unwrap(), "My macro is my_value\n");

// Process some multi-line text, changing the context
#define Line Row
Line One
Line Two
The Third Line", &mut context).unwrap(), "
Row One
Row Two
The Third Row

// The context persists
assert_eq!(context.macros.get("Line").unwrap(), "Row");

// Try some more advanced commands
Line Four
#ifdef Line
#undef Line
Line Five", &mut context).unwrap(), "
Row Four
Line Five


Context of the current processing.


Error enum for parsing errors.


Process a generic BufRead.

Process a file.

Process a string line of input.

Process a multi-line string of text.