Initial commit
This commit is contained in:
commit
d2182a433c
9 changed files with 421 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Nix
|
||||||
|
result*
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.direnv
|
||||||
18
CMakeLists.txt
Normal file
18
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(
|
||||||
|
json
|
||||||
|
LANGUAGES
|
||||||
|
C
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 23)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
main.c
|
||||||
|
json.c
|
||||||
|
)
|
||||||
|
|
||||||
6
README.md
Normal file
6
README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Json
|
||||||
|
|
||||||
|
A simple json stringifying library written in C out of frustration.
|
||||||
|
|
||||||
|
See `main.c` for a usage example.
|
||||||
|
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1743315132,
|
||||||
|
"narHash": "sha256-6hl6L/tRnwubHcA4pfUUtk542wn2Om+D4UnDhlDW9BE=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "52faf482a3889b7619003c0daec593a1912fddc1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
42
flake.nix
Normal file
42
flake.nix
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
description = "C Template";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
nixpkgs
|
||||||
|
, flake-utils
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
pname = "hello-world"; #package name
|
||||||
|
version = "0.0.1";
|
||||||
|
src = ./.;
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
];
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
cmake
|
||||||
|
ninja
|
||||||
|
pkg-config
|
||||||
|
clang-tools
|
||||||
|
ctags
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell.override { stdenv = pkgs.clangStdenv; } {
|
||||||
|
inherit buildInputs nativeBuildInputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.default = pkgs.stdenv.mkDerivation {
|
||||||
|
inherit buildInputs nativeBuildInputs pname version src;
|
||||||
|
};
|
||||||
|
|
||||||
|
formatter = pkgs.alejandra;
|
||||||
|
});
|
||||||
|
}
|
||||||
193
json.c
Normal file
193
json.c
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define UNREACHABLE() assert(false)
|
||||||
|
|
||||||
|
Json json_init(FILE* stream, Whitespace whitespace)
|
||||||
|
{
|
||||||
|
return (Json){
|
||||||
|
.stream = stream,
|
||||||
|
.whitespace = whitespace,
|
||||||
|
.indent_level = 0,
|
||||||
|
.next_punctuation = BEGINNING,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_free(Json* json)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin_value(Json* json);
|
||||||
|
void end_value(Json* json);
|
||||||
|
void push_indentation(Json* json);
|
||||||
|
void pop_indentation(Json* json);
|
||||||
|
void indent(Json* json);
|
||||||
|
|
||||||
|
void json_begin_array(Json* json)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
putc('[', json->stream);
|
||||||
|
push_indentation(json);
|
||||||
|
json->next_punctuation = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_end_array(Json* json)
|
||||||
|
{
|
||||||
|
pop_indentation(json);
|
||||||
|
switch (json->next_punctuation) {
|
||||||
|
case NONE:
|
||||||
|
break;
|
||||||
|
case COMMA:
|
||||||
|
indent(json);
|
||||||
|
break;
|
||||||
|
case BEGINNING:
|
||||||
|
case COLON:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
putc(']', json->stream);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_begin_object(Json* json)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
putc('{', json->stream);
|
||||||
|
push_indentation(json);
|
||||||
|
json->next_punctuation = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_end_object(Json* json)
|
||||||
|
{
|
||||||
|
pop_indentation(json);
|
||||||
|
switch (json->next_punctuation) {
|
||||||
|
case NONE:
|
||||||
|
break;
|
||||||
|
case COMMA:
|
||||||
|
indent(json);
|
||||||
|
break;
|
||||||
|
case BEGINNING:
|
||||||
|
case COLON:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
putc('}', json->stream);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_add_object_field(Json* json, const char* key)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
fprintf(json->stream, "\"%s\"", key);
|
||||||
|
json->next_punctuation = COLON;
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_add_string(Json* json, const char* value)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
fprintf(json->stream, "\"%s\"", value);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_add_long(Json* json, long value)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
fprintf(json->stream, "%ld", value);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_add_double(Json* json, double value)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
fprintf(json->stream, "%f", value);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_add_bool(Json* json, bool value)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
const char* s;
|
||||||
|
if (value) {
|
||||||
|
s = "true";
|
||||||
|
} else {
|
||||||
|
s = "false";
|
||||||
|
}
|
||||||
|
fputs(s, json->stream);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_add_null(Json* json)
|
||||||
|
{
|
||||||
|
begin_value(json);
|
||||||
|
fputs("null", json->stream);
|
||||||
|
end_value(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin_value(Json* json)
|
||||||
|
{
|
||||||
|
switch (json->next_punctuation) {
|
||||||
|
case BEGINNING:
|
||||||
|
break;
|
||||||
|
case NONE:
|
||||||
|
indent(json);
|
||||||
|
break;
|
||||||
|
case COMMA:
|
||||||
|
fputc(',', json->stream);
|
||||||
|
indent(json);
|
||||||
|
break;
|
||||||
|
case COLON:
|
||||||
|
putc(':', json->stream);
|
||||||
|
if (json->whitespace != MINIFIED) {
|
||||||
|
fputc(' ', json->stream);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void end_value(Json* json)
|
||||||
|
{
|
||||||
|
json->next_punctuation = COMMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_indentation(Json* json)
|
||||||
|
{
|
||||||
|
json->indent_level += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_indentation(Json* json)
|
||||||
|
{
|
||||||
|
json->indent_level -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void indent(Json* json)
|
||||||
|
{
|
||||||
|
char indent_char = ' ';
|
||||||
|
int n;
|
||||||
|
switch (json->whitespace) {
|
||||||
|
case MINIFIED:
|
||||||
|
return;
|
||||||
|
case INDENT_1:
|
||||||
|
n = 1 * json->indent_level;
|
||||||
|
break;
|
||||||
|
case INDENT_2:
|
||||||
|
n = 2 * json->indent_level;
|
||||||
|
break;
|
||||||
|
case INDENT_3:
|
||||||
|
n = 3 * json->indent_level;
|
||||||
|
break;
|
||||||
|
case INDENT_4:
|
||||||
|
n = 4 * json->indent_level;
|
||||||
|
break;
|
||||||
|
case INDENT_8:
|
||||||
|
n = 8 * json->indent_level;
|
||||||
|
break;
|
||||||
|
case INDENT_TAB:
|
||||||
|
indent_char = '\t';
|
||||||
|
n = json->indent_level;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
putc('\n', json->stream);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
putc(indent_char, json->stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
45
json.h
Normal file
45
json.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef JSON_H
|
||||||
|
#define JSON_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef enum Whitespace {
|
||||||
|
MINIFIED,
|
||||||
|
INDENT_1,
|
||||||
|
INDENT_2,
|
||||||
|
INDENT_3,
|
||||||
|
INDENT_4,
|
||||||
|
INDENT_8,
|
||||||
|
INDENT_TAB,
|
||||||
|
} Whitespace;
|
||||||
|
|
||||||
|
typedef enum Punctuation {
|
||||||
|
BEGINNING,
|
||||||
|
NONE,
|
||||||
|
COMMA,
|
||||||
|
COLON,
|
||||||
|
} Punctuation;
|
||||||
|
|
||||||
|
typedef struct Json {
|
||||||
|
FILE* stream;
|
||||||
|
Whitespace whitespace;
|
||||||
|
int indent_level;
|
||||||
|
Punctuation next_punctuation;
|
||||||
|
} Json;
|
||||||
|
|
||||||
|
Json json_init(FILE* stream, Whitespace whitespace);
|
||||||
|
void json_free(Json* json);
|
||||||
|
|
||||||
|
void json_begin_array(Json* json);
|
||||||
|
void json_end_array(Json* json);
|
||||||
|
void json_begin_object(Json* json);
|
||||||
|
void json_end_object(Json* json);
|
||||||
|
void json_add_object_field(Json* json, const char* key);
|
||||||
|
void json_add_string(Json* json, const char* value);
|
||||||
|
void json_add_long(Json* json, long value);
|
||||||
|
void json_add_double(Json* json, double value);
|
||||||
|
void json_add_bool(Json* json, bool value);
|
||||||
|
void json_add_null(Json* json);
|
||||||
|
|
||||||
|
#endif // JSON_H
|
||||||
|
|
||||||
50
main.c
Normal file
50
main.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
typedef struct Info {
|
||||||
|
int id;
|
||||||
|
const char* description;
|
||||||
|
bool enabled;
|
||||||
|
} Info;
|
||||||
|
|
||||||
|
#define INFO_LEN 2
|
||||||
|
static const Info infos[INFO_LEN] = {
|
||||||
|
(Info){
|
||||||
|
.id = 0,
|
||||||
|
.description = "test",
|
||||||
|
.enabled = true,
|
||||||
|
},
|
||||||
|
(Info){
|
||||||
|
.id = 1,
|
||||||
|
.description = "Hello, World!",
|
||||||
|
.enabled = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
auto json = json_init(stdout, INDENT_2);
|
||||||
|
|
||||||
|
json_begin_array(&json);
|
||||||
|
for (int i = 0; i < INFO_LEN; i++) {
|
||||||
|
auto info = infos[i];
|
||||||
|
|
||||||
|
json_begin_object(&json);
|
||||||
|
{
|
||||||
|
json_add_object_field(&json, "id");
|
||||||
|
json_add_long(&json, info.id);
|
||||||
|
|
||||||
|
json_add_object_field(&json, "description");
|
||||||
|
json_add_string(&json, info.description);
|
||||||
|
|
||||||
|
json_add_object_field(&json, "enabled");
|
||||||
|
json_add_bool(&json, info.enabled);
|
||||||
|
}
|
||||||
|
json_end_object(&json);
|
||||||
|
}
|
||||||
|
json_end_array(&json);
|
||||||
|
|
||||||
|
json_free(&json);
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue