Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
Checks: >
clang-analyzer-*,
bugprone-*,
cert-*,
-cert-dcl37-c,
-cert-dcl51-cpp

HeaderFilterRegex: '^(.*/)?src/.*'
ExcludeHeaderFilterRegex: '/(external|thirdparty|vendor|deps|build|CMakeFiles|conan| vcpkg|subprojects)/'

WarningsAsErrors: '*'

CheckOptions:
- key: bugprone-easily-swappable-parameters.MinimumLength
value: '3'
14 changes: 11 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: "Clangd install"
run: sudo apt install clang-format
- name: "Clangd format"
- name: "Clang tools install"
run: sudo apt-get install -y clang-format clang-tidy
- name: "Clang format"
run: git ls-files -z '*.c' | xargs -0 clang-format --dry-run --Werror
- name: "Download submodules"
run: git submodule update --init --recursive
Expand All @@ -27,6 +27,14 @@ jobs:
libasound2-dev libgl1-mesa-dev libglu1-mesa-dev
libwayland-dev libxkbcommon-dev libegl-dev
wayland-protocols pkg-config valgrind
- name: Generate compile_commands.json
run: zig build cdb
- name: "Clang-tidy static analysis"
run: >
clang-tidy
src/cli.c src/config.c src/display.c src/keyicon.c
src/main.c src/search.c src/structures.c src/theme.c
-p compile_commands.json
- name: Cleanup cache folders
continue-on-error: true
run: |
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,22 @@ valgrind --leak-check=full \
```bash
zig build cdb
```

### Static analysis (clang-tidy)

Requires `clang-tidy` and a `compile_commands.json`. Generate the compilation
database first:

```bash
zig build cdb
```

Then run clang-tidy against the project sources:

```bash
clang-tidy \
src/cli.c src/config.c src/display.c src/keyicon.c \
src/main.c src/search.c src/structures.c src/theme.c \
-p compile_commands.json
```

3 changes: 2 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const c_flags = [_][]const u8{
"-pedantic",
"-D_POSIX_C_SOURCE=200809L",
"-Wshadow",
"-Wvla",
// "-Wvla",
"-Wno-vla",
"-Wfloat-equal",
"-Wdouble-promotion",
"-Wformat=2",
Expand Down
2 changes: 2 additions & 0 deletions src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ bool parse_cli(int argc, char **argv, cli_args *args) {
case '?':
cag_option_print_error(&context, stderr);
return false;
default:
break;
}
}

Expand Down
28 changes: 19 additions & 9 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ static void capitalize_into(const char *src, char *buf) {
size_t len = strlen(src);
memcpy(buf, src, len);
buf[len] = '\0';
buf[0] = toupper((unsigned char)buf[0]);
buf[0] = (char)toupper((unsigned char)buf[0]);
}

config_error_t config_read_file(const char *filepath, stringlist_t *out) {
Expand Down Expand Up @@ -46,14 +46,18 @@ config_error_t config_read_file(const char *filepath, stringlist_t *out) {
pos[sizeof(PATTERN) - 1] == ' ') {
if (stringlist_append(out, pos) != 0) {
free(line);
fclose(fp);
int err = fclose(fp);
if (err)
return CONFIG_ERR_IO;
return CONFIG_ERR_OUT_OF_MEMORY;
}
}
}

free(line);
fclose(fp);
int err = fclose(fp);
if (err)
return CONFIG_ERR_IO;
return CONFIG_SUCCESS;
}

Expand Down Expand Up @@ -92,7 +96,7 @@ void keymap_free(KeyMap *km) {
free(km->main_key);
for (size_t i = 0; i < km->modifier_count; i++)
free(km->modifiers[i]);
free(km->modifiers);
free((char *)(km->modifiers));
free(km->description);
}

