blob: 11555f20b20e3b40dc4e0744267e4d36f96a0504 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/stat.h>
#ifndef true
#define true 1
#define false 0
#endif
#include "CFCUtil.h"
void
CFCUtil_null_check(const void *arg, const char *name, const char *file,
int line) {
if (!arg) {
CFCUtil_die("%s cannot be NULL at %s line %d", name, file, line);
}
}
char*
CFCUtil_strdup(const char *string) {
if (!string) { return NULL; }
return CFCUtil_strndup(string, strlen(string));
}
char*
CFCUtil_strndup(const char *string, size_t len) {
if (!string) { return NULL; }
char *copy = (char*)MALLOCATE(len + 1);
memcpy(copy, string, len);
copy[len] = '\0';
return copy;
}
void
CFCUtil_trim_whitespace(char *text) {
if (!text) {
return;
}
// Find start.
char *ptr = text;
while (*ptr != '\0' && isspace(*ptr)) { ptr++; }
// Find end.
size_t orig_len = strlen(text);
char *limit = text + orig_len;
for (; limit > text; limit--) {
if (!isspace(*(limit - 1))) { break; }
}
// Modify string in place and NULL-terminate.
while (ptr < limit) {
*text++ = *ptr++;
}
*text = '\0';
}
void*
CFCUtil_wrapped_malloc(size_t count, const char *file, int line) {
void *pointer = malloc(count);
if (pointer == NULL && count != 0) {
if (sizeof(long) >= sizeof(size_t)) {
fprintf(stderr, "Can't malloc %lu bytes at %s line %d\n",
(unsigned long)count, file, line);
}
else {
fprintf(stderr, "malloc failed at %s line %d\n", file, line);
}
exit(1);
}
return pointer;
}
void*
CFCUtil_wrapped_calloc(size_t count, size_t size, const char *file, int line) {
void *pointer = calloc(count, size);
if (pointer == NULL && count != 0) {
if (sizeof(long) >= sizeof(size_t)) {
fprintf(stderr,
"Can't calloc %lu elements of size %lu at %s line %d\n",
(unsigned long)count, (unsigned long)size, file, line);
}
else {
fprintf(stderr, "calloc failed at %s line %d\n", file, line);
}
exit(1);
}
return pointer;
}
void*
CFCUtil_wrapped_realloc(void *ptr, size_t size, const char *file, int line) {
void *pointer = realloc(ptr, size);
if (pointer == NULL && size != 0) {
if (sizeof(long) >= sizeof(size_t)) {
fprintf(stderr, "Can't realloc %lu bytes at %s line %d\n",
(unsigned long)size, file, line);
}
else {
fprintf(stderr, "realloc failed at %s line %d\n", file, line);
}
exit(1);
}
return pointer;
}
void
CFCUtil_wrapped_free(void *ptr) {
free(ptr);
}
int
CFCUtil_current(const char *orig, const char *dest) {
// If the destination file doesn't exist, we're not current.
struct stat dest_stat;
if (stat(dest, &dest_stat) == -1) {
return false;
}
// If the source file is newer than the dest, we're not current.
struct stat orig_stat;
if (stat(orig, &orig_stat) == -1) {
CFCUtil_die("Missing source file '%s'", orig);
}
if (orig_stat.st_mtime > dest_stat.st_mtime) {
return false;
}
// Current!
return 1;
}
void
CFCUtil_write_file(const char *filename, const char *content, size_t len) {
FILE *fh = fopen(filename, "w+");
if (fh == NULL) {
CFCUtil_die("Couldn't open '%s': %s", filename, strerror(errno));
}
fwrite(content, sizeof(char), len, fh);
if (fclose(fh)) {
CFCUtil_die("Error when closing '%s': %s", filename, strerror(errno));
}
}
char*
CFCUtil_slurp_text(const char *file_path, size_t *len_ptr) {
FILE *const file = fopen(file_path, "r");
char *contents;
size_t binary_len;
long text_len;
/* Sanity check. */
if (file == NULL) {
CFCUtil_die("Error opening file '%s': %s", file_path, strerror(errno));
}
/* Find length; return NULL if the file has a zero-length. */
binary_len = CFCUtil_flength(file);
if (binary_len == 0) {
*len_ptr = 0;
return NULL;
}
/* Allocate memory and read the file. */
contents = (char*)MALLOCATE(binary_len * sizeof(char) + 1);
text_len = fread(contents, sizeof(char), binary_len, file);
/* Weak error check, because CRLF might result in fewer chars read. */
if (text_len <= 0) {
CFCUtil_die("Tried to read %ld bytes of '%s', got return code %ld",
(long)binary_len, file_path, (long)text_len);
}
/* NULL-terminate. */
contents[text_len] = '\0';
/* Set length pointer for benefit of caller. */
*len_ptr = text_len;
/* Clean up. */
if (fclose(file)) {
CFCUtil_die("Error closing file '%s': %s", file_path, strerror(errno));
}
return contents;
}
void
CFCUtil_write_if_changed(const char *path, const char *content, size_t len) {
FILE *f = fopen(path, "r");
if (f) { // Does file exist?
if (fclose(f)) {
CFCUtil_die("Error closing file '%s': %s", path, strerror(errno));
}
size_t existing_len;
char *existing = CFCUtil_slurp_text(path, &existing_len);
int changed = true;
if (existing_len == len && strcmp(content, existing) == 0) {
changed = false;
}
FREEMEM(existing);
if (changed == false) {
return;
}
}
CFCUtil_write_file(path, content, len);
}
long
CFCUtil_flength(void *file) {
FILE *f = (FILE*)file;
const long bookmark = (long)ftell(f);
long check_val;
long len;
/* Seek to end of file and check length. */
check_val = fseek(f, 0, SEEK_END);
if (check_val == -1) { CFCUtil_die("fseek error : %s\n", strerror(errno)); }
len = (long)ftell(f);
if (len == -1) { CFCUtil_die("ftell error : %s\n", strerror(errno)); }
/* Return to where we were. */
check_val = fseek(f, bookmark, SEEK_SET);
if (check_val == -1) { CFCUtil_die("fseek error : %s\n", strerror(errno)); }
return len;
}
void
CFCUtil_die(const char* format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
exit(1);
}
void
CFCUtil_warn(const char* format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
}
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
void*
CFCUtil_make_perl_obj(void *ptr, const char *klass) {
SV *inner_obj = newSV(0);
SvOBJECT_on(inner_obj);
PL_sv_objcount++;
SvUPGRADE(inner_obj, SVt_PVMG);
sv_setiv(inner_obj, PTR2IV(ptr));
// Connect class association.
HV *stash = gv_stashpvn((char*)klass, strlen(klass), TRUE);
SvSTASH_set(inner_obj, (HV*)SvREFCNT_inc(stash));
return inner_obj;
}