aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-06-02 02:27:43 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-06-02 02:27:43 +0200
commit7f37c580c4e55468ffedba910d01abffe26154f4 (patch)
tree3e50de469d1d871aa77ea23427d6d72d93c3b5cd
parent5b004563a06dd41e5ba474b82088b5ca516bda85 (diff)
downloadEpisodeBrowser-7f37c580c4e55468ffedba910d01abffe26154f4.tar.gz
Simplify C interface to Prolog.
-rw-r--r--Makefile3
-rw-r--r--c/defs.h3
-rw-r--r--c/episodelistview.c134
-rw-r--r--c/main.c133
-rw-r--r--c/pl.c76
5 files changed, 163 insertions, 186 deletions
diff --git a/Makefile b/Makefile
index a03c3b0..405e8c6 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ B = build/default/
C = c/main.c
PL = pl/cfg.pl pl/episode_data.pl pl/local_episodes.pl pl/track_episodes.pl
-OBJ = $(B)common.obj $(B)datalistview.obj $(B)episodelistview.obj $(B)listview.obj $(B)resource.obj
+OBJ = $(B)common.obj $(B)datalistview.obj $(B)episodelistview.obj $(B)listview.obj $(B)pl.obj $(B)resource.obj
CC = swipl-ld
CFLAGS += -O -ld-options,-mwindows
@@ -10,6 +10,7 @@ CFLAGS += -DUNICODE -D_UNICODE
LDFLAGS += -lcomctl32 -luxtheme
all: $(B)EpisodeBrowser.exe
+ cp $< "C:\Users\John\Desktop\Delat"
$(B)EpisodeBrowser.exe: $(C) $(OBJ) $(PL) c/defs.h Makefile
$(CC) -v $(CFLAGS) $(LDFLAGS) -goal true -o $@ $(C) $(OBJ) $(PL)
diff --git a/c/defs.h b/c/defs.h
index 35f7431..2b4e0ba 100644
--- a/c/defs.h
+++ b/c/defs.h
@@ -30,6 +30,9 @@ void ElvUpdateItem(LPLVITEM);
HWND DlvCreate();
void DlvShowEpisode(int);
+/* pl.c */
+int Pl(char *, char *, char *, ...);
+
/* defs.h */
#define DLVSIKEY 0
#define DLVSIVALUE 1
diff --git a/c/episodelistview.c b/c/episodelistview.c
index ac1ac2f..1fb20e2 100644
--- a/c/episodelistview.c
+++ b/c/episodelistview.c
@@ -15,7 +15,6 @@ HWND
ElvCreate()
{
LVCOLUMN lvc;
- term_t t;
HElv = LvCreate((HMENU)IDC_EPISODELISTVIEW, 0);
@@ -35,9 +34,8 @@ ElvCreate()
lvc.cx = Dpi(30);
ListView_InsertColumn(HElv, ELVSIRATING, &lvc);
- t = T(1);
- P("cfg","get_sort",1,t);
- GI(t,&ISort) ISort = 1;
+ if (!Pl("cfg","get_sort","i",&ISort))
+ ISort = 1;
return HElv;
}
@@ -67,12 +65,9 @@ ElvHandleNotify(LPARAM lParam)
case LVN_COLUMNCLICK: /* Sort by column. */
{
int iColumn;
- term_t t;
- t = T(1);
iColumn = lpNmLv->iSubItem+1;
ISort = abs(ISort) == iColumn? -ISort: iColumn;
- PI(t,ISort) goto s;
- P("cfg","set_sort",1,t);
+ Pl("cfg","set_sort","I",ISort);
s: ElvDoSort();
ElvShowFocus();
break;
@@ -101,11 +96,8 @@ ElvHandleNotify(LPARAM lParam)
break;
case CDDS_ITEMPREPAINT:
{
- term_t t;
extern HFONT HfBold;
- t = T(1);
- PI(t,lpLvCd->nmcd.lItemlParam) break;
- P("track_episodes","watched",1,t) {
+ if (!Pl("track_episodes","watched","I",lpLvCd->nmcd.lItemlParam)) {
SelectObject(lpLvCd->nmcd.hdc, HfBold);
return CDRF_NEWFONT;
}
@@ -116,27 +108,25 @@ ElvHandleNotify(LPARAM lParam)
}
case NM_DBLCLK: /* Open clicked episode. */
{
- term_t t;
- t = T(1);
- PI(t,LviElvFocus.lParam) break;
- P("local_episodes","open_episode_locally",1,t)
- P("local_episodes","open_episode_online",1,t);
+ if (!Pl("local_episodes","open_episode_locally","I",
+ LviElvFocus.lParam))
+ Pl("local_episodes","open_episode_online","I",
+ LviElvFocus.lParam);
break;
}
case NM_RETURN: /* Open all selected episodes. */
{
LVITEM lvi;
- term_t t;
extern HWND HElv;
lvi.mask = LVIF_PARAM;
lvi.iItem = -1;
- t = T(1);
while ((lvi.iItem = ListView_GetNextItem(
HElv, lvi.iItem, LVNI_SELECTED)) != -1) {
if (!ListView_GetItem(HElv, &lvi)) goto b;
- PI(t,lvi.lParam) goto b;
- P("local_episodes","open_episode_locally",1,t)
- P("local_episodes","open_episode_online",1,t);
+ if (!Pl("local_episodes","open_episode_locally","I",
+ lvi.lParam))
+ Pl("local_episodes","open_episode_online","I",
+ lvi.lParam);
}
b: break;
}
@@ -178,12 +168,9 @@ ElvSelectFocus()
{
int i, iEpisode, iItem;
LVFINDINFO lvfi;
- term_t t;
- t = T(1);
iItem = 0;
- P("cfg","get_focus",1,t) goto s;
- GI(t,&iEpisode) return;
+ if (!Pl("cfg","get_focus","i",&iEpisode)) return;
lvfi.flags = LVFI_PARAM;
lvfi.lParam = iEpisode;
@@ -214,10 +201,9 @@ s: ListView_SetItemState(HElv, -1, LVIF_STATE, LVIS_SELECTED);
void
ElvSelectUnwatched(int iDir)
{
- int bShift, i, iEpNew, iItemNew;
+ int i, iEpNew, iItemNew;
LVFINDINFO lvfi;
LVITEM lviFocus;
- term_t t;
/* Get focused episode. */
lviFocus.mask = LVIF_PARAM;
@@ -232,11 +218,9 @@ ElvSelectUnwatched(int iDir)
lvfi.lParam = lviFocus.lParam;
do {
- t = T(2);
- PI(t,lvfi.lParam) return;
- P("track_episodes",iDir > 0? "next_unwatched": "previous_unwatched",2,t)
+ if (!Pl("track_episodes",iDir > 0? "next_unwatched": "previous_unwatched",
+ "Ii",lvfi.lParam,&iEpNew))
return;
- GI(t+1,&iEpNew) return;
lvfi.lParam = iEpNew;
if ((iItemNew = ListView_FindItem(HElv, -1, &lvfi)) != -1) {
@@ -280,18 +264,11 @@ ElvSort(LPARAM iItem1, LPARAM iItem2, LPARAM iSort)
case ELVSIRATING:
{
int iRating1, iRating2;
- term_t t, t2;
iRating1 = iSort > 0? 99: -1;
iRating2 = iSort > 0? 99: -1;
- t = T(2);
- PI(t,lvi1.lParam) goto e;
- P("episode_data","episode_rating",2,t) goto e;
- GI(t+1,&iRating1);
- e: t2 = T(2);
- PI(t2,lvi2.lParam) goto f;
- P("episode_data","episode_rating",2,t2) goto f;
- GI(t2+1,&iRating2);
- f: if (iRating1 == iRating2)
+ Pl("episode_data","episode_rating","Ii",lvi1.lParam,&iRating1);
+ Pl("episode_data","episode_rating","Ii",lvi2.lParam,&iRating2);
+ if (iRating1 == iRating2)
return Cmp(lvi1.lParam, lvi2.lParam);
return iOrder*Cmp(iRating1, iRating2);
break;
@@ -300,15 +277,10 @@ ElvSort(LPARAM iItem1, LPARAM iItem2, LPARAM iSort)
{
char *sz1, *sz2;
int cch, cch1, cch2;
- term_t t, t2;
- t = T(2);
- PI(t,lvi1.lParam) return 0;
- P("episode_data","episode_title",2,t) return 0;
- GAC(t+1,&sz1) return 0;
- t2 = T(2);
- PI(t2,lvi2.lParam) return 0;
- P("episode_data","episode_title",2,t2) return 0;
- GAC(t2+1,&sz2) return 0;
+ if (!Pl("episode_data","episode_title","Is",lvi1.lParam,&sz1))
+ return 0;
+ if (!Pl("episode_data","episode_title","Is",lvi2.lParam,&sz2))
+ return 0;
cch1 = strlen(sz1);
cch2 = strlen(sz2);
cch = cch1 > cch2? cch2: cch1;
@@ -327,7 +299,6 @@ ElvUpdate()
int cEp, i, iEp, iEpFocus, iItem, iItemMark, iItemTopNew;
LVITEM lvi, lviEpisode, lviTop;
LVFINDINFO lvfi;
- term_t t;
extern HWND HWndStatus;
static TCHAR tszDisp[16], tszEpisode[16], tszTotal[16];
static int aEpSel[2048];
@@ -360,45 +331,26 @@ ElvUpdate()
SendMessage(HElv, WM_SETREDRAW, FALSE, 0);
ListView_DeleteAllItems(HElv);
- t = T(1);
- P("episode_data","ensure_episode_data",0,t) return;
- P("episode_data","episode_count",1,t) return;
- GI(t,&cEp) return;
+ if (!Pl("episode_data","ensure_episode_data","")) return;
+ if (!Pl("episode_data","episode_count","i",&cEp)) return;
for (iEp = 1, iItem = 0; iEp <= cEp; iEp++) {
extern char SzLimitScreenwriter[];
extern int BViewTVOriginal, BViewWatched;
- if (SzLimitScreenwriter[0]) {
- atom_t a1, a2;
- term_t t;
- t = T(3);
- a1 = A("Screenwriter");
- a2 = A(SzLimitScreenwriter);
- PI(t,iEp) goto a;
- PA(t+1,a1) goto a;
- PA(t+2,a2) goto a;
- P("episode_data","episode_datum",3,t) continue;
- }
-
- a: if (!BViewWatched) {
- term_t t;
- t = T(1);
- PI(t,iEp) goto b;
- P("track_episodes","watched",1,t) goto b;
- continue;
- }
+ if (SzLimitScreenwriter[0])
+ if (!Pl("episode_data","episode_datum","ISS",
+ iEp,"Screenwriter",SzLimitScreenwriter))
+ continue;
+
+ if (!BViewWatched)
+ if (Pl("track_episodes","watched","I",iEp)) continue;
- b: if (!BViewTVOriginal) {
- term_t t;
- t = T(1);
- PI(t,iEp) goto c;
- P("episode_data","tv_original",1,t) goto c;
- continue;
- }
+ if (!BViewTVOriginal)
+ if (Pl("episode_data","tv_original","I",iEp)) continue;
/* Format episode number string. */
- c: _stprintf_s(tszEpisode, sizeof(tszEpisode), TEXT("%d"), iEp);
+ _stprintf_s(tszEpisode, sizeof(tszEpisode), TEXT("%d"), iEp);
/* Insert item. */
lviEpisode.iItem = iItem++;
@@ -461,28 +413,22 @@ ElvUpdateItem(LPLVITEM lpLvi)
char *szName;
int iRating;
TCHAR *tszName;
- term_t t, t2;
static TCHAR tszRating[3];
- t = T(2);
tszName = NULL;
- PI(t,lpLvi->lParam) goto r;
- P("episode_data","episode_title",2,t) {
- P("episode_data","update_episode_data",0,t) goto r;
- P("episode_data","episode_title",2,t) goto r;
+ if (!Pl("episode_data","episode_title","Is",lpLvi->lParam,&szName)) {
+ if (!Pl("episode_data","update_episode_data","")) goto r;
+ if (!Pl("episode_data","episode_title","Is",lpLvi->lParam,&szName))
+ goto r;
}
- GAC(t+1,&szName) goto r;
tszName = TszFromSz(szName, CP_UTF8);
if (tszName)
ListView_SetItemText(HElv, lpLvi->iItem, ELVSITITLE, tszName);
-r: t2 = T(2);
- PI(t2,lpLvi->lParam) goto f;
- P("episode_data","episode_rating",2,t2) {
+r: if (!Pl("episode_data","episode_rating","Ii",lpLvi->lParam,&iRating)) {
ListView_SetItemText(HElv, lpLvi->iItem, ELVSIRATING, TEXT(""));
goto f;
}
- GI(t2+1,&iRating) goto f;
_stprintf_s(tszRating, sizeof(tszRating), TEXT("%d"), iRating);
ListView_SetItemText(HElv, lpLvi->iItem, ELVSIRATING, tszRating);
diff --git a/c/main.c b/c/main.c
index bcee867..3f94986 100644
--- a/c/main.c
+++ b/c/main.c
@@ -35,7 +35,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR tszErr;
MSG msg;
INITCOMMONCONTROLSEX icc;
- term_t t;
WNDCLASSEX wc;
/* Set constant values. */
@@ -89,8 +88,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
ShowWindow(hWnd, nCmdShow);
/* Populate episode list view. */
- t = T(0);
- P("track_episodes","update_tracked_episodes",0,t);
+ Pl("track_episodes", "update_tracked_episodes", "");
ElvUpdate();
ElvSelectFocus();
@@ -124,34 +122,22 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
FreeLibrary(hModule);
}
SetWindowPos(hWnd, NULL, -1, -1, Dpi(510), Dpi(400), SWP_NOMOVE);
- {
- term_t t;
- t = T(1);
- P("cfg","get_view_watched",1,t) goto s;
- GI(t,&BViewWatched) goto s;
+ if (Pl("cfg","get_view_watched","i",&BViewWatched))
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED,
BViewWatched? MF_CHECKED: MF_UNCHECKED);
- }
- s: {
- term_t t;
- t = T(1);
- P("cfg","get_view_tv_original",1,t) goto t;
- GI(t,&BViewTVOriginal) goto t;
+ if (Pl("cfg","get_view_tv_original","i",&BViewTVOriginal))
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL,
BViewTVOriginal? MF_CHECKED: MF_UNCHECKED);
- }
- t: {
+ {
char *sz;
- term_t t;
- t = T(1);
- P("cfg","get_limit_screenwriter",1,t) goto u;
- GAC(t,&sz) goto u;
+ if (!Pl("cfg","get_limit_screenwriter","s",&sz))
+ goto s;
strcpy_s(SzLimitScreenwriter,
sizeof(SzLimitScreenwriter), sz);
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS,
SzLimitScreenwriter[0]? MF_UNCHECKED: MF_CHECKED);
}
- u: SetupFonts();
+ s: SetupFonts();
DlvCreate();
ElvCreate();
UpdateTheme();
@@ -167,13 +153,9 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
extern HWND HElv;
lvi.mask = LVIF_PARAM;
if ((lvi.iItem=ListView_GetNextItem(HElv,-1,LVNI_FOCUSED)) != -1
- && ListView_GetItem(HElv, &lvi)) {
- term_t t;
- t = T(1);
- PI(t,lvi.lParam) goto q;
- P("cfg","set_focus",1,t);
- }
- q: PostQuitMessage(0);
+ && ListView_GetItem(HElv, &lvi))
+ Pl("cfg","set_focus","I",lvi.lParam);
+ PostQuitMessage(0);
break;
}
case WM_SIZE:
@@ -210,13 +192,9 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
break;
case WA_ACTIVE:
case WA_CLICKACTIVE:
- {
- term_t t;
SetFocus(HFocus);
- t = T(0);
- P("track_episodes","update_tracked_episodes",0,t);
+ Pl("track_episodes","update_tracked_episodes","");
ElvRedraw();
- }
}
break;
case WM_NOTIFY:
@@ -234,21 +212,13 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
ElvUpdate();
break;
case IDM_FILE_FETCH_DATA:
- {
- term_t t;
- t = T(0);
- P("episode_data","update_episode_data",0,t);
+ Pl("episode_data","update_episode_data","");
ElvUpdate();
break;
- }
case IDM_FILE_FETCH_SCREENWRITERS:
- {
- term_t t;
- t = T(0);
- P("episode_data","update_screenwriters",0,t);
+ Pl("episode_data","update_screenwriters","");
ElvUpdate();
break;
- }
case IDM_FILE_ABOUT:
DialogBox(
GetModuleHandle(NULL),
@@ -260,15 +230,12 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case IDM_VIEW_WATCHED:
{
int iEpFocus;
- term_t t;
extern HWND HElv;
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED,
BViewWatched? MF_UNCHECKED: MF_CHECKED);
BViewWatched = !BViewWatched;
ElvUpdate();
- t = T(1);
- PI(t,BViewWatched) break;
- P("cfg","set_view_watched",1,t);
+ Pl("cfg","set_view_watched","I",BViewWatched);
iEpFocus = ListView_GetNextItem(HElv, -1, LVNI_FOCUSED);
if (iEpFocus == -1) break;
ListView_EnsureVisible(HElv, iEpFocus, TRUE);
@@ -277,15 +244,12 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case IDM_VIEW_TV_ORIGINAL:
{
int iEpFocus;
- term_t t;
extern HWND HElv;
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL,
BViewTVOriginal? MF_UNCHECKED: MF_CHECKED);
BViewTVOriginal = !BViewTVOriginal;
ElvUpdate();
- t = T(1);
- PI(t,BViewTVOriginal) break;
- P("cfg","set_view_tv_original",1,t);
+ Pl("cfg","set_view_tv_original","I",BViewTVOriginal);
iEpFocus = ListView_GetNextItem(HElv, -1, LVNI_FOCUSED);
if (iEpFocus == -1) break;
ListView_EnsureVisible(HElv, iEpFocus, TRUE);
@@ -293,40 +257,31 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
case IDM_VIEW_OTHERS: /* Show/hide other screenwriters. */
{
- atom_t a;
int iEpFocus;
- term_t t;
extern HWND HElv;
if (SzLimitScreenwriter[0]) {
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS,
MF_CHECKED);
SzLimitScreenwriter[0] = 0;
} else {
- atom_t a;
char *sz;
LVITEM lvi;
- term_t t;
iEpFocus = ListView_GetNextItem(HElv, -1, LVNI_FOCUSED);
if (iEpFocus == -1) break;
lvi.iItem = iEpFocus;
lvi.mask = LVIF_PARAM;
if (!ListView_GetItem(HElv, &lvi)) break;
- t = T(3);
- a = A("Screenwriter");
- PI(t,lvi.lParam) break;
- PA(t+1,a) break;
- P("episode_data","episode_datum",3,t) break;
- GAC(t+2,&sz) break;
+ if (!Pl("episode_data","episode_datum","ISs",
+ lvi.lParam,"Screenwriter",&sz))
+ break;
strcpy_s(SzLimitScreenwriter,
sizeof(SzLimitScreenwriter), sz);
CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS,
MF_UNCHECKED);
}
ElvUpdate();
- t = T(1);
- a = A(SzLimitScreenwriter);
- PA(t,a) break;
- P("cfg","set_limit_screenwriter",1,t);
+ Pl("cfg","set_limit_screenwriter","S",
+ SzLimitScreenwriter);
iEpFocus = ListView_GetNextItem(HElv, -1, LVNI_FOCUSED);
if (iEpFocus == -1) break;
ListView_EnsureVisible(HElv, iEpFocus, TRUE);
@@ -350,8 +305,8 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case IDM_RATE1:
case IDM_RATE0:
{
+ int iRating;
LVITEM lvi;
- term_t t;
extern HWND HElv;
/* Look through selected items, applying the
@@ -359,70 +314,68 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
lvi.mask = LVIF_PARAM;
lvi.iItem = -1;
- t = T(2);
while ((lvi.iItem = ListView_GetNextItem(
HElv, lvi.iItem, LVNI_SELECTED)) != -1) {
if (!ListView_GetItem(HElv, &lvi)) goto b;
- PI(t,lvi.lParam) goto b;
switch (LOWORD(wParam)) {
case IDM_WATCH_LOCALLY:
- P("local_episode","open_episode_locally",1,t);
+ Pl("local_episode","open_episode_locally","I",lvi.lParam);
break;
case IDM_WATCH_ONLINE:
- P("local_episode","open_episode_online",1,t);
+ Pl("local_episode","open_episode_online","I",lvi.lParam);
break;
case IDM_TOGGLE:
- P("track_episodes","toggle_episode",1,t);
+ Pl("track_episodes","toggle_episode","I",lvi.lParam);
ElvRedraw();
break;
case IDM_FORGET:
- P("track_episodes","forget_episode",1,t);
- P("track_episodes","update_tracked_episodes",0,t);
+ Pl("track_episodes","forget_episode","I",lvi.lParam);
+ Pl("track_episodes","update_tracked_episodes","");
ElvRedraw();
break;
case IDM_LOOKUP:
- P("episode_data","retract_episode",1,t);
+ Pl("episode_data","retract_episode","I",lvi.lParam);
ElvUpdateItem(&lvi);
ElvRedraw();
DlvShowEpisode(lvi.lParam);
break;
case IDM_WIKI:
- P("episode_data","open_episode_wiki",1,t);
+ Pl("episode_data","open_episode_wiki","I",lvi.lParam);
break;
case IDM_RATE10:
- PI(t+1,10) break;
+ iRating = 0;
goto r;
case IDM_RATE9:
- PI(t+1,9) break;
+ iRating = 9;
goto r;
case IDM_RATE8:
- PI(t+1,8) break;
+ iRating = 8;
goto r;
case IDM_RATE7:
- PI(t+1,7) break;
+ iRating = 7;
goto r;
case IDM_RATE6:
- PI(t+1,6) break;
+ iRating = 6;
goto r;
case IDM_RATE5:
- PI(t+1,5) break;
+ iRating = 5;
goto r;
case IDM_RATE4:
- PI(t+1,4) break;
+ iRating = 4;
goto r;
case IDM_RATE3:
- PI(t+1,3) break;
+ iRating = 3;
goto r;
case IDM_RATE2:
- PI(t+1,2) break;
+ iRating = 2;
goto r;
case IDM_RATE1:
- PI(t+1,1) break;
+ iRating = 1;
goto r;
case IDM_RATE0:
- PI(t+1,0) break;
- r: P("episode_data","rate_episode",2,t);
+ iRating = 0;
+ r: Pl("episode_data","rate_episode","II",lvi.lParam,iRating);
ElvUpdateItem(&lvi);
break;
}
@@ -499,10 +452,8 @@ CreateStatusBar(HWND hWndParent, HINSTANCE hInstance)
int
Attach()
{
- term_t t;
- t = T(0);
- P("track_episodes","attach",0,t) return 0;
- P("episode_data","attach",0,t) return 0;
+ if (!Pl("track_episodes","attach","")) return 0;
+ if (!Pl("episode_data","attach","")) return 0;
return 1;
}
diff --git a/c/pl.c b/c/pl.c
new file mode 100644
index 0000000..6f7a07d
--- /dev/null
+++ b/c/pl.c
@@ -0,0 +1,76 @@
+#include <stdarg.h>
+#include <string.h>
+#include <SWI-Prolog.h>
+
+int
+Pl(char *szMod, char *szPred, char *szFmt, ...)
+{
+ int i, iArity;
+ term_t t;
+ va_list vl;
+
+ va_start(vl, szFmt);
+ iArity = strlen(szFmt);
+ t = PL_new_term_refs(iArity);
+
+ for (i = 0; szFmt[i]; i++) {
+ switch (szFmt[i]) {
+ case 'I':
+ {
+ int x;
+ x = va_arg(vl, int);
+ if (!PL_put_integer(t+i, x)) return 0;
+ break;
+ }
+ case 'A':
+ {
+ atom_t x;
+ x = va_arg(vl, atom_t);
+ if (!PL_put_atom(t+i, x)) return 0;
+ break;
+ }
+ case 'S':
+ {
+ atom_t a;
+ char *x;
+ x = va_arg(vl, char *);
+ a = PL_new_atom(x);
+ if (!PL_put_atom(t+i, a)) return 0;
+ break;
+ }
+ }
+ }
+
+ if (!PL_call_predicate(NULL, PL_Q_NORMAL,
+ PL_predicate(szPred, iArity, szMod), t))
+ return 0;
+
+ for (i = 0; szFmt[i]; i++) {
+ switch (szFmt[i]) {
+ case 'i':
+ {
+ int *lp;
+ lp = va_arg(vl, int *);
+ if (!PL_get_integer(t+i, lp)) return 0;
+ break;
+ }
+ case 'a':
+ {
+ atom_t *lp;
+ lp = va_arg(vl, atom_t *);
+ if (!PL_get_atom(t+i, lp)) return 0;
+ break;
+ }
+ case 's':
+ {
+ char **lp;
+ lp = va_arg(vl, char **);
+ if (!PL_get_atom_chars(t+i, lp)) return 0;
+ break;
+ }
+ }
+ }
+
+ va_end(vl);
+ return 1;
+}