diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/cepis.h | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/include/cepis.h b/include/cepis.h index ea8d378..a00982a 100644 --- a/include/cepis.h +++ b/include/cepis.h @@ -18,7 +18,7 @@ extern "C" { #endif -#define CEPIS_VERSION "0.1.0" +#define CEPIS_VERSION "0.2.0" /** Largest number of CEPs the API accepts in one /csv request. */ #define CEPIS_MAX_BATCH 500 @@ -26,6 +26,12 @@ extern "C" { /** Size of cepis_error::message, including the terminating NUL. */ #define CEPIS_MESSAGE_MAX 256 +/** Size of cepis_faixa::localidade, including the terminating NUL. The + * longest municipality name in the IBGE list is 32 characters; this leaves + * room for it in UTF-8 twice over. A longer name is truncated, never + * overflowed. */ +#define CEPIS_FAIXA_LOCALIDADE_MAX 72 + /** * Outcome of a call. Split by the decision the caller has to make, not by the * HTTP status that caused it: CEPIS_ERR_INVALID_CEP and CEPIS_ERR_NOT_FOUND @@ -145,10 +151,54 @@ struct cepis_health { }; /** + * The municipality a CEP that does not exist would have belonged to. + * + * 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 the API answers a 404 with the + * band the number falls in, when a municipality owns that band. This is + * context for an error and **not an address**: the lookup still failed, and + * cepis_lookup() still returns CEPIS_ERR_NOT_FOUND. + * + * Everything here is inline storage inside cepis_error - nothing to free, + * nothing that can be NULL. Read it only when `present` is non-zero; when it + * is zero the strings are `""` and `ceps` is 0. + * + * `cep_ini` and `cep_fim` are the **smallest and largest CEP that actually + * exist** in that municipality, not the band the Correios publish. For Areal + * the DNE's own band starts at 25845000 - exactly the CEP that just failed - + * while `cep_ini` is 25845001. + * + * The band is sparse. Areal's 118 CEPs are scattered over the ~4900 numbers + * between 25845001 and 25849899, so `ceps` is a count and the pair is a pair + * of endpoints. Never present the two as a range of valid CEPs, and never + * iterate it. + */ +typedef struct cepis_faixa { + /** Non-zero when the API named a municipality for this CEP. Zero means it + * did not - the field is omitted, never null, for a number in a band no + * municipality owns. */ + int present; + /** Municipality name, e.g. "Areal". Truncated at + * CEPIS_FAIXA_LOCALIDADE_MAX - 1 bytes. */ + char localidade[CEPIS_FAIXA_LOCALIDADE_MAX]; + /** Two-letter state, e.g. "RJ". */ + char uf[3]; + /** Smallest CEP that exists there, 8 digits unmasked. */ + char cep_ini[9]; + /** Largest CEP that exists there, 8 digits unmasked. */ + char cep_fim[9]; + /** How many CEPs exist there. Far smaller than cep_fim - cep_ini. */ + long long ceps; +} cepis_faixa; + +/** * Detail about a failure. Optional: pass NULL to any call that takes one. * * Caller-allocated, no ownership: declare one on the stack and reuse it. It is - * fully overwritten at the start of every call that receives it. + * fully overwritten at the start of every call that receives it, `faixa` + * included, so a band left over from a previous 404 cannot be mistaken for + * this one's. */ typedef struct cepis_error { /** Same value the call returned. */ @@ -159,8 +209,12 @@ typedef struct cepis_error { /** Seconds the server asked for via Retry-After, or 0 if it did not say. * Only meaningful for CEPIS_ERR_RATE_LIMITED. */ double retry_after; - /** Human-readable description, NUL-terminated, empty on success. */ + /** Human-readable description, NUL-terminated, empty on success. On a 404 + * with a `faixa` it names the municipality too. */ char message[CEPIS_MESSAGE_MAX]; + /** Only ever filled by CEPIS_ERR_NOT_FOUND, and only when the API sent a + * band. See cepis_faixa. */ + cepis_faixa faixa; } cepis_error; /** @@ -192,7 +246,7 @@ typedef struct cepis_config { * 0 leaves max_attempts as the only bound. */ double total_timeout; /** Overrides the User-Agent. Default - * "cepis-asm/0.1.0 (+https://cep.is)". */ + * "cepis-asm/0.2.0 (+https://cep.is)". */ const char *user_agent; } cepis_config; @@ -201,7 +255,7 @@ typedef struct cepis_config { * between requests, so one instance is safe to share across threads. */ typedef struct cepis_client cepis_client; -/** Library version, "0.1.0". Static storage; do not free. */ +/** Library version, "0.2.0". Static storage; do not free. */ const char *cepis_version(void); /** One-line description of a cepis_status. Static storage; do not free. */ @@ -263,7 +317,9 @@ cepis_status cepis_normalize_cep(const char *value, char *out); * The CEP is validated locally first: a 7-digit CEP returns * CEPIS_ERR_INVALID_CEP without a request being made. A 400 from the API is * also CEPIS_ERR_INVALID_CEP, carrying the API's own message. A 404 is - * CEPIS_ERR_NOT_FOUND. Neither is retried; 429, 5xx and network failures are. + * CEPIS_ERR_NOT_FOUND, and fills cepis_error::faixa when the API says which + * municipality owns that band. Neither is retried; 429, 5xx and network + * failures are. */ cepis_status cepis_lookup(cepis_client *client, const char *cep, cepis_address **out, cepis_error *err); |