xref: /netbsd-src/external/bsd/zstd/dist/examples/common.h (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos 
11*3117ece4Schristos /*
12*3117ece4Schristos  * This header file has common utility functions used in examples.
13*3117ece4Schristos  */
14*3117ece4Schristos #ifndef COMMON_H
15*3117ece4Schristos #define COMMON_H
16*3117ece4Schristos 
17*3117ece4Schristos #include <stdlib.h>    // malloc, free, exit
18*3117ece4Schristos #include <stdio.h>     // fprintf, perror, fopen, etc.
19*3117ece4Schristos #include <string.h>    // strerror
20*3117ece4Schristos #include <errno.h>     // errno
21*3117ece4Schristos #include <sys/stat.h>  // stat
22*3117ece4Schristos #include <zstd.h>
23*3117ece4Schristos 
24*3117ece4Schristos 
25*3117ece4Schristos /* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
26*3117ece4Schristos #if defined(__GNUC__)
27*3117ece4Schristos #  define UNUSED_ATTR __attribute__((unused))
28*3117ece4Schristos #else
29*3117ece4Schristos #  define UNUSED_ATTR
30*3117ece4Schristos #endif
31*3117ece4Schristos 
32*3117ece4Schristos #define HEADER_FUNCTION static UNUSED_ATTR
33*3117ece4Schristos 
34*3117ece4Schristos 
35*3117ece4Schristos /*
36*3117ece4Schristos  * Define the returned error code from utility functions.
37*3117ece4Schristos  */
38*3117ece4Schristos typedef enum {
39*3117ece4Schristos     ERROR_fsize = 1,
40*3117ece4Schristos     ERROR_fopen = 2,
41*3117ece4Schristos     ERROR_fclose = 3,
42*3117ece4Schristos     ERROR_fread = 4,
43*3117ece4Schristos     ERROR_fwrite = 5,
44*3117ece4Schristos     ERROR_loadFile = 6,
45*3117ece4Schristos     ERROR_saveFile = 7,
46*3117ece4Schristos     ERROR_malloc = 8,
47*3117ece4Schristos     ERROR_largeFile = 9,
48*3117ece4Schristos } COMMON_ErrorCode;
49*3117ece4Schristos 
50*3117ece4Schristos /*! CHECK
51*3117ece4Schristos  * Check that the condition holds. If it doesn't print a message and die.
52*3117ece4Schristos  */
53*3117ece4Schristos #define CHECK(cond, ...)                        \
54*3117ece4Schristos     do {                                        \
55*3117ece4Schristos         if (!(cond)) {                          \
56*3117ece4Schristos             fprintf(stderr,                     \
57*3117ece4Schristos                     "%s:%d CHECK(%s) failed: ", \
58*3117ece4Schristos                     __FILE__,                   \
59*3117ece4Schristos                     __LINE__,                   \
60*3117ece4Schristos                     #cond);                     \
61*3117ece4Schristos             fprintf(stderr, "" __VA_ARGS__);    \
62*3117ece4Schristos             fprintf(stderr, "\n");              \
63*3117ece4Schristos             exit(1);                            \
64*3117ece4Schristos         }                                       \
65*3117ece4Schristos     } while (0)
66*3117ece4Schristos 
67*3117ece4Schristos /*! CHECK_ZSTD
68*3117ece4Schristos  * Check the zstd error code and die if an error occurred after printing a
69*3117ece4Schristos  * message.
70*3117ece4Schristos  */
71*3117ece4Schristos #define CHECK_ZSTD(fn)                                           \
72*3117ece4Schristos     do {                                                         \
73*3117ece4Schristos         size_t const err = (fn);                                 \
74*3117ece4Schristos         CHECK(!ZSTD_isError(err), "%s", ZSTD_getErrorName(err)); \
75*3117ece4Schristos     } while (0)
76*3117ece4Schristos 
77*3117ece4Schristos /*! fsize_orDie() :
78*3117ece4Schristos  * Get the size of a given file path.
79*3117ece4Schristos  *
80*3117ece4Schristos  * @return The size of a given file path.
81*3117ece4Schristos  */
82*3117ece4Schristos HEADER_FUNCTION size_t fsize_orDie(const char *filename)
83*3117ece4Schristos {
84*3117ece4Schristos     struct stat st;
85*3117ece4Schristos     if (stat(filename, &st) != 0) {
86*3117ece4Schristos         /* error */
87*3117ece4Schristos         perror(filename);
88*3117ece4Schristos         exit(ERROR_fsize);
89*3117ece4Schristos     }
90*3117ece4Schristos 
91*3117ece4Schristos     off_t const fileSize = st.st_size;
92*3117ece4Schristos     size_t const size = (size_t)fileSize;
93*3117ece4Schristos     /* 1. fileSize should be non-negative,
94*3117ece4Schristos      * 2. if off_t -> size_t type conversion results in discrepancy,
95*3117ece4Schristos      *    the file size is too large for type size_t.
96*3117ece4Schristos      */
97*3117ece4Schristos     if ((fileSize < 0) || (fileSize != (off_t)size)) {
98*3117ece4Schristos         fprintf(stderr, "%s : filesize too large \n", filename);
99*3117ece4Schristos         exit(ERROR_largeFile);
100*3117ece4Schristos     }
101*3117ece4Schristos     return size;
102*3117ece4Schristos }
103*3117ece4Schristos 
104*3117ece4Schristos /*! fopen_orDie() :
105*3117ece4Schristos  * Open a file using given file path and open option.
106*3117ece4Schristos  *
107*3117ece4Schristos  * @return If successful this function will return a FILE pointer to an
108*3117ece4Schristos  * opened file otherwise it sends an error to stderr and exits.
109*3117ece4Schristos  */
110*3117ece4Schristos HEADER_FUNCTION FILE* fopen_orDie(const char *filename, const char *instruction)
111*3117ece4Schristos {
112*3117ece4Schristos     FILE* const inFile = fopen(filename, instruction);
113*3117ece4Schristos     if (inFile) return inFile;
114*3117ece4Schristos     /* error */
115*3117ece4Schristos     perror(filename);
116*3117ece4Schristos     exit(ERROR_fopen);
117*3117ece4Schristos }
118*3117ece4Schristos 
119*3117ece4Schristos /*! fclose_orDie() :
120*3117ece4Schristos  * Close an opened file using given FILE pointer.
121*3117ece4Schristos  */
122*3117ece4Schristos HEADER_FUNCTION void fclose_orDie(FILE* file)
123*3117ece4Schristos {
124*3117ece4Schristos     if (!fclose(file)) { return; };
125*3117ece4Schristos     /* error */
126*3117ece4Schristos     perror("fclose");
127*3117ece4Schristos     exit(ERROR_fclose);
128*3117ece4Schristos }
129*3117ece4Schristos 
130*3117ece4Schristos /*! fread_orDie() :
131*3117ece4Schristos  *
132*3117ece4Schristos  * Read sizeToRead bytes from a given file, storing them at the
133*3117ece4Schristos  * location given by buffer.
134*3117ece4Schristos  *
135*3117ece4Schristos  * @return The number of bytes read.
136*3117ece4Schristos  */
137*3117ece4Schristos HEADER_FUNCTION size_t fread_orDie(void* buffer, size_t sizeToRead, FILE* file)
138*3117ece4Schristos {
139*3117ece4Schristos     size_t const readSize = fread(buffer, 1, sizeToRead, file);
140*3117ece4Schristos     if (readSize == sizeToRead) return readSize;   /* good */
141*3117ece4Schristos     if (feof(file)) return readSize;   /* good, reached end of file */
142*3117ece4Schristos     /* error */
143*3117ece4Schristos     perror("fread");
144*3117ece4Schristos     exit(ERROR_fread);
145*3117ece4Schristos }
146*3117ece4Schristos 
147*3117ece4Schristos /*! fwrite_orDie() :
148*3117ece4Schristos  *
149*3117ece4Schristos  * Write sizeToWrite bytes to a file pointed to by file, obtaining
150*3117ece4Schristos  * them from a location given by buffer.
151*3117ece4Schristos  *
152*3117ece4Schristos  * Note: This function will send an error to stderr and exit if it
153*3117ece4Schristos  * cannot write data to the given file pointer.
154*3117ece4Schristos  *
155*3117ece4Schristos  * @return The number of bytes written.
156*3117ece4Schristos  */
157*3117ece4Schristos HEADER_FUNCTION size_t fwrite_orDie(const void* buffer, size_t sizeToWrite, FILE* file)
158*3117ece4Schristos {
159*3117ece4Schristos     size_t const writtenSize = fwrite(buffer, 1, sizeToWrite, file);
160*3117ece4Schristos     if (writtenSize == sizeToWrite) return sizeToWrite;   /* good */
161*3117ece4Schristos     /* error */
162*3117ece4Schristos     perror("fwrite");
163*3117ece4Schristos     exit(ERROR_fwrite);
164*3117ece4Schristos }
165*3117ece4Schristos 
166*3117ece4Schristos /*! malloc_orDie() :
167*3117ece4Schristos  * Allocate memory.
168*3117ece4Schristos  *
169*3117ece4Schristos  * @return If successful this function returns a pointer to allo-
170*3117ece4Schristos  * cated memory.  If there is an error, this function will send that
171*3117ece4Schristos  * error to stderr and exit.
172*3117ece4Schristos  */
173*3117ece4Schristos HEADER_FUNCTION void* malloc_orDie(size_t size)
174*3117ece4Schristos {
175*3117ece4Schristos     void* const buff = malloc(size);
176*3117ece4Schristos     if (buff) return buff;
177*3117ece4Schristos     /* error */
178*3117ece4Schristos     perror("malloc");
179*3117ece4Schristos     exit(ERROR_malloc);
180*3117ece4Schristos }
181*3117ece4Schristos 
182*3117ece4Schristos /*! loadFile_orDie() :
183*3117ece4Schristos  * load file into buffer (memory).
184*3117ece4Schristos  *
185*3117ece4Schristos  * Note: This function will send an error to stderr and exit if it
186*3117ece4Schristos  * cannot read data from the given file path.
187*3117ece4Schristos  *
188*3117ece4Schristos  * @return If successful this function will load file into buffer and
189*3117ece4Schristos  * return file size, otherwise it will printout an error to stderr and exit.
190*3117ece4Schristos  */
191*3117ece4Schristos HEADER_FUNCTION size_t loadFile_orDie(const char* fileName, void* buffer, size_t bufferSize)
192*3117ece4Schristos {
193*3117ece4Schristos     size_t const fileSize = fsize_orDie(fileName);
194*3117ece4Schristos     CHECK(fileSize <= bufferSize, "File too large!");
195*3117ece4Schristos 
196*3117ece4Schristos     FILE* const inFile = fopen_orDie(fileName, "rb");
197*3117ece4Schristos     size_t const readSize = fread(buffer, 1, fileSize, inFile);
198*3117ece4Schristos     if (readSize != (size_t)fileSize) {
199*3117ece4Schristos         fprintf(stderr, "fread: %s : %s \n", fileName, strerror(errno));
200*3117ece4Schristos         exit(ERROR_fread);
201*3117ece4Schristos     }
202*3117ece4Schristos     fclose(inFile);  /* can't fail, read only */
203*3117ece4Schristos     return fileSize;
204*3117ece4Schristos }
205*3117ece4Schristos 
206*3117ece4Schristos /*! mallocAndLoadFile_orDie() :
207*3117ece4Schristos  * allocate memory buffer and then load file into it.
208*3117ece4Schristos  *
209*3117ece4Schristos  * Note: This function will send an error to stderr and exit if memory allocation
210*3117ece4Schristos  * fails or it cannot read data from the given file path.
211*3117ece4Schristos  *
212*3117ece4Schristos  * @return If successful this function will return buffer and bufferSize(=fileSize),
213*3117ece4Schristos  * otherwise it will printout an error to stderr and exit.
214*3117ece4Schristos  */
215*3117ece4Schristos HEADER_FUNCTION void* mallocAndLoadFile_orDie(const char* fileName, size_t* bufferSize)
216*3117ece4Schristos {
217*3117ece4Schristos     size_t const fileSize = fsize_orDie(fileName);
218*3117ece4Schristos     *bufferSize = fileSize;
219*3117ece4Schristos     void* const buffer = malloc_orDie(*bufferSize);
220*3117ece4Schristos     loadFile_orDie(fileName, buffer, *bufferSize);
221*3117ece4Schristos     return buffer;
222*3117ece4Schristos }
223*3117ece4Schristos 
224*3117ece4Schristos /*! saveFile_orDie() :
225*3117ece4Schristos  *
226*3117ece4Schristos  * Save buffSize bytes to a given file path, obtaining them from a location pointed
227*3117ece4Schristos  * to by buff.
228*3117ece4Schristos  *
229*3117ece4Schristos  * Note: This function will send an error to stderr and exit if it
230*3117ece4Schristos  * cannot write to a given file.
231*3117ece4Schristos  */
232*3117ece4Schristos HEADER_FUNCTION void saveFile_orDie(const char* fileName, const void* buff, size_t buffSize)
233*3117ece4Schristos {
234*3117ece4Schristos     FILE* const oFile = fopen_orDie(fileName, "wb");
235*3117ece4Schristos     size_t const wSize = fwrite(buff, 1, buffSize, oFile);
236*3117ece4Schristos     if (wSize != (size_t)buffSize) {
237*3117ece4Schristos         fprintf(stderr, "fwrite: %s : %s \n", fileName, strerror(errno));
238*3117ece4Schristos         exit(ERROR_fwrite);
239*3117ece4Schristos     }
240*3117ece4Schristos     if (fclose(oFile)) {
241*3117ece4Schristos         perror(fileName);
242*3117ece4Schristos         exit(ERROR_fclose);
243*3117ece4Schristos     }
244*3117ece4Schristos }
245*3117ece4Schristos 
246*3117ece4Schristos #endif
247