# C Code Generation Guide
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Overview](#overview)
- [Quick Start](#quick-start)
- [What You Get](#what-you-get)
- [Header File (.h)](#header-file-h)
- [Implementation File (.c) - **Complete Working Code**](#implementation-file-c-complete-working-code)
- [Example](#example)
- [Input: ASN.1 Schema](#input-asn1-schema)
- [Output: Header File (certificate.h)](#output-header-file-certificateh)
- [Output: Implementation File (certificate.c)](#output-implementation-file-certificatec)
- [Type Mappings](#type-mappings)
- [CLI Options](#cli-options)
- [Makefile Integration](#makefile-integration)
- [Usage Example](#usage-example)
- [Supported Features](#supported-features)
- [Fully Supported [+]](#fully-supported)
- [Partial Support [!]](#partial-support)
- [Not Yet Implemented [-]](#not-yet-implemented-)
- [Type Definition Ordering](#type-definition-ordering)
- [Code Statistics](#code-statistics)
- [Documentation](#documentation)
- [See Also](#see-also)
## Overview
synta-codegen can generate **complete C code** (both headers and implementations) from ASN.1 schemas, providing production-ready encoder/decoder functions that work with the libcsynta C API.
## Quick Start
```bash
# Generate header file
synta-codegen certificate.asn1 --c -o certificate.h
# Generate implementation file (--impl specifies which header to #include)
synta-codegen certificate.asn1 --impl certificate.h -o certificate.c
# Compile
gcc -c certificate.c -I/path/to/synta/include
# Link with your application
gcc -o myapp myapp.c certificate.o -lcsynta
```
## What You Get
### Header File (.h)
- Type definitions (structs, enums, unions)
- Forward declarations
- Function prototypes (encode, decode, free)
- Helper functions (optional, with `--with-helpers`)
- C/C++ compatibility headers
### Implementation File (.c) - **Complete Working Code**
- Full encoder implementations
- Full decoder implementations
- Memory management (free functions)
- Error handling with SyntaErrorCode
- NULL pointer checks
- Proper resource cleanup
## Example
### Input: ASN.1 Schema
```asn1
Certificate DEFINITIONS ::= BEGIN
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
END
```
### Output: Header File (certificate.h)
```c
#ifndef CERTIFICATE_H
#define CERTIFICATE_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "synta.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
typedef struct AlgorithmIdentifier AlgorithmIdentifier;
/* Type definitions */
struct AlgorithmIdentifier {
SyntaObjectIdentifier* algorithm;
bool has_parameters;
SyntaOctetString* parameters;
};
/* Function prototypes */
SyntaErrorCode algorithm_identifier_decode(SyntaDecoder* decoder, AlgorithmIdentifier* out);
SyntaErrorCode algorithm_identifier_encode(SyntaEncoder* encoder, const AlgorithmIdentifier* value);
void algorithm_identifier_free(AlgorithmIdentifier* value);
/* Helper functions (with --with-helpers) */
static inline void algorithm_identifier_init(AlgorithmIdentifier* value) {
if (value != NULL) {
memset(value, 0, sizeof(AlgorithmIdentifier));
}
}
#ifdef __cplusplus
}
#endif
#endif /* CERTIFICATE_H */
```
### Output: Implementation File (certificate.c)
```c
/* Generated implementation from ASN.1 module Certificate */
/* DO NOT EDIT - auto-generated code */
#include "certificate.h"
#include <string.h>
#include <stdlib.h>
SyntaErrorCode algorithm_identifier_decode(SyntaDecoder* decoder, AlgorithmIdentifier* out) {
if (decoder == NULL || out == NULL) {
return SyntaErrorCode_NullPointer;
}
// Enter SEQUENCE
SyntaDecoder* seq_decoder = NULL;
SyntaErrorCode err = synta_decoder_enter_sequence(decoder, &seq_decoder);
if (err != SyntaErrorCode_Success) {
return err;
}
// Decode field: algorithm
err = synta_decode_object_identifier(seq_decoder, &out->algorithm);
if (err != SyntaErrorCode_Success) {
synta_decoder_free(seq_decoder);
return err;
}
// Decode optional field: parameters
if (synta_decoder_remaining(seq_decoder) > 0) {
err = synta_decode_octet_string(seq_decoder, &out->parameters);
if (err != SyntaErrorCode_Success) {
synta_decoder_free(seq_decoder);
return err;
}
out->has_parameters = true;
} else {
out->has_parameters = false;
}
synta_decoder_free(seq_decoder);
return SyntaErrorCode_Success;
}
SyntaErrorCode algorithm_identifier_encode(SyntaEncoder* encoder, const AlgorithmIdentifier* value) {
if (encoder == NULL || value == NULL) {
return SyntaErrorCode_NullPointer;
}
SyntaEncoder* seq = NULL;
SyntaErrorCode err = synta_encoder_start_sequence(encoder, &seq);
if (err != SyntaErrorCode_Success) return err;
err = synta_encode_object_identifier(seq, value->algorithm);
if (err != SyntaErrorCode_Success) return err;
if (value->has_parameters) {
err = synta_encode_octet_string(seq,
synta_octet_string_data(value->parameters),
synta_octet_string_len(value->parameters));
if (err != SyntaErrorCode_Success) return err;
}
err = synta_encoder_end_constructed(seq);
return err;
}
void algorithm_identifier_free(AlgorithmIdentifier* value) {
if (value == NULL) return;
synta_oid_free(value->algorithm);
if (value->has_parameters) {
synta_octet_string_free(value->parameters);
}
}
```
## Type Mappings
| INTEGER | `SyntaInteger*` | Arbitrary precision |
| BOOLEAN | `bool` | C99 bool type |
| OCTET STRING | `SyntaOctetString*` | Binary data |
| BIT STRING | `SyntaBitString` | Struct with data + unused_bits |
| OBJECT IDENTIFIER | `SyntaObjectIdentifier*` | OID handling |
| NULL | `void` | Empty type |
| String types | `SyntaOctetString*` | UTF8, Printable, IA5 |
| Time types | `SyntaOctetString*` | UTC, Generalized |
| SEQUENCE | `struct` | Named struct |
| CHOICE | `tagged union` | Discriminated union |
| ANY | `SyntaOctetString*` | Opaque data |
| ANY DEFINED BY | `SyntaOctetString*` | Dynamic type |
## CLI Options
```bash
# Single-file: header only
synta-codegen schema.asn1 --c -o types.h
synta-codegen schema.asn1 --c --with-helpers -o types.h
synta-codegen schema.asn1 --c --header-path "../../include/synta.h" -o types.h
# Single-file: implementation (--impl specifies which header to #include)
synta-codegen schema.asn1 --impl types.h -o types.c
# Multi-file: headers and implementations
synta-codegen a.asn1 b.asn1 --c --emit both --output-dir ./generated/
# Multi-file: build system file + all C sources in one invocation
synta-codegen a.asn1 b.asn1 --cmake --output-dir ./generated/
# Help
synta-codegen --help
```
## Makefile Integration
```makefile
# Paths
SYNTA_CODEGEN = path/to/synta-codegen
SYNTA_INCLUDE = path/to/synta/include
SYNTA_LIB = path/to/synta/lib
# Single-file: generate header, then implementation separately
types.h: schema.asn1
$(SYNTA_CODEGEN) $< --c --with-helpers -o $@
# --impl names the header to #include inside the generated .c file
types.c: schema.asn1 types.h
$(SYNTA_CODEGEN) $< --impl types.h -o $@
# Multi-file: generate all headers and implementations in one invocation
# (use --emit both with --output-dir)
generated/: a.asn1 b.asn1
$(SYNTA_CODEGEN) $^ --c --emit both --output-dir generated/
# Compile generated code
types.o: types.c types.h
gcc -c $< -I$(SYNTA_INCLUDE)
# Link with application
myapp: myapp.c types.o
gcc -o $@ $^ -L$(SYNTA_LIB) -lcsynta
# Clean
clean:
rm -f types.h types.c types.o myapp
.PHONY: clean
```
## Usage Example
```c
#include "certificate.h"
int main(void) {
// Create and initialize
AlgorithmIdentifier alg_id;
algorithm_identifier_init(&alg_id);
// Set values
alg_id.algorithm = synta_oid_from_string("1.2.840.113549.1.1.11");
alg_id.has_parameters = false;
// Encode
SyntaEncoder* encoder = synta_encoder_new(SyntaEncoding_Der);
SyntaErrorCode err = algorithm_identifier_encode(encoder, &alg_id);
if (err != SyntaErrorCode_Success) {
fprintf(stderr, "Encode error: %s\n", synta_error_message(err));
return 1;
}
// Get encoded bytes
SyntaByteArray encoded;
synta_encoder_finish(encoder, &encoded);
// ... use encoded data ...
// Decode
SyntaDecoder* decoder = synta_decoder_new(
encoded.data, encoded.len, SyntaEncoding_Der
);
AlgorithmIdentifier decoded;
algorithm_identifier_init(&decoded);
err = algorithm_identifier_decode(decoder, &decoded);
if (err != SyntaErrorCode_Success) {
fprintf(stderr, "Decode error: %s\n", synta_error_message(err));
return 1;
}
// Cleanup
algorithm_identifier_free(&alg_id);
algorithm_identifier_free(&decoded);
// encoder was consumed by synta_encoder_finish; do not free it
synta_decoder_free(decoder);
synta_byte_array_free(&encoded);
return 0;
}
```
## Supported Features
### Fully Supported [+]
- SEQUENCE / SET types with full encode/decode
- SEQUENCE OF / SET OF with dynamic array allocation
- CHOICE types as discriminated unions (tag enum + union)
- INTEGER types including named numbers (enums)
- BIT STRING (dedicated `SyntaBitString` struct)
- OBJECT IDENTIFIER
- OCTET STRING and string variants (UTF8String, PrintableString, IA5String)
- Time types (UTCTime, GeneralizedTime)
- Optional fields with presence flags
- Type references between defined types
- Error handling and cleanup
- Memory management
### Partial Support [!]
- `[N] EXPLICIT` tagged fields — fully supported for primitive and TypeRef inner
types; anonymous inline SEQUENCE/SET inside an EXPLICIT tag is not yet supported
- `[N] IMPLICIT` tagged fields — fully supported for structural inner types
(SEQUENCE, SET, SEQUENCE OF, SET OF, and TypeRefs that resolve to them);
primitive inner types are also handled correctly
### Not Yet Implemented [-]
- Complex constraint validation in generated code
### Type Definition Ordering
Types in the generated header are emitted in **topological dependency order**:
a type that is embedded by value in another struct is always defined first.
SEQUENCE OF / SET OF element types are stored as pointers so only a forward
declaration is needed for them, not a full definition.
## Code Statistics
From the X.509 certificate example schema (10 types):
- **Header file**: ~192 lines
- **Implementation file**: ~665 lines
- **Total**: ~857 lines of production-ready C code
## Documentation
- **Full Guide**: `synta-codegen/README_C_GENERATION.md`
- **Examples**: `synta-ffi/examples/c/`
- **API Reference**: `include/synta.h`
## See Also
- [synta-codegen README](../synta-codegen/README.md)
- [C Examples](../synta-ffi/examples/c/README.md)
- [FFI Documentation](../include/README.md)