+/*
+ * mkstemp.c -- create a temporary file
+ *
+ * This code is Copyright (c) 2014 by the authors of nmh.
+ * See the COPYRIGHT file in the root directory of the nmh
+ * distribution for complete copyright information.
+ */
+
+/* define NMH to 0 to remove dependencies on nmh. */
+#ifndef NMH
+# define NMH 1
+#endif /* ! NMH */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#if ! defined HAVE_MKSTEMPS
+# define HAVE_MKSTEMPS 0
+#endif /* ! HAVE_MKSTEMPS */
+
+char *build_template(const char *, const char *, const char *);
+void process_args(int, char **, const char **, const char **, const char **);
+
+/*
+ * Use a template of the form:
+ * [directory/][prefix]XXXXXX[suffix]
+ * where some of those named components might be null. suffix is only
+ * supported if HAVE_MKSTEMPS.
+ */
+
+int
+main(int argc, char *argv[]) {
+ const char *directory = "", *prefix = "", *suffix = "";
+ size_t suffix_len;
+ int fd;
+ char *template;
+
+ process_args(argc, argv, &directory, &prefix, &suffix);
+ if ((template = build_template(directory, prefix, suffix)) == NULL) {
+ return -1;
+ }
+
+ if ((suffix_len = strlen(suffix)) > 0) {
+# if HAVE_MKSTEMPS
+ if ((fd = mkstemps(template, suffix_len)) < 0) { perror("mkstemps"); }
+# endif /* HAVE_MKSTEMPS */
+ } else {
+ if ((fd = mkstemp(template)) < 0) { perror("mkstemp"); }
+ }
+
+ if (fd >= 0) {
+ (void) puts(template);
+ (void) close(fd);
+ }
+
+ free(template);
+
+ return fd >= 0 ? 0 : -1;
+}
+
+
+char *
+build_template(const char *directory, const char *prefix, const char *suffix) {
+ const char pattern[] = "XXXXXX";
+ size_t len, directory_len, pathsep_len, prefix_len, suffix_len;
+ char *template;
+
+ directory_len = strlen(directory);
+ if (directory_len > 0) {
+ pathsep_len = 1;
+ if (directory[directory_len - 1] == '/') {
+ /* Will insert a '/' separately, so truncate the one provided
+ in the directory name. */
+ --directory_len;
+ }
+ } else {
+ pathsep_len = 0;
+ }
+ prefix_len = strlen(prefix);
+ suffix_len = strlen(suffix);
+ /* sizeof pattern includes its final NULL, so don't add another. */
+ len = directory_len + pathsep_len + prefix_len + sizeof pattern +
+ suffix_len;
+
+ if ((template = malloc(len))) {
+ char *tp = template;
+
+ (void) strncpy(tp, directory, directory_len);
+ tp += directory_len;
+
+ if (pathsep_len == 1) { *tp++ = '/'; }
+
+ (void) strncpy(tp, prefix, prefix_len);
+ tp += prefix_len;
+
+ (void) strncpy(tp, pattern, sizeof pattern - 1);
+ tp += sizeof pattern - 1;
+
+ (void) strncpy(tp, suffix, suffix_len);
+ tp += suffix_len;
+
+ template[len-1] = '\0';
+
+ return template;
+ } else {
+ perror("malloc");
+ return NULL;
+ }
+}
+
+
+#if NMH
+#include <h/mh.h>
+
+#if HAVE_MKSTEMPS
+# define MHFIXMSG_SWITCHES \
+ X("directory", 0, DIRECTORYSW) \
+ X("prefix", 0, PREFIXSW) \
+ X("suffix", 0, SUFFIXSW) \
+ X("version", 0, VERSIONSW) \
+ X("help", 0, HELPSW)
+#else /* ! HAVE_MKSTEMPS */
+# define MHFIXMSG_SWITCHES \
+ X("directory", 0, DIRECTORYSW) \
+ X("prefix", 0, PREFIXSW) \
+ X("version", 0, VERSIONSW) \
+ X("help", 0, HELPSW)
+#endif /* ! HAVE_MKSTEMPS */
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(MHFIXMSG);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(MHFIXMSG, switches);
+#undef X
+
+void
+process_args(int argc, char **argv, const char **directory,
+ const char **prefix, const char **suffix) {
+ char **argp, **arguments, *cp, buf[100];
+# if ! HAVE_MKSTEMPS
+ NMH_UNUSED(suffix);
+# endif /* ! HAVE_MKSTEMPS */
+
+ if (nmh_init(argv[0], 1)) { done(NOTOK); }
+ arguments = getarguments (invo_name, argc, argv, 1);
+ argp = arguments;
+
+ /*
+ * Parse arguments
+ */
+ while ((cp = *argp++)) {
+ if (*cp == '-') {
+ switch (smatch(++cp, switches)) {
+ case AMBIGSW:
+ ambigsw(cp, switches);
+ done(NOTOK);
+ case UNKWNSW:
+ advise (NULL, "-%s unknown", cp);
+ (void) snprintf(buf, sizeof buf, "%s [switches]", invo_name);
+ print_help(buf, switches, 1);
+ done(NOTOK);
+ case HELPSW:
+ (void) snprintf(buf, sizeof buf, "%s [switches]", invo_name);
+ print_help(buf, switches, 1);
+ done(OK);
+ case VERSIONSW:
+ print_version(invo_name);
+ done(OK);
+
+ case DIRECTORYSW:
+ /* Allow the directory to start with '-'. */
+ if ((cp = *argp++) == NULL) {
+ adios(NULL, "missing argument to %s", argp[-2]);
+ }
+ *directory = cp;
+ continue;
+
+ case PREFIXSW:
+ /* Allow the prefix to start with '-'. */
+ if ((cp = *argp++) == NULL) {
+ adios(NULL, "missing argument to %s", argp[-2]);
+ }
+ *prefix = cp;
+ continue;
+
+# if HAVE_MKSTEMPS
+ case SUFFIXSW:
+ /* Allow the suffix to start with '-'. */
+ if ((cp = *argp++) == NULL) {
+ adios(NULL, "missing argument to %s", argp[-2]);
+ }
+ *suffix = cp;
+ continue;
+# endif /* HAVE_MKSTEMPS */
+ }
+ }
+ }
+}
+#else /* ! NMH */
+void
+process_args(int argc, char **argv, const char **directory,
+ const char **prefix, const char **suffix) {
+# if HAVE_MKSTEMPS
+ const char usage[] =
+ "usage: %s [-h] [-d directory] [-p prefix] [-s suffix]\n";
+ const char optstring[] = "d:hp:s:";
+# else /* ! HAVE_MKSTEMPS */
+ const char usage[] = "usage: %s [-h] [-d directory] [-p prefix]\n";
+ const char optstring[] = "d:hp:";
+# endif /* ! HAVE_MKSTEMPS */
+ int opt;
+
+ while ((opt = getopt(argc, argv, optstring)) != -1) {
+ switch (opt) {
+ case 'd':
+ *directory = optarg;
+ break;
+ case 'p':
+ *prefix = optarg;
+ break;
+ case 's':
+ *suffix = optarg;
+ break;
+ case 'h':
+ (void) printf(usage, argv[0]);
+ exit(0);
+ default:
+ (void) fprintf(stderr, usage, argv[0]);
+ exit(-1);
+ }
+ }
+}
+#endif /* ! NMH */