summaryrefslogtreecommitdiff
path: root/src/xine-engine/nvtvd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-engine/nvtvd.c')
-rw-r--r--src/xine-engine/nvtvd.c761
1 files changed, 761 insertions, 0 deletions
diff --git a/src/xine-engine/nvtvd.c b/src/xine-engine/nvtvd.c
new file mode 100644
index 000000000..b9f01b956
--- /dev/null
+++ b/src/xine-engine/nvtvd.c
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2000-2002 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: nvtvd.c,v 1.1 2002/06/10 21:42:45 mshopf Exp $
+ *
+ * nvtvd - Routines for communication with nvtvd.
+ *
+ * This is the combination of several files from the nvtvd package
+ * by Dirk Thierbach <dthierbach@gmx.de>. They have been inserted into
+ * one single file in order not to clutter the source filespace too much.
+ * The only change has been the removal of some '#include' statements,
+ * and only a small fraction from debug.h has been included.
+ *
+ * This file contains (in this order):
+ * pipe.h debug.h back_client.c pipe.c
+ */
+
+#include "nvtvd.h"
+
+
+/* NVTV pipe header -- Dirk Thierbach <dthierbach@gmx.de>
+ *
+ * This file is part of nvtv, a tool for tv-output on NVidia cards.
+ *
+ * nvtv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nvtv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: nvtvd.c,v 1.1 2002/06/10 21:42:45 mshopf Exp $
+ *
+ * Contents:
+ *
+ * Routine prototypes to access the named pipe for server/client
+ * communication, and communication protocol constants.
+ *
+ */
+
+#ifndef _PIPE_H
+#define _PIPE_H
+
+#define PIPE_IN "/tmp/.nvtv-in"
+#define PIPE_OUT "/tmp/.nvtv-out"
+
+#define PIPE_VERSION 2 /* 0.3.1 */
+
+/* even commands expect no return, odd commands do */
+
+typedef enum {
+ PCmd_None = 0, /* In: None */
+ PCmd_Init = 1, /* In: None; Out: card list */
+ PCmd_Kill = 2, /* In: None */
+ PCmd_Version = 3, /* In: None; Out: version */
+ PCmd_CloseCard = 10, /* In: None */
+ PCmd_OpenCard = 11, /* In: Card index; Out: chip list */
+ PCmd_SetChip = 12, /* In: Chip index, init; */
+ PCmd_ProbeChips = 13, /* In: None; Out: chip list */
+ PCmd_SetSettings = 14, /* In: Settings; */
+ PCmd_GetSettings = 15, /* In: None; Out: Settings */
+ PCmd_SetMode = 16, /* In: Flags, crt, tv; */
+ PCmd_GetMode = 17, /* In: None; Out: Crt, tv */
+ PCmd_SetModeSettings = 18, /* In: Flags, crt, tv, set; */
+ PCmd_SetTestImage = 20, /* In: Flags, tv, set; */
+ PCmd_GetStatus = 23, /* In: Index; Out: status */
+ PCmd_GetConnection = 25, /* In: None; Out: connect */
+ PCmd_FindBySize = 31, /* In: System, x, y, size; Out: mode */
+ PCmd_FindByOverscan = 33, /* In: System, x, y, hoc, voc; Out: mode */
+ PCmd_SetHeads = 40, /* In: 3 heads */
+ PCmd_GetHeads = 41, /* In: None; Out: 3 heads */
+ PCmd_InitSharedView = 51, /* In: None; Out: 4 int */
+ PCmd_GetTwinView = 53, /* In: None; Out: 2 int, bool */
+ PCmd_AdjustView = 55, /* In: 3 int; Out: 2 int, bool */
+ PCmd_ServiceVC = 57, /* In: 5 int; Out: 2 int, bool */
+} PipeCmd;
+
+PipeCmd pipeReadCmd (FILE *pipe);
+void pipeWriteCmd (FILE *pipe, PipeCmd cmd);
+
+int pipeReadArgs (FILE *pipe, int n, ...);
+int pipeReadArgsOpt (FILE *pipe, int n, ...);
+void pipeWriteArgs (FILE *pipe, int n, ...);
+
+void* pipeReadList (FILE *pipe, int size);
+void pipeWriteList (FILE *pipe, int size, void *list);
+
+#endif /* _PIPE_H */
+
+/* excerpt from debug.h */
+#define ERROR(X...) fprintf(stderr, X)
+
+/* Fake output */
+#define FPRINTF(X...) fprintf(stderr, X)
+
+#ifdef NVTV_DEBUG
+#define DPRINTF(X...) fprintf(stderr, X)
+#define NO_TIMEOUT
+#else
+#define DPRINTF(X...) /* */
+#endif
+
+/* NVTV client backend -- Dirk Thierbach <dthierbach@gmx.de>
+ *
+ * This file is part of nvtv, a tool for tv-output on NVidia cards.
+ *
+ * nvtv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nvtv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: nvtvd.c,v 1.1 2002/06/10 21:42:45 mshopf Exp $
+ *
+ * Contents:
+ *
+ * Client backend for accessing the server
+ *
+ */
+
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* -------- State -------- */
+
+static FILE *pipe_in = NULL;
+static FILE *pipe_out = NULL;
+
+static CardPtr bcl_root = NULL;
+static CardPtr bcl_card = NULL;
+
+/* -------- Driver routines -------- */
+
+void bcl_openPipes (void)
+{
+ /* IMPORTANT: Open out pipe first, otherwise deadlock */
+ pipe_out = fopen (PIPE_OUT, "w");
+ pipe_in = fopen (PIPE_IN, "r");
+}
+
+void bcl_closePipes (void)
+{
+ fclose (pipe_in );
+ fclose (pipe_out);
+}
+
+void bcl_openCard (CardPtr card)
+{
+ CardPtr c;
+ int i, index;
+
+ DPRINTF ("bcl_open\n");
+ bcl_card = card;
+ bcl_openPipes ();
+ /* convert card to index */
+ i = index = 0;
+ for (c = bcl_root; c; c = c->next) {
+ i++;
+ if (c == card) index = i;
+ }
+ pipeWriteCmd (pipe_out, PCmd_OpenCard);
+ pipeWriteArgs (pipe_out, 1, sizeof(index), &index);
+ pipeReadCmd (pipe_in);
+ bcl_card->chips = pipeReadList (pipe_in, sizeof (ChipInfo));
+}
+
+void bcl_closeCard (void)
+{
+ DPRINTF ("bcl_close\n");
+ pipeWriteCmd (pipe_out, PCmd_CloseCard);
+ pipeWriteArgs (pipe_out, 0);
+ bcl_closePipes ();
+}
+
+void bcl_setHeads (int main, int tv, int video)
+{
+ DPRINTF ("bcl_setHeads %i %i %i\n", main, tv, video);
+ pipeWriteCmd (pipe_out, PCmd_SetHeads);
+ pipeWriteArgs (pipe_out, 3, sizeof(int), &main, sizeof(int), &tv,
+ sizeof(int), &video);
+}
+
+void bcl_getHeads (int *main, int *tv, int *video, int *max)
+{
+ DPRINTF ("bcl_getHeads\n");
+ pipeWriteCmd (pipe_out, PCmd_GetHeads);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 4, sizeof(int), main, sizeof(int), tv,
+ sizeof(int), video, sizeof(int), max);
+}
+
+void bcl_probeChips (void)
+{
+ ChipPtr chip, del;
+
+ DPRINTF ("bcl_probe\n");
+ chip = bcl_card->chips;
+ while (chip) {
+ del = chip;
+ chip = chip->next;
+ free (del->name);
+ free (del);
+ }
+ pipeWriteCmd (pipe_out, PCmd_ProbeChips);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ bcl_card->chips = pipeReadList (pipe_in, sizeof (ChipInfo));
+}
+
+void bcl_setChip (ChipPtr chip, Bool init)
+{
+ ChipPtr c;
+ int i, index;
+
+ DPRINTF ("bcl_setChip %s %i\n", chip->name, init);
+ /* convert chip to index */
+ i = index = 0;
+ for (c = bcl_card->chips; c; c = c->next) {
+ i++;
+ if (c == chip) index = i;
+ }
+ pipeWriteCmd (pipe_out, PCmd_SetChip);
+ pipeWriteArgs (pipe_out, 2, sizeof(index), &index, sizeof(init), &init);
+}
+
+void bcl_setSettings (TVSettings *set)
+{
+ DPRINTF ("bcl_setSettings\n");
+ pipeWriteCmd (pipe_out, PCmd_SetSettings);
+ pipeWriteArgs (pipe_out, 1, sizeof(TVSettings), set);
+}
+
+void bcl_getSettings (TVSettings *set)
+{
+ DPRINTF ("bcl_getSettings\n");
+ pipeWriteCmd (pipe_out, PCmd_GetSettings);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 1, sizeof(TVSettings), set);
+}
+
+void bcl_setMode (int ModeFlags, TVCrtRegs *crt, TVRegs *tv)
+{
+ DPRINTF ("bcl_setMode\n");
+ pipeWriteCmd (pipe_out, PCmd_SetMode);
+ pipeWriteArgs (pipe_out, 3, sizeof(ModeFlags), &ModeFlags,
+ sizeof(TVCrtRegs), crt, sizeof(TVRegs), tv);
+}
+
+void bcl_getMode (TVCrtRegs *crt, TVRegs *tv)
+{
+ DPRINTF ("bcl_getMode\n");
+ pipeWriteCmd (pipe_out, PCmd_GetMode);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 2, sizeof(TVCrtRegs), crt, sizeof(TVRegs), tv);
+}
+
+void bcl_setModeSettings (int ModeFlags, TVCrtRegs *crt,
+ TVRegs *tv, TVSettings *set)
+{
+ DPRINTF ("bcl_setModeSettings\n");
+ pipeWriteCmd (pipe_out, PCmd_SetModeSettings);
+ pipeWriteArgs (pipe_out, 4, sizeof(ModeFlags), &ModeFlags,
+ sizeof(TVCrtRegs), crt, sizeof(TVRegs), tv,
+ sizeof(TVSettings), set);
+}
+
+void bcl_setTestImage (int ModeFlags, TVRegs *tv, TVSettings *set)
+{
+ DPRINTF ("bcl_setTestImage\n");
+ pipeWriteCmd (pipe_out, PCmd_SetTestImage);
+ pipeWriteArgs (pipe_out, 3, sizeof(int), &ModeFlags,
+ sizeof(TVRegs), tv, sizeof(TVSettings), set);
+}
+
+long bcl_getStatus (int index)
+{
+ long l;
+
+ DPRINTF ("bcl_getStatus\n");
+ pipeWriteCmd (pipe_out, PCmd_GetStatus);
+ pipeWriteArgs (pipe_out, 1, sizeof(index), &index);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 1, sizeof(l), &l);
+ return l;
+}
+
+TVConnect bcl_getConnection (void)
+{
+ TVConnect c;
+
+ DPRINTF ("bcl_getConnection\n");
+ pipeWriteCmd (pipe_out, PCmd_GetConnection);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 1, sizeof(c), &c);
+ DPRINTF ("bcl_getConnection got %i\n", c);
+ return c;
+}
+
+Bool bcl_findBySize (TVSystem system, int xres, int yres, char *size,
+ TVMode *mode, TVCrtRegs *crt, TVRegs *tv)
+{
+ int n;
+
+ DPRINTF ("bcl_findBySize %i %i,%i %s\n", system, xres, yres, size);
+ pipeWriteCmd (pipe_out, PCmd_FindBySize);
+ pipeWriteArgs (pipe_out, 4, sizeof(system), &system,
+ sizeof(xres), &xres, sizeof(yres), &yres,
+ strlen(size)+1, size);
+ pipeReadCmd (pipe_in);
+ n = pipeReadArgs (pipe_in, 3, sizeof(TVMode), mode,
+ sizeof(TVCrtRegs), crt, sizeof(TVRegs), tv);
+ if (mode) {
+ mode->crt = crt;
+ mode->tv = tv;
+ }
+ return (n >= 1);
+}
+
+Bool bcl_findByOverscan (TVSystem system, int xres, int yres,
+ double hoc, double voc, TVMode *mode, TVCrtRegs *crt, TVRegs *tv)
+{
+ int n;
+
+ DPRINTF ("bcl_findByOC %i %i,%i\n", system, xres, yres);
+ pipeWriteCmd (pipe_out, PCmd_FindByOverscan);
+ pipeWriteArgs (pipe_out, 5, sizeof(system), &system,
+ sizeof(xres), &xres, sizeof(yres), &yres,
+ sizeof(hoc), &hoc, sizeof(voc), &voc);
+ pipeReadCmd (pipe_in);
+ n = pipeReadArgs (pipe_in, 3, sizeof(TVMode), mode,
+ sizeof(TVCrtRegs), crt, sizeof(TVRegs), tv);
+ if (mode) {
+ mode->crt = crt;
+ mode->tv = tv;
+ }
+ return (n >= 1);
+}
+
+void bcl_initSharedView (int *view_x, int *view_y)
+{
+ DPRINTF ("bcl_initSharedView\n");
+ pipeWriteCmd (pipe_out, PCmd_InitSharedView);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 2, sizeof(int), view_x, sizeof(int), view_y);
+}
+
+Bool bcl_getTwinView (int *view_x, int *view_y)
+{
+ Bool result;
+
+ DPRINTF ("bcl_getTwinVie\n");
+ pipeWriteCmd (pipe_out, PCmd_GetTwinView);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 3, sizeof(Bool), &result,
+ sizeof(int), view_x, sizeof(int), view_y);
+ return result;
+}
+
+Bool bcl_adjustViewport (int flags, int *view_x, int *view_y)
+{
+ Bool result;
+
+ DPRINTF ("bcl_adjustViewport\n");
+ pipeWriteCmd (pipe_out, PCmd_AdjustView);
+ pipeWriteArgs (pipe_out, 3, sizeof(int), &flags,
+ sizeof(int), view_x, sizeof(int), view_y);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_out, 3, sizeof(int), &result,
+ sizeof(int), view_x, sizeof(int), view_y);
+ return result;
+}
+
+Bool bcl_serviceViewportCursor (int flags, int cursor_x, int cursor_y,
+ int *view_x, int *view_y)
+{
+ Bool result;
+
+ DPRINTF ("bcl_serviceViewportCursor\n");
+ pipeWriteCmd (pipe_out, PCmd_ServiceVC);
+ pipeWriteArgs (pipe_out, 5, sizeof(int), &flags,
+ sizeof(int), &cursor_x, sizeof(int), &cursor_y,
+ sizeof(int), view_x, sizeof(int), view_y);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_out, 3, sizeof(int), &result,
+ sizeof(int), view_x, sizeof(int), view_y);
+ return result;
+}
+
+BackAccessRec bcl_access_func = {
+ openCard: bcl_openCard,
+ closeCard: bcl_closeCard,
+#ifdef DEBUG_PROBE
+ probeSystem: bnull_probeSystem,
+#endif
+};
+
+BackCardRec bcl_card_func = {
+ openCard: bcl_openCard,
+ closeCard: bcl_closeCard,
+#ifdef DEBUG_PROBE
+ probeCard: bnull_probeCard,
+ probeBus: bnull_probeBus,
+#endif
+ setHeads: bcl_setHeads,
+ getHeads: bcl_getHeads,
+ probeChips: bcl_probeChips,
+ setChip: bcl_setChip,
+ setSettings: bcl_setSettings,
+ getSettings: bcl_getSettings,
+ setMode: bcl_setMode,
+ getMode: bcl_getMode,
+ setModeSettings: bcl_setModeSettings,
+ setTestImage: bcl_setTestImage,
+ getStatus: bcl_getStatus,
+ getConnection: bcl_getConnection,
+ findBySize: bcl_findBySize,
+ findByOverscan: bcl_findByOverscan,
+ initSharedView: bcl_initSharedView,
+ getTwinView: bcl_getTwinView,
+ adjustViewport: bcl_adjustViewport,
+ serviceViewportCursor: bcl_serviceViewportCursor,
+};
+
+/* -------- Init -------- */
+
+Bool back_client_avail (void)
+{
+ int version;
+ int fd_out, fd_in;
+
+ /* IMPORTANT: Open out pipe first, otherwise deadlock */
+ fd_out = open (PIPE_OUT, O_WRONLY | O_NONBLOCK);
+ if (fd_out < 0) return FALSE;
+ fd_in = open (PIPE_IN, O_RDONLY | O_NONBLOCK);
+ if (fd_in < 0) {
+ close (fd_out);
+ return FALSE;
+ }
+ close (fd_in);
+ close (fd_out);
+ bcl_openPipes ();
+ if (!pipe_in || !pipe_out) {
+ /* FIXME: error message */
+ bcl_closePipes ();
+ return FALSE;
+ }
+ pipeWriteCmd (pipe_out, PCmd_Version);
+ pipeWriteArgs (pipe_out, 0);
+ pipeReadCmd (pipe_in);
+ pipeReadArgs (pipe_in, 1, sizeof(version), &version);
+ bcl_closePipes ();
+ return (version == PIPE_VERSION);
+}
+
+
+CardPtr back_client_init (void)
+{
+ CardPtr card;
+
+ back_access = &bcl_access_func;
+ back_card = &bcl_card_func;
+ bcl_openPipes ();
+ pipeWriteCmd (pipe_out, PCmd_Init);
+ pipeWriteArgs (pipe_out, 0);
+ bcl_root = pipeReadList (pipe_in, sizeof (CardInfo));
+ bcl_card = bcl_root;
+ bcl_closePipes ();
+ for (card = bcl_card; card; card = card->next) {
+ card->chips = NULL;
+ card->dev = NULL;
+ }
+ return bcl_root;
+}
+
+/* NVTV pipe -- Dirk Thierbach <dthierbach@gmx.de>
+ *
+ * This file is part of nvtv, a tool for tv-output on NVidia cards.
+ *
+ * nvtv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nvtv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: nvtvd.c,v 1.1 2002/06/10 21:42:45 mshopf Exp $
+ *
+ * Contents:
+ *
+ * Routines to access the named pipe for server/client communication
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/*
+ * Read a command from a pipe
+ */
+
+PipeCmd pipeReadCmd (FILE *pipe)
+{
+ PipeCmd cmd;
+
+ DPRINTF ("pipe read cmd\n");
+ fread (&cmd, sizeof(PipeCmd), 1, pipe);
+ DPRINTF ("pipe read cmd, got %i\n", cmd);
+ return cmd;
+}
+
+/*
+ * Write a command to a pipe
+ */
+
+void pipeWriteCmd (FILE *pipe, PipeCmd cmd)
+{
+ DPRINTF ("pipe write cmd %i\n", cmd);
+ fwrite (&cmd, sizeof(PipeCmd), 1, pipe);
+ fflush (pipe);
+ DPRINTF ("pipe write cmd done\n");
+}
+
+/*
+ * Write arguments to a pipe. Ellipsis paramaters are:
+ * size1, pointer1, size2, pointer2, ..., 0
+ * Ignore zero size of null pointer arguments.
+ */
+
+void pipeWriteArgs (FILE *pipe, int n, ...)
+{
+ va_list ap;
+ int i, s;
+ void *p;
+
+ DPRINTF ("pipe write args\n");
+ fwrite (&n, sizeof(n), 1, pipe);
+ va_start(ap, n);
+ for (i = 0; i < n; i++) {
+ s = va_arg(ap, int);
+ p = va_arg(ap, void *);
+ if (!p) s = 0;
+ fwrite (&s, sizeof(s), 1, pipe);
+ if (s != 0) {
+ fwrite (p, s, 1, pipe);
+ }
+ }
+ fflush (pipe);
+ va_end(ap);
+}
+
+/*
+ * Implements the three following read routines. Allocate elements
+ * with zero size, and optionally set results.
+ */
+
+int pipeReadArgsMulti (FILE *pipe, int res, int n, va_list ap)
+{
+ int i, j;
+ int m, s, t, r;
+ void *p;
+ void **q;
+ int ok;
+
+ r = 0;
+ fread (&m, sizeof(m), 1, pipe);
+ ok = (m == n);
+ for (i = 0; i < m; i++) {
+ fread (&t, sizeof(t), 1, pipe);
+ s = va_arg(ap, int);
+ p = va_arg(ap, void *);
+ if (ok) {
+ if (s != 0 && t != 0 && s != t) ok = 0;
+ }
+ if (ok) {
+ r++;
+ } else {
+ p = NULL;
+ }
+ if (t == 0) p = NULL;
+ if (s == 0 && p) { /* alloc zero size */
+ q = (void **) p;
+ p = malloc (t);
+ *q = p;
+ }
+ if (res) { /* store result pointer */
+ q = va_arg(ap, void **);
+ if (q) *q = p;
+ }
+ if (p) {
+ fread (p, t, 1, pipe);
+ } else {
+ for (j = 0; j < t; j++) fgetc (pipe);
+ }
+ }
+ return r;
+}
+
+/*
+ * Read arguments from a pipe. Ellipsis parameters are:
+ * size_1, pointer_1, size_2, pointer_2, ..., size_n, pointer_n
+ * Ignore null pointer arguments, and allocate arguments with zero size.
+ * Return number of initial arguments that matched input stream.
+ */
+
+int pipeReadArgs (FILE *pipe, int n, ...)
+{
+ va_list ap;
+ int r;
+
+ DPRINTF ("pipe read args\n");
+ va_start(ap, n);
+ r = pipeReadArgsMulti (pipe, 0, n, ap);
+ va_end(ap);
+ return r;
+}
+
+/*
+ * Read optional arguments from a pipe. Ellipsis parameters are:
+ * size_1, pointer_1, result_1, ..., size_n, pointer_n, result_n
+ * Ignore zero size or null pointer arguments. Return number of
+ * initial arguments that matched input stream, and set each result
+ * either to NULL or to pointer.
+ */
+
+int pipeReadArgsOpt (FILE *pipe, int n, ...)
+{
+ va_list ap;
+ int r;
+
+ DPRINTF ("pipe read args opt\n");
+ va_start(ap, n);
+ r = pipeReadArgsMulti (pipe, 1, n, ap);
+ va_end(ap);
+ return r;
+}
+
+/*
+ * Read list from a pipe, alloc elements, and return pointer to first
+ * element. The elements MUST contain the next field as first entry,
+ * and a string as second entry.
+ */
+
+void* pipeReadList (FILE *pipe, int size)
+{
+ void *root, *p, *q;
+ int i, j, n, t;
+ char *s;
+
+ DPRINTF ("pipe read list\n");
+ root = p = NULL;
+ fread (&n, sizeof(n), 1, pipe);
+ n /= 2;
+ for (i = 0; i < n; i++) {
+ fread (&t, sizeof(t), 1, pipe);
+ if (t == size) {
+ q = malloc (t);
+ fread (q, t, 1, pipe);
+ if (p) {
+ * (void **) p = q;
+ } else {
+ root = q;
+ }
+ p = q;
+ } else {
+ q = NULL;
+ for (j = 0; j < t; j++) fgetc (pipe);
+ }
+ fread (&t, sizeof(t), 1, pipe);
+ if (q) {
+ s = NULL;
+ if (t != 0) {
+ s = malloc (t);
+ fread (s, sizeof(char), t, pipe);
+ }
+ * (((char **) q) + 1) = s;
+ } else {
+ for (j = 0; j < t; j++) fgetc (pipe);
+ }
+ }
+ return root;
+}
+
+/*
+ * Write list to a pipe. The elements MUST contain the next field as
+ * first entry, and a string as second entry.
+ */
+
+void pipeWriteList (FILE *pipe, int size, void *list)
+{
+ void *l;
+ char *s;
+ int n, k;
+
+ DPRINTF ("pipe write list\n");
+ n = 0;
+ for (l = list; l; l = * (void **) l) n++;
+ n *= 2;
+ fwrite (&n, sizeof(n), 1, pipe);
+ for (l = list; l; l = * (void **) l) {
+ fwrite (&size, sizeof(size), 1, pipe);
+ fwrite (l, size, 1, pipe);
+ s = * (((char **) l) + 1);
+ if (s) {
+ k = strlen(s) + 1;
+ fwrite (&k, sizeof(k), 1, pipe);
+ fwrite (s, sizeof(char), k, pipe);
+ } else {
+ k = 0;
+ fwrite (&k, sizeof(k), 1, pipe);
+ }
+ }
+ fflush (pipe);
+}
+