io_builtins_xsb_i.h

00001 /* File:      io_builtins_xsb_i.h
00002 ** Author(s): davulcu, kifer
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 1999
00006 ** 
00007 ** XSB is free software; you can redistribute it and/or modify it under the
00008 ** terms of the GNU Library General Public License as published by the Free
00009 ** Software Foundation; either version 2 of the License, or (at your option)
00010 ** any later version.
00011 ** 
00012 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00013 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00015 ** more details.
00016 ** 
00017 ** You should have received a copy of the GNU Library General Public License
00018 ** along with XSB; if not, write to the Free Software Foundation,
00019 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 **
00021 ** $Id: io_builtins_xsb_i.h,v 1.46 2006/05/22 15:40:04 dwarren Exp $
00022 ** 
00023 */
00024 
00025 
00026 /* This file is separate from io_builtins.c because here we have the
00027    in-lined file_function (to speed up file_get/put). */
00028 
00029 
00030 #include "file_modes_xsb.h"
00031 
00032 #if (defined(CYGWIN))
00033 #include <fcntl.h>
00034 #endif
00035 
00036 #ifdef WIN_NT
00037 #include <io.h>
00038 #endif
00039 
00040 /* protected by MUTEX IO */
00041 STRFILE *iostrs[MAXIOSTRS] = {NULL,NULL,NULL,NULL,NULL};
00042 
00043 extern char   *expand_filename(char *filename);
00044 extern int xsb_intern_fileptr(FILE *, char *, char *, char *);
00045 
00046 static FILE *stropen(char *str)
00047 {
00048   int i, len;
00049   STRFILE *tmp;
00050   char *stringbuff;
00051 
00052   for (i=0; i<MAXIOSTRS; i++) {
00053     if (iostrs[i] == NULL) break;
00054   }
00055   if (i>=MAXIOSTRS) return FALSE;
00056   tmp = (STRFILE *)mem_alloc(sizeof(STRFILE),OTHER_SPACE);
00057   iostrs[i] = tmp;
00058   len = strlen(str);
00059   // new copy is needed in case string came from concatenated longstring
00060   stringbuff = (char *)mem_alloc(len+1,OTHER_SPACE);
00061   strcpy(stringbuff,str);
00062 
00063   tmp->strcnt = len;
00064   tmp->strptr = stringbuff;
00065   tmp->strbase = stringbuff;
00066   return (FILE *)iostrdecode(i);
00067 }
00068 
00069 static void strclose(int i)
00070 {
00071   i = iostrdecode(i);
00072   if (iostrs[i] != NULL) {
00073     mem_dealloc(iostrs[i]->strbase,iostrs[i]->strcnt+1,OTHER_SPACE);
00074     mem_dealloc((byte *)iostrs[i],sizeof(STRFILE),OTHER_SPACE);
00075     iostrs[i] = NULL;
00076   }
00077 }
00078 
00079 #ifdef MULTI_THREAD
00080 #define XSB_STREAM_LOCK(index) { \
00081   if (index >= 0) pthread_mutex_lock(OPENFILES_MUTEX(index)); \
00082   else pthread_mutex_lock(OPENFILES_MUTEX(iostrdecode(index))); \
00083 }
00084 #define XSB_STREAM_UNLOCK(index) { \
00085   if (index >= 0) pthread_mutex_unlock(OPENFILES_MUTEX(index)); \
00086   else pthread_mutex_unlock(OPENFILES_MUTEX(iostrdecode(index))); \
00087 }
00088 #else
00089 #define XSB_STREAM_LOCK(index) 
00090 #define XSB_STREAM_UNLOCK(index) 
00091 #endif
00092 
00093 /* TLS: these are ports, rather than file descriptors, therefore using
00094    the Prolog defines.  Should they be moved into a different .h file? 
00095 */
00096 
00097 #define STDIN 0
00098 #define STDOUT 1
00099 
00100 /* file_flush, file_pos, file_truncate, file_seek */
00101 
00102 /* Two levels of locking: MUTEX_IO locks table iteself, and is used
00103    when we arent changing a given stream itself, as in file_open.  In
00104    addition, however, the io_locks are used to ensure atomic operation
00105    for all io operations.
00106 
00107 Best to put locks AFTER SET_FILEPTR to avoid problems with mutexes
00108    (they should be unlocked via error_handler, but ...) */
00109 inline static xsbBool file_function(CTXTdecl)
00110 {
00111   FILE *fptr;
00112   int io_port, value, size, offset, length, mode;
00113   STRFILE *sfptr;
00114   XSB_StrDefine(VarBuf);
00115   char *addr, *tmpstr;
00116   prolog_term pterm;
00117   Cell term;
00118   char *strmode;
00119 
00120   switch (ptoc_int(CTXTc 1)) {
00121   case FILE_FLUSH: /* file_function(0,+IOport,-Ret,_,_) */
00122     /* ptoc_int(CTXTc 2) is XSB I/O port */
00123     io_port = ptoc_int(CTXTc 2);
00124     XSB_STREAM_LOCK(io_port);
00125     SET_FILEPTR(fptr, io_port);   
00126     value = fflush(fptr);
00127     XSB_STREAM_UNLOCK(io_port);
00128     ctop_int(CTXTc 3, (int) value);
00129     break;
00130   case FILE_SEEK: /* file_function(1,+IOport, +Offset, +Place, -Ret) */
00131     io_port = ptoc_int(CTXTc 2);
00132     if (io_port < 0) {
00133       if (ptoc_int(CTXTc 4) != 0) 
00134         xsb_permission_error(CTXTc "file_seek","atom",ptoc_int(CTXTc 4),"file_seek",1); 
00135       XSB_STREAM_LOCK(io_port);
00136       sfptr = iostrs[iostrdecode(io_port)];
00137       value = ptoc_int(CTXTc 3);
00138       length = sfptr->strcnt + sfptr->strptr - sfptr->strbase ;
00139       if (value <= length) {
00140         if (sfptr->strcnt == -1) length++;
00141         sfptr->strptr = sfptr->strbase + value;
00142         sfptr->strcnt = length - value;
00143         ctop_int(CTXTc 5, 0);
00144       }
00145       else ctop_int(CTXTc 5,-1);
00146       XSB_STREAM_UNLOCK(io_port);
00147     }
00148     else {
00149       XSB_STREAM_LOCK(io_port);
00150       SET_FILEPTR(fptr, io_port);
00151       value = fseek(fptr, (long) ptoc_int(CTXTc 3), ptoc_int(CTXTc 4));
00152       XSB_STREAM_UNLOCK(io_port);
00153       ctop_int(CTXTc 5, (int) value);
00154     }
00155     break;
00156   case FILE_TRUNCATE: /* file_function(2,+IOport,+Length,-Ret,_) */
00157     size = ptoc_int(CTXTc 3);
00158     io_port = ptoc_int(CTXTc 2);
00159     XSB_STREAM_LOCK(io_port);
00160     SET_FILEPTR(fptr, io_port);
00161 #ifndef WIN_NT
00162     fseek(fptr, (long) size, 0);
00163     value = ftruncate( fileno(fptr), (off_t) size);
00164     ctop_int(CTXTc 4, (int) value);
00165 #else
00166     ctop_int(CTXTc 4, (int) _chsize(fileno(fptr), size));
00167 #endif
00168     XSB_STREAM_UNLOCK(io_port);
00169     break;
00170   case FILE_POS: /* file_function(3, +IOport, -Pos) */
00171     io_port = ptoc_int(CTXTc 2); 
00172     term = ptoc_tag(CTXTc 3);
00173     if (io_port >= 0) {
00174       XSB_STREAM_LOCK(io_port);
00175       SET_FILEPTR(fptr, io_port);
00176       if (isnonvar(term)) {
00177         XSB_STREAM_UNLOCK(io_port);
00178         return ptoc_int(CTXTc 3) == ftell(fptr);
00179       }
00180       else
00181         ctop_int(CTXTc 3, ftell(fptr));
00182     } else { /* reading from string */
00183       XSB_STREAM_LOCK(io_port);
00184       sfptr = strfileptr(io_port);
00185       if (sfptr->strcnt == EOF) 
00186         offset = EOF;
00187       else 
00188         offset = sfptr->strptr - sfptr->strbase;
00189       if (isnonvar(term)) {
00190         XSB_STREAM_UNLOCK(io_port);
00191         return ptoc_int(CTXTc 3) == offset;
00192       }
00193       else
00194         ctop_int(CTXTc 3, offset);
00195     }
00196     XSB_STREAM_UNLOCK(io_port);
00197     break;
00198   case XSB_FILE_OPEN: {
00199     /* file_function(4, +FileName, +Mode, -IOport) TLS: changing modes
00200      and differentiating binaries, so its best to not allow integer
00201      modes any more */
00202     int ioport, opennew;
00203     int str_type = 0;
00204     char string_mode[3];
00205 
00206     tmpstr = ptoc_longstring(CTXTc 2);
00207     pterm = reg_term(CTXTc 3);
00208 
00209     SYS_MUTEX_LOCK( MUTEX_IO );
00210 
00211     if (isstring(pterm)) {
00212       strcpy(string_mode,string_val(pterm));
00213 
00214       switch ((string_mode)[0]) {
00215       case 'r': 
00216         mode = OREAD; 
00217         if ((string_mode)[1] == 'b')
00218           str_type = BINARY_FILE_STREAM;
00219         else  str_type = TEXT_FILE_STREAM;
00220         break;
00221       case 'w': 
00222         mode = OWRITE; 
00223         if ((string_mode)[1] == 'b')
00224           str_type = BINARY_FILE_STREAM;
00225         else  str_type = TEXT_FILE_STREAM;
00226         break;
00227       case 'a': 
00228         mode = OAPPEND; 
00229         if ((string_mode)[1] == 'b')
00230           str_type = BINARY_FILE_STREAM;
00231         else  str_type = TEXT_FILE_STREAM;
00232         break;
00233       case 's':
00234         str_type = STRING_STREAM;
00235         if ((string_mode)[1] == 'r')
00236           /* reading from string */
00237           mode = OSTRINGR;
00238         else if ((string_mode)[1] == 'w')
00239           /* writing to string */
00240           mode = OSTRINGW;
00241         else
00242           mode = -1;
00243         break;
00244       default: mode = -1;
00245       }
00246     } else {
00247       SYS_MUTEX_UNLOCK( MUTEX_IO );
00248       xsb_abort("[FILE_OPEN] File opening mode must be an atom.");
00249       mode = -1;
00250     } /* end mode handling code */
00251 
00252     switch (mode) {
00253 
00254       /* In UNIX the 'b" does nothing, but in Windows it
00255          differentiates a binary from a text file.  If I take the 'b'
00256          out, this breaks the compiler. */
00257 
00258     case OREAD: strmode = "rb"; break; /* READ_MODE */
00259     case OWRITE:  strmode = "wb"; break; /* WRITE_MODE */
00260     case OAPPEND: strmode = "ab"; break; /* APPEND_MODE */
00261     case OSTRINGR:
00262       if ((fptr = stropen(tmpstr))) {
00263         ctop_int(CTXTc 5, (Integer)fptr);
00264       } else {
00265         ctop_int(CTXTc 5, -1000);
00266       }
00267       SYS_MUTEX_UNLOCK( MUTEX_IO );
00268       return TRUE;
00269     case OSTRINGW:
00270       xsb_abort("[FILE_OPEN] Output to strings has not been implemented yet");
00271       ctop_int(CTXTc 5, -1000);
00272       SYS_MUTEX_UNLOCK( MUTEX_IO );
00273       return TRUE;
00274     default:
00275       xsb_warn("FILE_OPEN: Invalid open file mode");
00276       ctop_int(CTXTc 5, -1000);
00277       SYS_MUTEX_UNLOCK( MUTEX_IO );
00278       return TRUE;
00279     }
00280     
00281     /* we reach here only if the mode is OREAD,OWRITE,OAPPEND */
00282     addr = expand_filename(tmpstr);
00283 
00284     opennew = ptoc_int(CTXTc 4);
00285     if (!xsb_intern_file("FILE_OPEN",addr, &ioport,strmode,opennew)) {
00286       open_files[ioport].stream_type = str_type;
00287       ctop_int(CTXTc 5,ioport);
00288     }
00289     else ctop_int(CTXTc 5,-1);
00290     mem_dealloc(addr,MAXPATHLEN,OTHER_SPACE);
00291 
00292     SYS_MUTEX_UNLOCK( MUTEX_IO );
00293     break;
00294   }
00295     /* TLS: handling the case in which we are closing a flag that
00296        we're currently seeing or telling.  Probably bad programming
00297        style to mix streams w. open/close, though. */
00298   case FILE_CLOSE: /* file_function(5, +Stream,FORCE/NOFORCE) */
00299     {
00300       int rtrn; 
00301       io_port = ptoc_int(CTXTc 2);
00302       if (io_port < 0) {
00303         XSB_STREAM_LOCK(io_port);
00304         strclose(io_port);
00305         XSB_STREAM_UNLOCK(io_port);
00306       }
00307       else {
00308         XSB_STREAM_LOCK(io_port);
00309         SET_FILEPTR(fptr, io_port);
00310         if ((rtrn = fclose(fptr))) {
00311           if (ptoc_int(CTXTc 3) == NOFORCE_FILE_CLOSE) {
00312             XSB_STREAM_UNLOCK(io_port);
00313             xsb_permission_error(CTXTc "fclose","file",reg[2],"file_close",1); 
00314           }
00315         }
00316         open_files[io_port].file_ptr = NULL;
00317         open_files[io_port].file_name = NULL;
00318         open_files[io_port].io_mode = '\0';
00319         open_files[io_port].stream_type = 0;
00320         if (pflags[CURRENT_INPUT] == (Cell) io_port) 
00321           { pflags[CURRENT_INPUT] = STDIN;}
00322         if (pflags[CURRENT_OUTPUT] == (Cell) io_port) 
00323           { pflags[CURRENT_OUTPUT] = STDOUT;}
00324       }
00325       XSB_STREAM_UNLOCK(io_port);
00326       break;
00327     }
00328   case FILE_GET:        /* file_function(6, +IOport, -IntVal) */
00329     io_port = ptoc_int(CTXTc 2);
00330     if ((io_port < 0) && (io_port >= -MAXIOSTRS)) {
00331       XSB_STREAM_LOCK(io_port);
00332       sfptr = strfileptr(io_port);
00333       ctop_int(CTXTc 3, strgetc(sfptr));
00334     } else {
00335       SET_FILEPTR(fptr, io_port);
00336       XSB_STREAM_LOCK(io_port);
00337       ctop_int(CTXTc 3, getc(fptr));
00338     }
00339     XSB_STREAM_UNLOCK(io_port);
00340     break;
00341   case FILE_PUT:   /* file_function(7, +IOport, +IntVal) */
00342     io_port = ptoc_int(CTXTc 2);
00343     XSB_STREAM_LOCK(io_port);
00344     SET_FILEPTR(fptr, io_port);
00345     /* ptoc_int(CTXTc 3) is char to write */
00346     value = ptoc_int(CTXTc 3);
00347     putc(value, fptr);
00348 #ifdef WIN_NT
00349     if (io_port==2 && value=='\n') fflush(fptr); /* hack for Java interface */
00350 #endif
00351     XSB_STREAM_UNLOCK(io_port);
00352     break;
00353   case FILE_GETBUF:
00354     /* file_function(8, +IOport, +ByteCount (int), -String, -BytesRead)
00355        Read ByteCount bytes from IOport into String starting 
00356        at position Offset. */
00357     size = ptoc_int(CTXTc 3);
00358     io_port = ptoc_int(CTXTc 2);
00359     XSB_STREAM_LOCK(io_port);
00360     SET_FILEPTR(fptr, io_port);
00361     XSB_StrSet(&VarBuf,"");
00362     XSB_StrEnsureSize(&VarBuf,size);
00363     value = fread(VarBuf.string, 1, size, fptr);
00364     VarBuf.length = value;
00365     XSB_StrNullTerminate(&VarBuf);
00366     XSB_STREAM_UNLOCK(io_port);
00367     ctop_string(CTXTc 4, string_find(VarBuf.string,1));
00368     ctop_int(CTXTc 5, value);
00369     break;
00370   case FILE_PUTBUF:
00371     /* file_function(9, +IOport, +ByteCount (int), +String, +Offset,
00372                         -BytesWritten) */
00373     /* Write ByteCount bytes into IOport from String beginning with Offset in
00374        that string            */
00375     pterm = reg_term(CTXTc 4);
00376     if (islist(pterm))
00377       addr = 
00378         p_charlist_to_c_string(CTXTc pterm,&VarBuf,"FILE_WRITE_LINE","input string");
00379     else if (isstring(pterm))
00380       addr = string_val(pterm);
00381     else {
00382       xsb_abort("[FILE_PUTBUF] Output argument must be an atom or a character list");
00383       addr = NULL;
00384     }
00385     size = ptoc_int(CTXTc 3);
00386     offset = ptoc_int(CTXTc 5);
00387     length = strlen(addr);
00388     size = ( size < length - offset ? size : length - offset);
00389     io_port = ptoc_int(CTXTc 2);
00390     XSB_STREAM_LOCK(io_port);
00391     SET_FILEPTR(fptr, io_port);
00392     value = fwrite(addr+offset, 1, size, fptr);
00393     XSB_STREAM_UNLOCK(io_port);
00394     ctop_int(CTXTc 6, value);
00395     break;
00396   case FILE_READ_LINE: {
00397     /* Works like fgets(buf, size, stdin). Fails on reaching the end of file
00398     ** Invoke: file_function(FILE_READ_LINE, +File, -Str). Returns
00399     ** the string read.
00400     ** Prolog invocation: file_read_line(+File, -Str) */
00401     char buf[MAX_IO_BUFSIZE+1];
00402     int break_loop = FALSE;
00403     int eof=FALSE;
00404 
00405     io_port = ptoc_int(CTXTc 2);
00406     XSB_STREAM_LOCK(io_port);
00407     SET_FILEPTR(fptr, io_port);
00408     XSB_StrSet(&VarBuf,"");
00409 
00410     do {
00411       if (fgets(buf, MAX_IO_BUFSIZE, fptr) == NULL && feof(fptr)) {
00412         eof=TRUE;
00413         break;
00414       } else {
00415         XSB_StrAppend(&VarBuf,buf);
00416         break_loop = (buf[(strlen(buf)-1)] == '\n');
00417       }
00418     } while (!break_loop);
00419     
00420     ctop_string(CTXTc 3, string_find(VarBuf.string,1));
00421     
00422     XSB_STREAM_UNLOCK(io_port);
00423     /* this complex cond takes care of incomplete lines: lines that end with
00424        end of file and not with end-of-line. */
00425     if ((VarBuf.length>0) || (!eof))
00426       return TRUE;
00427     else
00428       return FALSE;
00429   }
00430   case FILE_READ_LINE_LIST: {
00431     /* Works like FILE_READ_LINE but returns a list of codes
00432     ** Invoke: file_function(FILE_READ_LINE, +File, -List). Returns
00433     ** the list of codes read. Rewritten by DSW 5/18/04 to allow \0 in lines.
00434     ** Prolog invocation: file_read_line_list(+File, -Str) */
00435     char *line_buff = NULL;
00436     int line_buff_len = 0;
00437     int line_buff_disp;
00438     char *atomname;
00439     int c;
00440     Cell new_list;
00441     CPtr top = NULL;
00442     int i;
00443 
00444     io_port = ptoc_int(CTXTc 2);
00445     XSB_STREAM_LOCK(io_port);
00446     SET_FILEPTR(fptr, io_port);
00447 
00448     line_buff_disp = 0;
00449     do {
00450       if (line_buff_disp >= line_buff_len) {
00451         int old_len = line_buff_len;
00452         line_buff_len = line_buff_disp+MAX_IO_BUFSIZE;
00453         if(!(line_buff = mem_realloc(line_buff,old_len,line_buff_len,LEAK_SPACE)))
00454           xsb_exit("No space for line buffer");
00455       }
00456       *(line_buff+line_buff_disp) = c = getc(fptr);
00457       if (c == EOF) break;
00458       line_buff_disp++;
00459     } while (c != '\n');
00460     *(line_buff+line_buff_disp) = 0;
00461     
00462     check_glstack_overflow(3, pcreg, 2*sizeof(Cell)*line_buff_disp);
00463     atomname = line_buff;
00464 
00465     if (line_buff_disp == 0) new_list = makenil;
00466     else {
00467       new_list = makelist(hreg);
00468       for (i = 0; i < line_buff_disp; i++) {
00469         follow(hreg++) = makeint(*(unsigned char *)atomname);
00470         atomname++;
00471         top = hreg++;
00472         follow(top) = makelist(hreg);
00473       }
00474       follow(top) = makenil;
00475     }
00476 
00477     ctop_tag(CTXTc 3, new_list);
00478     
00479     if (line_buff) mem_dealloc(line_buff,line_buff_len,LEAK_SPACE);
00480 
00481     /* this complex cond takes care of incomplete lines: lines that end with
00482        end of file and not with end-of-line. */
00483     //    if ((line_buff_disp>0) || (c != EOF))
00484     XSB_STREAM_UNLOCK(io_port);
00485     if (line_buff_disp>0)
00486       return TRUE;
00487     else
00488       return FALSE;
00489   }
00490   /* Like FILE_PUTBUF, but ByteCount=Line length. Also, takes atoms and lists
00491      of characters: file_function(11, +IOport, +String, +Offset) */
00492   case FILE_WRITE_LINE:
00493     pterm = reg_term(CTXTc 3);
00494     if (islist(pterm))
00495       addr =
00496         p_charlist_to_c_string(CTXTc pterm,&VarBuf,"FILE_WRITE_LINE","input string");
00497     else if (isstring(pterm))
00498       addr = string_val(pterm);
00499     else {
00500       xsb_abort("[FILE_WRITE_LINE] Outmput arg must be an atom or a char list");
00501       addr = NULL;
00502     }
00503     offset = ptoc_int(CTXTc 4);
00504     size = strlen(addr)-offset;
00505     io_port = ptoc_int(CTXTc 2);
00506     XSB_STREAM_LOCK(io_port);
00507     SET_FILEPTR(fptr, io_port);
00508     fwrite(addr+offset, 1, size, fptr);
00509     XSB_STREAM_UNLOCK(io_port);
00510     break;
00511 
00512   case FILE_REOPEN: 
00513     /* file_function(FILE_REOPEN, +Filename,+Mode,+IOport,-ErrorCode) */
00514     tmpstr = ptoc_string(CTXTc 2);
00515     pterm = reg_term(CTXTc 3);
00516     if (isinteger(pterm)|isboxedinteger(pterm))
00517       mode = oint_val(pterm);
00518     else if (isstring(pterm)) {
00519       switch ((string_val(pterm))[0]) {
00520       case 'r': mode = OREAD; break;
00521       case 'w': mode = OWRITE; break;
00522       case 'a': mode = OAPPEND; break;
00523       case 's':
00524         if ((string_val(pterm))[1] == 'r')
00525           /* reading from string */
00526           mode = OSTRINGR;
00527         else if ((string_val(pterm))[1] == 'w')
00528           /* writing to string */
00529           mode = OSTRINGW;
00530         else
00531           mode = -1;
00532         break;
00533       default: mode = -1;
00534       }
00535     } else {
00536       xsb_abort("[FILE_REOPEN] Open mode must be an atom or an integer");
00537       mode = -1;
00538     }
00539 
00540     switch (mode) {
00541       /* "b" does nothing, but POSIX allows it */
00542     case OREAD:   strmode = "rb";  break; /* READ_MODE */
00543     case OWRITE:  strmode = "wb";  break; /* WRITE_MODE */
00544     case OAPPEND: strmode = "ab";  break; /* APPEND_MODE */
00545     case OSTRINGR:
00546       xsb_abort("[FILE_REOPEN] Reopening of strings hasn't been implemented");
00547       ctop_int(CTXTc 5, -1000);
00548       return TRUE;
00549     case OSTRINGW:
00550       xsb_abort("[FILE_REOPEN] Reopening of strings hasn't been implemented");
00551       ctop_int(CTXTc 5, -1000);
00552       return TRUE;
00553     default:
00554       xsb_warn("FILE_REOPEN: Invalid open file mode");
00555       ctop_int(CTXTc 5, -1000);
00556       return TRUE;
00557     }
00558     
00559     /* we reach here only if the mode is OREAD,OWRITE,OAPPEND */
00560     addr = expand_filename(tmpstr);
00561     io_port = ptoc_int(CTXTc 4);
00562     XSB_STREAM_LOCK(io_port);
00563     SET_FILEPTR(fptr, io_port);
00564     fflush(fptr);
00565     fptr = freopen(addr, string_val(pterm), fptr);
00566     XSB_STREAM_UNLOCK(io_port);
00567 
00568     if (fptr) {
00569       struct stat stat_buff;
00570       if (!stat(addr, &stat_buff) && !S_ISDIR(stat_buff.st_mode))
00571         /* file exists and isn't a dir */
00572         ctop_int(CTXTc 5, 0);
00573       else {
00574         xsb_warn("FILE_REOPEN: File %s is a directory, cannot open!", addr);
00575         ctop_int(CTXTc 5, -2);
00576       }
00577     } else
00578       ctop_int(CTXTc 5, -3);
00579     mem_dealloc(addr,MAXPATHLEN,OTHER_SPACE);
00580 
00581     break;
00582 
00583     /* TLS: I looked through this, and it seems to work with streams,
00584        but its possible that the file clone should move the file name
00585        and mode from the source to the destination when it copies or
00586        creates an io port? */
00587 
00588   case FILE_CLONE: {
00589     /* file_function(FILE_CLONE,SrcIOport,DestIOport,ErrorCode) */
00590     /* Note: when cloning (dup) streams, NT doesn't copy the buffering mode of
00591        the source file. So, if this will turn out to be a problem, a new
00592        builtin (interface to setvbuf) will have to be introduced. */
00593     FILE *src_fptr, *dest_fptr;
00594     int src_fd, dest_fd, dest_xsb_fileno, src_xsb_fileno, errcode=0;
00595     char *mode = NULL;
00596     prolog_term dest_fptr_term;
00597 
00598     src_xsb_fileno = ptoc_int(CTXTc 2);
00599     dest_fptr_term = reg_term(CTXTc 3);
00600     XSB_STREAM_LOCK(src_xsb_fileno);
00601     XSB_STREAM_LOCK(int_val(dest_fptr_term));
00602     SET_FILEPTR(src_fptr, src_xsb_fileno);
00603     fflush(src_fptr);
00604     src_fd = fileno(src_fptr);
00605 
00606     if (isnonvar(dest_fptr_term)) {
00607       /* assume the user wants dup2-like functionality */
00608       SET_FILEPTR(dest_fptr, int_val(dest_fptr_term));
00609       dest_fd = fileno(dest_fptr);
00610       errcode = dup2(src_fd,dest_fd);
00611     } else {
00612       /* user wanted dup-like functionality */
00613       dest_fd = dup(src_fd);
00614       if (dest_fd >= 0) {
00615 #if (defined (WIN_NT) && ! defined(CYGWIN))
00616         /* NT doesn't have fcntl(). Brain damage? But Cygwin does */
00617         mode = "r+";
00618 #else /* Unix */ 
00619         int fd_flags;
00620         /* get the flags that open has set for this file descriptor */
00621         fd_flags = fcntl(dest_fd, F_GETFL) & (O_ACCMODE | O_APPEND); 
00622         switch (fd_flags) {
00623         case O_RDONLY:
00624             mode = "rb";
00625             break;
00626 
00627         case O_WRONLY:
00628             mode = "wb";
00629             break;
00630 
00631         case O_ACCMODE:
00632                 /* Should not happen */
00633                 /* Falls through */
00634 
00635         case O_RDWR:
00636             mode = "rb+";
00637             break;
00638 
00639         case O_RDONLY | O_APPEND:
00640             mode = "rb";
00641             break;
00642 
00643         case O_WRONLY | O_APPEND:
00644             mode = "ab";
00645             break;
00646 
00647         case O_ACCMODE | O_APPEND:
00648                 /* Should not happen */
00649                 /* Falls through */
00650 
00651         case O_RDWR | O_APPEND:
00652             mode = "ab+";
00653             break;
00654 
00655         default:
00656                 mode = "rb+";
00657                 break;
00658         }
00659 #endif
00660         dest_fptr = fdopen(dest_fd, mode);
00661         if (dest_fptr) {
00662           dest_xsb_fileno = 
00663             xsb_intern_fileptr(dest_fptr,"FILE_CLONE",
00664                                open_files[src_xsb_fileno].file_name,
00665                                &open_files[src_xsb_fileno].io_mode);
00666           c2p_int(CTXTc dest_xsb_fileno, dest_fptr_term);
00667         } else {
00668           /* error */
00669           errcode = -1;
00670         }
00671       } else
00672         /* error */
00673         errcode = -1;
00674     }
00675     ctop_int(CTXTc 4, errcode);
00676 
00677     XSB_STREAM_UNLOCK(int_val(dest_fptr_term));
00678     XSB_STREAM_UNLOCK(src_xsb_fileno);
00679     break;
00680   }
00681 
00682   case PIPE_OPEN: { /* open_pipe(-ReadPipe, -WritePipe) */
00683     int pipe_fd[2];
00684 
00685     if (PIPE(pipe_fd) < 0) {
00686       ctop_int(CTXTc 2, PIPE_TO_PROC_FAILED);
00687       ctop_int(CTXTc 3, PIPE_FROM_PROC_FAILED);
00688       return TRUE;
00689     }
00690     ctop_int(CTXTc 2, pipe_fd[0]);
00691     ctop_int(CTXTc 3, pipe_fd[1]);
00692     break;
00693   }
00694 
00695   case FD2IOPORT: { /* fd2ioport(+Pipe, -IOport,+Mode) */
00696     /* this can take any C file descriptor and make it into an XSB I/O port.
00697         For backward compatability,mode may not be used -- where it is "u" */
00698     int pipe_fd, i;
00699     char *mode=NULL;
00700 #ifndef WIN_NT /* unix */
00701     int fd_flags;
00702 #endif
00703     pipe_fd = ptoc_int(CTXTc 2); /* the C file descriptor */
00704     pterm = reg_term(CTXTc 4);
00705 
00706     if (isstring(pterm)) {
00707       if ((string_val(pterm))[0] == 'u') {
00708         /* Need to try to find mode */
00709 #ifdef WIN_NT
00710     /* NT doesn't have fcntl(). Brain damage? */
00711     mode = "r+";
00712 #else /* unix */
00713     fd_flags = fcntl(pipe_fd, F_GETFL); 
00714     if (fd_flags == O_RDONLY)
00715       mode = "rb";
00716     else if (fd_flags == O_WRONLY)
00717       mode = "wb";
00718     else {
00719       /* can't determine the mode of the C fd -- return "r+" */
00720       mode = "r+";
00721     }
00722 #endif
00723       } 
00724       else mode = string_val(pterm);
00725     }
00726     else {
00727       xsb_abort("[FD2IOPORT] Opening mode must be an atom.");
00728       mode = "x";
00729     }
00730 
00731     fptr = fdopen(pipe_fd, mode);
00732 
00733     SYS_MUTEX_LOCK( MUTEX_IO );
00734     /* xsb_intern_file will return -1, if fdopen fails */
00735     i = xsb_intern_fileptr(fptr, "FD2IOPORT","created from fd",mode);
00736     ctop_int(CTXTc 3, i);
00737     open_files[i].stream_type = PIPE_STREAM;
00738     SYS_MUTEX_UNLOCK( MUTEX_IO );
00739     break;
00740   }
00741     
00742     /* TLS: relying on thread-safety of library -- no mutex here */
00743   case FILE_CLEARERR: { /* file_function(16, +IOport) */
00744     io_port = ptoc_int(CTXTc 2);
00745     if ((io_port < 0) && (io_port >= -MAXIOSTRS)) {
00746     }
00747     else {
00748       XSB_STREAM_LOCK(io_port);
00749       SET_FILEPTR(fptr, io_port);
00750       clearerr(fptr);
00751       XSB_STREAM_UNLOCK(io_port);
00752     }
00753     break;
00754   }
00755 
00756   case TMPFILE_OPEN: {
00757     /* file_function(17, -IOport)
00758        Opens a temp file in r/w mode and returns its IO port */
00759     SYS_MUTEX_LOCK( MUTEX_IO );
00760     if ((fptr = tmpfile())) 
00761       ctop_int(CTXTc 2, xsb_intern_fileptr(fptr, "TMPFILE_OPEN",
00762                                          "TMPFILE","wb+"));
00763     else
00764       ctop_int(CTXTc 2, -1);
00765     SYS_MUTEX_UNLOCK( MUTEX_IO );
00766     break;
00767   }
00768     
00769   case STREAM_PROPERTY: {
00770     int stream;
00771     stream = ptoc_int(CTXTc 2);
00772     XSB_STREAM_LOCK(stream);
00773     switch (ptoc_int(CTXTc 3)) {
00774 
00775       /* Type, Repos, eof_actions are all currently functions of class */
00776     case STREAM_EOF_ACTION:
00777     case STREAM_REPOSITIONABLE:
00778     case STREAM_TYPE: 
00779     case STREAM_CLASS: 
00780       ctop_int(CTXTc 4, open_files[stream].stream_type);
00781       break;
00782     
00783     case STREAM_FILE_NAME:  
00784       if (open_files[stream].stream_type < 3)
00785         ctop_string(CTXTc 4, open_files[stream].file_name);
00786       break;
00787 
00788     case STREAM_MODE: 
00789     case STREAM_INPUT: 
00790     case STREAM_OUTPUT: {
00791 
00792       mode = open_files[stream].io_mode; 
00793       if (mode == 'r' || mode == 's') {
00794         ctop_int(CTXTc 4,READ_MODE);
00795       } else if (mode == 'w' || mode == 'x') {
00796         ctop_int(CTXTc 4,WRITE_MODE);
00797       } else if (mode == 'a' || mode == 'b') {
00798         ctop_int(CTXTc 4,APPEND_MODE);
00799       }
00800       break;
00801     }
00802     }
00803     XSB_STREAM_UNLOCK(stream);
00804     break;
00805   }
00806 
00807   case IS_VALID_STREAM: {
00808     int stream;
00809     char iomode;
00810 
00811     stream = ptoc_int(CTXTc 2);
00812     if (stream >= MAX_OPEN_FILES)
00813         return FALSE;
00814     XSB_STREAM_LOCK(stream);
00815     if ((stream < 0) && (stream >= -MAXIOSTRS)) {
00816       /* port for reading from string */
00817       sfptr = strfileptr(stream);
00818       XSB_STREAM_UNLOCK(stream);
00819       if (sfptr == NULL) {
00820         return FALSE;
00821       }
00822       else {
00823         ctop_int(CTXTc 3,READ_MODE);
00824         return TRUE;
00825       }
00826     }
00827     if (stream < -MAXIOSTRS) {
00828       XSB_STREAM_UNLOCK(stream);
00829       return FALSE;
00830     }
00831     fptr = fileptr(stream); \
00832     if ((fptr==NULL) && (stream != 0)) {
00833       XSB_STREAM_UNLOCK(stream);
00834       return FALSE;
00835     }
00836     else {
00837         iomode = open_files[stream].io_mode; 
00838         XSB_STREAM_UNLOCK(stream);
00839         if (iomode == 'r' || iomode == 's') {
00840           ctop_int(CTXTc 3,READ_MODE);
00841         } else ctop_int(CTXTc 3,WRITE_MODE);
00842         return TRUE;
00843       }  
00844   }
00845 
00846   case PRINT_OPENFILES: { /* no args */
00847     int i; 
00848     for (i= 0 ; i < MAX_OPEN_FILES ; i++) {
00849       if (open_files[i].file_name == NULL) {
00850         printf("i: %d File Ptr %p Mode %c Type %d \n",
00851                 i,open_files[i].file_ptr,open_files[i].io_mode,
00852                 open_files[i].stream_type);
00853       } else {
00854         printf("i; %d File Ptr %p Name %s Mode %c Type %d\n",i,
00855                open_files[i].file_ptr, open_files[i].file_name,open_files[i].io_mode,
00856                open_files[i].stream_type);
00857       }
00858     }
00859     break;
00860   }
00861 
00862     /* TLS: range checking for streams done by is_valid_stream */
00863   case FILE_END_OF_FILE: {
00864 
00865     io_port = ptoc_int(CTXTc 2);
00866     XSB_STREAM_LOCK(io_port);
00867     if (io_port < 0) {
00868       sfptr = strfileptr(io_port);
00869       XSB_STREAM_UNLOCK(io_port);
00870       if (sfptr->strcnt == EOF) {
00871         XSB_STREAM_UNLOCK(io_port);
00872         return TRUE;
00873       } else {
00874         XSB_STREAM_UNLOCK(io_port);
00875         return FALSE;
00876       }
00877     }
00878     else {
00879       if (feof(open_files[ptoc_int(CTXTc 2)].file_ptr) != 0) {
00880         XSB_STREAM_UNLOCK(io_port);
00881         return TRUE;
00882       } else {
00883         XSB_STREAM_UNLOCK(io_port);
00884         return FALSE;
00885       }
00886     }
00887   }
00888 
00889   case FILE_PEEK: {
00890     int bufchar;
00891 
00892     io_port = ptoc_int(CTXTc 2);
00893     XSB_STREAM_LOCK(io_port);
00894     if ((io_port < 0) && (io_port >= -MAXIOSTRS)) {
00895       sfptr = strfileptr(io_port);
00896       ctop_int(CTXTc 3, strpeekc(sfptr));
00897     } else {
00898       SET_FILEPTR(fptr, io_port);
00899       bufchar = getc(fptr);
00900       ctop_int(CTXTc 3, bufchar);
00901       if (bufchar >= 0) 
00902         ungetc(bufchar, fptr);
00903     }
00904     XSB_STREAM_UNLOCK(io_port);
00905     break;
00906   }
00907 
00908   case XSB_STREAM_LOCK_B: {
00909 #ifdef MULTI_THREAD
00910     XSB_STREAM_LOCK(ptoc_int(CTXTc 2));
00911 #else
00912     return TRUE;
00913 #endif
00914     break;
00915   }
00916 
00917   case XSB_STREAM_UNLOCK_B: {
00918 #ifdef MULTI_THREAD
00919     XSB_STREAM_UNLOCK(ptoc_int(CTXTc 2));
00920 #else
00921     return TRUE;
00922 #endif
00923     break;
00924   }
00925 
00926   default:
00927     xsb_abort("[FILE_FUNCTION]: Invalid file operation, %d\n", ptoc_int(CTXTc 1));
00928   }
00929   
00930   return TRUE;
00931 }
00932 

Generated on Wed Jul 26 13:30:41 2006 for XSB by  doxygen 1.4.5