1. 程式人生 > 實用技巧 >8.CaDiCal程式碼解讀——單獨的型別相關程式碼--file.hpp-file.cpp

8.CaDiCal程式碼解讀——單獨的型別相關程式碼--file.hpp-file.cpp

說明:

(1)file.hpp中包含了相關的輸入輸出函式;

(2)File型別內部有一個Internal指標,該指標用於銜接;

              Internal * internal;

(3)可以接受讀取各種壓縮個格式的cnf輸入檔案

(4)開啟檔案函式open有兩個,關閉檔案函式close只有一個;

(5)


file.hpp程式碼解讀

  1 #ifndef _file_hpp_INCLUDED
  2 #define _file_hpp_INCLUDED
  3 
  4 #include <cstdio>
  5 #include <cassert>
  6
#include <cstdlib> 7 8 #ifndef NDEBUG 9 #include <climits> 10 #endif 11 12 /*------------------------------------------------------------------------*/ 13 #ifndef NUNLOCKED 14 #define cadical_putc_unlocked putc_unlocked 15 #define cadical_getc_unlocked getc_unlocked 16 #else
17 #define cadical_putc_unlocked putc 18 #define cadical_getc_unlocked getc 19 #endif 20 /*------------------------------------------------------------------------*/ 21 22 namespace CaDiCaL { 23 24 // Wraps a 'C' file 'FILE' with name and supports zipped reading and writing 25 // through 'popen' using external helper tools. Reading has line numbers.
26 // Compression and decompression relies on external utilities, e.g., 'gzip', 27 // 'bzip2', 'xz', and '7z', which should be in the 'PATH'. 28 29 struct Internal; //前置宣告 30 31 class File { 32 33 #ifndef QUIET 34 Internal * internal; //該指標用於與整體銜接 35 #endif 36 #if !defined(QUIET) || !defined(NDEBUG) 37 bool writing; 38 #endif 39 40 int close_file; // need to close file (1=fclose, 2=pclose) 41 FILE * file; 42 const char * _name; 43 uint64_t _lineno; 44 uint64_t _bytes; 45 46 File (Internal *, bool, int, FILE *, const char *); 47 48 static FILE * open_file (Internal *, 49 const char * path, const char * mode); 50 static FILE * read_file (Internal *, const char * path); 51 static FILE * write_file (Internal *, const char * path); 52 53 static FILE * open_pipe (Internal *, 54 const char * fmt, 55 const char * path, 56 const char * mode); 57 static FILE * read_pipe (Internal *, 58 const char * fmt, 59 const int * sig, 60 const char * path); 61 static FILE * write_pipe (Internal *, 62 const char * fmt, const char * path); 63 public: 64 65 static char* find (const char * prg); // search in 'PATH' 66 static bool exists (const char * path); // file exists? 67 static bool writable (const char * path);// can write to that file? 68 static size_t size (const char * path); // file size in bytes 69 70 // Does the file match the file type signature. 71 // 72 static bool match (Internal *, const char * path, const int * sig); 73 74 // Read from existing file. Assume given name. 75 // 76 static File * read (Internal *, FILE * f, const char * name); 77 78 // Open file from path name for reading (possibly through opening a pipe 79 // to a decompression utility, based on the suffix). 80 // 81 static File * read (Internal *, const char * path); 82 83 // Same for writing as for reading above. 84 // 85 static File * write (Internal *, FILE *, const char * name); 86 static File * write (Internal *, const char * path); 87 88 ~File (); 89 90 // Using the 'unlocked' versions here is way faster but 91 // not thread safe if the same file is used by different 92 // threads, which on the other hand currently is impossible. 93 94 int get () { 95 assert (!writing); 96 int res = cadical_getc_unlocked (file); 97 if (res == '\n') _lineno++; 98 if (res != EOF) _bytes++; 99 return res; 100 } 101 102 bool put (char ch) { 103 assert (writing); 104 if (cadical_putc_unlocked (ch, file) == EOF) return false; 105 _bytes++; 106 return true; 107 } 108 109 bool put (unsigned char ch) { 110 assert (writing); 111 if (cadical_putc_unlocked (ch, file) == EOF) return false; 112 _bytes++; 113 return true; 114 } 115 116 bool put (const char * s) { 117 for (const char * p = s; *p; p++) 118 if (!put (*p)) return false; 119 return true; 120 } 121 122 bool put (int lit) { 123 assert (writing); 124 if (!lit) return put ('0'); 125 else if (lit == -2147483648) { 126 assert (lit == INT_MIN); 127 return put ("-2147483648"); 128 } else { 129 char buffer[11]; 130 int i = sizeof buffer; 131 buffer[--i] = 0; 132 assert (lit != INT_MIN); 133 unsigned idx = abs (lit); 134 while (idx) { 135 assert (i > 0); 136 buffer[--i] = '0' + idx % 10; 137 idx /= 10; 138 } 139 if (lit < 0 && !put ('-')) return false; 140 return put (buffer + i); 141 } 142 } 143 144 bool put (int64_t l) { 145 assert (writing); 146 if (!l) return put ('0'); 147 else if (l == INT64_MIN) { 148 assert (sizeof l == 8); 149 return put ("-9223372036854775808"); 150 } else { 151 char buffer[21]; 152 int i = sizeof buffer; 153 buffer[--i] = 0; 154 assert (l != INT64_MIN); 155 uint64_t k = l < 0 ? -l : l; 156 while (k) { 157 assert (i > 0); 158 buffer[--i] = '0' + k % 10; 159 k /= 10; 160 } 161 if (l < 0 && !put ('-')) return false; 162 return put (buffer + i); 163 } 164 } 165 166 const char * name () const { return _name; } 167 uint64_t lineno () const { return _lineno; } 168 uint64_t bytes () const { return _bytes; } 169 170 bool closed () { return !file; } 171 void close (); //open函式有兩個(open_file,open_pipe),close函式只有一個 172 void flush (); 173 }; 174 175 } 176 177 #endif

