PageRenderTime 57ms CodeModel.GetById 42ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/libs/libgroff/tmpfile.cpp

https://bitbucket.org/freebsd/freebsd-head/
C++ | 190 lines | 124 code | 18 blank | 48 comment | 22 complexity | dc2a2a7163033cdbbac1fa1e91d3d3b5 MD5 | raw file
  1// -*- C++ -*-
  2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003
  3   Free Software Foundation, Inc.
  4     Written by James Clark (jjc@jclark.com)
  5
  6This file is part of groff.
  7
  8groff is free software; you can redistribute it and/or modify it under
  9the terms of the GNU General Public License as published by the Free
 10Software Foundation; either version 2, or (at your option) any later
 11version.
 12
 13groff is distributed in the hope that it will be useful, but WITHOUT ANY
 14WARRANTY; without even the implied warranty of MERCHANTABILITY or
 15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 16for more details.
 17
 18You should have received a copy of the GNU General Public License along
 19with groff; see the file COPYING.  If not, write to the Free Software
 20Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
 21
 22#include "lib.h"
 23
 24#include <errno.h>
 25#include <stdlib.h>
 26
 27#include "posix.h"
 28#include "errarg.h"
 29#include "error.h"
 30#include "nonposix.h"
 31
 32// If this is set, create temporary files there
 33#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR"
 34// otherwise if this is set, create temporary files there
 35#define TMPDIR_ENVVAR "TMPDIR"
 36// otherwise, on MS-DOS or MS-Windows ...
 37#if defined(__MSDOS__) || defined(_WIN32)
 38// if either of these is set, create temporary files there
 39// (giving priority to WIN32_TMPDIR_ENVVAR)
 40#define WIN32_TMPDIR_ENVVAR "TMP"
 41#define MSDOS_TMPDIR_ENVVAR "TEMP"
 42#endif
 43// otherwise if P_tmpdir is defined, create temporary files there
 44#ifdef P_tmpdir
 45# define DEFAULT_TMPDIR P_tmpdir
 46#else
 47// otherwise create temporary files here.
 48# define DEFAULT_TMPDIR "/tmp"
 49#endif
 50// Use this as the prefix for temporary filenames.
 51#define TMPFILE_PREFIX_SHORT ""
 52#define TMPFILE_PREFIX_LONG "groff"
 53
 54char *tmpfile_prefix;
 55size_t tmpfile_prefix_len;
 56int use_short_postfix = 0;
 57
 58struct temp_init {
 59  temp_init();
 60  ~temp_init();
 61} _temp_init;
 62
 63temp_init::temp_init()
 64{
 65  // First, choose a location for creating temporary files...
 66  const char *tem;
 67  // using the first match for any of the environment specs in listed order.
 68  if (
 69      (tem = getenv(GROFF_TMPDIR_ENVVAR)) == NULL
 70      && (tem = getenv(TMPDIR_ENVVAR)) == NULL
 71#if defined(__MSDOS__) || defined(_WIN32)
 72      // If we didn't find a match for either of the above
 73      // (which are preferred, regardless of the host operating system),
 74      // and we are hosted on either MS-Windows or MS-DOS,
 75      // then try the Microsoft conventions.
 76      && (tem = getenv(WIN32_TMPDIR_ENVVAR)) == NULL
 77      && (tem = getenv(MSDOS_TMPDIR_ENVVAR)) == NULL
 78#endif
 79     )
 80    // If we didn't find an environment spec fall back to this default.
 81    tem = DEFAULT_TMPDIR;
 82  size_t tem_len = strlen(tem);
 83  const char *tem_end = tem + tem_len - 1;
 84  int need_slash = strchr(DIR_SEPS, *tem_end) == NULL ? 1 : 0;
 85  char *tem2 = new char[tem_len + need_slash + 1];
 86  strcpy(tem2, tem);
 87  if (need_slash)
 88    strcat(tem2, "/");
 89  const char *tem3 = TMPFILE_PREFIX_LONG;
 90  if (file_name_max(tem2) <= 14) {
 91    tem3 = TMPFILE_PREFIX_SHORT;
 92    use_short_postfix = 1;
 93  }
 94  tmpfile_prefix_len = tem_len + need_slash + strlen(tem3);
 95  tmpfile_prefix = new char[tmpfile_prefix_len + 1];
 96  strcpy(tmpfile_prefix, tem2);
 97  strcat(tmpfile_prefix, tem3);
 98  a_delete tem2;
 99}
100
101temp_init::~temp_init()
102{
103  a_delete tmpfile_prefix;
104}
105
106/*
107 *  Generate a temporary name template with a postfix
108 *  immediately after the TMPFILE_PREFIX.
109 *  It uses the groff preferences for a temporary directory.
110 *  Note that no file name is either created or opened,
111 *  only the *template* is returned.
112 */
113
114char *xtmptemplate(const char *postfix_long, const char *postfix_short)
115{
116  const char *postfix = use_short_postfix ? postfix_short : postfix_long;
117  int postlen = 0;
118  if (postfix)
119    postlen = strlen(postfix);
120  char *templ = new char[tmpfile_prefix_len + postlen + 6 + 1];
121  strcpy(templ, tmpfile_prefix);
122  if (postlen > 0)
123    strcat(templ, postfix);
124  strcat(templ, "XXXXXX");
125  return templ;
126}
127
128// The trick with unlinking the temporary file while it is still in
129// use is not portable, it will fail on MS-DOS and most MS-Windows
130// filesystems.  So it cannot be used on non-Posix systems.
131// Instead, we maintain a list of files to be deleted on exit.
132// This should be portable to all platforms.
133
134struct xtmpfile_list {
135  char *fname;
136  xtmpfile_list *next;
137  xtmpfile_list(char *fn) : fname(fn), next(0) {}
138};
139
140xtmpfile_list *xtmpfiles_to_delete = 0;
141
142struct xtmpfile_list_init {
143  ~xtmpfile_list_init();
144} _xtmpfile_list_init;
145
146xtmpfile_list_init::~xtmpfile_list_init()
147{
148  xtmpfile_list *x = xtmpfiles_to_delete;
149  while (x != 0) {
150    if (unlink(x->fname) < 0)
151      error("cannot unlink `%1': %2", x->fname, strerror(errno));
152    xtmpfile_list *tmp = x;
153    x = x->next;
154    a_delete tmp->fname;
155    delete tmp;
156  }
157}
158
159static void add_tmp_file(const char *name)
160{
161  char *s = new char[strlen(name)+1];
162  strcpy(s, name);
163  xtmpfile_list *x = new xtmpfile_list(s);
164  x->next = xtmpfiles_to_delete;
165  xtmpfiles_to_delete = x;
166}
167
168// Open a temporary file and with fatal error on failure.
169
170FILE *xtmpfile(char **namep,
171	       const char *postfix_long, const char *postfix_short,
172	       int do_unlink)
173{
174  char *templ = xtmptemplate(postfix_long, postfix_short);
175  errno = 0;
176  int fd = mkstemp(templ);
177  if (fd < 0)
178    fatal("cannot create temporary file: %1", strerror(errno));
179  errno = 0;
180  FILE *fp = fdopen(fd, FOPEN_RWB); // many callers of xtmpfile use binary I/O
181  if (!fp)
182    fatal("fdopen: %1", strerror(errno));
183  if (do_unlink)
184    add_tmp_file(templ);
185  if (namep)
186    *namep = templ;
187  else
188    a_delete templ;
189  return fp;
190}