summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/cepis.h68
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);