Ghostscript C coding guidelines

## Table of contents

> - Summary of the coding guidelines
>   - Preprocessor
>   - Types and scopes
>   - Formatting
>   - Miscellany
> - Introduction
> - Use of C language features
>   - Preprocessor
>     - Conditionals
>     - Macros
>   - Types and declarations
>     - Pointers and structures
>     - Scalars
>   - `static` and `extern` scoping
>   - Standard library features
>   - Miscellany
> - File structuring and naming
>   - All files
>   - Makefiles
>   - C code in general
>     - Headers (`.h` files)
>     - Executable code (`.c` files)
> - Formatting
>   - Indentation
>   - Spaces
>   - Parentheses
> - Naming
>   - General rules
>   - Names used by convention
>     - `code`
>     - `status`
> - Miscellany
>   - Single-use procedures
>   - Local variables
>   - Error handling
>   - Compiler warnings

For other information, see the Ghostscript overview.

# Summary of the coding guidelines

## Preprocessor

- Use preprocessor conditionals that test for individual platforms or compilers, if necessary, only in header files named xxx`_.h`.
- Don't define a macro if you can do it with a procedure.
- Use

  > `gx_device_fubar * const fdev = (gx_device_fubar *)dev;`

  rather than

  > `#define fdev ((gx_device_fubar *)dev)`

- Put `()` around the body of expression-macro definitions, and around each use of an argument.
- Make all variables referenced in a macro body arguments of the macro.

## Types and scopes

- Use `const` for pointer referents (that is, `const T *`) wherever possible.
- Use unions or (less preferably) casts in preference to `void *`.
- Don't use anonymous structures or unions.
- Don't declare procedure parameters of type `float`, `short`, or `char`.
- Never explicitly cast `float` to `double`.
- Use "`private`" instead of "`static`" at the top level of a file.
- Don't create any new non-`const` static variables.
- Put externs in `.h` files, not `.c` files.

## Formatting

- `gsindent` (GNU `indent` + fixup script) will do 98% of the job for you.
- Put indentation points every 4 spaces, with 8 spaces = 1 tab stop.
- "`{`" should always be the last non-blank character on its line (except for comments); "`}`" should always be the first non-blank on its line.
- Use spaces after comma ("`,`") and semicolon ("`;`"), around binary operators, and on both sides of the parentheses for `if`, `for`, and `while`, and nowhere else.
- Use parentheses only when mixing `&&` and `||`, when mixing `&`, `|` and shifts with each other or other operators, and around "`? :`" expressions.

## Miscellany

- Use `#include` statements in the order
  1. `*_.h`
  2. `gs*.h`
  3. `gx*.h`
  4. `s*.h`
  5. `i*.h`
- In names use full words rather than contractions, and don't run words together.
- Don't assign new values to procedure parameters.
- Initialize local variables when they are declared.

# Introduction

The many rules that Ghostscript's code follows almost everywhere are meant to produce code that is easy to read. It's important to observe them as much as possible in order to maintain a consistent style, but if you find a rule getting in your way or producing ugly-looking results once in a while, it's OK to break it.

# Use of C language features

## Preprocessor

### Conditionals

Using preprocessor conditionals can easily lead to unreadable code, since the eye really wants to read linearly rather than having to parse the conditionals just to figure out what code is relevant. It's OK to use conditionals that have small scope and that don't change the structure or logic of the program (typically, they select between different sets of values depending on some configuration parameter), but where possible, break up source modules rather than use conditionals that affect the structure or logic.

In `.c` files don't use preprocessor conditionals that test for individual platforms or compilers. Use them only in header files named xxx`_.h`.

### Macros

Ghostscript code uses macros heavily to effectively extend the rather weak abstraction capabilities of the C language, specifically in the area of memory management and garbage collection: in order to read Ghostscript code effectively, you simply have to learn some of these macros as though they were part of the language. The current code also uses macros heavily for other purposes, but we are trying to phase these out as rapidly as possible, because they make the code harder to read and debug, and to use the rules that follow consistently in new code.

Define macros in the smallest scope you can manage (procedure, file, or `.h` file), and `#undef` them at the end of that scope: that way, someone reading the code can see the definitions easily when reading the uses. If that isn't appropriate, define them in as large a scope as possible, so that they effectively become part of the language. This places an additional burden on the reader, but it can be amortized over reading larger amounts of code.

Try hard to use procedures instead of macros. Use "`inline`" if you really think the extra speed is needed, but only within a `.c` file: don't put inline procedures in `.h` files, because most compilers don't honor "`inline`" and you'll wind up with a copy of the procedure in every `.c` file that includes the `.h` file.

Don't use macros to define shorthands for casted pointers. For instance, avoid