Expand Down Expand Up @@ -120,14 +124,14 @@ config_error_t parse_key_maps(stringlist_t *lines, KeyMapList *out) {
if (!space)
continue;

key_combo = strndup(pos, space - pos);
key_combo = strndup(pos, (size_t)(space - pos));
if (!key_combo)
goto fail;

size_t len = strlen(space + 1); // Length after the space
desc = malloc(len + 1);
if (!desc) {
return CONFIG_ERR_ALLOC_FAILED;
goto fail;
}
capitalize_into(space + 1, desc);
if (!desc)
Expand All @@ -139,8 +143,8 @@ config_error_t parse_key_maps(stringlist_t *lines, KeyMapList *out) {

char *tok = strtok(tmp, "+");
while (tok) {
char **new_tokens =
realloc(tokens, (token_count + 1) * sizeof(char *));
char **new_tokens = (char **)(realloc(
(char *)tokens, (token_count + 1) * sizeof(char *)));
if (!new_tokens)
goto fail;
tokens = new_tokens;
Expand All @@ -157,6 +161,12 @@ config_error_t parse_key_maps(stringlist_t *lines, KeyMapList *out) {
free(key_combo);
key_combo = NULL;

if (token_count == 0) {
free(desc);
free((char *)tokens);
return CONFIG_ERR_ALLOC_FAILED; // or continue;
}

KeyMap km = {0};
km.description = desc;
km.main_key = tokens[token_count - 1];
Expand All @@ -172,7 +182,7 @@ config_error_t parse_key_maps(stringlist_t *lines, KeyMapList *out) {
fail:
for (size_t j = 0; j < token_count; j++)
free(tokens[j]);
free(tokens);
free((char *)tokens);
free(tmp);
free(key_combo);
free(desc);
Expand Down
1 change: 1 addition & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef enum {
CONFIG_ERR_INVALID_FORMAT,
CONFIG_ERR_INVALID_ARGUMENT,
CONFIG_ERR_ALLOC_FAILED,
CONFIG_ERR_IO,
} config_error_t;

typedef struct {
Expand Down
23 changes: 15 additions & 8 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ size_t font_paths_len(const char *arr[]) {
return i;
}

static font_container_t load_system_font(int size);
static font_container_t load_system_font(float size);
static void format_keys(const KeyMap *km, char *buf, size_t bufsize);
static Scroll scroll_create(int content_height, int window_height);
static Scroll scroll_create(float content_height, float window_height);
static void scroll_update(Scroll *s);
static void draw_top(theme_color_t color, theme_color_t text_color, Font font,
float font_size, float spacing);
Expand All @@ -75,7 +75,7 @@ static void draw_body(theme_color_t color, theme_color_t text_color,
const size_t count, float offset_y);

static font_container_t load_font_from_paths(const stringlist_t *paths,
int size) {
float size) {
if (!paths || paths->count == 0) {
return (font_container_t){.font = GetFontDefault(),
.error = DISPLAY_STRINGLIST_UNINITIALIZED};
Expand All @@ -90,13 +90,13 @@ static font_container_t load_font_from_paths(const stringlist_t *paths,
codepoints[i] = 32 + i;

memcpy(&codepoints[ascii_count], key_codepoints,
key_codepoints_count * sizeof(int));
(size_t)key_codepoints_count * sizeof(int));

for (size_t i = 0; i < paths->count; i++) {
const char *path = paths->items[i];

if (FileExists(path)) {
Font font = LoadFontEx(path, size, codepoints, total);
Font font = LoadFontEx(path, (int)size, codepoints, total);
printf("Loading font %s\n", path);
return (font_container_t){.font = font, .error = DISPLAY_SUCCESS};
}
Expand All @@ -106,7 +106,7 @@ static font_container_t load_font_from_paths(const stringlist_t *paths,
.error = DISPLAY_FONT_LOAD_ERROR};
}

static font_container_t load_system_font(int size) {
static font_container_t load_system_font(float size) {
stringlist_t list;
stringlist_init(&list);

Expand Down Expand Up @@ -147,6 +147,9 @@ static Font load_best_font(const theme_font_t *font) {
}

static void format_keys(const KeyMap *km, char *buf, size_t bufsize) {
if (km == NULL) {
return;
}
buf[0] = '\0';
for (size_t j = 0; j < km->modifier_count; j++) {
strncat(buf, key_to_symbol(km->modifiers[j]),
Expand All @@ -156,7 +159,7 @@ static void format_keys(const KeyMap *km, char *buf, size_t bufsize) {
strncat(buf, key_to_symbol(km->main_key), bufsize - strlen(buf) - 1);
}

static Scroll scroll_create(int content_height, int window_height) {
static Scroll scroll_create(float content_height, float window_height) {
float min = -(content_height - window_height);
return (Scroll){.y = 0, .min = min > 0 ? 0 : min};
}
Expand Down Expand Up @@ -197,6 +200,9 @@ static void draw_text_highlighted(Font font, visible_item_t item,
float spacing, Color text_color,
Color highlight_text_color,
Color highlight_color) {
if (item.km == NULL) {
return;
}
const char *text = item.km->description;
if (text == NULL)
return;
Expand Down Expand Up @@ -330,7 +336,8 @@ void display(const KeyMapList *kml, const theme_t *theme) {

float spacing = 1.0f;

int content_height = PADDING + (int)kml->count * ROW_HEIGHT + PADDING;
float content_height =
(float)(PADDING + (int)kml->count * ROW_HEIGHT + PADDING);
Scroll scroll = scroll_create(content_height, WINDOW_HEIGHT);

Font top_font = load_best_font(&theme->top.font);
Expand Down
3 changes: 3 additions & 0 deletions src/keyicon.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef KEYICON_H
#define KEYICON_H

#define MAX_CODEPOINTS 512

#include <stddef.h>
typedef struct {
const char *name;
const char *symbol;
Expand Down
14 changes: 10 additions & 4 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef enum {
Success = 0,
ConfigError,
ThemeError,
IOError,
} Error;

int main(int argc, char *argv[]) {
Expand All @@ -34,18 +35,22 @@ int main(int argc, char *argv[]) {
err = theme_load_from_config(&theme);
}
if (err != THEME_SUCCESS) {
fprintf(stderr, "Failed to set THEME: %s\n", theme_error_str(err));
if (fprintf(stderr, "Failed to set THEME: %s\n", theme_error_str(err)))
return IOError;

return ThemeError;
}

char *filepath = config_get_sway_filepath();
if (!filepath) {
fprintf(stderr, "failed to determine sway config path\n");
if (fprintf(stderr, "failed to determine sway config path\n"))
return IOError;
return ConfigError;
}

if (config_read_file(filepath, &list) != 0) {
fprintf(stderr, "failed to read file\n");
if (fprintf(stderr, "failed to read file\n"))
return IOError;
free(filepath);
stringlist_free(&list);
return ConfigError;
Expand All @@ -56,7 +61,8 @@ int main(int argc, char *argv[]) {
keymaplist_init(&kml);

if (parse_key_maps(&list, &kml) != 0) {
fprintf(stderr, "failed to parse key maps\n");
if (fprintf(stderr, "failed to parse key maps\n"))
return IOError;
stringlist_free(&list);
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ void free_search_result(search_result_t *result) {
intlist_delete(result->positions[i]); /* uses new helper */
}
}
free(result->positions);
free((intlist_t *)(result->positions));
}
free(result->mask);
memset(result, 0, sizeof(*result));
Expand Down
8 changes: 5 additions & 3 deletions src/structures.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
stringlist_error_t stringlist_append(stringlist_t *list, const char *s) {
if (list->count == list->capacity) {
size_t new_cap = list->capacity ? list->capacity * 2 : 8;
char **tmp = (char **)realloc(list->items, new_cap * sizeof(*tmp));
char **tmp =
(char **)realloc((char *)(list->items), new_cap * sizeof(*tmp));
if (!tmp)
return STRINGLIST_ERR_ALLOC_FAILED;
list->items = tmp;
Expand All @@ -33,7 +34,7 @@ void stringlist_free(stringlist_t *list) {
if (list->items) {
for (size_t i = 0; i < list->count; i++)
free(list->items[i]);
free(list->items);
free((char *)(list->items));
}
stringlist_init(list);
}
Expand Down Expand Up @@ -134,7 +135,8 @@ size_t get_segments(const char *text, const intlist_t *positions,
segment_type_t tmp = in_intlist(0, positions) ? HIGHLIGHTED : NORMAL;

for (size_t i = 0; i < len; ++i) {
segment_type_t type = in_intlist(i, positions) ? HIGHLIGHTED : NORMAL;
segment_type_t type =
in_intlist((int)i, positions) ? HIGHLIGHTED : NORMAL;

if (type != tmp) {
segment_t segment = {
Expand Down
Loading
Loading