summaryrefslogtreecommitdiff
path: root/docs/handbook/genqrcode/code-style.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/handbook/genqrcode/code-style.md')
-rw-r--r--docs/handbook/genqrcode/code-style.md351
1 files changed, 351 insertions, 0 deletions
diff --git a/docs/handbook/genqrcode/code-style.md b/docs/handbook/genqrcode/code-style.md
new file mode 100644
index 0000000000..d85ee7a416
--- /dev/null
+++ b/docs/handbook/genqrcode/code-style.md
@@ -0,0 +1,351 @@
+# genqrcode / libqrencode — Code Style and Conventions
+
+## Naming Conventions
+
+### Module Prefixes
+
+Every function and type is prefixed with its module:
+
+| Prefix | Module | File |
+|---|---|---|
+| `QRcode_` | Encoded symbol / high-level API | `qrencode.c` |
+| `QRinput_` | Input data management | `qrinput.c` |
+| `QRinput_Struct_` | Structured append input | `qrinput.c` |
+| `QRspec_` | QR Code spec tables | `qrspec.c` |
+| `MQRspec_` | Micro QR spec tables | `mqrspec.c` |
+| `QRraw_` | Raw RS block management | `qrencode.c` |
+| `MQRraw_` | Micro QR raw management | `qrencode.c` |
+| `Mask_` | Full QR masking | `mask.c` |
+| `MMask_` | Micro QR masking | `mmask.c` |
+| `RSECC_` | Reed-Solomon encoder | `rsecc.c` |
+| `BitStream_` | Bit stream builder | `bitstream.c` |
+| `Split_` | Input string splitter | `split.c` |
+| `FrameFiller_` | Module placement | `qrencode.c` |
+
+### Function Naming Patterns
+
+- `*_new()` / `*_free()` — Constructor / destructor pairs
+- `*_init()` — In-place initialization (no allocation)
+- `*_get*()` / `*_set*()` — Accessor / mutator pairs
+- `*_encode*()` — Encoding operations
+- `*_check*()` — Validation without side effects
+- `*_estimate*()` — Capacity estimation
+
+### Static Functions
+
+Internal functions use the module prefix plus a descriptive name:
+
+```c
+static int QRinput_encodeModeNum(QRinput_List *entry, int version, int mqr);
+static int QRinput_checkModeNum(int size, const char *data);
+static int QRinput_estimateBitsModeNum(int size);
+```
+
+---
+
+## STATIC_IN_RELEASE Macro
+
+A key pattern for testability — internal functions are static in release builds but visible in test builds:
+
+```c
+#ifdef STATIC_IN_RELEASE
+#define STATIC_IN_RELEASE static
+#else
+#define STATIC_IN_RELEASE
+#endif
+```
+
+When `WITH_TESTS` is defined (via CMake or autotools), `STATIC_IN_RELEASE` is undefined and internal functions get external linkage, making them callable from test programs.
+
+Usage throughout the codebase:
+
+```c
+STATIC_IN_RELEASE int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num);
+STATIC_IN_RELEASE int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data);
+```
+
+This avoids `__attribute__((visibility("default")))` hacks — simply controlling `static` linkage via a macro.
+
+---
+
+## The `qrencode_inner.h` Header
+
+Test programs include `qrencode_inner.h` instead of (or in addition to) `qrencode.h`. This header exposes:
+
+```c
+// Internal struct types
+typedef struct { ... } RSblock;
+typedef struct { ... } QRRawCode;
+typedef struct { ... } MQRRawCode;
+
+// Internal functions for testing
+extern unsigned char *FrameFiller_test(int version);
+extern QRcode *QRcode_encodeMask(QRinput *input, int mask);
+extern QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask);
+extern QRcode *QRcode_new(int version, int width, unsigned char *data);
+```
+
+This separation keeps the public API clean while enabling thorough unit testing.
+
+---
+
+## Error Handling Pattern
+
+### errno-Based Errors
+
+All functions that can fail set `errno` and return a sentinel:
+
+```c
+// Pointer-returning functions: return NULL on error
+QRinput *QRinput_new2(int version, QRecLevel level)
+{
+ if(version < 0 || version > QRSPEC_VERSION_MAX) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if(/* invalid level */) {
+ errno = EINVAL;
+ return NULL;
+ }
+ // ...
+ input = malloc(sizeof(QRinput));
+ if(input == NULL) {
+ // errno set by malloc (ENOMEM)
+ return NULL;
+ }
+ // ...
+}
+
+// int-returning functions: return -1 on error
+int QRinput_append(QRinput *input, QRencodeMode mode, int size,
+ const unsigned char *data)
+{
+ int ret = QRinput_check(mode, size, data);
+ if(ret != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ // ...
+}
+```
+
+### Common errno Values
+
+- `EINVAL` — Invalid parameters
+- `ENOMEM` — Memory allocation failure
+- `ERANGE` — Data too large for any QR version
+
+---
+
+## Memory Management
+
+### Ownership Model
+
+- `QRinput_append()` **copies** its data — the caller retains ownership
+- `QRcode_encodeInput()` does **not** free the input — caller must free both
+- `QRinput_Struct_free()` frees all contained `QRinput` objects
+- `QRcode_List_free()` frees all contained `QRcode` objects
+- `QRcode_free()` frees the `data` array inside the `QRcode`
+
+### Allocation Patterns
+
+```c
+// Typical constructor pattern
+QRinput *QRinput_new(void)
+{
+ QRinput *input;
+ input = (QRinput *)malloc(sizeof(QRinput));
+ if(input == NULL) return NULL;
+ // initialize fields
+ input->head = NULL;
+ input->tail = NULL;
+ // ...
+ return input;
+}
+
+// Typical destructor pattern — walk linked list
+void QRinput_free(QRinput *input)
+{
+ if(input != NULL) {
+ QRinput_List *list = input->head;
+ while(list != NULL) {
+ QRinput_List *next = list->next;
+ // free list entry data
+ if(list->data) free(list->data);
+ if(list->bstream) BitStream_free(list->bstream);
+ free(list);
+ list = next;
+ }
+ free(input);
+ }
+}
+```
+
+### BitStream Growth
+
+`BitStream` uses doubling strategy:
+
+```c
+#define DEFAULT_BUFSIZE 128
+
+static int BitStream_allocate(BitStream *bstream, size_t length)
+{
+ // doubles capacity until sufficient
+ while(bstream->datasize < length) {
+ bstream->datasize *= 2;
+ }
+ bstream->data = realloc(bstream->data, bstream->datasize);
+}
+```
+
+---
+
+## Macro Usage
+
+### Spec Accessor Macros
+
+Five macros for RS block spec access (from `qrspec.h`):
+
+```c
+#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3])
+#define QRspec_rsBlockNum1(__spec__) (__spec__[0])
+#define QRspec_rsDataCodes1(__spec__) (__spec__[1])
+#define QRspec_rsEccCodes1(__spec__) (__spec__[2])
+#define QRspec_rsBlockNum2(__spec__) (__spec__[3])
+#define QRspec_rsDataCodes2(__spec__) (__spec__[4])
+#define QRspec_rsEccCodes2(__spec__) (__spec__[2])
+```
+
+### MASKMAKER
+
+Code generation macro for mask functions (see masking docs):
+
+```c
+#define MASKMAKER(__exp__) \
+ int x, y;\
+ int b = 0;\
+ for(y = 0; y < width; y++) {\
+ for(x = 0; x < width; x++) {\
+ if(*s & 0x80) { *d = *s; }\
+ else { *d = *s ^ ((__exp__) == 0); }\
+ s++; d++;\
+ }\
+ }\
+ return b;
+```
+
+---
+
+## Header Include Pattern
+
+Each module follows a consistent pattern:
+
+```c
+// In .c files:
+#include "config.h" // generated by autotools/cmake
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "qrencode.h" // public header (if needed)
+#include "qrencode_inner.h" // internal declarations (if needed)
+#include "module.h" // own header
+```
+
+### Config Macros
+
+Key `config.h` defines checked throughout:
+- `HAVE_CONFIG_H` — autotools-generated config
+- `HAVE_LIBPTHREAD` — pthread support available
+- `STATIC_IN_RELEASE` — controls function visibility
+- `WITH_TESTS` — test build mode
+- `HAVE_STRDUP` — strdup availability
+
+---
+
+## Data Type Conventions
+
+- `unsigned char *` for binary data and QR module arrays
+- `int` for sizes, lengths, and error returns
+- `unsigned int` for bit values and format info
+- `signed char` for the AN lookup table (needs -1 sentinel)
+- Opaque types via `typedef struct _Name Name` pattern
+
+---
+
+## Const Correctness
+
+Input data parameters are consistently `const`:
+
+```c
+int RSECC_encode(int data_length, int ecc_length,
+ const unsigned char *data, unsigned char *ecc);
+
+int QRinput_append(QRinput *input, QRencodeMode mode, int size,
+ const unsigned char *data);
+```
+
+Spec tables are `static const`:
+
+```c
+static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = { ... };
+static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = { ... };
+static const unsigned int formatInfo[4][8] = { ... };
+static const signed char QRinput_anTable[128] = { ... };
+```
+
+---
+
+## Thread Safety Approach
+
+The library uses a minimal locking strategy:
+
+1. **Single mutex** in `rsecc.c`: `RSECC_mutex` protects lazy initialization of GF tables and generator polynomials
+2. **No global mutable state** after initialization — spec tables are `const`, generator polynomials become read-only after first build
+3. **Local allocations** in encoding functions — each call creates its own frame, mask buffers, etc.
+4. **Conditional compilation**: `#ifdef HAVE_LIBPTHREAD` guards all pthread usage
+
+---
+
+## Build-System Integration
+
+### CMake Conditionals
+
+```cmake
+if(WITH_TESTS)
+ add_definitions(-DWITH_TESTS)
+endif()
+```
+
+When `WITH_TESTS` is on, `STATIC_IN_RELEASE` is not defined, exposing internal functions.
+
+### Autotools Conditionals
+
+```m4
+AC_ARG_WITH([tests],
+ [AS_HELP_STRING([--with-tests], [build tests])],
+ [], [with_tests=no])
+if test x$with_tests = xyes ; then
+ AC_DEFINE([WITH_TESTS], [1])
+fi
+```
+
+---
+
+## File Organization
+
+Each module is a `.c` / `.h` pair:
+
+- `bitstream.c` / `bitstream.h` — Bit stream container
+- `mask.c` / `mask.h` — QR masking and penalty
+- `mmask.c` / `mmask.h` — Micro QR masking
+- `qrencode.c` / `qrencode.h` — Public API + encoder core
+- `qrinput.c` / `qrinput.h` — Input management + mode encoding
+- `qrspec.c` / `qrspec.h` — QR Code specification tables
+- `mqrspec.c` / `mqrspec.h` — Micro QR specification tables
+- `rsecc.c` / `rsecc.h` — Reed-Solomon encoder
+- `split.c` / `split.h` — String splitter / mode optimizer
+
+Standalone files:
+- `qrencode_inner.h` — Test-only internal declarations
+- `qrenc.c` — CLI tool (not a library module)