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