home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1169 / stream.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  9.1 KB  |  493 lines

  1. /* stream commands for tcl */
  2. #include <stdio.h>
  3. #include <tcl.h>
  4. #include <errno.h>
  5. #include <ctype.h>
  6. #include "handler.h"
  7. #include "stream.h"
  8.  
  9. #define STATIC
  10.  
  11. int streamOpen(),
  12.     streamClose(),
  13.     streamGets(),
  14.     streamPuts(),
  15.     streamEof(),
  16.     streamName(),
  17.     streamErr(),
  18.     streamTell(),
  19.     streamList();
  20.     streamSeek();
  21.  
  22. static struct subcmd commands[] = {
  23.     { streamOpen, "open", 2, 2, "name mode" },
  24.     { streamClose, "close", 1, 1, "handle" },
  25.     { streamGets, "gets", 1, 2, "handle [var]" },
  26.     { streamPuts, "puts", 2, 2, "handle line" },
  27.     { streamEof, "eof", 1, 1, "handle" },
  28.     { streamErr, "error", 1, 1, "handle" },
  29.     { streamName, "name", 1, 1, "handle" },
  30.     { streamTell, "tell", 1, 1, "handle" },
  31.     { streamList, "list", 0, 0, "" },
  32.     { streamSeek, "seek", 2, 3, "handle offset [whence]" },
  33. };
  34.  
  35. save_err(s)
  36. struct stream *s;
  37. {
  38.     char *strerror();
  39.     extern int errno;
  40.     char *name;
  41.  
  42.     name = strerror(errno);
  43.     if(!name)
  44.         return;
  45.  
  46.     if(s->error) ckfree(s->error);
  47.     s->error = 0;
  48.     s->error = ckalloc(strlen(name)+1);
  49.     strcpy(s->error, name);
  50. }
  51.  
  52. static struct {
  53.     char *name;
  54.     int len;
  55.     int type;
  56. } types[] = {
  57.     { "file", 4, ST_FILE },
  58.     { "pipe", 4, ST_PIPE }
  59. };
  60. int ntypes = sizeof types / sizeof *types;
  61.  
  62. STATIC int get_id(streams, name)
  63. struct streams *streams;
  64. char *name;
  65. {
  66.     int id;
  67.     int t;
  68.  
  69.     for(t = 0; t < ntypes; t++)
  70.         if(strncmp(name, types[t].name, types[t].len) == 0)
  71.             break;
  72.     if(t >= ntypes)
  73.         return -1;
  74.     name+=types[t].len;
  75.     if(!isdigit(*name))
  76.         return -1;
  77.     id = atoi(name);
  78.     if(streams->s[id] && streams->s[id]->type == types[t].type)
  79.         return id;
  80.     return -1;
  81. }
  82.  
  83. STATIC char *get_name(streams, id)
  84. struct streams *streams;
  85. int id;
  86. {
  87.     static char name[32];
  88.     int t;
  89.  
  90.     if(id < 0)
  91.         return 0;
  92.  
  93.     for(t = 0; t < ntypes; t++)
  94.         if(streams->s[id]->type == types[t].type)
  95.             break;
  96.     if(t >= ntypes)
  97.         return 0;
  98.  
  99.     sprintf(name, "%s%d", types[t].name, id);
  100.  
  101.     return name;
  102. }
  103.  
  104. STATIC struct stream *get_stream(streams, name)
  105. struct streams *streams;
  106. char *name;
  107. {
  108.     int id;
  109.     struct stream *s;
  110.  
  111.     id = get_id(streams, name);
  112.     if(id >= 0)
  113.         return streams->s[id];
  114.     else
  115.         return 0;
  116. }
  117.  
  118. STATIC struct stream *add_stream(streams, filename, fp)
  119. struct streams *streams;
  120. char *filename;
  121. FILE *fp;
  122. {
  123.     int id;
  124.     struct stream *s;
  125.  
  126.     for(id = 0; id < streams->n; id++)
  127.         if(!streams->s[id])
  128.             break;
  129.     if(id >= MAXSTREAMS) {
  130.         extern int errno;
  131.         
  132.         errno = ENOMEM;
  133.         return 0;
  134.     }
  135.     if(id >= streams->n)
  136.         streams->n++;
  137.  
  138.     s = (struct stream *)ckalloc(sizeof(struct stream)
  139.         + (filename ? (strlen(filename)+1) : 0) );
  140.  
  141.     if(filename) {
  142.         s->filename = (char *)(s+1);
  143.         strcpy(s->filename, filename);
  144.     } else
  145.         s->filename = NULL;
  146.     s->id = id;
  147.     s->fp = fp;
  148.     s->error = NULL;
  149.     streams->s[id] = s;
  150.  
  151.     return s;
  152. }
  153.  
  154. STATIC del_stream(streams, id)
  155. struct streams *streams;
  156. int id;
  157. {
  158.     struct stream *s;
  159.  
  160.     if(s = streams->s[id]) {
  161.         streams->s[id] = 0;
  162.         if(s->error) ckfree(s->error);
  163.         ckfree(s);
  164.         return 1;
  165.     }
  166.     return 0;
  167. }
  168.  
  169. stream_term(stab)
  170. struct cmd_table *stab;
  171. {
  172.     int id;
  173.     struct streams *streams = (struct streams *)stab->data;
  174.  
  175.     for(id = 0; id < streams->n; id++)
  176.         if(streams->s[id])
  177.             del_stream(streams, id);
  178.     ckfree(streams);
  179.     ckfree(stab);
  180. }
  181.  
  182. stream_init(interp)
  183. Tcl_Interp *interp;
  184. {
  185.     struct cmd_table *streamTable;
  186.     struct streams *streamHead;
  187.  
  188.     streamTable = (struct cmd_table *) ckalloc(sizeof *streamTable);
  189.     streamHead = (struct streams *) ckalloc(sizeof (struct streams));
  190.     streamHead->n = 0;
  191.  
  192.     streamTable->name = "stream";
  193.     streamTable->data = (ClientData) streamHead;
  194.     streamTable->cmdc = sizeof(commands) / sizeof(*commands);
  195.     streamTable->cmdv = commands;
  196.  
  197.     Tcl_CreateCommand(interp, "stream",
  198.         cmdHandler, (ClientData) streamTable, stream_term);
  199.     add_stream(streamTable->data, (char *)NULL, stdin);
  200.     add_stream(streamTable->data, (char *)NULL, stdout);
  201.     add_stream(streamTable->data, (char *)NULL, stderr);
  202. }
  203.  
  204. STATIC int streamOpen(interp, streams, argc, argv)
  205. Tcl_Interp *interp;
  206. struct streams *streams;
  207. int argc;
  208. char **argv;
  209. {
  210.     FILE *fp;
  211.     struct stream *s;
  212.     int type;
  213.     char *ptr, *strchr();
  214.  
  215.     if(ptr = strchr(argv[1], 'p')) {
  216.         do
  217.             ptr[0] = ptr[1];
  218.         while(*ptr++);
  219.         fp = popen(argv[0], argv[1]);
  220.         type = ST_PIPE;
  221.     } else {
  222.         fp = fopen(argv[0], argv[1]);
  223.         type = ST_FILE;
  224.     }
  225.         
  226.     if(!fp) {
  227.         char *strerror();
  228.         extern int errno;
  229.         char *s = strerror(errno);
  230.         if(s)
  231.             sprintf(interp->result, "%s: %s", argv[0], s);
  232.         else
  233.             Tcl_Return(interp, (char *)NULL, TCL_STATIC);
  234.         return TCL_ERROR;
  235.     }
  236.  
  237.     s = add_stream(streams, argv[0], fp);
  238.     s->type = type;
  239.     if(s) {
  240.         if(s->id < 0)
  241.             Tcl_Return(interp, (char *)NULL, TCL_STATIC);
  242.         else
  243.             Tcl_Return(interp, get_name(streams, s->id), TCL_VOLATILE);
  244.         return TCL_OK;
  245.     } else {
  246.         sprintf(interp->result, "%s: Too many open streams", argv[0]);
  247.         return TCL_ERROR;
  248.     }
  249. }
  250.  
  251. STATIC not_open(interp, name)
  252. Tcl_Interp *interp;
  253. char *name;
  254. {
  255.     sprintf(interp->result,
  256.         "%.50s is not an open stream", name);
  257. }
  258.  
  259. STATIC int streamClose(interp, streams, argc, argv)
  260. Tcl_Interp *interp;
  261. struct streams *streams;
  262. int argc;
  263. char **argv;
  264. {
  265.     char *handle = (--argc, *argv++);
  266.     struct stream *s = get_stream(streams, handle);
  267.  
  268.     if(!s) {
  269.         not_open(interp, handle);
  270.         return TCL_ERROR;
  271.     }
  272.  
  273.     if(s->type==ST_PIPE)
  274.         pclose(s->fp);
  275.     else if(s->type==ST_FILE)
  276.         fclose(s->fp);
  277.  
  278.     del_stream(streams, s->id);
  279.     return TCL_OK;
  280. }
  281.  
  282. STATIC int streamGets(interp, streams, argc, argv)
  283. Tcl_Interp *interp;
  284. struct streams *streams;
  285. int argc;
  286. char **argv;
  287. {
  288.     char *handle = (--argc, *argv++);
  289.     struct stream *s = get_stream(streams, handle);
  290.     char *buffer = ckalloc(BUFSIZ);
  291.     char *ptr, *strchr();
  292.     int len;
  293.  
  294.     if(!s) {
  295.         not_open(interp, handle);
  296.         ckfree(buffer);
  297.         return TCL_ERROR;
  298.     }
  299.  
  300.     if(fgets(buffer, BUFSIZ, s->fp)) {
  301.         len = strlen(buffer);
  302.         ptr = strchr(buffer, '\n');
  303.         if(ptr) 
  304.             *ptr = 0;
  305.         if(argc==1) {
  306.             sprintf(interp->result, "%d", len);
  307.             Tcl_SetVar(interp, argv[0], buffer, 0);
  308.         } else
  309.             Tcl_Return(interp, buffer, TCL_VOLATILE);
  310.     }
  311.     else
  312.     {
  313.         if(argc==1)
  314.             Tcl_Return(interp, "0", TCL_STATIC);
  315.         else
  316.             Tcl_Return(interp, (char *)NULL, TCL_STATIC);
  317.     }
  318.     ckfree(buffer);
  319.     return TCL_OK;
  320. }
  321.  
  322. STATIC int streamPuts(interp, streams, argc, argv)
  323. Tcl_Interp *interp;
  324. struct streams *streams;
  325. int argc;
  326. char **argv;
  327. {
  328.     char *handle = (--argc, *argv++);
  329.     struct stream *s = get_stream(streams, handle);
  330.     char buffer[BUFSIZ];
  331.  
  332.     if(!s) {
  333.         not_open(interp, handle);
  334.         return TCL_ERROR;
  335.     }
  336.  
  337.     if(fputs(argv[0], s->fp) == EOF) save_err(s);
  338.     if(putc('\n', s->fp) == EOF) save_err(s);
  339.  
  340.     return TCL_OK;
  341. }
  342.  
  343. STATIC int streamTell(interp, streams, argc, argv)
  344. Tcl_Interp *interp;
  345. struct streams *streams;
  346. int argc;
  347. char **argv;
  348. {
  349.     char *handle = (--argc, *argv++);
  350.     struct stream *s = get_stream(streams, handle);
  351.     long offset, ftell();
  352.  
  353.     if(!s) {
  354.         not_open(interp, handle);
  355.         return TCL_ERROR;
  356.     }
  357.  
  358.     sprintf(interp->result, "%ld", offset = ftell(s->fp));
  359.     if(offset == -1) save_err(s);
  360.     return TCL_OK;
  361. }
  362.  
  363. STATIC int streamEof(interp, streams, argc, argv)
  364. Tcl_Interp *interp;
  365. struct streams *streams;
  366. int argc;
  367. char **argv;
  368. {
  369.     char *handle = (--argc, *argv++);
  370.     struct stream *s = get_stream(streams, handle);
  371.  
  372.     if(!s) {
  373.         not_open(interp, handle);
  374.         return TCL_ERROR;
  375.     }
  376.  
  377.     sprintf(interp->result, "%d", !!feof(s->fp));
  378.     return TCL_OK;
  379. }
  380.  
  381. STATIC int streamErr(interp, streams, argc, argv)
  382. Tcl_Interp *interp;
  383. struct streams *streams;
  384. int argc;
  385. char **argv;
  386. {
  387.     char *handle = (--argc, *argv++);
  388.     struct stream *s = get_stream(streams, handle);
  389.  
  390.     if(!s) {
  391.         not_open(interp, handle);
  392.         return TCL_ERROR;
  393.     }
  394.  
  395.     if(ferror(s->fp) && s->error)
  396.         Tcl_Return(interp, s->error, TCL_VOLATILE);
  397.     else
  398.         Tcl_Return(interp, (char *)NULL, TCL_STATIC);
  399.  
  400.     return TCL_OK;
  401. }
  402.  
  403. STATIC int streamName(interp, streams, argc, argv)
  404. Tcl_Interp *interp;
  405. struct streams *streams;
  406. int argc;
  407. char **argv;
  408. {
  409.     char *handle = (--argc, *argv++);
  410.     struct stream *s = get_stream(streams, handle);
  411.  
  412.     if(!s) {
  413.         not_open(interp, handle);
  414.         return TCL_ERROR;
  415.     }
  416.  
  417.     if(s->filename)
  418.         Tcl_Return(interp, s->filename, TCL_VOLATILE);
  419.     else
  420.         Tcl_Return(interp, (char *)NULL, TCL_STATIC);
  421.  
  422.     return TCL_OK;
  423. }
  424.  
  425. STATIC int streamSeek(interp, streams, argc, argv)
  426. Tcl_Interp *interp;
  427. struct streams *streams;
  428. int argc;
  429. char **argv;
  430. {
  431.     char *handle = (--argc, *argv++);
  432.     struct stream *s = get_stream(streams, handle);
  433.     int whence, ret, fseek();
  434.     long offset, fftell();
  435.     long strtol();
  436.     char *endptr;
  437.  
  438.     if(!s) {
  439.         not_open(interp, handle);
  440.         return TCL_ERROR;
  441.     }
  442.  
  443.     if(argc > 1) whence = atoi(argv[1]);
  444.     else whence = 0;
  445.  
  446.     offset = strtol(argv[0], &endptr, 0);
  447.  
  448.     ret = fseek(s->fp, offset, whence);
  449.     if(ret==0) offset = ftell(s->fp);
  450.     else offset = -1;
  451.     sprintf(interp->result, "%ld", offset);
  452.     if(offset == -1) save_err(s);
  453.  
  454.     return TCL_OK;
  455. }
  456.  
  457. STATIC int streamList(interp, streams, argc, argv)
  458. Tcl_Interp *interp;
  459. struct streams *streams;
  460. int argc;
  461. char **argv;
  462. {
  463.     char buffer[BUFSIZ];
  464.     int id;
  465.     struct stream *s;
  466.     char *p;
  467.  
  468.     p = 0;
  469.     for(id = 0; id < streams->n; id++) {
  470.         if(s = streams->s[id]) {
  471.             if(!p)
  472.                 p = buffer;
  473.             else    
  474.                 *p++ = ' ';
  475.             if(s->filename) {
  476.                 char *strchr();
  477.                 if(strchr(s->filename, ' ') == NULL)
  478.                     sprintf(p, "{%s %s}",
  479.                         get_name(streams, id),
  480.                         s->filename);
  481.                 else
  482.                     sprintf(p, "{%s {%s}}",
  483.                         get_name(streams, id),
  484.                         s->filename);
  485.             } else
  486.                 sprintf(p, "%s", get_name(streams, id));
  487.             p += strlen(p);
  488.         }
  489.     }
  490.     Tcl_Return(interp, buffer, TCL_VOLATILE);
  491.     return TCL_OK;
  492. }
  493.