Initial commit

This commit is contained in:
ktkk 2025-04-02 12:52:45 +00:00
commit d2182a433c
9 changed files with 421 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
# Nix
result*
# Misc
.direnv

18
CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}