Sunday, August 31, 2014

Unix Prog: Standard I/O Implementation

1. fileno

fileno is used to get the file descriptor of given file stream

definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/stdio.h  
 ......  
 /* Return the system file descriptor for STREAM. */  
 extern int fileno (FILE *__stream) __THROW __wur;  
 ......  

fileio.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  FILE* fp;  
   
  if((fp = fopen("test.txt", "w+")) == NULL) {  
   printf("fopen error!\n");  
   exit(1);  
  }  
   
  printf("file descriptor: %d\n", fileno(fp));  
   
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ ./io.out  
 file descriptor: 3  

2. FILE struct implementation
 ubuntu@ip-172-31-23-227:~$ less /usr/include/libio.h  
 ......  
 struct _IO_FILE {  
  int _flags;      /* High-order word is _IO_MAGIC; rest is flags. */  
 #define _IO_file_flags _flags  
   
  /* The following pointers correspond to the C++ streambuf protocol. */  
  /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */  
  char* _IO_read_ptr;  /* Current read pointer */  
  char* _IO_read_end;  /* End of get area. */  
  char* _IO_read_base; /* Start of putback+get area. */  
  char* _IO_write_base; /* Start of put area. */  
  char* _IO_write_ptr; /* Current put pointer. */  
  char* _IO_write_end; /* End of put area. */  
  char* _IO_buf_base;  /* Start of reserve area. */  
  char* _IO_buf_end;  /* End of reserve area. */  
  /* The following fields are used to support backing up and undo. */  
  char *_IO_save_base; /* Pointer to start of non-current get area. */  
  char *_IO_backup_base; /* Pointer to first valid character of backup area */  
  char *_IO_save_end; /* Pointer to end of non-current get area. */  
   
  struct _IO_marker *_markers;  
   
  struct _IO_FILE *_chain;  
   
  int _fileno;  
 #if 0  
  int _blksize;  
 #else  
  int _flags2;  
 #endif  
  _IO_off_t _old_offset; /* This used to be _offset but it's too small. */  
   
 #define __HAVE_COLUMN /* temporary */  
  /* 1+column number of pbase(); 0 is unknown. */  
  unsigned short _cur_column;  
  signed char _vtable_offset;  
  char _shortbuf[1];  
   
  /* char* _save_gptr; char* _save_egptr; */  
   
  _IO_lock_t *_lock;  
 #ifdef _IO_USE_OLD_IO_FILE  
 };  
 ......  
 ubuntu@ip-172-31-23-227:~$ less /usr/include/stdio.h  
 ......  
 typedef struct _IO_FILE FILE;  
 ......  

3. Get the buffer information of file stream
We will use _IO_file_flags and _IO_UNBUFFERED, _IO_LINE_BUF to detect the buffer type of file stream. We also will use _IO_buf_end, _IO_buf_base to detect the buffer size of the file stream.

fileio.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 void pr_stdio(const char* name, FILE* fp)  
 {  
  printf("stream = %s.", name);  
  if(fp -> _IO_file_flags & _IO_UNBUFFERED) {  
   printf("unbuffered");  
  } else if(fp -> _IO_file_flags & _IO_LINE_BUF) {  
   printf("line buffered");  
  } else {  
   printf("fully buffered");  
  }  
   
  printf(", buffer size = %ld\n", fp -> _IO_buf_end - fp -> _IO_buf_base);  
 }  
   
 int main(int argc, char* argv[])  
 {  
  FILE *fp;  
   
  fputs("test line at standard output.\n", stdout);  
  fputs("test line at standard error.\n", stderr);  
   
  // Test the stream buffer for standard input/output/error  
  pr_stdio("stdin", stdin);  
  pr_stdio("stdout", stdout);  
  pr_stdio("stderr", stderr);  
   
  if((fp = fopen("test.txt", "w+")) == NULL) {  
   printf("fopen error!\n");  
   exit(1);  
  }  
   
  // Test the stream buffer of open file "test.txt"  
  pr_stdio("test.txt", fp);  
   
  // change the buffer  
  char buf[BUFSIZ];  
  setvbuf(fp, buf, _IOFBF, BUFSIZ);  
   
  printf("after changing the buffer to %d\n", BUFSIZ);  
  pr_stdio("test.txt", fp);  
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ ./io.out  
 test line at standard output.  
 test line at standard error.  
 stream = stdin.fully buffered, buffer size = 0  
 stream = stdout.line buffered, buffer size = 1024  
 stream = stderr.unbuffered, buffer size = 1  
 stream = test.txt.fully buffered, buffer size = 0  
 after changing the buffer to 8192  
 stream = test.txt.fully buffered, buffer size = 8192  

No comments:

Post a Comment