libexplain  1.4.D001
libexplain/string_flags.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008, 2009, 2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 3 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/fcntl.h>
00021 
00022 #include <libexplain/string_buffer.h>
00023 #include <libexplain/string_flags.h>
00024 
00025 
00026 void
00027 explain_string_flags_init(explain_string_flags_t *sf, const char *flags)
00028 {
00029     int             acc_mode;
00030     int             options;
00031     const char      *cp;
00032     explain_string_buffer_t yuck_buf;
00033     int             plus_seen;
00034 
00035     explain_string_buffer_init(&yuck_buf, sf->invalid, sizeof(sf->invalid));
00036 
00037     /*
00038      * Parse the flags string.
00039      *
00040      * (It turns out glibc is more generous than this, when it comes to
00041      * validity, but we only complain for EINVAL.  Different systems
00042      * will see validity differently.)
00043      */
00044     sf->rwa_seen = 0;
00045     acc_mode = O_RDONLY;
00046     options = 0;
00047 #ifdef O_LARGEFILE
00048     options |= O_LARGEFILE;
00049 #endif
00050 #ifdef O_LARGEFILE_HIDDEN
00051     options |= O_LARGEFILE_HIDDEN;
00052 #endif
00053     sf->flags_string_valid = 1;
00054     cp = flags;
00055     plus_seen = 0;
00056     for (;;)
00057     {
00058         unsigned char   c;
00059 
00060         c = *cp++;
00061         switch (c)
00062         {
00063         case '\0':
00064             /* end of string */
00065             if (!sf->rwa_seen)
00066                 sf->flags_string_valid = 0;
00067             sf->flags = acc_mode | options;
00068             return;
00069 
00070         case '+':
00071             /*
00072              * "r+" Open for reading and writing.  The stream is
00073              *      positioned at the beginning of the file.
00074              *
00075              * "w+" Open for reading and writing.  The file is created
00076              *      if it does not exist, otherwise it is truncated.
00077              *      The stream is positioned at the beginning of the
00078              *      file.
00079              *
00080              * "a+" Open for reading and appending (writing at end of
00081              *      file).  The file is created if it does not exist.
00082              *      The initial file position for reading is at the
00083              *      beginning of the file, but output is always appended
00084              *      to the end of the file.
00085              */
00086             if (!sf->rwa_seen || plus_seen)
00087                 goto duplicate;
00088             acc_mode = O_RDWR;
00089             plus_seen = 1;
00090             break;
00091 
00092         case 'a':
00093             /*
00094              * Open for appending (writing at end of file).  The file is
00095              * created if it does not exist.  The stream is positioned
00096              * at the end of the file.
00097              */
00098             if (sf->rwa_seen && (options & O_APPEND))
00099                 goto duplicate;
00100             acc_mode = O_WRONLY;
00101             options |= O_CREAT | O_APPEND;
00102             sf->rwa_seen = 1;
00103             break;
00104 
00105         case 'b':
00106             /*
00107              * The mode string can also include the letter 'b' either
00108              * as a last character or as a character between the
00109              * characters in any of the two-character strings
00110              * described above.  This is strictly for compatibility with
00111              * C89 and has no effect; the 'b' is ignored on all POSIX
00112              * conforming systems, including Linux.  (Other systems
00113              * may treat text files and binary files differently, and
00114              * adding the 'b' may be a good idea if you do I/O to a
00115              * binary file and expect that your program may be ported to
00116              * non-UNIX environments.)
00117              */
00118             options |= O_BINARY;
00119             break;
00120 
00121         case  'c':
00122             /*
00123              * GNU extension
00124              * not a thread cancellation point
00125              */
00126             break;
00127 
00128         case 'e':
00129             /* GNU extension */
00130             options |= O_CLOEXEC;
00131             break;
00132 
00133         case 'm':
00134             /*
00135              * GNU extension
00136              * try to use mmap
00137              */
00138             break;
00139 
00140         case 'r':
00141             /*
00142              * Open text file for reading.  The stream is positioned at
00143              * the beginning of the file.
00144              */
00145             if (sf->rwa_seen && acc_mode == O_RDONLY)
00146                 goto duplicate;
00147             acc_mode = O_RDONLY;
00148             sf->rwa_seen = 1;
00149             break;
00150 
00151         case 't':
00152             /* GNU extension */
00153             options |= O_TEXT;
00154             break;
00155 
00156         case 'w':
00157             /*
00158              * Truncate file to zero length or create text file for
00159              * writing.  The stream is positioned at the beginning of
00160              * the file.
00161              */
00162             if (sf->rwa_seen && acc_mode == O_WRONLY)
00163                 goto duplicate;
00164             acc_mode = O_WRONLY;
00165             options |= O_CREAT | O_TRUNC;
00166             sf->rwa_seen = 1;
00167             break;
00168 
00169         case 'x':
00170             /* GNU extension */
00171             options |= O_EXCL;
00172             break;
00173 
00174         default:
00175             duplicate:
00176             sf->flags_string_valid = 0;
00177             explain_string_buffer_putc(&yuck_buf, c);
00178             break;
00179         }
00180     }
00181 }
00182 
00183 /* vim: set ts=8 sw=4 et : */