klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

kport.c (5951B)


      1 /*
      2 ** kport.c
      3 ** Kernel Ports
      4 ** See Copyright Notice in klisp.h
      5 */
      6 
      7 #include <stdio.h>
      8 #include <assert.h>
      9 #include <string.h>
     10 
     11 #include "kport.h"
     12 #include "kobject.h"
     13 #include "kstate.h"
     14 #include "kmem.h"
     15 #include "kerror.h"
     16 #include "kstring.h"
     17 #include "kbytevector.h"
     18 #include "kgc.h"
     19 #include "kpair.h"
     20 
     21 bool kportp(TValue o)
     22 {
     23     return ttisport(o);
     24 }
     25 
     26 bool kinput_portp(TValue o)
     27 {
     28     return ttisport(o) && kport_is_input(o);
     29 }
     30 
     31 bool koutput_portp(TValue o)
     32 {
     33     return ttisport(o) && kport_is_output(o);
     34 }
     35 
     36 bool kbinary_portp(TValue o)
     37 {
     38     return ttisport(o) && kport_is_binary(o);
     39 }
     40 
     41 bool ktextual_portp(TValue o)
     42 {
     43     return ttisport(o) && kport_is_textual(o);
     44 }
     45 
     46 bool kfile_portp(TValue o)
     47 {
     48     return ttisfport(o);
     49 }
     50 
     51 bool kstring_portp(TValue o)
     52 {
     53     return ttismport(o) && kport_is_textual(o);
     54 }
     55 
     56 bool kbytevector_portp(TValue o)
     57 {
     58     return ttismport(o) && kport_is_binary(o);
     59 }
     60 
     61 bool kport_openp(TValue o) 
     62 { 
     63     klisp_assert(ttisport(o));
     64     return kport_is_open(o); 
     65 }
     66 
     67 bool kport_closedp(TValue o) 
     68 { 
     69     klisp_assert(ttisport(o));
     70     return kport_is_closed(o); 
     71 }
     72 
     73 /* XXX: per the c spec, this truncates the file if it exists! */
     74 /* Ask John: what would be best? Probably should also include delete,
     75    file-exists? and a mechanism to truncate or append to a file, or 
     76    throw error if it exists.
     77    Should use open, but it is non standard (fcntl.h, POSIX only) */
     78 
     79 /* GC: Assumes filename is rooted */
     80 TValue kmake_fport(klisp_State *K, TValue filename, bool writep, bool binaryp)
     81 {
     82     /* for now always use text mode */
     83     char *mode;
     84     if (binaryp)
     85         mode = writep? "wb": "rb";
     86     else
     87         mode = writep? "w": "r";
     88 	    
     89     FILE *f = fopen(kstring_buf(filename), mode);
     90     if (f == NULL) {
     91         TValue mode_str = kstring_new_b(K, mode);
     92         krooted_tvs_push(K, mode_str);
     93         klispE_throw_errno_with_irritants(K, "fopen", 2, filename, mode_str);
     94         return KINERT;
     95     } else {
     96         return kmake_std_fport(K, filename, writep, binaryp, f);
     97     }
     98 }
     99 
    100 /* this is for creating ports for stdin/stdout/stderr &
    101    also a helper for the above */
    102 
    103 /* GC: Assumes filename, name & si are rooted */
    104 TValue kmake_std_fport(klisp_State *K, TValue filename, bool writep, 
    105                        bool binaryp, FILE *file)
    106 {
    107     FPort *new_port = klispM_new(K, FPort);
    108 
    109     /* header + gc_fields */
    110     klispC_link(K, (GCObject *) new_port, K_TFPORT, 
    111                 K_FLAG_CAN_HAVE_NAME | 
    112                 (writep? K_FLAG_OUTPUT_PORT : K_FLAG_INPUT_PORT) |
    113                 (binaryp? K_FLAG_BINARY_PORT : 0));
    114 
    115     /* port specific fields */
    116     new_port->filename = filename;
    117     new_port->file = file;
    118     TValue tv_port = gc2fport(new_port);
    119     /* line is 1-based and col is 0-based */
    120     kport_line(tv_port) = 1;
    121     kport_col(tv_port) = 0;
    122 
    123     return tv_port;
    124 }
    125 
    126 TValue kmake_mport(klisp_State *K, TValue buffer, bool writep, bool binaryp)
    127 {
    128     klisp_assert(!writep || ttisinert(buffer));
    129     klisp_assert(writep || (ttisbytevector(buffer) && binaryp) ||
    130                  (ttisstring(buffer) && !binaryp));
    131 
    132     if (writep) {
    133         buffer = binaryp? kbytevector_new_s(K, MINBYTEVECTORPORTBUFFER) :
    134             kstring_new_s(K, MINSTRINGPORTBUFFER);
    135     }
    136 
    137     krooted_tvs_push(K, buffer);
    138     
    139     MPort *new_port = klispM_new(K, MPort);
    140 
    141     /* header + gc_fields */
    142     klispC_link(K, (GCObject *) new_port, K_TMPORT, 
    143                 K_FLAG_CAN_HAVE_NAME | 
    144                 (writep? K_FLAG_OUTPUT_PORT : K_FLAG_INPUT_PORT) |
    145                 (binaryp? K_FLAG_BINARY_PORT : 0));
    146 
    147     /* port specific fields */
    148     TValue tv_port = gc2mport(new_port);
    149     kport_filename(tv_port) = G(K)->empty_string; /* XXX for now no filename */
    150     /* line is 1-based and col is 0-based */
    151     kport_line(tv_port) = 1;
    152     kport_col(tv_port) = 0;
    153     kmport_buf(tv_port) = buffer;
    154     kmport_off(tv_port) = 0; /* no bytes read/written */
    155     krooted_tvs_pop(K); 
    156     return tv_port;
    157 }
    158 
    159 /* if the port is already closed do nothing */
    160 /* This is also called from GC, so it shouldn't throw any error */
    161 void kclose_port(klisp_State *K, TValue port)
    162 {
    163     assert(ttisport(port));
    164 
    165     if (!kport_is_closed(port)) {
    166         if (ttisfport(port)) {
    167             FILE *f = tv2fport(port)->file;
    168             if (f != stdin && f != stderr && f != stdout)
    169                 fclose(f); /* it isn't necessary to check the close ret val */
    170         }
    171         kport_set_closed(port);
    172     }
    173 
    174     return;
    175 }
    176 
    177 void kport_reset_source_info(TValue port)
    178 {
    179     /* line is 1-based and col is 0-based */
    180     kport_line(port) = 1;
    181     kport_col(port) = 0;
    182 }
    183 
    184 void kport_update_source_info(TValue port, int32_t line, int32_t col)
    185 {
    186     kport_line(port) = line;
    187     kport_col(port) = col;
    188 }
    189 
    190 /* Always grow by doubling the size (until min_size is reached) */
    191 /* GC: port should be rooted */
    192 void kmport_resize_buffer(klisp_State *K, TValue port, size_t min_size)
    193 {
    194     klisp_assert(ttismport(port));
    195     klisp_assert(kport_is_output(port));
    196 
    197     uint32_t old_size = (kport_is_binary(port))?
    198         kbytevector_size(kmport_buf(port)) :
    199         kstring_size(kmport_buf(port));
    200     uint64_t new_size = old_size;
    201     
    202     while (new_size < min_size) {
    203         new_size *= 2;
    204         if (new_size > SIZE_MAX)
    205             klispM_toobig(K);
    206     }
    207     
    208     if (new_size == old_size)
    209         return;
    210 
    211     if (kport_is_binary(port)) {
    212         TValue new_bb = kbytevector_new_s(K, new_size);
    213         uint32_t off = kmport_off(port);
    214         if (off != 0) {
    215             memcpy(kbytevector_buf(new_bb), 
    216                    kbytevector_buf(kmport_buf(port)), 
    217                    off);
    218         }
    219         kmport_buf(port) = new_bb; 	
    220     } else {
    221         TValue new_str = kstring_new_s(K, new_size);
    222         uint32_t off = kmport_off(port);
    223         if (off != 0) {
    224             memcpy(kstring_buf(new_str), 
    225                    kstring_buf(kmport_buf(port)), 
    226                    off);
    227         }
    228         kmport_buf(port) = new_str; 	
    229     }
    230 }