# Progreso ## Estado actual - **Fase 2**: buffer dinámico. La Fase 1 está cerrada en Fedora, pero falta probarla en Windows. - Paso actual: 2.3b. `hello.c` ya usa bien `goto cleanup` (punteros a `NULL` uno por línea, `result`, un solo `return`), sin avisos con gcc ni clang, y Valgrind limpio. Falta `escpos_buffer_append`: el parámetro con la cantidad, `const`, reservar `len + cantidad`, `memcpy` y el comentario de la cabecera. Ahora copia 1 byte (`sizeof *byte`). - Entorno activo: Fedora 42 nativo (gcc 15.2, clang 20, make 4.4, gdb 17, valgrind 3.26). ## Hecho - `include/escpos.h` + `src/escpos.c` con `escpos_version()`, y `hello.c` que la usa. Compila y enlaza a mano en Windows y en Fedora. - `samples/hello_world.bin`: ESC @, texto, LF, ESC d 5, GS V 0. - Emulador ESC/POS en Go (`emulator/`) para probar sin gastar papel. - Makefile con regla patrón, `clean` y `.PHONY`. Compila desde un clon limpio y sin avisos con gcc y con clang. - 2.1: `escpos_buffer_new` / `escpos_buffer_free` con tipo opaco. Valgrind limpio, y fuga provocada a propósito para leer el informe. - 2.2: `escpos_buffer_append_byte` con `realloc`: 64 bytes al principio, luego el doble. Comprobado con 100 bytes (crece de 64 a 128). Valgrind limpio. Sin el `free`, Valgrind da 24 `definitely` + 128 `indirectly`. - 2.3a: crecimiento extraído a `static int buffer_reserve(buffer, min_cap)`: arranca en 64 o en `cap` y dobla hasta que cabe; un único `realloc`. ## Conceptos de C aprendidos - Etapas de compilación, unidades de traducción, cabeceras, *include guards*, `static` para encapsular, `nm` y errores del enlazador. - Cadenas terminadas en `'\0'`, `const char *`, `'A'` frente a `"A"`. - Memoria virtual de un proceso, modo usuario y modo núcleo. `VmSize` frente a `VmRSS`, *overcommit* y OOM killer. - Make: reglas, dependencias por fechas, variables, regla patrón con `$@ $< $^`, `.PHONY`. - Pila y montón, `malloc`/`free`/`realloc`, `NULL`, propiedad de punteros, tipo opaco, `typedef`, `->`, `uint8_t`/`size_t`, qué tipo usar. - Liberar en caminos de error sin `defer`: patrón `goto cleanup`. - Depuración: *segfault* (139), `free(): invalid pointer` (134), gdb básico, y leer errores e informes de fugas en Valgrind. ## Forma de trabajar - Desde el 2026-10-02: sin *vibecoding*. Enunciado y pruebas, predicción antes de compilar, y pistas por niveles solo si las pide. Ante un error, primero su diagnóstico. ## Decisiones de diseño - Prefijo `escpos_` para toda la API pública. - `escpos_buffer` es un tipo opaco: declarado en `escpos.h` y definido en `src/buffer.c`. Campos `uint8_t *data`, `size_t len` y `size_t cap`. - Crecimiento del buffer: 64 bytes al principio y luego el doble. - Por ahora, las funciones que pueden fallar devuelven `int`: `0` si va bien y `-1` si no hay memoria. Pendiente de cambiar a códigos de error propios. - Estilo: nombres en `snake_case` y llave de apertura en línea aparte (estilo Allman) en funciones, structs y bloques. - Lo generado va en `build/`, que se crea en las recetas con `mkdir -p` y no se versiona. ## Pendiente / puntos débiles - Fase 1: probar el Makefile en Windows (MSYS2), con el sufijo `.exe`. - `.gitignore` creado. Siguen versionados `emulator/escpos-emu.exe` y `goruntime/goruntime.exe`. - Make: le costó entender que va hacia atrás desde el objetivo y que una regla patrón es una plantilla. Repasar con `docs/06-make.md`. - Punteros: le cuesta saber cuándo hace falta `*` y cuándo no, y distinguir la dirección del bloque (`data`) de una casilla (`data[i]`). Le funciona la analogía de papel y casa. Reforzar con ejemplos de su propio código. - Tipos: usó `uint8_t` para un código de retorno. Repasar la tabla "Qué tipo usar" de `docs/08-structs.md`. - Valorar añadir `-Wconversion` a `CFLAGS`: detecta conversiones con pérdida que gcc no avisa por defecto. - Bucles: en `buffer_reserve` calculaba cada vuelta a partir de un valor que no cambiaba (`buffer->cap`) o que empezaba en 0, y eso daba bucles infinitos. Lo resolvió siguiendo los valores vuelta a vuelta. Seguir pidiéndole trazas a mano. - Declaraciones múltiples: escribió `escpos_buffer *a, *b, *c = NULL;` creyendo que las tres valían `NULL` (solo la última). Lo detectó clang con `-Wsometimes-uninitialized`. Ahora declara una variable por línea. - Variables locales sin inicializar: creía que valían `NULL` como en Go. - Impresoras físicas: sin registrar marca y modelo. - Confunde puntero colgante ("se pierde") con fuga. Tampoco tenía claro por qué el slice viejo es seguro en Go tras `append` (el GC no libera el array viejo, no es por la copia). Repasar con la tabla de docs/07-dynamic-memory.md. ## Otros - `goescpos/`: equivalente en Go idiomático (`bytes.Buffer`) de lo hecho hasta ahora, para comparar.