의미가 보이는 C 프로젝트를 작성하기
by
gg582 · 2026-07-06 10:46:37 · 124 views
프로젝트 명세
나는 최근 들어 미니멀리스트 TODO 앱 todox를 작성하고 있었다.
이 todox의 골자는 단순하다. 복잡한 일정 관리 앱을 쓰느니, D-Bus에 바로 알림을 꽂아서 잊기 좋은 일정을 확인하자는 것이다.
src
├── app
│ ├── app.c
│ ├── io.c
│ └── parse.c
├── error
│ └── error.c
├── list
│ └── list.c
├── main.c
├── notify
│ ├── dbus.c
│ └── notify.c
├── repeat
│ └── repeat.c
└── time
├── table.c
└── time.c
include/
├── app
│ ├── app.h
│ ├── io.h
│ └── parse.h
├── error
│ └── error.h
├── file
│ ├── config.h
│ └── format.h
├── list
│ └── list.h
├── notify
│ └── notify.h
└── repeat
└── repeat.h
즉 핵심이 되는 것은 time 폴더의 알람 시간 관리, app 경로의 I/O와 파싱 로직, notify 폴더의 알림 로직, list 폴더의 알람 목록 관리 로직이다.
그리고 알람을 쉽게 관리하기 위해서, Perl GUI 스크립트 todoxy.pl이 설치되어 있다.
우리는 요일 반복 기능을 더 확장해서, 몇 주간만 요일을 반복할 수 있게 할 것이다.
이 중 우리가 유심히 봐야 할 것은 repeat.h, 그리고 todox의 기본 기능이다.
Todox의 기본 기능
todox의 기본 기능은 매우 간단하여, todox --help로도 쉽게 살필 수 있다.
usage: todox [command] [file] [args]
commands:
(none) parse and list alarms
add [file] "TS%%TASK%%COMMENT" add an alarm
add [file] "TS%%TASK%%COMMENT%%repeat"
add a weekly repeating alarm
add [file] "DAY%%TIME%%TASK%%COMMENT" add a weekly alarm on DAY at TIME
remove [file] "TASK" remove an alarm
--daemonize [file] run notification daemon in background
notes:
if TODOX_ALARM_FILE is set, the [file] argument can be omitted.
install.sh sets TODOX_ALARM_FILE in the service, so after installation
most commands do not need a file path.
date can be omitted from TS; time-only input is treated as today.
e.g. "21:00:00 +0900%%task%%comment" uses today's date.
DAY is a weekday expression: mon, tue, wed, thu, fri, sat, sun,
a range such as mon-fri, or a list such as mon:wed:fri.
TIME is a time of day with an optional timezone: HH:MM:SS [+|-]HHMM.
alarms created with DAY or the %%repeat token fire every week.
the daemon advances repeating alarms by one week after they fire.
examples:
todox alarm.txt
TODOX_ALARM_FILE=alarm.txt todox
todox add alarm.txt "1970-01-01 00:00:00 +0000%%test title%%test comment"
TODOX_ALARM_FILE=alarm.txt todox add "1970-01-01 00:00:00 +0000%%test title%%test comment"
todox add "21:00:00 +0900%%task%%comment" (today's date)
todox add "mon-fri%%09:00:00 +0900%%standup%%daily sync" (weekday alarm)
todox add "mon:wed:fri%%21:00:00 +0900%%gym%%workout" (selected weekdays)
todox add "09:00:00 +0900%%report%%weekly%%repeat" (weekly repeat)
todox remove alarm.txt "test title"
TODOX_ALARM_FILE=alarm.txt todox remove "test title"
todox --daemonize alarm.txt
TODOX_ALARM_FILE=alarm.txt todox --daemonize
그리고, todox만 칠 시 예약된 알람 목록을 보여 준다.
yjlee@elegant:~$ todox
2026-07-06 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-06 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-06 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-07 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
2026-07-07 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-07 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-07 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-08 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
2026-07-08 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-08 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-08 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-09 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
2026-07-09 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-09 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-09 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-10 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
2026-07-10 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-10 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-10 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-11 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
2026-07-11 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-11 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-11 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-12 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
2026-07-12 12:00:00 +0000 | 약을 먹읍시다 | 건강은 중요해요 | repeat
2026-07-12 13:00:00 +0000 | 비타민을 드세요 | 건강보조제 중요하죠 | repeat
2026-07-12 14:00:00 +0000 | 잠을 잡시다 | 일찍 자고 일찍 일어납시다 | repeat
2026-07-13 05:00:00 +0000 | 산책을 하세요 | 취업 준비도 쉬어 가면서 해요 | repeat
yjlee@elegant:~$
이와 같이 복약 지도, 비타민 복용, 산책과 같은 일정이 아래에 보이며, 유효 기간이 자동으로 갱신되는 알람들의 경우 우측에 repeat 태그 등이 보인다.
이 때, 같은 유형의 알람은 동일한 레이블을 가지며, 산책 일정을 삭제하고 싶다면 todox remove "산책을 하세요"로 간단하게 기본 알람 파일에서 삭제할 수 있음을 알 수 있다.
그렇다면, 이 앱의 기본 알람 파일은 어디에 있을까?
yjlee@elegant:~$ echo $TODOX_ALARM_FILE
/usr/local/etc/todox/alarm.txt
이 앱의 기본 알람 파일은 /usr/local/etc/todox/alarm.txt에 있다. 열어 보자.
2026-07-06 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-06 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-06 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-07 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
2026-07-07 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-07 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-07 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-08 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
2026-07-08 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-08 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-08 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-09 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
2026-07-09 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-09 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-09 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-10 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
2026-07-10 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-10 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-10 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-11 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
2026-07-11 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-11 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-11 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-12 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
2026-07-12 12:00:00 +0000%%약을 먹읍시다%%건강은 중요해요%%repeat
2026-07-12 13:00:00 +0000%%비타민을 드세요%%건강보조제 중요하죠%%repeat
2026-07-12 14:00:00 +0000%%잠을 잡시다%%일찍 자고 일찍 일어납시다%%repeat
2026-07-13 05:00:00 +0000%%산책을 하세요%%취업 준비도 쉬어 가면서 해요%%repeat
이 포맷을 파일로부터 직접 읽어 파싱하나, todox의 결과를 파싱하나 정보의 질이 동일하고 표시 포맷만 다른 것을 볼 수 있다.
언뜻 보기에는 구간 알람을 추가하기 위해 반복 여부만 불리언 처리하는 repeat 플래그를 "repeat?14"와 같이 확장해야 할 것처럼 보이다.
그러나, 이러한 부분은 소스를 직접 보면 고민이 깊어진다.
소스 (repeat.h)
#ifndef TODOX_FORMAT_H
#define TODOX_FORMAT_H
#include <stddef.h>
#include <stdio.h>
#include <time.h>
#define TODOX_TIME_FORMAT "%Y-%m-%d %H:%M:%S %z"
#define TODOX_TIME_COMPAT_FORMAT "%Y-%m-%d %H:%M:%S"
#define TODOX_ALARM_MAX_LEN 1024
#define TODOX_ALARM_TABLE_MAX_ROWS 128
#define TODOX_ALARM_TASK_MAX_LEN 256
#define TODOX_ALARM_COMMENT_MAX_LEN 256
/** @struct todox_format_t
* @brief a data format of todolist.
*/
typedef struct __todox_format_t {
/// unix timestamp
time_t ts;
/// a name of a task
char task[TODOX_ALARM_TASK_MAX_LEN];
/// a comment section of a task
char comment[TODOX_ALARM_COMMENT_MAX_LEN];
/// true when the alarm repeats weekly
bool does_repeat;
} todox_format_t;
/** @brief converts an ISO 8601 datetime string to time_t.
* @param[in] ts an ISO 8601 datetime string.
* @return a unix timestamp, or (time_t)-1 on failure.
*/
time_t iso8601_to_time_t(const char *ts);
#endif
여기서 does_repeat 불리언의 경우가 문제다.
만약 2주 간만 알람을 반복하는 포맷을 만들려고 하면, 해당 플래그가 새로운 도메인으로 확장되어야 할 것이다.
예를 들면:
typedef struct todox_repetitive_task {
/// true when the alarm is repetitive
bool does_repeat;
/// last alarm time to repeat
time_t last_alarm;
/** interval of the alarm.
* zero is regarded as one.
*/
uint16_t days_interval;
/// calendar system of the alarm
char[32] calendar_system;
}
구조체가 복잡해질 뿐더러, 상위 레이어까지 CLI 앱에 섞여서 관리가 어려워진다.
그러나 우리는 리눅스 시스템에서 비교적 잘 지원하는 Perl을 이용한 GUI 래퍼 스크립트를 작성하였으며, C언어 구현을 복잡하게 만들지 않고도 Perl을 이용하여 추상적인 구문을 todox가 이해할 수 있는 명시적 표준시 알람으로 변환하면 된다.
또한, todox의 포맷은 충분히 래핑하기 좋은 구조였기 때문에 굳이 래퍼의 구문 파서 부분과 todox 모두를 고쳐야 하는 수정을 하는 대신, 현재대로 두는 것이 사용자가 직접 메모장을 열어 알람을 바꾸는 시나리오에 유익하다.
그렇다면, 이 애플리케이션에 몇 주까지 반복하는지 등록할 필요가 없다.
만약 2주 동안만 반영하고 싶다면, 그 2주 치 알람을 Perl 스크립트가 계산하여 명령어로 변경하면 된다.
그리고, AI 시대에 단순한 Perl 스크립트를 생성하는 것쯤은 어려운 선택이 아니다.
심지어는 에티오피아력/율리우스력, 회회력(이슬람 음력), 현대 음력(아담 샬의 시헌력 기반)까지도 모두 CPAN에서 제공하는 역법 라이브러리를 이용하여서 문화권을 교차하는 지원까지 C 단을 건드리지 않고 수정할 수 있다.
사용자는 todox의 내부 포맷을 몰라도, 심지어는 음력 생일을 등록해야 할 때도 아무런 의심도 하지 않고 GUI 래퍼를 사용하면 그만인 것이다.
생각할 거리
만약 AI 코파일럿에세 TODO 앱을 만들라고 한 후 낮잠을 자고 일어났어도, TODO 앱은 정상적으로 구동되는 결과물을 가졌을 것이다. 하지만 몇 가지 보일러플레이트 코드 작성을 제외하고 손으로 모델링하고 구조를 작성하면, 4000줄의 QT 앱이 나오는 대신, 1193줄의 C 데몬과 946줄의 Perl 스크립트만으로 리눅스/유닉스 데스크톱에 유기적으로 통합된 일정 관리 앱을 만들 수 있었다.
이러한 상황에서, 정말 AI를 위한 PLANS.md를 더 잘 쓰는 것만이 미래적인 결론일까?
아니, 적어도 이 프로그램을 작성할 때에는 그렇지 않았다고 할 수 있다.
프로그램의 작성에는 다양한 맥락이 있다. 그리고 AI의 사용 범위 역시 성격에 따라 크게 달라질 수 있다.
그리고 이런 흐름은 이 맥락에선 이렇게 말할 수 있다.
목적이 단순하면, 모델링 방식도 단순해야 한다.
그리고 아직까지는 단순한 설계는 AI에게 취약한 부분일 수 있다.