> `#define fdev ((gx_device_fubar *)dev)`

and instead use

> `gx_device_fubar * const fdev = (gx_device_fubar *)dev;`

The use of `const` alerts the reader that this is effectively a synonym.

If you define a macro that looks like a procedure, make sure it will work wherever a procedure will work. In particular, put parentheses around every use of an argument within the macro body, so that the macro will parse correctly if some of the arguments are expressions, and put parentheses around the entire macro body. (This is still subject to the problem that an argument may be evaluated more than once, but there is no way around this in C, since C doesn't provide for local variables within expressions.)

If a macro generates anything larger than a single expression (that is, one or more statements), surround it with `BEGIN` and `END`. These work around the fact that simple statements and compound statements in C can't be substituted for each other syntactically.

If you define macros for special loop control structures, make their uses look somewhat like ordinary loops, for instance:

> `BEGIN_RECT(xx, yy) {`
> ... body indented one position ...
> `} END_RECT(xx, yy);`

If at all possible, don't use free variables in macros -- that is, variables that aren't apparent as arguments of the macro. If you must use free variables, list them all in a comment at the point where the macro is defined.

Preferably `CAPITALIZE` macro names.

## Types and declarations

### Pointers and structures

Use `const` for pointer referents (that is, `const T *`) wherever possible and appropriate. Don't bother using it for anything else, except as described above for casted pointers.

If you find yourself wanting to use `void *`, try to find an alternative using unions or (in the case of super- and subclasses) casts, unless you're writing something like a memory manager that really treats memory as opaque.

Don't use anonymous structures if you can possibly avoid it, except perhaps as components of other structures. Ideally, use the "`struct`" keyword only for declaring named structure types, like this:

> `typedef struct xxx_yyy_s {`
> ... members ...
> `} xxx_yyy_t;`

Many older structure names don't have `_t` on the end, but it should be used in all new code. (The `_s` name is needed only to satisfy some debuggers. No code should use it.)

If a procedure parameter is itself a procedure, do list its parameter types rather than just using `()`. For example,

> `int foo(P1(int (*callback)(P2(int, int))));`

rather than just

> `int foo(P1(int (*callback)()));`

### Scalars

Don't declare parameters as being of type `float`, `short`, or `char`. If you do this and forget to include the prototype at a call site, ANSI compilers will generate incompatible calling sequences. Use `floatp` (a synonym for `double`, mnemonic for "float parameter") instead of `float`, and use `int` or `uint` instead of `short` or `char`.

ANSI compilers in their default mode do all floating point computations in double precision, so never cast a `float` to a `double` explicitly.

Unless there's a good reason for doing otherwise, return `floatp` (`double`) rather than `float` values. Floating point hardware often does everything in double precision internally and has to do extra work to convert between double and single precision.

## Static and extern scoping

Use "`private`" instead of "`static`" for constructs (procedures and variables) declared at the outermost scope of a file. This allows making such constructs either visible or invisible to profilers with a single changed `#define`.

Don't create any new non-`const` static variables (whether exported or local to a file): they are incompatible with reentrancy, and we're in the process of eliminating all of them.

Avoid `static const` data, but don't knock yourself out over it, especially if it's local to a file.

Avoid `extern` in `.c` files: put it in header files.

## Standard library features

Only use library features that are documented in the established ANSI standard (e.g., Harbison & Steele's book). Do not use procedures that are "standards" promulgated by Microsoft (e.g., `stricmp`), or originate in BSD Unix (e.g., `strcasecmp`), or were added in later versions of the standard such as C 9X.

## Miscellany

The most important descriptive comments are ones in header files that describe structures, including invariants; but every procedure or structure declaration, or group of other declarations, should have a comment. Don't spend a lot of time commenting executable code unless something unusual or subtle is going on.

In older code, calling a variable or parameter procedure always used explicit indirection, for instance, `(*ptr->func)(...)` rather than `ptr->func(...)`. Since all current compilers accept the latter form, use it in new code.

Don't write expressions that depend on order of evaluation, unless the order is created explicitly by use of `||`, `&&`, `?:`, `,`, or function nesting (the arguments of a function must be evaluated before the function is called). In particular, don't assume that the arguments of a function will be evaluated left-to-right, or that the left side of an assignment will be evaluated before the right.

# File structuring

## All files

Keep file names within the "8.3" format for portability (the "long file name" facilities of MS Windows are a hack that sometimes doesn't work properly with code written by parties other than Microsoft):

- Use only letters, digits, dash, and underscore in file names.
- Don't assume upper and lower case letters are distinct.
- Put no more than 8 characters before the ".", if any.
- If there is a ".", put between 1 and 3 characters after the ".".

For files other than documentation files, use only lower case letters in the names; for HTML documentation files, capitalize the first letter.

Every code file should start with comments containing

1. a copyright notice,
2. the name of the file in the form of an RCS Id:

   > `/*Id$: filename.ext $*/`

   (using the comment convention appropriate to the language of the file), and

3. a summary, no more than one line, of what the file contains.

If you create a file by copying the beginning of another file, be sure to update the copyright year and change the file name.

## Makefiles

Use the extension `.mak` for makefiles.

For each

> `#include "xxx.h"`

make sure there is a dependency on `$(xxx_h)` in the makefile. If xxx ends with a "`_`", this rule still holds, so that if you code

> `#include "math_.h"`

the makefile must contain a dependency on "`$(math__h)`" (note the two underscores "`__`").

List the dependencies bottom-to-top, like the `#include` statements themselves; within each level, list them alphabetically. Do this also with `#include` statements themselves whenever possible (but sometimes there are inter-header dependencies that require bending this rule).

For compatibility with the build utilities on OpenVMS, always put a space before the colon that separates the target(s) of a rule from the dependents.

## C code in general

List `#include` statements from "bottom" to "top", that is, in the following order:

> 1. System includes (`"xxx_.h"`)
> 2. `gs*.h`
> 3. `gx*.h` (yes, `gs` and `gx` are in the wrong order.)
> 4. `s*.h`
> 5. `i*.h` (or other interpreter headers that don't start with "`i`")

### Headers (`.h` files)

In header files, always use the following at the beginning of a header file to prevent double inclusion:

> {{ Copyright notice etc. }}
> `#ifndef` <filename>`_INCLUDED`
> `#define` <filename>`_INCLUDED`
> {{ The contents of the file }}
> `#endif /*` <filename>`_INCLUDED */`

The header file is the first place that a reader goes for information about procedures, structures, constants, etc., so ensure that every procedure and structure has a comment that says what it does. Divide procedures into meaningful groups set off by some distinguished form of comment.

### Executable code (`.c` files)

After the initial comments, arrange C files in the following order:

> 1. `#include` statements
> 2. Exported data declarations
> 3. Explicit externs (if necessary)
> 4. Forward declarations of procedures
> 5. Private data declarations
> 6. Exported procedures
> 7. Private procedures

Be flexible about the order of the declarations if necessary to improve readability. Many older files don't follow this order, often without good reason.

# Formatting

## Indentation

We've formatted all of our code using the GNU `indent` program.

> `indent -bad -nbap -nsob -br -ce -cli4 -npcs -ncs \
> -i4 -di0 -psl -lp -lps somefile.c`

does a 98% accurate job of producing our preferred style. Unfortunately, there are bugs in all versions of GNU `indent`, requiring both pre- and post-processing of the code. The `gsindent` script in the Ghostscript fileset contains the necessary workarounds.

Put indentation points every 4 spaces, with 8 spaces = 1 tab stop.

Indent in-line blocks thus:

> `{`
> ... declarations ...
> {{ blank line if any declarations above }}
> ... statements ...
> `}`

Similarly, indent procedures thus:

> return_type
> proc_name(... arguments ...)
> `{`
> ... declarations ...
> {{ blank line if any declarations above }}
> ... statements ...
> `}`

If a control construct (`if`, `do`, `while`, or `for`) has a one-line body, use this:

> ... control construct ...
> ... subordinate simple statement ...

If it has a multi-line body, use this:

> ... control construct ... `{`
> ... subordinate code ...
> `}`

If the subordinate code has declarations, see blocks above.

For if-else statements, do this:

> `if (` ...`) {`
> ... subordinate code ...
> `} else if (` ...`) {`
> ... subordinate code ...
> `} else {`
> ... subordinate code ...
> `}`

When there are more than two alternatives, as in the example above, use the above ("parallel") syntax rather than the following ("nested") syntax:

> `if (` ...`) {`
> ... subordinate code ...
> `} else {`
> `if (` ...`) {`
> ... subordinate code ...
> `} else {`
> ... subordinate code ...
> `}`
> `}`

Similarly, for do-while statements, do this:

> `do {`
> ... body ...
> `} while (` ... condition ... `);`

## Spaces

Do put a space:

- after every comma and semicolon, unless it ends a line;
- around every binary operator, although you can omit the spaces around the innermost operator in a nested expression if you like;
- on both sides of the parentheses of an `if`, `for`, or `while`.

Don't put a space:

- at the end of a line;
- before a comma or semicolon;
- after unary prefix operators;
- before the parenthesis of a macro or procedure call.

## Parentheses

Parentheses are important in only a few places:

- Around the inner subexpressions in expressions that mix `&&` and `||`, even if they are not required by precedence, for example

  > `(xx && yy) || zz`

- Similarly around inner subexpressions in expressions that mix `&`, `|`, or shifts, especially if mixing these with other operators, for instance

  > `(x << 3) | (y >> 5)`

- In macro definitions around every use of an argument that logically could be an expression, for example

  > `((x) * (x) + (y) * (y))`

Anywhere else, given the choice, use fewer parentheses.

For stylistic consistency with the existing Ghostscript code, put parentheses around conditional expressions even if they aren't syntactically required, unless you really dislike doing this. Note that the parentheses should go around the entire expression, not the condition. For instance, instead of

> `hpgl_add_point_to_path(pgls, arccoord_x, arccoord_y,
> (pgls->g.pen_down) ? gs_lineto : gs_moveto);`

use

> `hpgl_add_point_to_path(pgls, arccoord_x, arccoord_y,
> (pgls->g.pen_down ? gs_lineto : gs_moveto));`

# Naming

## General rules

Use fully spelled-out English words in names, rather than contractions. This is most important for procedure and macro names, global variables and constants, values of `#define` and `enum`, `struct` and other `typedef` names, and structure member names, and for argument and variable names which have uninformative types like `int`. It's not very important for arguments or local variables of distinctive types, or for local index or count variables.

Avoid names that run English words together: "`hpgl_compute_arc_center`" is better than "`hpgl_compute_arccenter`". However, for terms drawn from some predefined source, like the names of PostScript operators, use a term in its well-known form (for instance, `gs_setlinewidth` rather than `gs_set_line_width`).

Procedures, variables, and structures visible outside a single `.c` file should generally have prefixes that indicate what subsystem they belong to (in the case of Ghostscript, `gs_` or `gx_`). This rule isn't followed very consistently.

## Names used by convention

The Ghostscript code uses certain names consistently for certain kinds of values. Some of the commonest and least obvious are these two:

### `code`

> A value to be returned from a procedure:

> < 0 |  | An error code defined in `gserrors.h` (or `errors.h`)
> 0 |  | Normal return
> > 0 |  | A non-standard but successful return (which must be documented, preferably with the procedure's prototype)

### `status`

> A value returned from a stream procedure:

> < 0 |  | An exceptional condition as defined in `scommon.h`
> 0 |  | Normal return (or, from the "`process`" procedure, means that more input is needed)
> 1 |  | More output space is needed (from the "`process`" procedure)

# Miscellany

## Single-use procedures

In general, don't create procedures that are private and only called from one place. However, if a compound statement (especially an arm of a conditional) is too long for the eye easily to match its enclosing braces "`{...}`" -- that is, longer than 10 or 15 lines -- and it doesn't use or set a lot of state held in outer local variables, it may be more readable if you put it in a procedure.

## Local variables

Don't assign new values to procedure parameters. It makes debugging very confusing when the parameter values printed for a procedure are not the ones actually supplied by the caller. Instead use a separate local variable initialized to the value of the parameter.

If a local variable is only assigned a value once, assign it that value at its declaration, if possible. For example,

> `int x =` some expression `;`

rather than

> `int x;`
> ...
> `x =` some expression `;`

Use a local pointer variable like this to "narrow" pointer types:

> `int`
> someproc(... `gx_device *dev` ...)
> `{
> gx_device_printer *const pdev = (gx_device_printer *)dev;`
> ...
> `}`

## Error handling

Every caller should check for error returns and, in general, propagate them to its callers. By convention, nearly every procedure returns an `int` to indicate the outcome of the call:

> < 0 |  | Error return
> 0 |  | Normal return
> > 0 |  | Non-error return other than the normal case

See the file `gserrors.h` for the error return codes used by the graphics library, most of which correspond directly to PostScript error conditions.

## Compiler warnings

The following section refers to the warnings produced by `gcc`: your compiler may produce different ones.

It's OK if compilation produces the following warnings:

- `<name> might be used uninitialized in this function`
- `cast discards `const' from pointer target type`

The first of these often occurs because the compiler isn't aware of control flow restrictions that guarantee the variable will be initialized before use: if it occurs in new code, check the code carefully, but don't worry about the message. The second is often unavoidable in code that initializes or frees a structure that is otherwise `const` during its lifetime.

Do work hard to eliminate all warnings other than these, since they often indicate the possible presence of coding errors. In particular, get rid of warnings about parameter passing or initialization that discards `const`, by using explicit casts.

Copyright © 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.

This file is part of AFPL Ghostscript. See the Aladdin Free Public License (the "License") for full details of the terms of using, copying, modifying, and redistributing AFPL Ghostscript.

Ghostscript version 6.50, 2 December 2000