summaryrefslogtreecommitdiffstats
path: root/src/cli.c
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 12:25:48 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 12:25:48 -0300
commite2c6ae13af335b311da2429c903032124f926df2 (patch)
tree73776fab7f3e52124a217e2768968fc9a8a76c34 /src/cli.c
downloadc-e2c6ae13af335b311da2429c903032124f926df2.tar.gz
Initial importv0.1.0
Diffstat (limited to 'src/cli.c')
-rw-r--r--src/cli.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/cli.c b/src/cli.c
new file mode 100644
index 0000000..e4c9bd4
--- /dev/null
+++ b/src/cli.c
@@ -0,0 +1,191 @@
+/**
+ * @file cli.c
+ * @brief Minimal command-line front end: `cepis 01001000`.
+ *
+ * It exists for one concrete case -- quickly confirming a local instance
+ * answers before pointing code at it:
+ *
+ * cepis --base-url http://localhost:8080 01001000
+ *
+ * A single CEP goes through the unit lookup, which carries `geo`; several go
+ * through the batch, which is one request instead of N and has no `geo`.
+ *
+ * It is not the library's main interface; for that, include `cepis.h`.
+ */
+#include "cepis.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void print_escaped(const char *text)
+{
+ size_t i;
+
+ putchar('"');
+ for (i = 0; text[i] != '\0'; i++) {
+ unsigned char c = (unsigned char)text[i];
+ switch (c) {
+ case '"':
+ fputs("\\\"", stdout);
+ break;
+ case '\\':
+ fputs("\\\\", stdout);
+ break;
+ case '\n':
+ fputs("\\n", stdout);
+ break;
+ case '\r':
+ fputs("\\r", stdout);
+ break;
+ case '\t':
+ fputs("\\t", stdout);
+ break;
+ default:
+ if (c < 0x20)
+ printf("\\u%04x", c);
+ else
+ putchar((int)c);
+ }
+ }
+ putchar('"');
+}
+
+static void print_pair(const char *key, const char *value, bool last)
+{
+ printf(" \"%s\": ", key);
+ print_escaped(value);
+ printf("%s\n", last ? "" : ",");
+}
+
+static void print_address(const cepis_address_t *address)
+{
+ if (address == NULL) {
+ printf(" null");
+ return;
+ }
+ printf(" {\n");
+ print_pair("cep", address->cep, false);
+ print_pair("logradouro", address->logradouro, false);
+ print_pair("complemento", address->complemento, false);
+ print_pair("unidade", address->unidade, false);
+ print_pair("bairro", address->bairro, false);
+ print_pair("localidade", address->localidade, false);
+ print_pair("uf", address->uf, false);
+ print_pair("estado", address->estado, false);
+ print_pair("regiao", address->regiao, false);
+ print_pair("ibge", address->ibge, false);
+ print_pair("gia", address->gia, false);
+ print_pair("ddd", address->ddd, false);
+ print_pair("siafi", address->siafi, address->geo == NULL);
+ if (address->geo != NULL) {
+ printf(" \"geo\": {\"lat\": %.6f, \"lon\": %.6f, "
+ "\"raio_m\": %ld, \"precisao\": ",
+ address->geo->lat, address->geo->lon,
+ address->geo->raio_m);
+ print_escaped(address->geo->precisao);
+ printf("}\n");
+ }
+ printf(" }");
+}
+
+static int usage(int code)
+{
+ FILE *stream = code == 0 ? stdout : stderr;
+
+ fprintf(stream,
+ "usage: cepis [--base-url URL] [--timeout SECONDS] CEP...\n"
+ "\n"
+ " --base-url URL API URL (default: %s)\n"
+ " --timeout SECONDS per-socket timeout (default: 10)\n"
+ " --version print the version and exit\n",
+ CEPIS_DEFAULT_BASE_URL);
+ return code;
+}
+
+int main(int argc, char **argv)
+{
+ cepis_config_t config;
+ cepis_client_t *client = NULL;
+ cepis_error_t err;
+ const char **ceps;
+ size_t count = 0;
+ int status = 0;
+ int i;
+
+ cepis_config_init(&config);
+ ceps = calloc((size_t)argc, sizeof(*ceps));
+ if (ceps == NULL)
+ return 1;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--help") == 0) {
+ free(ceps);
+ return usage(0);
+ }
+ if (strcmp(argv[i], "--version") == 0) {
+ printf("cepis %s\n", CEPIS_VERSION);
+ free(ceps);
+ return 0;
+ }
+ if (strcmp(argv[i], "--base-url") == 0 && i + 1 < argc) {
+ config.base_url = argv[++i];
+ continue;
+ }
+ if (strcmp(argv[i], "--timeout") == 0 && i + 1 < argc) {
+ config.timeout = strtod(argv[++i], NULL);
+ continue;
+ }
+ if (argv[i][0] == '-') {
+ free(ceps);
+ return usage(2);
+ }
+ ceps[count++] = argv[i];
+ }
+
+ if (count == 0) {
+ free(ceps);
+ return usage(2);
+ }
+
+ if (cepis_client_new(&config, &client, &err) != CEPIS_OK) {
+ fprintf(stderr, "error: %s\n", err.message);
+ free(ceps);
+ return 1;
+ }
+
+ if (count == 1) {
+ cepis_address_t *address = NULL;
+ if (cepis_lookup(client, ceps[0], &address, &err) != CEPIS_OK) {
+ fprintf(stderr, "error: %s: %s\n",
+ cepis_status_str(err.status), err.message);
+ status = 1;
+ } else {
+ print_address(address);
+ printf("\n");
+ cepis_address_free(address);
+ }
+ } else {
+ cepis_address_list_t list = {NULL, 0};
+ if (cepis_lookup_many(client, ceps, count, &list, &err) !=
+ CEPIS_OK) {
+ fprintf(stderr, "error: %s: %s\n",
+ cepis_status_str(err.status), err.message);
+ status = 1;
+ } else {
+ size_t index;
+ printf("[\n");
+ for (index = 0; index < list.count; index++) {
+ print_address(list.items[index]);
+ printf("%s\n",
+ index + 1 < list.count ? "," : "");
+ }
+ printf("]\n");
+ cepis_address_list_free(&list);
+ }
+ }
+
+ cepis_client_free(client);
+ free(ceps);
+ return status;
+}