#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <errno.h>
#include <time.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <assert.h>
#include "common.h"
+#include "fs.h"
#define MAXSTR 256
/*---------------------------------------------------------------------------*/
-int read_line(char **dst, FILE *fin)
+int read_line(char **dst, fs_file fin)
{
- char buffer[MAXSTR] = "";
- int buffer_size = 0;
+ char buff[MAXSTR];
- char *store = NULL;
- char *store_new = NULL;
- int store_size = 0;
+ char *line, *new;
+ size_t len0, len1;
- int seen_newline = 0;
+ line = NULL;
- while (!seen_newline)
+ while (fs_gets(buff, sizeof (buff), fin))
{
- if (fgets(buffer, sizeof (buffer), fin) == NULL)
- {
- if (store_size > 0)
- break;
- else
- {
- *dst = NULL;
- return 0;
- }
- }
-
- buffer_size = strlen(buffer) + 1;
+ /* Append to data read so far. */
- /* Erase trailing newline. */
-
- if (buffer[buffer_size - 2] == '\n')
+ if (line)
{
- seen_newline = 1;
- buffer[buffer_size - 2] = '\0';
- buffer_size--;
+ new = concat_string(line, buff, NULL);
+ free(line);
+ line = new;
}
-
- /* Allocate or reallocate space for the buffer. */
-
- if ((store_new = (char *) realloc(store, store_size + buffer_size)))
+ else
{
- /* Avoid passing garbage to string functions. */
+ line = strdup(buff);
+ }
- if (store == NULL)
- store_new[0] = '\0';
+ /* Strip newline, if any. */
- store = store_new;
- store_size += buffer_size;
+ len0 = strlen(line);
+ strip_newline(line);
+ len1 = strlen(line);
- store_new = NULL;
- }
- else
+ if (len1 != len0)
{
- fprintf(stderr, "Failed to allocate memory.\n");
-
- free(store);
- *dst = NULL;
- return 0;
+ /* We hit a newline, clean up and break. */
+ line = realloc(line, len1 + 1);
+ break;
}
-
- strncat(store, buffer, buffer_size);
}
- *dst = store;
-
- return 1;
+ return (*dst = line) ? 1 : 0;
}
char *strip_newline(char *str)
return str;
}
-char *strdup(const char *src)
+char *dupe_string(const char *src)
{
char *dst = NULL;
return dst;
}
+char *concat_string(const char *first, ...)
+{
+ char *full;
+
+ if ((full = strdup(first)))
+ {
+ const char *part;
+ va_list ap;
+
+ va_start(ap, first);
+
+ while ((part = va_arg(ap, const char *)))
+ {
+ char *new;
+
+ if ((new = realloc(full, strlen(full) + strlen(part) + 1)))
+ {
+ full = new;
+ strcat(full, part);
+ }
+ else
+ {
+ free(full);
+ full = NULL;
+ break;
+ }
+ }
+
+ va_end(ap);
+ }
+
+ return full;
+}
+
+char *trunc_string(const char *src, char *dst, int len)
+{
+ static const char ell[] = "...";
+
+ assert(len > sizeof (ell));
+
+ if (dst[len - 1] = '\0', strncpy(dst, src, len), dst[len - 1] != '\0')
+ strcpy(dst + len - sizeof (ell), ell);
+
+ return dst;
+}
+
time_t make_time_from_utc(struct tm *tm)
{
struct tm local, *utc;
fwrite(buff, 1, size, fout);
}
-char *base_name(const char *name, const char *suffix)
+/*---------------------------------------------------------------------------*/
+
+int path_is_sep(int c)
{
- static char buf[MAXSTR];
- char *base;
+#ifdef _WIN32
+ return c == '/' || c == '\\';
+#else
+ return c == '/';
+#endif
+}
- if (!name)
- return NULL;
+int path_is_abs(const char *path)
+{
+ if (path_is_sep(path[0]))
+ return 1;
- /* Remove the directory part. */
+#ifdef _WIN32
+ if (isalpha(path[0]) && path[1] == ':' && path_is_sep(path[2]))
+ return 1;
+#endif
- base = strrchr(name, '/');
+ return 0;
+}
+
+static char *path_last_sep(const char *path)
+{
+ char *sep;
+
+ sep = strrchr(path, '/');
#ifdef _WIN32
- if (!base)
- base = strrchr(name, '\\');
+ if (!sep)
+ {
+ sep = strrchr(path, '\\');
+ }
else
{
char *tmp;
- if ((tmp = strrchr(base, '\\')))
- base = tmp;
+ if ((tmp = strrchr(sep, '\\')))
+ sep = tmp;
}
#endif
- strncpy(buf, base ? base + 1 : name, sizeof (buf));
+ return sep;
+}
+
+char *base_name(const char *name, const char *suffix)
+{
+ static char buf[MAXSTR];
+ char *base;
+
+ if (!name)
+ return NULL;
+
+ /* Remove the directory part. */
+
+ base = path_last_sep(name);
+
+ strncpy(buf, base ? base + 1 : name, sizeof (buf) - 1);
/* Remove the suffix. */
return buf;
}
+const char *dir_name(const char *name)
+{
+ static char buff[MAXSTR];
+
+ char *sep;
+
+ strncpy(buff, name, sizeof (buff) - 1);
+
+ if ((sep = path_last_sep(buff)))
+ {
+ if (sep == buff)
+ return "/";
+
+ *sep = '\0';
+
+ return buff;
+ }
+
+ return ".";
+}
+
+/*
+ * Given a path to a file REF and another path REL relative to REF,
+ * construct and return a new path that can be used to refer to REL
+ * directly.
+ */
+char *path_resolve(const char *ref, const char *rel)
+{
+ static char new[MAXSTR * 2];
+
+ if (path_is_abs(rel))
+ {
+ strncpy(new, rel, sizeof (new) - 1);
+ return new;
+ }
+
+ strncpy(new, dir_name(ref), sizeof (new) - 1);
+ strncat(new, "/", sizeof (new) - strlen(new) - 1);
+ strncat(new, rel, sizeof (new) - strlen(new) - 1);
+
+ return new;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int rand_between(int low, int high)
+{
+ return low + rand() / (RAND_MAX / (high - low + 1) + 1);
+}
+
/*---------------------------------------------------------------------------*/