file.cpp程式碼解讀

  1 #include "internal.hpp"  //沒有直接包含file.hpp標頭檔案,該標頭檔案在internal.hpp之中
  2 
  3 /*------------------------------------------------------------------------*/
  4 
  5 // Some more low-level 'C' headers.
  6 
  7 extern "C" {
  8 #include <string.h>
  9 #include <errno.h>
 10 #include <sys/stat.h>
 11 #include <sys/types.h>
 12 #include <unistd.h>
 13 #include <stdlib.h>
 14 }
 15 
 16 /*------------------------------------------------------------------------*/
 17 
 18 namespace CaDiCaL {
 19 
 20 /*------------------------------------------------------------------------*/
 21 
 22 // Private constructor.
 23 
 24 File::File (Internal *i, bool w, int c, FILE * f, const char * n)
 25 :
 26 #ifndef QUIET
 27   internal (i),
 28 #endif
 29 #if !defined(QUIET) || !defined(NDEBUG)
 30   writing (w),
 31 #endif
 32   close_file (c), file (f),
 33   _name (n), _lineno (1), _bytes (0)
 34 {
 35   (void) i, (void) w;
 36   assert (f), assert (n);
 37 }
 38 
 39 /*------------------------------------------------------------------------*/
 40 
 41 bool File::exists (const char * path) {
 42   struct stat buf;
 43   if (stat (path, &buf)) return false;
 44   if (access (path, R_OK)) return false;
 45   return true;
 46 }
 47 
 48 bool File::writable (const char * path) {
 49   int res;
 50   if (!path) res = 1;
 51   else if (!strcmp (path, "/dev/null")) res = 0;
 52   else {
 53     if (!*path) res = 2;
 54     else {
 55       struct stat buf;
 56       const char * p = strrchr (path, '/');
 57       if (!p) {
 58         if (stat (path, &buf)) res = ((errno == ENOENT) ? 0 : -2);
 59         else if (S_ISDIR (buf.st_mode)) res = 3;
 60         else res = (access (path, W_OK) ? 4 : 0);
 61       } else if (!p[1]) res = 5;
 62       else {
 63         size_t len = p - path;
 64         char * dirname = new char[len + 1];
 65         strncpy (dirname, path, len);
 66         dirname[len] = 0;
 67         if (stat (dirname, &buf)) res = 6;
 68         else if (!S_ISDIR (buf.st_mode)) res = 7;
 69         else if (access (dirname, W_OK)) res = 8;
 70         else if (stat (path, &buf)) res = (errno == ENOENT) ? 0 : -3;
 71         else res = access (path, W_OK) ? 9 : 0;
 72         delete [] dirname;
 73       }
 74     }
 75   }
 76   return !res;
 77 }
 78 
 79 // These are signatures for supported compressed file types.  In 2018 the
 80 // SAT Competition was running on StarExec and used internally 'bzip2'
 81 // compressed files, but gave them uncompressed to the solver using exactly
 82 // the same path (with '.bz2' suffix).  Then 'CaDiCaL' tried to read that
 83 // actually uncompressed file through 'bzip2', which of course failed.  Now
 84 // we double check and fall back to reading the file as is, if the signature
 85 // does not match after issuing a warning.
// 譯文:這些是支援的壓縮檔案型別的簽名
86 87 static int xzsig[] = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, EOF }; 88 static int bz2sig[] = { 0x42, 0x5A, 0x68, EOF }; 89 static int gzsig[] = { 0x1F, 0x8B, EOF }; 90 static int sig7z[] = { 0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, EOF }; 91 static int lzmasig[] = { 0x5D, 0x00, 0x00, 0x80, 0x00, EOF }; 92 93 bool File::match (Internal * internal, 94 const char * path, const int * sig) { 95 assert (path); 96 FILE * tmp = fopen (path, "r"); 97 if (!tmp) { 98 WARNING ("failed to open '%s' to check signature", path); 99 return false; 100 } 101 bool res = true; 102 for (const int *p = sig; res && (*p != EOF); p++) 103 res = (cadical_getc_unlocked (tmp) == *p); 104 fclose (tmp); 105 if (!res) WARNING ("file type signature check for '%s' failed", path); 106 return res; 107 } 108 109 size_t File::size (const char * path) { 110 struct stat buf; 111 if (stat (path, &buf)) return 0; 112 return (size_t) buf.st_size; 113 } 114 115 // Check that 'prg' is in the 'PATH' and thus can be found if executed 116 // through 'popen'. 117 118 char * File::find (const char * prg) { 119 size_t prglen = strlen (prg); 120 const char * c = getenv ("PATH"); 121 if (!c) return 0;; 122 size_t len = strlen (c); 123 char * e = new char[len + 1]; 124 strcpy (e, c); 125 char * res = 0; 126 for (char * p = e, * q; !res && p < e + len; p = q) { 127 for (q = p; *q && *q != ':'; q++) 128 ; 129 *q++ = 0; 130 size_t pathlen = (q - p) + prglen; 131 char * path = new char [pathlen + 1]; 132 sprintf (path, "%s/%s", p, prg); 133 assert (strlen (path) == pathlen); 134 if (exists (path)) res = path; 135 else delete [] path; 136 } 137 delete [] e; 138 return res; 139 } 140 141 /*------------------------------------------------------------------------*/ 142 143 FILE * File::open_file (Internal * internal, const char * path, 144 const char * mode) { 145 (void) internal; 146 return fopen (path, mode); 147 } 148 149 FILE * File::read_file (Internal * internal, const char * path) { 150 MSG ("opening file to read '%s'", path); 151 return open_file (internal, path, "r"); 152 } 153 154 FILE * File::write_file (Internal * internal, const char * path) { 155 MSG ("opening file to write '%s'", path); 156 return open_file (internal, path, "w"); 157 } 158 159 /*------------------------------------------------------------------------*/ 160 161 FILE * File::open_pipe (Internal * internal, 162 const char * fmt, const char * path, 163 const char * mode) { 164 #ifdef QUIET 165 (void) internal; 166 #endif 167 size_t prglen = 0; 168 while (fmt[prglen] && fmt[prglen] != ' ') prglen++; 169 char * prg = new char [prglen + 1]; 170 strncpy (prg, fmt, prglen); 171 prg[prglen] = 0; 172 char * found = find (prg); 173 if (found) MSG ("found '%s' in path for '%s'", found, prg); 174 if (!found) MSG ("did not find '%s' in path", prg); 175 delete [] prg; 176 if (!found) return 0; 177 delete [] found; 178 char * cmd = new char [strlen (fmt) + strlen (path)]; 179 sprintf (cmd, fmt, path); 180 FILE * res = popen (cmd, mode); 181 delete [] cmd; 182 return res; 183 } 184 185 FILE * File::read_pipe (Internal * internal, 186 const char * fmt, 187 const int * sig, 188 const char * path) { 189 if (!File::exists (path)) { 190 LOG ("file '%s' does not exist", path); 191 return 0; 192 } 193 LOG ("file '%s' exists", path); 194 if (sig && !File::match (internal, path, sig)) return 0; 195 LOG ("file '%s' matches signature for '%s'", path, fmt); 196 MSG ("opening pipe to read '%s'", path); 197 return open_pipe (internal, fmt, path, "r"); 198 } 199 200 FILE * File::write_pipe (Internal * internal, 201 const char * fmt, const char * path) { 202 MSG ("opening pipe to write '%s'", path); 203 return open_pipe (internal, fmt, path, "w"); 204 } 205 206 /*------------------------------------------------------------------------*/ 207 208 File * File::read (Internal * internal, FILE * f, const char * n) { 209 return new File (internal, false, 0, f, n); 210 } 211 212 File * File::write (Internal * internal, FILE * f, const char * n) { 213 return new File (internal, true, 0, f, n); 214 } 215 216 File * File::read (Internal * internal, const char * path) { 217 FILE * file; 218 int close_input = 2; 219 if (has_suffix (path, ".xz")) { 220 file = read_pipe (internal, "xz -c -d %s", xzsig, path); 221 if (!file) goto READ_FILE; 222 } else if (has_suffix (path, ".lzma")) { 223 file = read_pipe (internal, "lzma -c -d %s", lzmasig, path); 224 if (!file) goto READ_FILE; 225 } else if (has_suffix (path, ".bz2")) { 226 file = read_pipe (internal, "bzip2 -c -d %s", bz2sig, path); 227 if (!file) goto READ_FILE; 228 } else if (has_suffix (path, ".gz")) { 229 file = read_pipe (internal, "gzip -c -d %s", gzsig, path); 230 if (!file) goto READ_FILE; 231 } else if (has_suffix (path, ".7z")) { 232 file = read_pipe (internal, "7z x -so %s 2>/dev/null", sig7z, path); 233 if (!file) goto READ_FILE; 234 } else { 235 READ_FILE: 236 file = read_file (internal, path); 237 close_input = 1; 238 } 239 240 return file ? new File (internal, false, close_input, file, path) : 0; 241 } 242 243 File * File::write (Internal * internal, const char * path) { 244 FILE * file; 245 int close_input = 2; 246 if (has_suffix (path, ".xz")) 247 file = write_pipe (internal, "xz -c > %s", path); 248 else if (has_suffix (path, ".bz2")) 249 file = write_pipe (internal, "bzip2 -c > %s", path); 250 else if (has_suffix (path, ".gz")) 251 file = write_pipe (internal, "gzip -c > %s", path); 252 else if (has_suffix (path, ".7z")) 253 file = write_pipe (internal, 254 "7z a -an -txz -si -so > %s 2>/dev/null", path); 255 else 256 file = write_file (internal, path), close_input = 1; 257 258 return file ? new File (internal, true, close_input, file, path) : 0; 259 } 260 261 void File::close () { 262 assert (file); 263 if (close_file == 0) { 264 MSG ("disconnecting from '%s'", name ()); 265 } 266 if (close_file == 1) { 267 MSG ("closing file '%s'", name ()); 268 fclose (file); 269 } 270 if (close_file == 2) { 271 MSG ("closing pipe command on '%s'", name ()); 272 pclose (file); 273 } 274 275 file = 0; // mark as closed 276 277 #ifndef QUIET 278 if (internal->opts.verbose > 1) return; 279 double mb = bytes () / (double) (1 << 20); 280 if (writing) 281 MSG ("after writing %" PRIu64 " bytes %.1f MB", bytes (), mb); 282 else 283 MSG ("after reading %" PRIu64 " bytes %.1f MB", bytes (), mb); 284 if (close_file == 2) { 285 int64_t s = size (name ()); 286 double mb = s / (double) (1<<20); 287 if (writing) 288 MSG ("deflated to %" PRId64 " bytes %.1f MB by factor %.2f " 289 "(%.2f%% compression)", 290 s, mb, relative (bytes (), s), percent (bytes () - s, bytes ())); 291 else 292 MSG ("inflated from %" PRId64 " bytes %.1f MB by factor %.2f " 293 "(%.2f%% compression)", 294 s, mb, relative (bytes (), s), percent (bytes () - s, bytes ())); 295 } 296 #endif 297 } 298 299 void File::flush () { 300 assert (file); 301 fflush (file); 302 } 303 304 File::~File () { if (file) close (); } 305 306 }