summaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:42:22 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:44:20 -0300
commitc3b525537e944064869a2cd6495733388144ce64 (patch)
treea30fa16568ffe470876f670e6bd75873c201df1a /README.md
parentb7b08a7d29d84de187dd8a55e0c94de66b07a572 (diff)
downloadasm-0.2.0.tar.gz
Surface the faixa a 404 now carriesHEADv0.2.0main
A CEP that fails is almost never a random number. It is someone who knows the city and guessed the last digits, and the guess is usually the -000 that 957 municipalities never received. The API answers those 404s with a faixa object naming the municipality that owns the band, which turns "not found" from a dead end into something the caller can act on - and the caller cannot reach it through this library, because the 404 path never looked at the body at all. cepis_error is where a 404 already reports itself, so faixa goes there, as inline storage rather than a pointer: the struct is documented as owning nothing and declared on the caller's stack, and that stays true. It costs sizeof(cepis_error), 272 bytes to 384, so 0.2.0 needs a recompile. The parser needed one new primitive. cepis__json_field could only pull scalars out of a flat object; splitting it over cepis__json_find, which returns a pointer to a value of any shape, reaches one level down without building a document tree - the same depth cepis__geo_parse already needs for geo. Absence is the case that matters: no faixa, an empty one, or one that is not an object all leave the error byte-for-byte what it was before. cep_ini and cep_fim are deliberately not presented as a range. They are the lowest and highest CEP that exist, the band is sparse - Areal's 118 CEPs are scattered over ~4900 numbers - and ceps is the only honest count.
Diffstat (limited to 'README.md')
-rw-r--r--README.md64
1 files changed, 63 insertions, 1 deletions
diff --git a/README.md b/README.md
index 25fbff6..0efefdb 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,16 @@ make install PREFIX=/usr/local
Link with `-lcepis -lcurl`. Requires libcurl's headers only for the build of
your own program (this library ships no curl types in its header).
+> **0.2.0 changed `sizeof(cepis_error)`** — it grew a `faixa` member, from 272
+> to 384 bytes. The source API is unchanged, but a program built against
+> 0.1.0 must be recompiled, not just relinked. While the version starts with
+> a `0`, that is the promise: source compatibility, not binary.
+>
+> The soname went with it, `libcepis.so.0` to `libcepis.so.1`. Callers declare
+> `cepis_error` on their own stack, so an old binary against the new library
+> would have it written past its end — a silent corruption. The soname bump
+> turns that into an honest "not found" from the loader instead.
+
## Usage
### A single lookup
@@ -60,7 +70,7 @@ case CEPIS_OK:
cepis_address_free(a);
break;
case CEPIS_ERR_NOT_FOUND:
- break;
+ break; /* err.faixa may name the municipality - see Errors */
default:
fprintf(stderr, "%s\n", err.message);
}
@@ -201,6 +211,55 @@ to make**, not by the HTTP status that caused it:
Pass a `cepis_error` to get `message`, `http_status` and `retry_after`;
`cepis_strerror` names the status itself.
+### Not found: which city was it?
+
+A CEP that fails is rarely a random number. It is usually someone who knows
+the city and guessed the last digits, and the classic guess is the `-000` that
+957 municipalities never received. So a 404 carries an optional `faixa`
+naming the municipality that owns the band the number falls in, and
+`cepis_lookup` copies it into `err.faixa`:
+
+```c
+if (cepis_lookup(NULL, "25845-000", &a, &err) == CEPIS_ERR_NOT_FOUND) {
+ fprintf(stderr, "%s\n", err.message);
+ /* CEP 25845000 does not exist in the DNE database
+ (Areal/RJ has 118 CEPs, the lowest 25845001 and the highest
+ 25849899) */
+
+ if (err.faixa.present) {
+ err.faixa.localidade; /* "Areal" */
+ err.faixa.uf; /* "RJ" */
+ err.faixa.cep_ini; /* "25845001" */
+ err.faixa.cep_fim; /* "25849899" */
+ err.faixa.ceps; /* 118 */
+ }
+}
+```
+
+**It is still a 404.** `faixa` is context for a failure, never an address, and
+the status stays `CEPIS_ERR_NOT_FOUND`. Everything in it is inline storage
+inside the `cepis_error` you already own: nothing to free, nothing that can be
+`NULL`.
+
+Three things about the numbers:
+
+- `cep_ini` and `cep_fim` are the **smallest and largest CEP that actually
+ exist** there, not the band the Correios publish. Areal's published band
+ starts at 25845000 — exactly the CEP that just failed — while `cep_ini` is
+ 25845001.
+- **The band is sparse.** Those 118 CEPs are scattered over the ~4900 numbers
+ between the two endpoints. `ceps` is a count; the pair is a pair of
+ endpoints. Do not show it as a range of valid CEPs and do not iterate it.
+- The API **omits** `faixa`, and never sends it as null, when the number falls
+ in a band no municipality owns. Then `present` is 0, the strings are `""`,
+ `ceps` is 0, and `message` is exactly what it has always been.
+
+`err.faixa` is reset by every call that receives the `cepis_error`, so a band
+left over from a previous 404 cannot be read as this one's. The other keys the
+API sends inside `faixa` — `estado`, `regiao`, `ibge` — are not modelled here;
+`cepis_lookup_many` never fills `faixa` at all, since the CSV endpoint behind
+it does not carry one.
+
`CEPIS_ERR_INVALID_RESPONSE` almost always means something between you and the
API is answering instead of it — a captive Wi-Fi portal, a corporate proxy, an
HTML error page. Useful as a diagnosis: the problem is not in your code.
@@ -222,6 +281,9 @@ HTML error page. Useful as a diagnosis: the problem is not in your code.
unknown fields of any shape, and decodes `\uXXXX` including surrogate pairs.
It is not a general-purpose JSON parser and does not build a document tree —
`raw` is there for anything it does not model.
+- It reaches exactly one level into a nested object, and only for the two the
+ API defines: `geo` on a 200 and `faixa` on a 404. Either one arriving as
+ something other than an object is dropped, not an error.
## Development