mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 17:03:05 +02:00
Merge branch 'main' of https://github.com/kuhyx/testsAndMisc
This commit is contained in:
commit
0467513900
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@ -42,6 +42,18 @@
|
||||
"command": "python -m pip install -r requirements.txt && pytest -q",
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "pytest quick",
|
||||
"type": "shell",
|
||||
"command": "python -m pip install -r requirements.txt && pytest -q",
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "pytest quick",
|
||||
"type": "shell",
|
||||
"command": "python -m pip install -r requirements.txt && pytest -q",
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "pytest quick",
|
||||
"type": "shell",
|
||||
|
||||
30
C/opening_learner/Makefile
Normal file
30
C/opening_learner/Makefile
Normal file
@ -0,0 +1,30 @@
|
||||
CC := gcc
|
||||
CFLAGS := -O2 -Wall -Wextra -std=c11
|
||||
|
||||
# SDL2 flags: require sdl2-config (no fallback)
|
||||
SDL2CONF := $(shell command -v sdl2-config 2>/dev/null)
|
||||
ifeq ($(SDL2CONF),)
|
||||
$(error sdl2-config not found. Please install SDL2 development package.)
|
||||
endif
|
||||
SDL_CFLAGS := $(shell sdl2-config --cflags)
|
||||
SDL_LDFLAGS := $(shell sdl2-config --libs)
|
||||
|
||||
SRC := main.c gui.c engine.c chess.c mistakes.c
|
||||
OBJ := $(SRC:.c=.o)
|
||||
BIN := opening_learner
|
||||
|
||||
.PHONY: all clean run
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(SDL_LDFLAGS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
run: $(BIN)
|
||||
./$(BIN)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(BIN)
|
||||
26
C/opening_learner/README.md
Normal file
26
C/opening_learner/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Opening Learner (C + SDL2)
|
||||
|
||||
- Click a piece, then click a destination to move.
|
||||
- Thick board outline, board uses non-pure colors.
|
||||
- Uses local Stockfish or asmfish via UCI.
|
||||
- Logs mistakes to `mistakes.txt` and lets you revisit them with the `m` key.
|
||||
|
||||
Build and check:
|
||||
|
||||
```sh
|
||||
./check_build.sh
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
./opening_learner
|
||||
```
|
||||
|
||||
Tips:
|
||||
- ESC clears selection.
|
||||
- Press `m` to cycle to a stored mistake position and practice the best move there.
|
||||
- If you play Black, the board flips so Black is at the bottom.
|
||||
|
||||
Notes:
|
||||
- Rendering avoids TTF dependency; pieces are clear, high-contrast geometric glyphs.
|
||||
28
C/opening_learner/check_build.sh
Executable file
28
C/opening_learner/check_build.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "Checking for engine (stockfish or asmfish)"
|
||||
if command -v stockfish >/dev/null 2>&1; then
|
||||
echo "Found stockfish"
|
||||
elif command -v asmfish >/dev/null 2>&1; then
|
||||
echo "Found asmfish"
|
||||
else
|
||||
echo "Error: Neither stockfish nor asmfish found in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking for SDL2 dev (sdl2-config)"
|
||||
if command -v sdl2-config >/dev/null 2>&1; then
|
||||
echo "Found sdl2-config"
|
||||
else
|
||||
echo "Error: sdl2-config not found. Install SDL2 dev (e.g., libsdl2-dev)." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "Building project"
|
||||
make clean
|
||||
make -j
|
||||
|
||||
echo "Build OK"
|
||||
296
C/opening_learner/chess.c
Normal file
296
C/opening_learner/chess.c
Normal file
@ -0,0 +1,296 @@
|
||||
#include "chess.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const int knight_offsets[8] = {15, 17, -15, -17, 10, -10, 6, -6};
|
||||
static const int bishop_dirs[4] = {9, 7, -9, -7};
|
||||
static const int rook_dirs[4] = {8, -8, 1, -1};
|
||||
static const int king_dirs[8] = {8,-8,1,-1,9,7,-9,-7};
|
||||
|
||||
static inline int file_of(int sq){return sq%8;}
|
||||
static inline int rank_of(int sq){return sq/8;}
|
||||
static inline bool on_board(int sq){return sq>=0 && sq<64;}
|
||||
static inline bool same_color(char a, char b){return (isupper(a)&&isupper(b))||(islower(a)&&islower(b));}
|
||||
static inline bool is_white(char p){return isupper((unsigned char)p);}
|
||||
|
||||
void chess_init_start(Position *pos){
|
||||
// a1..h1 (0..7) are white back rank; rank 8 at indexes 56..63 are black back rank
|
||||
const char *start = "RNBQKBNRPPPPPPPP................................pppppppprnbqkbnr";
|
||||
for (int i=0;i<64;i++) pos->board[i] = start[i];
|
||||
pos->white_to_move = true;
|
||||
pos->castle_wk = pos->castle_wq = pos->castle_bk = pos->castle_bq = true;
|
||||
pos->ep_square = -1; pos->halfmove_clock = 0; pos->fullmove_number = 1;
|
||||
}
|
||||
|
||||
void chess_copy(Position *dst, const Position *src){ *dst = *src; }
|
||||
|
||||
static bool is_empty(const Position *p, int sq){ return p->board[sq]=='.'; }
|
||||
|
||||
bool chess_square_attacked(const Position *pos, int sq, bool by_white){
|
||||
// pawns
|
||||
int r = rank_of(sq), f = file_of(sq);
|
||||
if (by_white){
|
||||
int s1 = (r-1)*8 + (f-1); if (f>0 && r>0 && on_board(s1) && pos->board[s1]=='P') return true;
|
||||
int s2 = (r-1)*8 + (f+1); if (f<7 && r>0 && on_board(s2) && pos->board[s2]=='P') return true;
|
||||
} else {
|
||||
int s1 = (r+1)*8 + (f-1); if (f>0 && r<7 && on_board(s1) && pos->board[s1]=='p') return true;
|
||||
int s2 = (r+1)*8 + (f+1); if (f<7 && r<7 && on_board(s2) && pos->board[s2]=='p') return true;
|
||||
}
|
||||
// knights
|
||||
for (int i=0;i<8;i++){
|
||||
int t = sq + knight_offsets[i];
|
||||
if (!on_board(t)) continue;
|
||||
int df = file_of(t)-f; int dr = rank_of(t)-r; if (df< -2||df>2||dr<-2||dr>2) continue; // edge wrap guard
|
||||
char pc = pos->board[t];
|
||||
if (by_white && pc=='N') return true;
|
||||
if (!by_white && pc=='n') return true;
|
||||
}
|
||||
// bishops/queens
|
||||
for (int d=0; d<4; d++){
|
||||
int off = bishop_dirs[d]; int t = sq + off;
|
||||
while (on_board(t) && abs(file_of(t)-f)==abs(rank_of(t)-r)){
|
||||
char pc = pos->board[t];
|
||||
if (pc!='.') { if (by_white && (pc=='B'||pc=='Q')) return true; if (!by_white && (pc=='b'||pc=='q')) return true; break; }
|
||||
t += off;
|
||||
}
|
||||
}
|
||||
// rooks/queens
|
||||
for (int d=0; d<4; d++){
|
||||
int off = rook_dirs[d]; int t = sq + off;
|
||||
while (on_board(t) && (file_of(t)==f || rank_of(t)==r)){
|
||||
char pc = pos->board[t];
|
||||
if (pc!='.') { if (by_white && (pc=='R'||pc=='Q')) return true; if (!by_white && (pc=='r'||pc=='q')) return true; break; }
|
||||
t += off;
|
||||
}
|
||||
}
|
||||
// king
|
||||
for (int i=0;i<8;i++){
|
||||
int t=sq+king_dirs[i]; if (!on_board(t)) continue; if (abs(file_of(t)-f)>1||abs(rank_of(t)-r)>1) continue;
|
||||
char pc = pos->board[t]; if (by_white && pc=='K') return true; if (!by_white && pc=='k') return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool chess_is_in_check(const Position *pos, bool white){
|
||||
int ks = -1; char k = white? 'K' : 'k';
|
||||
for (int i=0;i<64;i++) if (pos->board[i]==k) { ks = i; break; }
|
||||
if (ks==-1) return false; // malformed
|
||||
return chess_square_attacked(pos, ks, !white);
|
||||
}
|
||||
|
||||
static void add_move_if_legal(const Position *pos, int from, int to, char promo, Move *out, size_t *n, size_t max){
|
||||
if (*n >= max) return;
|
||||
Position tmp; chess_copy(&tmp, pos);
|
||||
Move m = {0}; m.from=from; m.to=to; m.promo=promo; m.moved=pos->board[from]; m.captured=pos->board[to];
|
||||
int prev_ep = tmp.ep_square; m.prev_ep = prev_ep; m.prev_wk=tmp.castle_wk; m.prev_wq=tmp.castle_wq; m.prev_bk=tmp.castle_bk; m.prev_bq=tmp.castle_bq; m.prev_halfmove=tmp.halfmove_clock;
|
||||
if (!chess_make_move(&tmp, &m)) return;
|
||||
if (chess_is_in_check(&tmp, !tmp.white_to_move)) return; // after make, side switched
|
||||
out[(*n)++] = m; // store pseudo move with added flags from make_move
|
||||
}
|
||||
|
||||
size_t chess_generate_legal_moves(const Position *pos, Move *out, size_t max){
|
||||
size_t n=0;
|
||||
bool white = pos->white_to_move;
|
||||
for (int sq=0; sq<64; sq++){
|
||||
char p = pos->board[sq]; if (p=='.') continue; if (white != is_white(p)) continue;
|
||||
int f=file_of(sq), r=rank_of(sq);
|
||||
switch (tolower(p)){
|
||||
case 'p': {
|
||||
int dir = white? 8 : -8; int start_rank = white? 1 : 6; int prom_rank = white? 6 : 1;
|
||||
int one = sq + dir;
|
||||
if (on_board(one) && is_empty(pos, one)){
|
||||
if (r==prom_rank){
|
||||
const char *pr = white? "QRBN" : "qrbn";
|
||||
for (int i=0;i<4;i++) add_move_if_legal(pos, sq, one, pr[i], out, &n, max);
|
||||
} else add_move_if_legal(pos, sq, one, 0, out, &n, max);
|
||||
// two
|
||||
int two = sq + 2*dir; if (r==start_rank && is_empty(pos, two)) add_move_if_legal(pos, sq, two, 0, out, &n, max);
|
||||
}
|
||||
// captures
|
||||
int caps[2] = { dir+1, dir-1 };
|
||||
for (int i=0;i<2;i++){
|
||||
int t = sq + caps[i]; if (!on_board(t)) continue; if (abs(file_of(t)-f)!=1) continue;
|
||||
if (!is_empty(pos, t) && !same_color(pos->board[sq], pos->board[t])){
|
||||
if (r==prom_rank){ const char *pr = white? "QRBN" : "qrbn"; for (int j=0;j<4;j++) add_move_if_legal(pos, sq, t, pr[j], out, &n, max); }
|
||||
else add_move_if_legal(pos, sq, t, 0, out, &n, max);
|
||||
}
|
||||
}
|
||||
// en passant
|
||||
if (pos->ep_square!=-1){
|
||||
int ep = pos->ep_square; if (abs(file_of(ep)-f)==1 && (ep == sq+dir+1 || ep==sq+dir-1)) add_move_if_legal(pos, sq, ep, 0, out, &n, max);
|
||||
}
|
||||
} break;
|
||||
case 'n': {
|
||||
for (int i=0;i<8;i++){
|
||||
int t = sq + knight_offsets[i]; if (!on_board(t)) continue; if (abs(file_of(t)-f)>2 || abs(rank_of(t)-r)>2) continue; if (!is_empty(pos, t) && same_color(p, pos->board[t])) continue; add_move_if_legal(pos, sq, t, 0, out, &n, max);
|
||||
}
|
||||
} break;
|
||||
case 'b': {
|
||||
for (int d=0; d<4; d++){
|
||||
int off = bishop_dirs[d]; int t = sq + off; while (on_board(t) && abs(file_of(t)-f)==abs(rank_of(t)-r)){
|
||||
if (!is_empty(pos, t)){ if (!same_color(p, pos->board[t])) add_move_if_legal(pos, sq, t, 0, out, &n, max); break; }
|
||||
add_move_if_legal(pos, sq, t, 0, out, &n, max); t += off;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 'r': {
|
||||
for (int d=0; d<4; d++){
|
||||
int off = rook_dirs[d]; int t = sq + off; while (on_board(t) && (file_of(t)==f || rank_of(t)==r)){
|
||||
if (!is_empty(pos, t)){ if (!same_color(p, pos->board[t])) add_move_if_legal(pos, sq, t, 0, out, &n, max); break; }
|
||||
add_move_if_legal(pos, sq, t, 0, out, &n, max); t += off;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 'q': {
|
||||
for (int d=0; d<4; d++){
|
||||
int off = bishop_dirs[d]; int t = sq + off; while (on_board(t) && abs(file_of(t)-f)==abs(rank_of(t)-r)){
|
||||
if (!is_empty(pos, t)){ if (!same_color(p, pos->board[t])) add_move_if_legal(pos, sq, t, 0, out, &n, max); break; }
|
||||
add_move_if_legal(pos, sq, t, 0, out, &n, max); t += off;
|
||||
}
|
||||
}
|
||||
for (int d=0; d<4; d++){
|
||||
int off = rook_dirs[d]; int t = sq + off; while (on_board(t) && (file_of(t)==f || rank_of(t)==r)){
|
||||
if (!is_empty(pos, t)){ if (!same_color(p, pos->board[t])) add_move_if_legal(pos, sq, t, 0, out, &n, max); break; }
|
||||
add_move_if_legal(pos, sq, t, 0, out, &n, max); t += off;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 'k': {
|
||||
for (int i=0;i<8;i++){
|
||||
int t = sq + king_dirs[i]; if (!on_board(t)) continue; if (abs(file_of(t)-f)>1||abs(rank_of(t)-r)>1) continue; if (!is_empty(pos, t) && same_color(p, pos->board[t])) continue; add_move_if_legal(pos, sq, t, 0, out, &n, max);
|
||||
}
|
||||
// castling
|
||||
if (white){
|
||||
if (pos->castle_wk && pos->board[5]=='.' && pos->board[6]=='.' && !chess_square_attacked(pos,4,false) && !chess_square_attacked(pos,5,false) && !chess_square_attacked(pos,6,false)) add_move_if_legal(pos, 4, 6, 0, out, &n, max);
|
||||
if (pos->castle_wq && pos->board[3]=='.' && pos->board[2]=='.' && pos->board[1]=='.' && !chess_square_attacked(pos,4,false) && !chess_square_attacked(pos,3,false) && !chess_square_attacked(pos,2,false)) add_move_if_legal(pos, 4, 2, 0, out, &n, max);
|
||||
} else {
|
||||
if (pos->castle_bk && pos->board[61]=='.' && pos->board[62]=='.' && !chess_square_attacked(pos,60,true) && !chess_square_attacked(pos,61,true) && !chess_square_attacked(pos,62,true)) add_move_if_legal(pos, 60, 62, 0, out, &n, max);
|
||||
if (pos->castle_bq && pos->board[59]=='.' && pos->board[58]=='.' && pos->board[57]=='.' && !chess_square_attacked(pos,60,true) && !chess_square_attacked(pos,59,true) && !chess_square_attacked(pos,58,true)) add_move_if_legal(pos, 60, 58, 0, out, &n, max);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
bool chess_make_move(Position *pos, Move *m){
|
||||
m->is_castle=false; m->is_enpassant=false;
|
||||
char p = pos->board[m->from]; char tgt = pos->board[m->to];
|
||||
if (p=='.') return false;
|
||||
// handle special: en passant capture
|
||||
if (tolower(p)=='p' && m->to == pos->ep_square && file_of(m->to)!=file_of(m->from) && tgt=='.'){
|
||||
m->is_enpassant = true;
|
||||
int cap_sq = pos->white_to_move ? (m->to - 8) : (m->to + 8);
|
||||
m->captured = pos->board[cap_sq]; pos->board[cap_sq]='.';
|
||||
}
|
||||
|
||||
// move piece
|
||||
pos->board[m->to] = p;
|
||||
pos->board[m->from] = '.';
|
||||
|
||||
// promotion
|
||||
if (tolower(p)=='p' && m->promo){ pos->board[m->to] = m->promo; }
|
||||
|
||||
// castling rook move
|
||||
if (tolower(p)=='k'){
|
||||
int from = m->from, to = m->to;
|
||||
if (from==4 && to==6){ pos->board[5]='R'; pos->board[7]='.'; m->is_castle=true; }
|
||||
else if (from==4 && to==2){ pos->board[3]='R'; pos->board[0]='.'; m->is_castle=true; }
|
||||
else if (from==60 && to==62){ pos->board[61]='r'; pos->board[63]='.'; m->is_castle=true; }
|
||||
else if (from==60 && to==58){ pos->board[59]='r'; pos->board[56]='.'; m->is_castle=true; }
|
||||
}
|
||||
|
||||
// update castling rights
|
||||
if (m->from==0||m->to==0) pos->castle_wq=false;
|
||||
if (m->from==7||m->to==7) pos->castle_wk=false;
|
||||
if (m->from==56||m->to==56) pos->castle_bq=false;
|
||||
if (m->from==63||m->to==63) pos->castle_bk=false;
|
||||
if (tolower(p)=='k'){ if (is_white(p)) { pos->castle_wk=pos->castle_wq=false;} else {pos->castle_bk=pos->castle_bq=false;} }
|
||||
|
||||
// update ep square
|
||||
pos->ep_square = -1;
|
||||
if (tolower(p)=='p'){
|
||||
int df = rank_of(m->to) - rank_of(m->from);
|
||||
if (df==2 || df==-2){ pos->ep_square = (m->from + m->to)/2; }
|
||||
}
|
||||
|
||||
// halfmove clock
|
||||
if (tolower(p)=='p' || tgt!='.') pos->halfmove_clock = 0; else pos->halfmove_clock++;
|
||||
|
||||
// side to move
|
||||
pos->white_to_move = !pos->white_to_move; if (pos->white_to_move) pos->fullmove_number++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void chess_unmake_move(Position *pos, const Move *m){
|
||||
pos->white_to_move = !pos->white_to_move; if (!pos->white_to_move) pos->fullmove_number--;
|
||||
// restore halfmove/flags
|
||||
pos->ep_square = m->prev_ep;
|
||||
pos->castle_wk = m->prev_wk; pos->castle_wq = m->prev_wq; pos->castle_bk = m->prev_bk; pos->castle_bq = m->prev_bq;
|
||||
pos->halfmove_clock = m->prev_halfmove;
|
||||
|
||||
char p = m->moved;
|
||||
// undo promotions
|
||||
if (tolower(p)=='p' && m->promo){ p = is_white(p)? 'P':'p'; }
|
||||
|
||||
pos->board[m->from] = p;
|
||||
pos->board[m->to] = m->captured? m->captured : '.';
|
||||
if (m->is_enpassant){ int cap_sq = pos->white_to_move ? (m->to - 8) : (m->to + 8); pos->board[m->to]='.'; pos->board[cap_sq]= m->captured; }
|
||||
if (m->is_castle){
|
||||
if (m->from==4 && m->to==6){ pos->board[7]='R'; pos->board[5]='.'; }
|
||||
else if (m->from==4 && m->to==2){ pos->board[0]='R'; pos->board[3]='.'; }
|
||||
else if (m->from==60 && m->to==62){ pos->board[63]='r'; pos->board[61]='.'; }
|
||||
else if (m->from==60 && m->to==58){ pos->board[56]='r'; pos->board[59]='.'; }
|
||||
}
|
||||
}
|
||||
|
||||
void sq_to_coord(int sq, int *file, int *rank){ if (file) *file=file_of(sq); if (rank) *rank=rank_of(sq); }
|
||||
int coord_to_sq(int file, int rank){ return rank*8 + file; }
|
||||
|
||||
void move_to_uci(const Move *m, char buf[8]){
|
||||
int f1=file_of(m->from), r1=rank_of(m->from), f2=file_of(m->to), r2=rank_of(m->to);
|
||||
buf[0]='a'+f1; buf[1]='1'+r1; buf[2]='a'+f2; buf[3]='1'+r2; int i=4;
|
||||
if (m->promo){ buf[i++]=tolower(m->promo); }
|
||||
buf[i]='\0';
|
||||
}
|
||||
|
||||
bool parse_uci_move(const char *s, const Position *pos, Move *out){
|
||||
if (!s || strlen(s)<4) return false;
|
||||
int f1=s[0]-'a', r1=s[1]-'1', f2=s[2]-'a', r2=s[3]-'1'; if (f1<0||f1>7||f2<0||f2>7||r1<0||r1>7||r2<0||r2>7) return false;
|
||||
int from = r1*8+f1, to=r2*8+f2; char promo = s[4]? s[4]:0; if (promo) promo = pos->white_to_move? toupper((unsigned char)promo):tolower((unsigned char)promo);
|
||||
Move list[MAX_MOVES]; size_t n = chess_generate_legal_moves(pos, list, MAX_MOVES);
|
||||
for (size_t i=0;i<n;i++){ if (list[i].from==from && list[i].to==to){ *out = list[i]; out->promo = promo? promo : list[i].promo; return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool chess_to_fen(const Position *pos, char *out, size_t outsz){
|
||||
char buf[256]; int idx=0;
|
||||
for (int r=7;r>=0;r--){
|
||||
int empty=0;
|
||||
for (int f=0;f<8;f++){
|
||||
char p = pos->board[r*8+f];
|
||||
if (p=='.') empty++; else { if (empty){ buf[idx++]= '0'+empty; empty=0; } buf[idx++]=p; }
|
||||
}
|
||||
if (empty) buf[idx++]= '0'+empty;
|
||||
if (r) buf[idx++]='/';
|
||||
}
|
||||
buf[idx++]=' ';
|
||||
buf[idx++]= pos->white_to_move ? 'w':'b';
|
||||
buf[idx++]=' ';
|
||||
int start=idx;
|
||||
if (pos->castle_wk) buf[idx++]='K';
|
||||
if (pos->castle_wq) buf[idx++]='Q';
|
||||
if (pos->castle_bk) buf[idx++]='k';
|
||||
if (pos->castle_bq) buf[idx++]='q';
|
||||
if (idx==start) buf[idx++]='-';
|
||||
buf[idx++]=' ';
|
||||
if (pos->ep_square==-1){ buf[idx++]='-'; }
|
||||
else { int f=file_of(pos->ep_square), r=rank_of(pos->ep_square); buf[idx++]='a'+f; buf[idx++]='1'+r; }
|
||||
idx += snprintf(buf+idx, sizeof(buf)-idx, " %d %d", pos->halfmove_clock, pos->fullmove_number);
|
||||
buf[idx]='\0';
|
||||
snprintf(out, outsz, "%s", buf);
|
||||
return true;
|
||||
}
|
||||
56
C/opening_learner/chess.h
Normal file
56
C/opening_learner/chess.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef CHESS_H
|
||||
#define CHESS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Board is 64 chars, a1=0, b1=1, ..., h8=63
|
||||
// Pieces: 'P','N','B','R','Q','K' for white, lowercase for black, '.' empty
|
||||
|
||||
typedef struct {
|
||||
char board[64];
|
||||
bool white_to_move;
|
||||
bool castle_wk, castle_wq, castle_bk, castle_bq;
|
||||
int ep_square; // -1 if none
|
||||
int halfmove_clock;
|
||||
int fullmove_number;
|
||||
} Position;
|
||||
|
||||
typedef struct {
|
||||
int from, to;
|
||||
char promo; // 0 or 'q','r','b','n' (lowercase for black)
|
||||
char captured; // piece captured or 0
|
||||
char moved; // piece moved
|
||||
bool is_castle;
|
||||
bool is_enpassant;
|
||||
int prev_ep;
|
||||
bool prev_wk, prev_wq, prev_bk, prev_bq;
|
||||
int prev_halfmove;
|
||||
} Move;
|
||||
|
||||
void chess_init_start(Position *pos);
|
||||
void chess_copy(Position *dst, const Position *src);
|
||||
|
||||
// Move gen and make/unmake
|
||||
size_t chess_generate_legal_moves(const Position *pos, Move *out, size_t max);
|
||||
bool chess_make_move(Position *pos, Move *m);
|
||||
void chess_unmake_move(Position *pos, const Move *m);
|
||||
|
||||
// Utility
|
||||
bool chess_is_in_check(const Position *pos, bool white);
|
||||
bool chess_square_attacked(const Position *pos, int sq, bool by_white);
|
||||
|
||||
// Conversions
|
||||
void sq_to_coord(int sq, int *file, int *rank);
|
||||
int coord_to_sq(int file, int rank);
|
||||
|
||||
// UCI strings like e2e4, with optional promotion char
|
||||
void move_to_uci(const Move *m, char buf[8]);
|
||||
bool parse_uci_move(const char *s, const Position *pos, Move *out);
|
||||
|
||||
// FEN
|
||||
bool chess_to_fen(const Position *pos, char *out, size_t outsz);
|
||||
|
||||
#define MAX_MOVES 256
|
||||
|
||||
#endif
|
||||
BIN
C/opening_learner/chess.o
Normal file
BIN
C/opening_learner/chess.o
Normal file
Binary file not shown.
141
C/opening_learner/engine.c
Normal file
141
C/opening_learner/engine.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include "engine.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
|
||||
static bool spawn_process(const char *path, Engine *e){
|
||||
int inpipe[2], outpipe[2];
|
||||
if (pipe(inpipe)<0 || pipe(outpipe)<0) return false;
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) return false;
|
||||
if (pid == 0){
|
||||
dup2(inpipe[0], STDIN_FILENO); // child stdin from inpipe[0]
|
||||
dup2(outpipe[1], STDOUT_FILENO); // child stdout to outpipe[1]
|
||||
dup2(outpipe[1], STDERR_FILENO);
|
||||
close(inpipe[0]); close(inpipe[1]); close(outpipe[0]); close(outpipe[1]);
|
||||
execlp(path, path, (char*)NULL);
|
||||
_exit(127);
|
||||
}
|
||||
// parent
|
||||
close(inpipe[0]); close(outpipe[1]);
|
||||
e->pid = pid; e->in_fd = inpipe[1]; e->out_fd = outpipe[0]; e->ready=false;
|
||||
// make out_fd non-blocking for reads with polling
|
||||
int flags = fcntl(e->out_fd, F_GETFL, 0); fcntl(e->out_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool try_start(Engine *e, const char *name){
|
||||
if (!spawn_process(name, e)) return false;
|
||||
// send UCI init
|
||||
engine_cmd(e, "uci\n");
|
||||
char buf[4096]; int attempts=50; // ~5s total
|
||||
while (attempts--){
|
||||
usleep(100000);
|
||||
ssize_t n = read(e->out_fd, buf, sizeof(buf)-1);
|
||||
if (n>0){
|
||||
buf[n]='\0';
|
||||
if (strstr(buf, "uciok")) { e->ready=true; break; }
|
||||
}
|
||||
}
|
||||
if (!e->ready){ engine_stop(e); return false; }
|
||||
engine_cmd(e, "isready\n");
|
||||
attempts=50;
|
||||
while (attempts--){
|
||||
usleep(100000);
|
||||
ssize_t n = read(e->out_fd, buf, sizeof(buf)-1);
|
||||
if (n>0){ buf[n]='\0'; if (strstr(buf, "readyok")) break; }
|
||||
}
|
||||
return e->ready;
|
||||
}
|
||||
|
||||
bool engine_start(Engine *e){
|
||||
memset(e, 0, sizeof(*e)); e->pid=-1; e->in_fd=-1; e->out_fd=-1; e->ready=false;
|
||||
if (try_start(e, "stockfish")) return true;
|
||||
if (try_start(e, "asmfish")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void engine_stop(Engine *e){
|
||||
if (e->in_fd!=-1){ write(e->in_fd, "quit\n", 5); close(e->in_fd); }
|
||||
if (e->out_fd!=-1) close(e->out_fd);
|
||||
if (e->pid>0){ int status; waitpid(e->pid, &status, 0); }
|
||||
e->pid=-1; e->in_fd=e->out_fd=-1; e->ready=false;
|
||||
}
|
||||
|
||||
bool engine_cmd(Engine *e, const char *cmd){
|
||||
if (e->in_fd==-1) return false;
|
||||
size_t len = strlen(cmd);
|
||||
ssize_t n = write(e->in_fd, cmd, len);
|
||||
if (n < 0) {
|
||||
return false;
|
||||
}
|
||||
return n == (ssize_t)len;
|
||||
}
|
||||
|
||||
static void position_to_uci(const Position *pos, char *out, size_t outsz){
|
||||
// Send starting position and moves list by comparing with startpos; for simplicity, use FEN always.
|
||||
char fen[256]; chess_to_fen(pos, fen, sizeof(fen));
|
||||
snprintf(out, outsz, "position fen %s\n", fen);
|
||||
}
|
||||
|
||||
size_t engine_get_top_moves(Engine *e, const Position *pos, EngineMove *out, size_t max){
|
||||
if (!e->ready) return 0;
|
||||
char cmd[512]; position_to_uci(pos, cmd, sizeof(cmd)); engine_cmd(e, cmd);
|
||||
// ask multiPV up to max (cap at 5 as requested)
|
||||
size_t req = max; if (req>5) req=5; char go[128]; snprintf(go, sizeof(go), "setoption name MultiPV value %zu\n", req); engine_cmd(e, go);
|
||||
engine_cmd(e, "go movetime 400\n");
|
||||
char buf[8192]; size_t count=0; int attempts=50;
|
||||
while (attempts--){
|
||||
usleep(100000);
|
||||
ssize_t n = read(e->out_fd, buf, sizeof(buf)-1);
|
||||
if (n<=0) continue;
|
||||
buf[n]='\0';
|
||||
char *line = strtok(buf, "\n");
|
||||
while (line){
|
||||
if (strncmp(line, "info ", 5)==0){
|
||||
// parse "info ... multipv X score cp Y ... pv <uci>"
|
||||
char *mpv = strstr(line, " multipv "); char *score = strstr(line, " score "); char *pv = strstr(line, " pv ");
|
||||
if (mpv && score && pv){
|
||||
int idx = atoi(mpv+9); if (idx>=1 && (size_t)idx<=req){
|
||||
int cp=0; if (strstr(score, "cp ")) cp = atoi(strstr(score, "cp ")+3);
|
||||
char mv[8]={0};
|
||||
sscanf(pv+4, "%7s", mv);
|
||||
size_t i = (size_t)idx-1; if (i<req){ out[i].score_cp = cp; snprintf(out[i].uci, sizeof(out[i].uci), "%s", mv); if (i+1>count) count=i+1; }
|
||||
}
|
||||
}
|
||||
} else if (strncmp(line, "bestmove ", 9)==0){ attempts=0; break; }
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
// simple sort by score descending (best to worst), keeping empties at end
|
||||
for (size_t i=0;i<count;i++){
|
||||
for (size_t j=i+1;j<count;j++){
|
||||
if (out[j].score_cp > out[i].score_cp){ EngineMove tmp=out[i]; out[i]=out[j]; out[j]=tmp; }
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool engine_get_best_move(Engine *e, const Position *pos, char out_uci[8]){
|
||||
if (!e->ready) return false;
|
||||
char cmd[512]; position_to_uci(pos, cmd, sizeof(cmd)); engine_cmd(e, cmd);
|
||||
engine_cmd(e, "go movetime 300\n");
|
||||
char buf[4096]; int attempts=50;
|
||||
while (attempts--){
|
||||
usleep(100000);
|
||||
ssize_t n = read(e->out_fd, buf, sizeof(buf)-1);
|
||||
if (n<=0) continue;
|
||||
buf[n]='\0';
|
||||
char *line = strtok(buf, "\n");
|
||||
while (line){
|
||||
if (strncmp(line, "bestmove ", 9)==0){ sscanf(line+9, "%7s", out_uci); return true; }
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
34
C/opening_learner/engine.h
Normal file
34
C/opening_learner/engine.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef ENGINE_H
|
||||
#define ENGINE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "chess.h"
|
||||
|
||||
typedef struct {
|
||||
int score_cp; // centipawns relative to side to move
|
||||
char uci[8];
|
||||
} EngineMove;
|
||||
|
||||
typedef struct {
|
||||
int pid;
|
||||
int in_fd; // write to engine stdin
|
||||
int out_fd; // read from engine stdout
|
||||
bool ready;
|
||||
} Engine;
|
||||
|
||||
// Start engine: tries stockfish, then asmfish. Returns false if none.
|
||||
bool engine_start(Engine *e);
|
||||
void engine_stop(Engine *e);
|
||||
|
||||
// Synchronous send command
|
||||
bool engine_cmd(Engine *e, const char *cmd);
|
||||
|
||||
// Ask for top N moves from a position (short fixed time). Returns count.
|
||||
size_t engine_get_top_moves(Engine *e, const Position *pos, EngineMove *out, size_t max);
|
||||
|
||||
// Ask for best move only.
|
||||
bool engine_get_best_move(Engine *e, const Position *pos, char out_uci[8]);
|
||||
|
||||
#endif
|
||||
BIN
C/opening_learner/engine.o
Normal file
BIN
C/opening_learner/engine.o
Normal file
Binary file not shown.
158
C/opening_learner/gui.c
Normal file
158
C/opening_learner/gui.c
Normal file
@ -0,0 +1,158 @@
|
||||
#include "gui.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const SDL_Color COLOR_LIGHT = { 238, 238, 210, 255 }; // light square (not pure white)
|
||||
const SDL_Color COLOR_DARK = { 118, 150, 86, 255 }; // dark square (not pure black)
|
||||
const SDL_Color COLOR_GRID = { 20, 20, 20, 255 }; // thick outline
|
||||
const SDL_Color COLOR_SEL = { 200, 50, 50, 200 }; // selection highlight
|
||||
const SDL_Color COLOR_TEXT = { 10, 10, 10, 255 };
|
||||
|
||||
static void set_color(SDL_Renderer *r, SDL_Color c) {
|
||||
SDL_SetRenderDrawColor(r, c.r, c.g, c.b, c.a);
|
||||
}
|
||||
|
||||
bool gui_init(Gui *g, int w, int h, const char *title) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
fprintf(stderr, "SDL_Init error: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
g->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||
if (!g->window) {
|
||||
fprintf(stderr, "SDL_CreateWindow error: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
g->renderer = SDL_CreateRenderer(g->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if (!g->renderer) {
|
||||
fprintf(stderr, "SDL_CreateRenderer error: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
g->win_w = w; g->win_h = h; g->flipped = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void gui_destroy(Gui *g) {
|
||||
if (g->renderer) SDL_DestroyRenderer(g->renderer);
|
||||
if (g->window) SDL_DestroyWindow(g->window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void gui_set_flipped(Gui *g, bool flipped) { g->flipped = flipped; }
|
||||
|
||||
static void draw_rect(SDL_Renderer *r, int x, int y, int w, int h, SDL_Color c) {
|
||||
set_color(r, c);
|
||||
SDL_Rect rc = { x, y, w, h };
|
||||
SDL_RenderFillRect(r, &rc);
|
||||
}
|
||||
|
||||
static void draw_outline(SDL_Renderer *r, int x, int y, int w, int h, int thickness, SDL_Color c) {
|
||||
set_color(r, c);
|
||||
for (int i=0;i<thickness;i++) {
|
||||
SDL_Rect rc = { x+i, y+i, w-2*i, h-2*i };
|
||||
SDL_RenderDrawRect(r, &rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_piece_letter(SDL_Renderer *r, int x, int y, int size, char p) {
|
||||
// Minimal: draw a filled circle/square plus an initial letter approximated with rectangles.
|
||||
// To keep dependencies minimal, no TTF. Ensure contrast: white pieces light, black pieces dark.
|
||||
SDL_Color fill = (p >= 'A' && p <= 'Z') ? (SDL_Color){250, 250, 250, 255} : (SDL_Color){30, 30, 30, 255};
|
||||
SDL_Color glyph = (p >= 'A' && p <= 'Z') ? (SDL_Color){30, 30, 30, 255} : (SDL_Color){240, 240, 240, 255};
|
||||
// Base disk
|
||||
draw_rect(r, x+size*0.15, y+size*0.15, (int)(size*0.7), (int)(size*0.7), fill);
|
||||
// Glyph: draw a simple letter-like mark
|
||||
set_color(r, glyph);
|
||||
// vertical bar
|
||||
SDL_Rect bar1 = { x + size/2 - size/16, y + size/3, size/8, size/3 };
|
||||
SDL_RenderFillRect(r, &bar1);
|
||||
// top bar
|
||||
SDL_Rect bar2 = { x + size/3, y + size/3 - size/10, size/3, size/10 };
|
||||
SDL_RenderFillRect(r, &bar2);
|
||||
}
|
||||
|
||||
void gui_draw(Gui *g, const char board[64], const GuiSelection *sel, const char *status_line) {
|
||||
SDL_GetWindowSize(g->window, &g->win_w, &g->win_h);
|
||||
|
||||
set_color(g->renderer, (SDL_Color){ 35, 35, 35, 255 });
|
||||
SDL_RenderClear(g->renderer);
|
||||
|
||||
int size = (g->win_w < g->win_h ? g->win_w : g->win_h) - 40; // margins
|
||||
if (size < 200) size = 200;
|
||||
int cell = size / 8;
|
||||
size = cell * 8;
|
||||
int ox = (g->win_w - size)/2;
|
||||
int oy = (g->win_h - size)/2;
|
||||
|
||||
// Board outline (thick)
|
||||
draw_outline(g->renderer, ox-6, oy-6, size+12, size+12, 6, COLOR_GRID);
|
||||
|
||||
// Squares
|
||||
for (int r=0;r<8;r++) {
|
||||
for (int f=0;f<8;f++) {
|
||||
int idx = g->flipped ? (63 - (r*8+f)) : (r*8+f);
|
||||
SDL_Color c = ((r+f)&1) ? COLOR_DARK : COLOR_LIGHT;
|
||||
draw_rect(g->renderer, ox + f*cell, oy + r*cell, cell, cell, c);
|
||||
|
||||
char p = board[idx];
|
||||
if (p != '.' && p != '\0') {
|
||||
draw_piece_letter(g->renderer, ox + f*cell, oy + r*cell, cell, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Selection overlay
|
||||
if (sel && sel->clicked && sel->from_sq >= 0) {
|
||||
int s = sel->from_sq;
|
||||
int rr = g->flipped ? 7 - (s/8) : (s/8);
|
||||
int ff = g->flipped ? 7 - (s%8) : (s%8);
|
||||
draw_outline(g->renderer, ox + ff*cell+2, oy + rr*cell+2, cell-4, cell-4, 3, COLOR_SEL);
|
||||
}
|
||||
|
||||
// Status strip
|
||||
draw_outline(g->renderer, 10, g->win_h - 40, g->win_w - 20, 30, 2, COLOR_GRID);
|
||||
// Without TTF, we can't render text; draw a minimal indicator bar to signal state.
|
||||
// If status_line indicates success/failure, alter color.
|
||||
SDL_Color bar = { 80, 120, 200, 255 };
|
||||
if (status_line && status_line[0]) {
|
||||
if (SDL_strstr(status_line, "Correct")) bar = (SDL_Color){80, 200, 120, 255};
|
||||
else if (SDL_strstr(status_line, "Wrong")) bar = (SDL_Color){200, 80, 80, 255};
|
||||
}
|
||||
draw_rect(g->renderer, 12, g->win_h - 38, g->win_w - 24, 26, bar);
|
||||
|
||||
SDL_RenderPresent(g->renderer);
|
||||
}
|
||||
|
||||
int gui_coord_to_sq(Gui *g, int x, int y) {
|
||||
int w, h; SDL_GetWindowSize(g->window, &w, &h);
|
||||
int size = (w < h ? w : h) - 40; if (size < 200) size = 200;
|
||||
int cell = size / 8; size = cell * 8;
|
||||
int ox = (w - size)/2; int oy = (h - size)/2;
|
||||
if (x < ox || y < oy || x >= ox+size || y >= oy+size) return -1;
|
||||
int f = (x - ox) / cell;
|
||||
int r = (y - oy) / cell;
|
||||
int sq = r*8 + f;
|
||||
if (g->flipped) sq = 63 - sq;
|
||||
return sq;
|
||||
}
|
||||
|
||||
bool gui_poll_move(Gui *g, GuiSelection *sel, bool *quit_requested, int *key_out) {
|
||||
SDL_Event e;
|
||||
bool updated = false;
|
||||
if (key_out) *key_out = 0;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_QUIT) { if (quit_requested) *quit_requested = true; }
|
||||
else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||
updated = true;
|
||||
} else if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT) {
|
||||
int sq = gui_coord_to_sq(g, e.button.x, e.button.y);
|
||||
if (sq >= 0) {
|
||||
if (!sel->clicked) { sel->from_sq = sq; sel->to_sq = -1; sel->clicked = true; }
|
||||
else { sel->to_sq = sq; updated = true; }
|
||||
}
|
||||
} else if (e.type == SDL_KEYDOWN) {
|
||||
if (e.key.keysym.sym == SDLK_ESCAPE) { sel->clicked = false; sel->from_sq = sel->to_sq = -1; updated = true; }
|
||||
if (key_out) *key_out = e.key.keysym.sym;
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
36
C/opening_learner/gui.h
Normal file
36
C/opening_learner/gui.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef GUI_H
|
||||
#define GUI_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
typedef struct {
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
int win_w, win_h;
|
||||
bool flipped; // true if black at bottom
|
||||
} Gui;
|
||||
|
||||
typedef struct {
|
||||
int from_sq; // 0..63 or -1
|
||||
int to_sq; // 0..63 or -1
|
||||
char promo; // 'q','r','b','n' or 0
|
||||
bool clicked;
|
||||
} GuiSelection;
|
||||
|
||||
bool gui_init(Gui *g, int w, int h, const char *title);
|
||||
void gui_destroy(Gui *g);
|
||||
void gui_set_flipped(Gui *g, bool flipped);
|
||||
void gui_draw(Gui *g, const char board[64], const GuiSelection *sel, const char *status_line);
|
||||
// Returns true if something changed. If a key was pressed, key_out receives SDL_Keycode else 0.
|
||||
bool gui_poll_move(Gui *g, GuiSelection *sel, bool *quit_requested, int *key_out);
|
||||
int gui_coord_to_sq(Gui *g, int x, int y);
|
||||
|
||||
// colors
|
||||
extern const SDL_Color COLOR_LIGHT;
|
||||
extern const SDL_Color COLOR_DARK;
|
||||
extern const SDL_Color COLOR_GRID;
|
||||
extern const SDL_Color COLOR_SEL;
|
||||
extern const SDL_Color COLOR_TEXT;
|
||||
|
||||
#endif
|
||||
BIN
C/opening_learner/gui.o
Normal file
BIN
C/opening_learner/gui.o
Normal file
Binary file not shown.
193
C/opening_learner/main.c
Normal file
193
C/opening_learner/main.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "gui.h"
|
||||
#include "chess.h"
|
||||
#include "engine.h"
|
||||
#include "mistakes.h"
|
||||
|
||||
typedef struct {
|
||||
Position pos;
|
||||
Engine engine;
|
||||
Gui gui;
|
||||
MistakeList mistakes;
|
||||
bool replay_mode; // allow revisiting mistakes
|
||||
size_t replay_index;
|
||||
} App;
|
||||
|
||||
static void append_uci(char *line, size_t sz, const char *mv){
|
||||
if (line[0]) strncat(line, " ", sz-1);
|
||||
strncat(line, mv, sz-1);
|
||||
}
|
||||
|
||||
static void position_push_move_text(Position *pos, const Move *m, char *line, size_t lsz){
|
||||
(void)pos;
|
||||
char u[8]; move_to_uci(m, u);
|
||||
append_uci(line, lsz, u);
|
||||
}
|
||||
|
||||
static void collect_all_legal_uci(const Position *pos, char list[][8], size_t *n, size_t max){
|
||||
Move mv[MAX_MOVES]; size_t k = chess_generate_legal_moves(pos, mv, MAX_MOVES);
|
||||
*n = 0;
|
||||
for (size_t i=0;i<k && *n<max;i++){ char u[8]; move_to_uci(&mv[i], u); strncpy(list[(*n)++], u, 8); }
|
||||
}
|
||||
|
||||
static bool uci_in_list(const char *u, char list[][8], size_t n){
|
||||
for (size_t i=0;i<n;i++){
|
||||
if (strncmp(u, list[i], 8)==0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *mistake_file_path(){ return "mistakes.txt"; }
|
||||
|
||||
int main(){
|
||||
srand((unsigned)time(NULL));
|
||||
|
||||
App app; memset(&app, 0, sizeof(app));
|
||||
mistakes_init(&app.mistakes);
|
||||
mistakes_load(&app.mistakes, mistake_file_path());
|
||||
|
||||
// Avoid SIGPIPE crashes when engine pipe closes
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (!gui_init(&app.gui, 720, 760, "Opening Learner")){
|
||||
fprintf(stderr, "GUI init failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!engine_start(&app.engine)){
|
||||
fprintf(stderr, "Error: Neither stockfish nor asmfish found locally. Please install one.\n");
|
||||
gui_destroy(&app.gui);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize position
|
||||
chess_init_start(&app.pos);
|
||||
|
||||
// Randomly pick side
|
||||
bool player_is_white = rand()%2==0;
|
||||
gui_set_flipped(&app.gui, !player_is_white);
|
||||
|
||||
// gameplay state
|
||||
char status[128] = "";
|
||||
GuiSelection sel = { .from_sq=-1,.to_sq=-1,.promo=0,.clicked=false };
|
||||
char line_uci[512] = ""; // history of moves uci
|
||||
|
||||
// If white, player moves first
|
||||
bool awaiting_player = player_is_white;
|
||||
char expected_player_move[8] = ""; // best move suggested by engine for player
|
||||
bool quit=false;
|
||||
|
||||
while (!quit){
|
||||
// Show board
|
||||
gui_draw(&app.gui, app.pos.board, &sel, status);
|
||||
|
||||
// Engine to act when it's engine turn
|
||||
if (!awaiting_player){
|
||||
// 2. Ask engine for proposed responses (5)
|
||||
EngineMove props[5]; size_t n = engine_get_top_moves(&app.engine, &app.pos, props, 5);
|
||||
// 3. Sort is done in engine; also collect legal ones not proposed
|
||||
char legal[256][8]; size_t lcnt=0; collect_all_legal_uci(&app.pos, legal, &lcnt, 256);
|
||||
// 4. pick response with decreasing probability
|
||||
size_t total = n;
|
||||
// add non-proposed at the end with minimal priority
|
||||
char pool[300][8]; int weights[300]; size_t pcnt=0;
|
||||
for (size_t i=0;i<n;i++){ strncpy(pool[pcnt], props[i].uci, 8); weights[pcnt++] = (int)(n - i); }
|
||||
for (size_t i=0;i<lcnt;i++){
|
||||
if (!uci_in_list(legal[i], pool, pcnt)) {
|
||||
memcpy(pool[pcnt], legal[i], 8);
|
||||
pool[pcnt][7] = '\0';
|
||||
weights[pcnt++] = 1; total++;
|
||||
}
|
||||
}
|
||||
// weighted pick
|
||||
int wsum=0; for (size_t i=0;i<pcnt;i++) wsum += weights[i];
|
||||
int r = (wsum>0)? (rand()%wsum) : 0;
|
||||
size_t pick=0; for (size_t i=0;i<pcnt;i++){ if (r < weights[i]) { pick=i; break; } r -= weights[i]; }
|
||||
// 5. play response
|
||||
Move m; if (!parse_uci_move(pool[pick], &app.pos, &m)){ // fallback: best
|
||||
if (n>0 && parse_uci_move(props[0].uci, &app.pos, &m)) pick=0; else { snprintf(status, sizeof(status), "No engine move"); quit=true; continue; }
|
||||
}
|
||||
chess_make_move(&app.pos, &m);
|
||||
position_push_move_text(&app.pos, &m, line_uci, sizeof(line_uci));
|
||||
awaiting_player = true;
|
||||
// 6. Ask engine for optimal response from player
|
||||
engine_get_best_move(&app.engine, &app.pos, expected_player_move);
|
||||
snprintf(status, sizeof(status), "Your turn");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Player move input
|
||||
int key=0;
|
||||
bool updated = gui_poll_move(&app.gui, &sel, &quit, &key);
|
||||
if (quit) break;
|
||||
if (key=='m' || key=='M'){
|
||||
// enter simple replay: load a mistake line and restart from it to the position where best move is required
|
||||
if (app.mistakes.count>0){
|
||||
if (app.replay_index >= app.mistakes.count) app.replay_index = 0;
|
||||
Mistake *mk = &app.mistakes.items[app.replay_index++];
|
||||
// reset and play the line moves to reach the mistake position
|
||||
chess_init_start(&app.pos);
|
||||
char tmp[512]; snprintf(tmp, sizeof(tmp), "%s", mk->line);
|
||||
char *tok = strtok(tmp, " ");
|
||||
while (tok){ Move m; if (parse_uci_move(tok, &app.pos, &m)) chess_make_move(&app.pos, &m); tok = strtok(NULL, " "); }
|
||||
snprintf(status, sizeof(status), "Practice: best is %s", mk->best_move);
|
||||
strncpy(expected_player_move, mk->best_move, sizeof(expected_player_move));
|
||||
awaiting_player = true;
|
||||
gui_set_flipped(&app.gui, !app.pos.white_to_move); // if it's black to move, flip so black bottom
|
||||
}
|
||||
}
|
||||
if (updated && sel.clicked && sel.to_sq>=0){
|
||||
Move list[MAX_MOVES]; size_t n = chess_generate_legal_moves(&app.pos, list, MAX_MOVES);
|
||||
bool moved=false; Move chosen={0};
|
||||
for (size_t i=0;i<n;i++){
|
||||
if (list[i].from==sel.from_sq && list[i].to==sel.to_sq){ chosen = list[i]; moved=true; break; }
|
||||
}
|
||||
sel.clicked=false; sel.from_sq=sel.to_sq=-1; sel.promo=0;
|
||||
if (!moved) continue;
|
||||
|
||||
// 7. Compare with expected move
|
||||
char uci[8]; move_to_uci(&chosen, uci);
|
||||
bool correct = (expected_player_move[0] && strncmp(uci, expected_player_move, 8)==0);
|
||||
if (correct){
|
||||
chess_make_move(&app.pos, &chosen);
|
||||
position_push_move_text(&app.pos, &chosen, line_uci, sizeof(line_uci));
|
||||
snprintf(status, sizeof(status), "Correct");
|
||||
awaiting_player = false; // engine move next
|
||||
} else {
|
||||
// log mistake: 1) save all moves that lead to mistake, 2) allow revisit later, 3) reset position
|
||||
char fen[256]; chess_to_fen(&app.pos, fen, sizeof(fen));
|
||||
mistakes_add(&app.mistakes, fen, expected_player_move, line_uci);
|
||||
mistakes_save(&app.mistakes, mistake_file_path());
|
||||
snprintf(status, sizeof(status), "Wrong, best was %s", expected_player_move);
|
||||
// redo best move to show
|
||||
Move best; if (parse_uci_move(expected_player_move, &app.pos, &best)){
|
||||
chess_make_move(&app.pos, &best);
|
||||
position_push_move_text(&app.pos, &best, line_uci, sizeof(line_uci));
|
||||
}
|
||||
gui_draw(&app.gui, app.pos.board, &sel, status);
|
||||
SDL_Delay(600);
|
||||
// reset to start
|
||||
chess_init_start(&app.pos);
|
||||
line_uci[0]='\0';
|
||||
// randomize side again
|
||||
player_is_white = rand()%2==0; gui_set_flipped(&app.gui, !player_is_white);
|
||||
awaiting_player = player_is_white;
|
||||
expected_player_move[0]='\0';
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
mistakes_save(&app.mistakes, mistake_file_path());
|
||||
gui_destroy(&app.gui);
|
||||
engine_stop(&app.engine);
|
||||
mistakes_free(&app.mistakes);
|
||||
return 0;
|
||||
}
|
||||
BIN
C/opening_learner/main.o
Normal file
BIN
C/opening_learner/main.o
Normal file
Binary file not shown.
65
C/opening_learner/mistakes.c
Normal file
65
C/opening_learner/mistakes.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include "mistakes.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void mistakes_init(MistakeList *ml) {
|
||||
ml->items = NULL; ml->count = 0; ml->cap = 0;
|
||||
}
|
||||
|
||||
void mistakes_free(MistakeList *ml) {
|
||||
free(ml->items); ml->items = NULL; ml->count = ml->cap = 0;
|
||||
}
|
||||
|
||||
static void ensure_cap(MistakeList *ml, size_t need) {
|
||||
if (need <= ml->cap) return;
|
||||
size_t ncap = ml->cap ? ml->cap*2 : 16;
|
||||
while (ncap < need) ncap *= 2;
|
||||
Mistake *ni = realloc(ml->items, ncap * sizeof(Mistake));
|
||||
if (!ni) return; // OOM silently ignored
|
||||
ml->items = ni; ml->cap = ncap;
|
||||
}
|
||||
|
||||
void mistakes_add(MistakeList *ml, const char *fen, const char *best_move, const char *line) {
|
||||
ensure_cap(ml, ml->count+1);
|
||||
Mistake *m = &ml->items[ml->count++];
|
||||
snprintf(m->fen, sizeof(m->fen), "%s", fen);
|
||||
snprintf(m->best_move, sizeof(m->best_move), "%s", best_move);
|
||||
snprintf(m->line, sizeof(m->line), "%s", line);
|
||||
}
|
||||
|
||||
bool mistakes_save(const MistakeList *ml, const char *path) {
|
||||
FILE *f = fopen(path, "w");
|
||||
if (!f) return false;
|
||||
for (size_t i=0;i<ml->count;i++) {
|
||||
const Mistake *m = &ml->items[i];
|
||||
fprintf(f, "FEN:%s\nBEST:%s\nLINE:%s\n.\n", m->fen, m->best_move, m->line);
|
||||
}
|
||||
fclose(f); return true;
|
||||
}
|
||||
|
||||
bool mistakes_load(MistakeList *ml, const char *path) {
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) return false;
|
||||
char buf[1024]; char fen[128] = ""; char best[16] = ""; char line[512] = "";
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
if (strncmp(buf, "FEN:", 4) == 0) {
|
||||
// copy up to 127 chars, strip newline
|
||||
size_t l = strnlen(buf+4, sizeof(fen)-1);
|
||||
memcpy(fen, buf+4, l); fen[l]='\0';
|
||||
if (l && fen[l-1]=='\n') fen[l-1]='\0';
|
||||
} else if (strncmp(buf, "BEST:", 5) == 0) {
|
||||
size_t l = strnlen(buf+5, sizeof(best)-1);
|
||||
memcpy(best, buf+5, l); best[l]='\0';
|
||||
if (l && best[l-1]=='\n') best[l-1]='\0';
|
||||
} else if (strncmp(buf, "LINE:", 5) == 0) {
|
||||
size_t l = strnlen(buf+5, sizeof(line)-1);
|
||||
memcpy(line, buf+5, l); line[l]='\0';
|
||||
if (l && line[l-1]=='\n') line[l-1]='\0';
|
||||
} else if (buf[0]=='.') {
|
||||
mistakes_add(ml, fen, best, line);
|
||||
fen[0]=best[0]=line[0]='\0';
|
||||
}
|
||||
}
|
||||
fclose(f); return true;
|
||||
}
|
||||
28
C/opening_learner/mistakes.h
Normal file
28
C/opening_learner/mistakes.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef MISTAKES_H
|
||||
#define MISTAKES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// A lightweight mistake store in memory + file persistence.
|
||||
|
||||
typedef struct {
|
||||
char fen[128];
|
||||
char best_move[8];
|
||||
// PGN-like ply list in UCI for context
|
||||
char line[512];
|
||||
} Mistake;
|
||||
|
||||
typedef struct {
|
||||
Mistake *items;
|
||||
size_t count;
|
||||
size_t cap;
|
||||
} MistakeList;
|
||||
|
||||
void mistakes_init(MistakeList *ml);
|
||||
void mistakes_free(MistakeList *ml);
|
||||
void mistakes_add(MistakeList *ml, const char *fen, const char *best_move, const char *line);
|
||||
bool mistakes_save(const MistakeList *ml, const char *path);
|
||||
bool mistakes_load(MistakeList *ml, const char *path);
|
||||
|
||||
#endif
|
||||
BIN
C/opening_learner/mistakes.o
Normal file
BIN
C/opening_learner/mistakes.o
Normal file
Binary file not shown.
12
C/opening_learner/mistakes.txt
Normal file
12
C/opening_learner/mistakes.txt
Normal file
@ -0,0 +1,12 @@
|
||||
FEN:rnbqkbnr/pppp1ppp/4p3/8/8/N4N2/PPPPPPPP/R1BQKB1R b KQkq - 1 2
|
||||
BEST:f8a3
|
||||
LINE:g1f3 e7e6 b1a3
|
||||
.
|
||||
FEN:rnbqkbnr/pppppppp/8/8/8/7P/PPPPPPP1/RNBQKBNR b KQkq - 0 1
|
||||
BEST:e7e5
|
||||
LINE:h2h3
|
||||
.
|
||||
FEN:rnbqkbnr/pppp1ppp/8/4p3/8/4P3/PPPPKPPP/RNBQ1BNR b kq - 1 2
|
||||
BEST:d7d5
|
||||
LINE:e2e3 e7e5 e1e2
|
||||
.
|
||||
BIN
C/opening_learner/opening_learner
Executable file
BIN
C/opening_learner/opening_learner
Executable file
Binary file not shown.
43
C/opening_learner/run.sh
Executable file
43
C/opening_learner/run.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Install SDL2 dev if sdl2-config is missing; otherwise build and run.
|
||||
|
||||
if ! command -v sdl2-config >/dev/null 2>&1; then
|
||||
echo "sdl2-config not found. Attempting to install SDL2 dev..."
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
case "$ID" in
|
||||
ubuntu|debian|linuxmint|neon|pop)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libsdl2-dev
|
||||
;;
|
||||
arch|manjaro|endeavouros)
|
||||
sudo pacman -Syu --noconfirm sdl2
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf install -y SDL2-devel
|
||||
;;
|
||||
opensuse*|sles)
|
||||
sudo zypper install -y libSDL2-devel
|
||||
;;
|
||||
void)
|
||||
sudo xbps-install -Sy SDL2-devel
|
||||
;;
|
||||
alpine)
|
||||
sudo apk add sdl2-dev
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distro ($ID). Please install SDL2 dev manually and rerun." >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "/etc/os-release not found; cannot auto-detect distro. Install SDL2 dev manually." >&2
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
|
||||
./check_build.sh
|
||||
./opening_learner
|
||||
16
articles/.clang-format
Normal file
16
articles/.clang-format
Normal file
@ -0,0 +1,16 @@
|
||||
BasedOnStyle: LLVM
|
||||
Language: Cpp
|
||||
ColumnLimit: 100
|
||||
ReflowComments: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBraces: Attach
|
||||
PointerAlignment: Left
|
||||
IndentWidth: 2
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
SortIncludes: false
|
||||
@ -2,11 +2,50 @@ CC ?= cc
|
||||
CFLAGS ?= -O2 -Wall -Wextra -pedantic
|
||||
LDFLAGS ?=
|
||||
|
||||
.ONESHELL:
|
||||
|
||||
all: server_c
|
||||
|
||||
server_c: server_c.c
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||
|
||||
format:
|
||||
@command -v clang-format >/dev/null 2>&1 || { echo "clang-format not found"; exit 1; }
|
||||
@echo "Running clang-format (ColumnLimit=100)..."
|
||||
@clang-format -i -style=file server_c.c
|
||||
|
||||
format-check:
|
||||
@command -v clang-format >/dev/null 2>&1 || { echo "clang-format not found"; exit 1; }
|
||||
@echo "Checking formatting with clang-format..."
|
||||
@# Use clang-format dry-run so this works without git and doesn't depend on commit state
|
||||
@if clang-format --dry-run -Werror -style=file server_c.c >/dev/null 2>&1; then \
|
||||
echo "Format check passed"; \
|
||||
else \
|
||||
echo "Formatting changes needed (run 'make format')"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
# fail if any function exceeds 20 non-empty lines between '{' and matching '}'
|
||||
funcsize-check:
|
||||
@echo "Checking function sizes (<= 20 lines)..."
|
||||
@command -v clang-tidy >/dev/null 2>&1 || { echo "clang-tidy not found"; exit 1; }
|
||||
@clang-tidy \
|
||||
-checks=readability-function-size \
|
||||
-warnings-as-errors=readability-function-size \
|
||||
-config='{ "CheckOptions": [ { "key": "readability-function-size.LineThreshold", "value": "20" } ] }' \
|
||||
server_c.c -- -std=gnu11 $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
lint:
|
||||
@echo "Running clang-tidy..."
|
||||
@clang-tidy \
|
||||
-checks=clang-analyzer-*,clang-diagnostic-*,readability-function-size,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling \
|
||||
-config='{ "CheckOptions": [ { "key": "readability-function-size.LineThreshold", "value": "20" } ] }' \
|
||||
server_c.c -- -std=gnu11 $(CFLAGS) $(LDFLAGS) || true
|
||||
@echo "Running cppcheck..."
|
||||
@cppcheck --enable=all --inconclusive --std=c11 --language=c --quiet --inline-suppr --check-level=exhaustive --suppress=missingIncludeSystem server_c.c || true
|
||||
@echo "Checking line length (<= 100 chars) in server_c.c..."
|
||||
@awk 'length($$0)>100{print "server_c.c:" NR ": line too long (" length($$0) " > 100)"; err=1} END{if(err){print "Line length check FAILED"; exit 1} else {print "Line length check passed"}}' server_c.c
|
||||
|
||||
build: minify
|
||||
|
||||
minify:
|
||||
|
||||
479
articles/cppcheck.txt
Normal file
479
articles/cppcheck.txt
Normal file
@ -0,0 +1,479 @@
|
||||
server_c.c:2:0: information: Include file: <arpa/inet.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <arpa/inet.h>
|
||||
^
|
||||
server_c.c:3:0: information: Include file: <errno.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <errno.h>
|
||||
^
|
||||
server_c.c:4:0: information: Include file: <ctype.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <ctype.h>
|
||||
^
|
||||
server_c.c:5:0: information: Include file: <fcntl.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <fcntl.h>
|
||||
^
|
||||
server_c.c:6:0: information: Include file: <netinet/in.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <netinet/in.h>
|
||||
^
|
||||
server_c.c:7:0: information: Include file: <signal.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <signal.h>
|
||||
^
|
||||
server_c.c:8:0: information: Include file: <stdbool.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <stdbool.h>
|
||||
^
|
||||
server_c.c:9:0: information: Include file: <stdio.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <stdio.h>
|
||||
^
|
||||
server_c.c:10:0: information: Include file: <stdlib.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <stdlib.h>
|
||||
^
|
||||
server_c.c:11:0: information: Include file: <string.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <string.h>
|
||||
^
|
||||
server_c.c:12:0: information: Include file: <sys/socket.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <sys/socket.h>
|
||||
^
|
||||
server_c.c:13:0: information: Include file: <sys/stat.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <sys/stat.h>
|
||||
^
|
||||
server_c.c:14:0: information: Include file: <sys/types.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <sys/types.h>
|
||||
^
|
||||
server_c.c:15:0: information: Include file: <time.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <time.h>
|
||||
^
|
||||
server_c.c:16:0: information: Include file: <unistd.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
||||
#include <unistd.h>
|
||||
^
|
||||
server_c.c:0:0: information: Limiting analysis of branches. Use --check-level=exhaustive to analyze all branches. [normalCheckLevelMaxBranches]
|
||||
|
||||
^
|
||||
server_c.c:411:77: warning: Either the condition 'elen<8' is redundant or the array 'ext[4]' is accessed at index 7, which is out of bounds. [arrayIndexOutOfBoundsCond]
|
||||
size_t elen=0; while(ext[elen] && elen<8 && isalnum((unsigned char)ext[elen])) elen++; char* ext_safe=strndup_local(ext,elen?elen:3); if(!ext_safe){ send_response(c,500,"Internal Server Error","application/json","",0,true); return; }
|
||||
^
|
||||
server_c.c:411:45: note: Assuming that condition 'elen<8' is not redundant
|
||||
size_t elen=0; while(ext[elen] && elen<8 && isalnum((unsigned char)ext[elen])) elen++; char* ext_safe=strndup_local(ext,elen?elen:3); if(!ext_safe){ send_response(c,500,"Internal Server Error","application/json","",0,true); return; }
|
||||
^
|
||||
server_c.c:411:77: note: Array index out of bounds
|
||||
size_t elen=0; while(ext[elen] && elen<8 && isalnum((unsigned char)ext[elen])) elen++; char* ext_safe=strndup_local(ext,elen?elen:3); if(!ext_safe){ send_response(c,500,"Internal Server Error","application/json","",0,true); return; }
|
||||
^
|
||||
server_c.c:411:31: style: Array index 'elen' is used before limits check. [arrayIndexThenCheck]
|
||||
size_t elen=0; while(ext[elen] && elen<8 && isalnum((unsigned char)ext[elen])) elen++; char* ext_safe=strndup_local(ext,elen?elen:3); if(!ext_safe){ send_response(c,500,"Internal Server Error","application/json","",0,true); return; }
|
||||
^
|
||||
server_c.c:314:129: style: Condition 'tcontent[0]=='['' is always true [knownConditionTrueFalse]
|
||||
char* tcontent=ltrim_dup(content); if(tcontent && tcontent[0]=='['){ size_t clen=strlen(tcontent); if(clen>=2 && tcontent[0]=='[' && tcontent[clen-1]==']'){
|
||||
^
|
||||
server_c.c:314:66: note: Assuming that condition 'tcontent[0]=='['' is not redundant
|
||||
char* tcontent=ltrim_dup(content); if(tcontent && tcontent[0]=='['){ size_t clen=strlen(tcontent); if(clen>=2 && tcontent[0]=='[' && tcontent[clen-1]==']'){
|
||||
^
|
||||
server_c.c:314:129: note: Condition 'tcontent[0]=='['' is always true
|
||||
char* tcontent=ltrim_dup(content); if(tcontent && tcontent[0]=='['){ size_t clen=strlen(tcontent); if(clen>=2 && tcontent[0]=='[' && tcontent[clen-1]==']'){
|
||||
^
|
||||
server_c.c:463:6: warning: inconclusive: Width 1023 given in format string (no. 2) is smaller than destination buffer 'path[4096]'. [invalidScanfFormatWidth_smaller]
|
||||
if(sscanf(buf, "%15s %1023s", method, path) < 2){ close(c); return; }
|
||||
^
|
||||
server_c.c:289:37: error: Common realloc mistake: 'objs' nulled but not freed upon failure [memleakOnRealloc]
|
||||
if(count==cap){ cap*=2; objs=realloc(objs, cap*sizeof(char*)); }
|
||||
^
|
||||
server_c.c:369:39: error: Common realloc mistake: 'objs' nulled but not freed upon failure [memleakOnRealloc]
|
||||
if(count==cap){ cap*=2; objs=realloc(objs, cap*sizeof(char*)); }
|
||||
^
|
||||
server_c.c:42:136: warning: If memory allocation fails, then there is a possible null pointer dereference: data [nullPointerOutOfMemory]
|
||||
static int write_file_all(const char* path, const char* data, size_t len){ FILE* f=fopen(path,"wb"); if(!f) return -1; size_t n=fwrite(data,1,len,f); fclose(f); return n==len?0:-1; }
|
||||
^
|
||||
server_c.c:312:59: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:169: note: Calling function 'write_file_all', 2nd argument 'arr' value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:42:105: note: Assuming condition is false
|
||||
static int write_file_all(const char* path, const char* data, size_t len){ FILE* f=fopen(path,"wb"); if(!f) return -1; size_t n=fwrite(data,1,len,f); fclose(f); return n==len?0:-1; }
|
||||
^
|
||||
server_c.c:42:136: note: Null pointer dereference
|
||||
static int write_file_all(const char* path, const char* data, size_t len){ FILE* f=fopen(path,"wb"); if(!f) return -1; size_t n=fwrite(data,1,len,f); fclose(f); return n==len?0:-1; }
|
||||
^
|
||||
server_c.c:64:21: warning: If memory allocation fails, then there is a possible null pointer dereference: p [nullPointerOutOfMemory]
|
||||
while((p = strstr(p, qkey))){
|
||||
^
|
||||
server_c.c:358:187: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:360:40: note: Calling function 'json_get_string', 1st argument 'obj' value is 0
|
||||
char* id=json_get_string(obj, "id"); char* title=json_get_string(obj, "title"); char* author=json_get_string(obj, "author"); char* body_s=json_get_string(obj, "body"); char* thumb=json_get_string(obj, "thumb"); long long createdAt=json_get_number(obj, "\"createdAt\"");
|
||||
^
|
||||
server_c.c:59:8: note: Assuming condition is false
|
||||
if(!tmp) return strdup("");
|
||||
^
|
||||
server_c.c:63:19: note: Assignment 'p=json', assigned value is 0
|
||||
const char* p = json;
|
||||
^
|
||||
server_c.c:64:21: note: Null pointer dereference
|
||||
while((p = strstr(p, qkey))){
|
||||
^
|
||||
server_c.c:76:93: warning: If memory allocation fails, then there is a possible null pointer dereference: json [nullPointerOutOfMemory]
|
||||
static long long json_get_number(const char* json, const char* key){ const char* p = strstr(json, key); if(!p) return 0; const char* colon=strchr(p,':'); if(!colon) return 0; const char* v=colon+1; while(*v==' '||*v=='\t') v++; return atoll(v); }
|
||||
^
|
||||
server_c.c:358:187: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:360:262: note: Calling function 'json_get_number', 1st argument 'obj' value is 0
|
||||
char* id=json_get_string(obj, "id"); char* title=json_get_string(obj, "title"); char* author=json_get_string(obj, "author"); char* body_s=json_get_string(obj, "body"); char* thumb=json_get_string(obj, "thumb"); long long createdAt=json_get_number(obj, "\"createdAt\"");
|
||||
^
|
||||
server_c.c:76:93: note: Null pointer dereference
|
||||
static long long json_get_number(const char* json, const char* key){ const char* p = strstr(json, key); if(!p) return 0; const char* colon=strchr(p,':'); if(!colon) return 0; const char* v=colon+1; while(*v==' '||*v=='\t') v++; return atoll(v); }
|
||||
^
|
||||
server_c.c:268:261: warning: If memory allocation fails, then there is a possible null pointer dereference: obj [nullPointerOutOfMemory]
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:241: note: Assuming allocation function fails
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:241: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:261: note: Null pointer dereference
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:285: warning: If memory allocation fails, then there is a possible null pointer dereference: obj [nullPointerOutOfMemory]
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:241: note: Assuming allocation function fails
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:241: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:268:285: note: Null pointer dereference
|
||||
size_t len=strlen(t); size_t i=1; int depth=0; size_t start=0; for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0'; char* got=json_get_string(obj, "\"id\""); int match=got && strcmp(got,id)==0; free(got); if(match){ free(t); return obj; } free(obj); }
|
||||
^
|
||||
server_c.c:283:198: warning: If memory allocation fails, then there is a possible null pointer dereference: obj [nullPointerOutOfMemory]
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:178: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:178: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:198: note: Null pointer dereference
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:222: warning: If memory allocation fails, then there is a possible null pointer dereference: obj [nullPointerOutOfMemory]
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:178: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:178: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:283:222: note: Null pointer dereference
|
||||
for(; i<len; ++i){ char c=t[i]; if(c=='{'){ if(depth==0) start=i; depth++; } else if(c=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:299:46: warning: If memory allocation fails, then there is a possible null pointer dereference: out [nullPointerOutOfMemory]
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t L=strlen(objs[k]); memcpy(out+w, objs[k], L); w+=L; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:299:19: note: Assuming allocation function fails
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t L=strlen(objs[k]); memcpy(out+w, objs[k], L); w+=L; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:299:19: note: Assignment 'out=malloc(total_len+1)', assigned value is 0
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t L=strlen(objs[k]); memcpy(out+w, objs[k], L); w+=L; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:299:46: note: Null pointer dereference
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t L=strlen(objs[k]); memcpy(out+w, objs[k], L); w+=L; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:312:80: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:80: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:121: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:121: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:135: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:135: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:319:49: warning: If memory allocation fails, then there is a possible null pointer dereference: out [nullPointerOutOfMemory]
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assuming allocation function fails
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assignment 'out=malloc(newlen+1)', assigned value is 0
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:49: note: Null pointer dereference
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:172: warning: If memory allocation fails, then there is a possible null pointer dereference: out [nullPointerOutOfMemory]
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assuming allocation function fails
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assignment 'out=malloc(newlen+1)', assigned value is 0
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:172: note: Null pointer dereference
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:186: warning: If memory allocation fails, then there is a possible null pointer dereference: out [nullPointerOutOfMemory]
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assuming allocation function fails
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assignment 'out=malloc(newlen+1)', assigned value is 0
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:186: note: Null pointer dereference
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:321:84: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:84: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:125: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:125: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:139: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:139: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:82: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:82: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:123: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:123: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:137: warning: If memory allocation fails, then there is a possible null pointer dereference: arr [nullPointerOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:137: note: Null pointer dereference
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:358:207: warning: If memory allocation fails, then there is a possible null pointer dereference: obj [nullPointerOutOfMemory]
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:207: note: Null pointer dereference
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:231: warning: If memory allocation fails, then there is a possible null pointer dereference: obj [nullPointerOutOfMemory]
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:231: note: Null pointer dereference
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:363:331: warning: If memory allocation fails, then there is a possible null pointer dereference: thumb [nullPointerOutOfMemory]
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); }
|
||||
^
|
||||
server_c.c:363:314: note: Assuming allocation function fails
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); }
|
||||
^
|
||||
server_c.c:363:314: note: Assignment 'thumb=malloc(urlL)', assigned value is 0
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); }
|
||||
^
|
||||
server_c.c:363:331: note: Null pointer dereference
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); }
|
||||
^
|
||||
server_c.c:376:52: warning: If memory allocation fails, then there is a possible null pointer dereference: out [nullPointerOutOfMemory]
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t Lx=strlen(objs[k]); memcpy(out+w, objs[k], Lx); w+=Lx; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:376:25: note: Assuming allocation function fails
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t Lx=strlen(objs[k]); memcpy(out+w, objs[k], Lx); w+=Lx; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:376:25: note: Assignment 'out=malloc(total_len+1)', assigned value is 0
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t Lx=strlen(objs[k]); memcpy(out+w, objs[k], Lx); w+=Lx; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:376:52: note: Null pointer dereference
|
||||
char* out=malloc(total_len+1); size_t w=0; out[w++]='['; for(size_t k=0;k<count;k++){ size_t Lx=strlen(objs[k]); memcpy(out+w, objs[k], Lx); w+=Lx; if(k+1<count) out[w++]=','; } out[w++]=']'; out[w]='\0';
|
||||
^
|
||||
server_c.c:384:325: warning: If memory allocation fails, then there is a possible null pointer dereference: thumb [nullPointerOutOfMemory]
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); } }
|
||||
^
|
||||
server_c.c:384:308: note: Assuming allocation function fails
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); } }
|
||||
^
|
||||
server_c.c:384:308: note: Assignment 'thumb=malloc(urlL)', assigned value is 0
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); } }
|
||||
^
|
||||
server_c.c:384:325: note: Null pointer dereference
|
||||
if(thumb && strncmp(thumb, "data:",5)==0){ char* mime=NULL; unsigned char* bytes=NULL; size_t bl2=0; if(parse_data_url(thumb,&mime,&bytes,&bl2)==0){ const char* ext=ext_from_mime(mime); char* saved=save_bytes_with_ext(bytes,bl2,ext); if(saved){ free(thumb); size_t urlL=strlen(saved)+2; thumb=malloc(urlL); snprintf(thumb,urlL,"/%s",saved); free(saved); obj_changed=1; } free(mime); free(bytes); } }
|
||||
^
|
||||
server_c.c:312:104: error: If memory allocation fails: pointer addition with NULL pointer. [nullPointerArithmeticOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:59: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:312:104: note: Null pointer addition
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:319:73: error: If memory allocation fails: pointer addition with NULL pointer. [nullPointerArithmeticOutOfMemory]
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assuming allocation function fails
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:25: note: Assignment 'out=malloc(newlen+1)', assigned value is 0
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:319:73: note: Null pointer addition
|
||||
char* out=malloc(newlen+1); size_t w=0; out[w++]='['; memcpy(out+w,obj,Lobj); w+=Lobj; if(!empty){ out[w++]=','; memcpy(out+w, tcontent+1, clen-2); w+=(clen-2); } out[w++]=']'; out[w]='\0'; write_file_all(file, out, w); free(out);
|
||||
^
|
||||
server_c.c:321:108: error: If memory allocation fails: pointer addition with NULL pointer. [nullPointerArithmeticOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:63: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:321:108: note: Null pointer addition
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:106: error: If memory allocation fails: pointer addition with NULL pointer. [nullPointerArithmeticOutOfMemory]
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assuming allocation function fails
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:61: note: Assignment 'arr=malloc(tot+1)', assigned value is 0
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:325:106: note: Null pointer addition
|
||||
size_t L=strlen(obj); size_t tot=L+2; char* arr=malloc(tot+1); size_t w=0; arr[w++]='['; memcpy(arr+w,obj,L); w+=L; arr[w++]=']'; arr[w]='\0'; write_file_all(file, arr, w); free(arr);
|
||||
^
|
||||
server_c.c:136:159: style: Variable 'h' can be declared as const array [constVariable]
|
||||
size_t L=strlen(payload); bytes=malloc(L+1); if(!bytes){ free(mime); return -1; } size_t w=0; for(size_t i=0;i<L;i++){ if(payload[i]=='%' && i+2<L){ char h[3]={payload[i+1],payload[i+2],'\0'}; bytes[w++]=(unsigned char)strtol(h,NULL,16); i+=2; } else if(payload[i]=='+'){ bytes[w++]=' '; } else { bytes[w++]=(unsigned char)payload[i]; } } blen=w; }
|
||||
^
|
||||
server_c.c:465:34: style: Variable 'cl' can be declared as pointer to const [constVariablePointer]
|
||||
size_t content_length=0; char* cl = strcasestr(buf, "Content-Length:"); if(cl){ content_length = strtoul(cl+15, NULL, 10); }
|
||||
^
|
||||
server_c.c:468:9: style: Variable 'hdr_end' can be declared as pointer to const [constVariablePointer]
|
||||
char* hdr_end = strstr(buf, "\r\n\r\n"); size_t header_bytes = hdr_end? (size_t)(hdr_end - buf) + 4 : (size_t)total; size_t have_body = total > (ssize_t)header_bytes ? (size_t)total - header_bytes : 0;
|
||||
^
|
||||
server_c.c:355:47: style: Variable 'L2' is assigned a value that is never used. [unreadVariable]
|
||||
if(t[0] != '['){ free(file); size_t L2=2; send_response(c,200,"OK","application/json","[]",2,true); free(t); return; }
|
||||
^
|
||||
server_c.c:355:45: style: Variable 'L2' is assigned a value that is never used. [unreadVariable]
|
||||
if(t[0] != '['){ free(file); size_t L2=2; send_response(c,200,"OK","application/json","[]",2,true); free(t); return; }
|
||||
^
|
||||
server_c.c:76:93: warning: If memory allocation fails, then there is a possible null pointer dereference: json [ctunullpointerOutOfMemory]
|
||||
static long long json_get_number(const char* json, const char* key){ const char* p = strstr(json, key); if(!p) return 0; const char* colon=strchr(p,':'); if(!colon) return 0; const char* v=colon+1; while(*v==' '||*v=='\t') v++; return atoll(v); }
|
||||
^
|
||||
server_c.c:358:187: note: Assuming allocation function fails
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:358:187: note: Assignment 'obj=malloc(obj_len+1)', assigned value is 0
|
||||
for(; i<len; ++i){ char ch=t[i]; if(ch=='{'){ if(depth==0) start=i; depth++; } else if(ch=='}'){ depth--; if(depth==0){ size_t end=i; size_t obj_len=end-start+1; char* obj=malloc(obj_len+1); memcpy(obj, t+start, obj_len); obj[obj_len]='\0';
|
||||
^
|
||||
server_c.c:360:261: note: Calling function json_get_number, 1st argument is null
|
||||
char* id=json_get_string(obj, "id"); char* title=json_get_string(obj, "title"); char* author=json_get_string(obj, "author"); char* body_s=json_get_string(obj, "body"); char* thumb=json_get_string(obj, "thumb"); long long createdAt=json_get_number(obj, "\"createdAt\"");
|
||||
^
|
||||
server_c.c:76:93: note: Dereferencing argument json that is null
|
||||
static long long json_get_number(const char* json, const char* key){ const char* p = strstr(json, key); if(!p) return 0; const char* colon=strchr(p,':'); if(!colon) return 0; const char* v=colon+1; while(*v==' '||*v=='\t') v++; return atoll(v); }
|
||||
^
|
||||
server_c.c:44:12: style: The function 'append_file_line' is never used. [unusedFunction]
|
||||
static int append_file_line(const char* path, const char* line){ FILE* f=fopen(path,"ab"); if(!f) return -1; size_t n=fwrite(line,1,strlen(line),f); n+=fwrite("\n",1,1,f); fclose(f); return (int)n>=0?0:-1; }
|
||||
^
|
||||
nofile:0:0: information: Active checkers: 117/966 (use --checkers-report=<filename> to see details) [checkersReport]
|
||||
|
||||
@ -1 +1 @@
|
||||
[{"id":"199259f41b8933b8","title":"Whats heveier","body":"A kilogrem of stel or kilogrem of fethers","thumb":"/uploads/27d6402e78a09d65.jpg","createdAt":1757272818104},{"id":"19925965dead21e7","title":"UwU its my first article","body":":)))<div><img src=\"/uploads/27d640335a16f85f.jpg\"><br></div>","thumb":"/uploads/27d640310e163446.jpg","createdAt":1757272235498}]
|
||||
[{"id":"29176c917f1a66c3","title":"full featuresd article","author":"author","body":"<img loading=\"lazy\" decoding=\"async\" src=\"/uploads/29176c9e5c008daf.jpg\" alt=\"image\"><div><br></div><div>This is an important image of course :)</div><div><br></div><div>and nother:<br><img loading=\"lazy\" decoding=\"async\" src=\"/uploads/29176c9f62367245.jpg\" alt=\"image\"><br></div>","thumb":"/uploads/29176c9e7818ee30.jpg","createdAt":1757331025041},{"id":"199259f41b8933b8","title":"Whats heveier","body":"A kilogrem of stel or kilogrem of fethers","thumb":"/uploads/27d6402e78a09d65.jpg","createdAt":1757272818104},{"id":"19925965dead21e7","title":"UwU its my first article","body":":)))<div><img src=\"/uploads/27d640335a16f85f.jpg\"><br></div>","thumb":"/uploads/27d640310e163446.jpg","createdAt":1757272235498}]
|
||||
@ -29,7 +29,7 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
.spinner{width:16px;height:16px;border:2px solid #ccc;border-top-color:#333;border-radius:50%;display:inline-block;animation:spin 1s linear infinite}
|
||||
@keyframes spin{to{transform:rotate(360deg)}}
|
||||
.reading header nav{display:none}
|
||||
.reading #delBtn,.reading #dateInfo{display:none}
|
||||
.reading #delBtn{display:none}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
@ -60,8 +60,11 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
<label>Title</label>
|
||||
<input id="title" type="text" placeholder="Article title"/>
|
||||
|
||||
<label>Author</label>
|
||||
<input id="author" type="text" placeholder="Author (optional)"/>
|
||||
|
||||
<label>Thumbnail</label>
|
||||
<div id="thumbDrop" class="drop">Drop image here or choose…<br><img id="thumbPrev"/></div>
|
||||
<div id="thumbDrop" class="drop">Choose image…<br><img id="thumbPrev"/></div>
|
||||
<input id="thumbFile" type="file"/>
|
||||
|
||||
<label>Body</label>
|
||||
@ -69,12 +72,11 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
<button id="insImg">Insert image</button>
|
||||
<button id="insVid">Insert video</button>
|
||||
</div>
|
||||
<div id="content" contenteditable="true" data-ph="Write here. Drag & drop images/videos where you want them."></div>
|
||||
<div id="content" contenteditable="true" data-ph="Write here, anything html-able should work"></div>
|
||||
|
||||
<div class="controls">
|
||||
<button id="saveBtn">Save</button>
|
||||
<button id="cancelBtn">Cancel</button>
|
||||
<span class="small">Stored locally or on server if available.</span>
|
||||
</div>
|
||||
<input id="imgFile" type="file" hidden>
|
||||
<input id="vidFile" type="file" hidden>
|
||||
@ -88,11 +90,12 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
const loading=$('#loading');
|
||||
const rT=$('#readTitle'), rB=$('#readBody'), rTh=$('#readThumb'), dt=$('#dateInfo');
|
||||
const toList=$('#toList'), toNew=$('#toNew'), back=$('#backBtn'), del=$('#delBtn');
|
||||
const title=$('#title'), content=$('#content');
|
||||
const title=$('#title'), author=$('#author'), content=$('#content');
|
||||
const tDrop=$('#thumbDrop'), tPrev=$('#thumbPrev'), tFile=$('#thumbFile');
|
||||
const insImg=$('#insImg'), insVid=$('#insVid'), imgFile=$('#imgFile'), vidFile=$('#vidFile');
|
||||
const saveBtn=$('#saveBtn'), cancelBtn=$('#cancelBtn');
|
||||
const KEY='articles14k';
|
||||
const PH="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 120'%3E%3Crect width='100%25' height='100%25' fill='%23eee'/%3E%3C/svg%3E";
|
||||
let selId=null; let API=null; let preList; // cache first list to avoid duplicate initial fetches
|
||||
const AC={};
|
||||
function setLoading(on,msg){ if(!loading) return; if(msg) loading.querySelector('.msg').textContent=msg; loading.classList.toggle('hidden',!on); }
|
||||
@ -150,7 +153,7 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
finally{ setLoading(false); }
|
||||
}
|
||||
if(!a.length){listV.innerHTML='<div class="small">No articles yet. Click New to create one.</div>';return}
|
||||
listV.innerHTML=a.map(x=>`<div class="card" data-id="${x.id}"><img loading="lazy" decoding="async" src="${x.thumb||''}" alt="thumb"><h3>${esc(x.title)}</h3></div>`).join('');
|
||||
listV.innerHTML=a.map(x=>`<div class="card" data-id="${x.id}"><img loading="lazy" decoding="async" src="${x.thumb||PH}" alt="thumb"><h3>${esc(x.title)}</h3></div>`).join('');
|
||||
}
|
||||
|
||||
function esc(s){return (s||'').replace(/[&<>]/g,m=>({"&":"&","<":"<",">":">"}[m]))}
|
||||
@ -159,14 +162,11 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
function fileToDataURL(f){return new Promise((res,rej)=>{const r=new FileReader(); r.onload=()=>res(r.result); r.onerror=rej; r.readAsDataURL(f)})}
|
||||
function dataURLToBlob(dataURL){ try{ const [h,b]=dataURL.split(','); const m=h.match(/data:([^;]+)(;base64)?/); if(!m) return null; const mime=m[1]; const isB64=!!m[2]; const raw=isB64? atob(b): decodeURIComponent(b); const arr=new Uint8Array(raw.length); for(let i=0;i<raw.length;i++) arr[i]=raw.charCodeAt(i); return new Blob([arr], {type:mime}); }catch(e){ return null; } }
|
||||
function insertAtSel(node){const s=window.getSelection(); if(!s||!s.rangeCount){content.appendChild(node); return} const r=s.getRangeAt(0); r.deleteContents(); r.insertNode(node); r.setStartAfter(node); r.setEndAfter(node); s.removeAllRanges(); s.addRange(r)}
|
||||
function dropHandler(zone, cb){zone.addEventListener('dragover',e=>{e.preventDefault(); zone.style.background='#f7f7f7'}); zone.addEventListener('dragleave',()=>zone.style.background=''); zone.addEventListener('drop',e=>{e.preventDefault(); zone.style.background=''; const fs=[...(e.dataTransfer.files||[])]; fs.forEach(cb)});}
|
||||
|
||||
// Thumb drag/drop or file select
|
||||
dropHandler(tDrop, f=>{ if(!f.type.startsWith('image/')) return; fileToDataURL(f).then(u=>{tPrev.src=u})});
|
||||
// Thumbnail via file chooser only
|
||||
tFile.addEventListener('change',e=>{const f=e.target.files[0]; if(f) fileToDataURL(f).then(u=>tPrev.src=u)});
|
||||
tDrop.addEventListener('click',()=>tFile.click());
|
||||
|
||||
// Content drag/drop insert and paste
|
||||
content.addEventListener('paste',e=>{const it=(e.clipboardData||{}).items||[]; for(const x of it){const f=x.getAsFile&&x.getAsFile(); if(!f) continue; e.preventDefault(); if(f.type.startsWith('image/')) {
|
||||
// Insert a placeholder while uploading
|
||||
const ph=imgEl(''); ph.alt='image'; ph.style.minHeight='120px'; ph.style.background='#f0f0f0'; insertAtSel(ph);
|
||||
@ -174,10 +174,6 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
} else if(f.type.startsWith('video/')) {
|
||||
fileToDataURL(f).then(u=>{const v=videoEl(u); insertAtSel(v)});
|
||||
} } });
|
||||
dropHandler(content, f=>{ if(f.type.startsWith('image/')) {
|
||||
const ph=imgEl(''); ph.alt='image'; ph.style.minHeight='120px'; ph.style.background='#f0f0f0'; insertAtSel(ph);
|
||||
(async()=>{ const url=await uploadBlobAndGetURL(f); if(url){ ph.removeAttribute('style'); ph.src=url; } else { fileToDataURL(f).then(u=>{ ph.removeAttribute('style'); ph.src=u; }); } })();
|
||||
} else if(f.type.startsWith('video/')) { fileToDataURL(f).then(u=>{const v=videoEl(u); insertAtSel(v)}) } });
|
||||
|
||||
// Insert buttons
|
||||
insImg.onclick=()=>{ imgFile.onchange=async e=>{ const f=e.target.files&&e.target.files[0]; if(!f) return; const ph=imgEl(''); ph.alt='image'; ph.style.minHeight='120px'; ph.style.background='#f0f0f0'; insertAtSel(ph); const url=await uploadBlobAndGetURL(f); if(url){ ph.removeAttribute('style'); ph.src=url; } else { fileToDataURL(f).then(u=>{ ph.removeAttribute('style'); ph.src=u; }); } }; imgFile.click(); };
|
||||
@ -190,7 +186,7 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
let th=tPrev.src||''; if(!th){const fi=content.querySelector('img'); if(fi) th=fi.src}
|
||||
// If thumbnail is data URL, try uploading to separate file so it loads separately
|
||||
if(th && th.startsWith('data:')){ const blob=dataURLToBlob(th); if(blob){ const u=await uploadBlobAndGetURL(blob); if(u) th=u; } }
|
||||
const obj={title:title.value.trim()||'Untitled', body:content.innerHTML, thumb:th||''};
|
||||
const obj={title:title.value.trim()||'Untitled', author:author.value.trim(), body:content.innerHTML, thumb:th||''};
|
||||
setLoading(true,'Saving…');
|
||||
await API.create(obj);
|
||||
selId=null; clearEditor();
|
||||
@ -199,12 +195,12 @@ article h1{margin:.25rem 0 .5rem;font-size:1.6rem}
|
||||
show(listV);
|
||||
};
|
||||
|
||||
function clearEditor(){ title.value=''; content.innerHTML=''; tPrev.removeAttribute('src') }
|
||||
function clearEditor(){ title.value=''; author.value=''; content.innerHTML=''; tPrev.removeAttribute('src') }
|
||||
cancelBtn.onclick=()=>{selId=null; clearEditor(); show(listV)};
|
||||
|
||||
// List click -> read (ensure full focus by switching view)
|
||||
listV.addEventListener('click',async e=>{const card=e.target.closest('.card'); if(!card) return; const id=card.getAttribute('data-id'); const c=AC[id]; if(c){ openRead(c); return; } setLoading(true,'Loading article…'); try{ const a=await API.get(id); if(!a) return; AC[id]=a; openRead(a); } finally { setLoading(false); }});
|
||||
function openRead(a){ selId=a.id; rTh.loading='lazy'; rTh.decoding='async'; rTh.src=a.thumb||''; rT.textContent=a.title||''; rB.innerHTML=a.body||''; rB.querySelectorAll('img').forEach(im=>{ im.loading='lazy'; im.decoding='async'; }); dt.textContent=new Date(a.createdAt||Date.now()).toLocaleString(); show(readV) }
|
||||
function openRead(a){ selId=a.id; rTh.loading='lazy'; rTh.decoding='async'; rTh.src=a.thumb||''; rT.textContent=a.title||''; rB.innerHTML=a.body||''; rB.querySelectorAll('img').forEach(im=>{ im.loading='lazy'; im.decoding='async'; }); const d=new Date(a.createdAt||Date.now()).toLocaleString(); dt.textContent=(a.author? a.author+' · ': '')+d; show(readV) }
|
||||
|
||||
// Delete
|
||||
del.onclick=async()=>{ if(!selId) return; setLoading(true,'Deleting…'); await API.remove(selId); delete AC[selId]; selId=null; await renderList(); setLoading(false); show(listV) };
|
||||
|
||||
1889
articles/server_c.c
1889
articles/server_c.c
File diff suppressed because it is too large
Load Diff
31
articles/tools/funcsize.awk
Normal file
31
articles/tools/funcsize.awk
Normal file
@ -0,0 +1,31 @@
|
||||
BEGIN{ in_func=0; depth=0; start=0; err=0; prev="" }
|
||||
{
|
||||
line=$0
|
||||
# track function start when we see an opening brace at top-level and previous non-empty
|
||||
# line looks like a function signature (ends with ')' and not ';', and not a typedef/struct/enum/union)
|
||||
for(i=1;i<=length(line);i++){
|
||||
c=substr(line,i,1)
|
||||
if(c=="{"){
|
||||
if(depth==0 && !in_func){
|
||||
# Heuristic check on previous non-empty trimmed line
|
||||
t=prev
|
||||
sub(/^\s+/, "", t); sub(/\s+$/, "", t)
|
||||
if(t ~ /\)$/ && t !~ /;\s*$/ && t !~ /^(typedef|struct|enum|union)\b/){
|
||||
in_func=1; start=NR
|
||||
}
|
||||
}
|
||||
depth++
|
||||
} else if(c=="}"){
|
||||
depth--
|
||||
if(in_func && depth==0){
|
||||
lines=NR-start+1
|
||||
if(lines>20){ print FILENAME ":" start " function too long: " lines " lines"; err=1 }
|
||||
in_func=0
|
||||
}
|
||||
}
|
||||
}
|
||||
# update previous non-empty line
|
||||
tmp=line; sub(/^\s+/, "", tmp); sub(/\s+$/, "", tmp)
|
||||
if(length(tmp)>0){ prev=tmp }
|
||||
}
|
||||
END{ if(err) exit 1 }
|
||||
Loading…
Reference in New Issue
Block a user