Fixed resolution of ~ to home directory. (Bug #405) Also fixed potential buffer overruns in glob expansion
This commit is contained in:
parent
0bff1592c7
commit
f9e6664929
|
|
@ -6,9 +6,12 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
/*
|
||||
* Expand global characters.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/cpdefs.h"
|
||||
#include "ngspice/wordlist.h"
|
||||
#include "../misc/tilde.h"
|
||||
#include "glob.h"
|
||||
|
||||
#ifdef HAVE_SYS_DIR_H
|
||||
|
|
@ -30,198 +33,725 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#define OPT_WLL_COPY_ALL 1
|
||||
/* This structure is a "long-form" of the wordlist structure. The inital
|
||||
* wordlist structure fields have the same meanings as in a standalone
|
||||
* wordlist structure, except that the allocations for p_escape and
|
||||
* p_after are separate from the one for wl_word. This structure is useful
|
||||
* when a wordlist must undergo many modifications to its words, as when
|
||||
* globbing is being expanded */
|
||||
typedef struct wordlist_l {
|
||||
struct wordlist wl;
|
||||
size_t n_char_word; /* length of word excluding null */
|
||||
size_t n_elem_word_alloc; /* Allocated size of word array */
|
||||
} wordlist_l;
|
||||
|
||||
static void wl_modify_word(wordlist *wl_node, unsigned int n_input,
|
||||
const size_t *p_n_char_word, char **pp_worde);
|
||||
static wordlist *wll_to_wl(const wordlist_l *wll);
|
||||
static wordlist_l *wll_append(wordlist_l *wl_dst, wordlist_l *wl_to_append);
|
||||
static void wll_append_to_node(wordlist_l *dst, const wordlist_l *to_append);
|
||||
static wordlist_l *wll_cons(
|
||||
size_t n_elem_word_alloc, size_t n_char_word, const char *p_word,
|
||||
unsigned int opt, wordlist_l *tail);
|
||||
static void wll_free(wordlist_l *wll);
|
||||
static wordlist *wll_node_to_wl_node(const wordlist_l *wll);
|
||||
|
||||
char cp_comma = ',';
|
||||
char cp_ocurl = '{';
|
||||
char cp_ccurl = '}';
|
||||
char cp_til = '~';
|
||||
|
||||
static wordlist *bracexpand(char *string);
|
||||
static wordlist *brac1(char *string);
|
||||
static wordlist *brac2(char *string);
|
||||
static wordlist_l *brac1(size_t offset_ocurl1, const char *p_str_cur);
|
||||
static wordlist_l *brac2(const char *string,
|
||||
size_t *p_n_char_processed);
|
||||
static wordlist *bracexpand(const wordlist *w_exp);
|
||||
static void merge_home_with_rest(wordlist *wl_node,
|
||||
size_t n_char_home, const char *sz_home, size_t n_char_skip);
|
||||
static inline void strip_1st_char(wordlist *wl_node);
|
||||
static void tilde_expand_word(wordlist *wl_node);
|
||||
|
||||
|
||||
/* For each word, go through two steps: expand the {}'s, and then do ?*[]
|
||||
* globbing in them. Sort after the second phase but not the first...
|
||||
*/
|
||||
|
||||
/* MW. Now only tilde is supported, {}*? don't work */
|
||||
|
||||
wordlist *
|
||||
cp_doglob(wordlist *wlist)
|
||||
*
|
||||
* Globbing of arbitrary levels of brace nesting and tilde expansion to the
|
||||
* name of a "HOME" directory are supported. ?*[] are not */
|
||||
wordlist *cp_doglob(wordlist *wlist)
|
||||
{
|
||||
wordlist *wl;
|
||||
char *s;
|
||||
|
||||
/* Expand {a,b,c} */
|
||||
|
||||
for (wl = wlist; wl; wl = wl->wl_next) {
|
||||
wordlist *nwl, *w = bracexpand(wl->wl_word);
|
||||
if (!w) {
|
||||
wlist->wl_word = NULL; /* XXX */
|
||||
return (wlist);
|
||||
}
|
||||
nwl = wl_splice(wl, w);
|
||||
if (wlist == wl)
|
||||
wlist = w;
|
||||
wl = nwl;
|
||||
}
|
||||
|
||||
/* Do tilde expansion. */
|
||||
|
||||
for (wl = wlist; wl; wl = wl->wl_next)
|
||||
if (*wl->wl_word == cp_til) {
|
||||
s = cp_tildexpand(wl->wl_word);
|
||||
txfree(wl->wl_word); /* sjb - fix memory leak */
|
||||
if (!s)
|
||||
wl->wl_word = copy(""); /* MW. We Con't touch tmalloc addres */
|
||||
else
|
||||
wl->wl_word = s;
|
||||
}
|
||||
|
||||
return (wlist);
|
||||
}
|
||||
|
||||
|
||||
static wordlist *
|
||||
bracexpand(char *string)
|
||||
{
|
||||
wordlist *wl, *w;
|
||||
char *s;
|
||||
|
||||
if (!string)
|
||||
return (NULL);
|
||||
wl = brac1(string);
|
||||
if (!wl)
|
||||
return (NULL);
|
||||
for (w = wl; w; w = w->wl_next) {
|
||||
s = w->wl_word;
|
||||
w->wl_word = copy(s);
|
||||
tfree(s);
|
||||
}
|
||||
return (wl);
|
||||
}
|
||||
|
||||
/* Given a string, returns a wordlist of all the {} expansions. This is
|
||||
* called recursively by cp_brac2(). All the words here will be of size
|
||||
* BSIZE_SP, so it is a good idea to copy() and free() the old words.
|
||||
*/
|
||||
|
||||
static wordlist *
|
||||
brac1(char *string)
|
||||
{
|
||||
wordlist *words, *wl, *w, *nw, *nwl, *newwl;
|
||||
char *s;
|
||||
int nb;
|
||||
|
||||
words = wl_cons(TMALLOC(char, BSIZE_SP), NULL);
|
||||
words->wl_word[0] = '\0';
|
||||
for (s = string; *s; s++) {
|
||||
if (*s == cp_ocurl) {
|
||||
nwl = brac2(s);
|
||||
nb = 0;
|
||||
for (;;) {
|
||||
if (*s == cp_ocurl)
|
||||
nb++;
|
||||
if (*s == cp_ccurl)
|
||||
nb--;
|
||||
if (*s == '\0') {
|
||||
fprintf(cp_err, "Error: missing }.\n");
|
||||
return (NULL);
|
||||
}
|
||||
if (nb == 0)
|
||||
break;
|
||||
s++;
|
||||
{
|
||||
wordlist *wl = wlist;
|
||||
while (wl != (wordlist *) NULL) {
|
||||
wordlist *w = bracexpand(wl);
|
||||
if (!w) {
|
||||
wl_free(wlist);
|
||||
return (wordlist *) NULL;
|
||||
}
|
||||
/* Add nwl to the rest of the strings in words. */
|
||||
newwl = NULL;
|
||||
for (wl = words; wl; wl = wl->wl_next)
|
||||
for (w = nwl; w; w = w->wl_next) {
|
||||
nw = wl_cons(TMALLOC(char, BSIZE_SP), NULL);
|
||||
(void) strcpy(nw->wl_word, wl->wl_word);
|
||||
(void) strcat(nw->wl_word, w->wl_word);
|
||||
newwl = wl_append(newwl, nw);
|
||||
|
||||
/* Replace the node that was just expanded, wl, with the
|
||||
* expansion w (if different) and continue after that */
|
||||
if (wl != w) {
|
||||
wordlist *wl_next = wl->wl_next;
|
||||
(void) wl_splice(wl, w);
|
||||
|
||||
/* Update head of list if the replacement
|
||||
* changed it */
|
||||
if (wlist == wl) {
|
||||
wlist = w;
|
||||
}
|
||||
wl_free(words);
|
||||
wl_free(nwl);
|
||||
words = newwl;
|
||||
} else {
|
||||
for (wl = words; wl; wl = wl->wl_next)
|
||||
appendc(wl->wl_word, *s);
|
||||
|
||||
/* Continue after the spliced nodes since
|
||||
* they are already fully expanded */
|
||||
wl = wl_next;
|
||||
}
|
||||
else { /* same node, so just step to the next node */
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
} /* end of loop over words in wordlist */
|
||||
} /* end of block expanding braces */
|
||||
|
||||
/* Do tilde expansion on each word. */
|
||||
{
|
||||
wordlist *wl;
|
||||
for (wl = wlist; wl; wl = wl->wl_next) {
|
||||
if (*wl->wl_word == cp_til) {
|
||||
tilde_expand_word(wl);
|
||||
}
|
||||
} /* end of loop over words in wordlist */
|
||||
} /* end of block expanding braces */
|
||||
|
||||
return wlist;
|
||||
} /* end of function cp_doglob */
|
||||
|
||||
|
||||
|
||||
static wordlist *bracexpand(const wordlist *w_exp)
|
||||
{
|
||||
const char * const wl_word = w_exp->wl_word;
|
||||
|
||||
/* If no string, nothing to expand */
|
||||
if (wl_word == (char *) NULL) {
|
||||
return (wordlist *) NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Find first opening brace. If none, the string expands to itself as
|
||||
* a wordlist */
|
||||
size_t offset_ocurl = ~(size_t) 0; /* flag for not found */
|
||||
|
||||
/* Loop until find opening brace or end of string */
|
||||
{
|
||||
const char *p_cur = wl_word;
|
||||
char ch_cur;
|
||||
for ( ; (ch_cur = *p_cur) != '\0'; p_cur++) {
|
||||
if (ch_cur == cp_ocurl) {
|
||||
offset_ocurl = p_cur - wl_word;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (words);
|
||||
}
|
||||
|
||||
|
||||
/* Test for '{' and glob if there is one */
|
||||
if (offset_ocurl != ~(size_t) 0) {
|
||||
/* Found a brace, so glob */
|
||||
wordlist_l *wll_glob = brac1(offset_ocurl, wl_word);
|
||||
|
||||
wordlist *wl_glob = wll_to_wl(wll_glob);
|
||||
wll_free(wll_glob);
|
||||
return wl_glob;
|
||||
}
|
||||
|
||||
/* Unescaped '{' not found, so return the input node */
|
||||
return (wordlist *) w_exp;
|
||||
} /* end of function bracexpand */
|
||||
|
||||
|
||||
|
||||
/* Given a string, returns a wordlist of all the {} expansions. This function
|
||||
* calls cp_brac2() with braced expressions and is called recursively by
|
||||
* cp_brac2().
|
||||
*
|
||||
* Parameters
|
||||
* offset_ocurl1: Offset from p_str where the first opening brace occurs
|
||||
* or the offset to the terminating null of p_str (length of the
|
||||
* string) if it contains no opening brace.
|
||||
*/
|
||||
static wordlist_l *brac1(size_t offset_ocurl1, const char *p_str)
|
||||
{
|
||||
wordlist_l *words;
|
||||
const char *s;
|
||||
|
||||
/* Create the inital entry in the list using all of the characters
|
||||
* before the first '{' */
|
||||
{
|
||||
const size_t n_byte_alloc = BSIZE_SP + 1;
|
||||
|
||||
words = wll_cons(n_byte_alloc, offset_ocurl1, p_str,
|
||||
OPT_WLL_COPY_ALL, (wordlist_l *) NULL);
|
||||
}
|
||||
|
||||
/* Step through string. In each iteration one {} group and the ungrouped
|
||||
* characters following that group, if any are processed */
|
||||
for (s = p_str + offset_ocurl1; *s != '\0'; ) {
|
||||
{ /* Process braced expression */
|
||||
size_t n_char_processed;
|
||||
|
||||
/* Process braced list using brac2() */
|
||||
wordlist_l *nwl = brac2(s,
|
||||
&n_char_processed);
|
||||
if (nwl == (wordlist_l *) NULL) {
|
||||
/* brac2() already printed an error message */
|
||||
wll_free(words);
|
||||
return (wordlist_l *) NULL;
|
||||
}
|
||||
|
||||
/* New wordlist to replace existing words. Note
|
||||
* the number of nodes is
|
||||
* #(existing list) X #(brac2() list). Each of
|
||||
* the brac2() words is appended to each of the
|
||||
* existing words to form the new wordlist */
|
||||
wordlist_l *newwl = (wordlist_l *) NULL;
|
||||
|
||||
/* For each word in the existing word list (words) */
|
||||
wordlist_l *wl; /* loop iterator */
|
||||
for (wl = words; wl; wl = (wordlist_l *) wl->wl.wl_next) {
|
||||
|
||||
/* For each word in the word list from brac2() */
|
||||
wordlist_l *w; /* loop iterator */
|
||||
for (w = nwl; w; w = (wordlist_l *) w->wl.wl_next) {
|
||||
wordlist_l *nw = wll_cons(
|
||||
BSIZE_SP + 1, 0, (char *) NULL,
|
||||
OPT_WLL_COPY_ALL, (wordlist_l *) NULL);
|
||||
wll_append_to_node(nw, wl);
|
||||
wll_append_to_node(nw, w);
|
||||
newwl = wll_append(newwl, nw);
|
||||
} /* end of loop over words from brac2() */
|
||||
} /* end of loop over words */
|
||||
wll_free(words);
|
||||
wll_free(nwl);
|
||||
words = newwl;
|
||||
s += n_char_processed; /* skip braced list */
|
||||
} /* end of processing of braced expression */
|
||||
|
||||
{
|
||||
/* Apend all chars after {} expression until the next
|
||||
* '{' or the end of the word to each word in the wordlist */
|
||||
const char * const p_start = s;
|
||||
char ch_cur;
|
||||
for ( ; (ch_cur = *s) != cp_ocurl; s++) {
|
||||
if (ch_cur == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t n_char_append = s - p_start;
|
||||
|
||||
if (n_char_append > 0) {
|
||||
wordlist_l *wl;
|
||||
for (wl = words; wl; wl = (wordlist_l *) wl->wl.wl_next) {
|
||||
const size_t n_char_total = wl->n_char_word +
|
||||
n_char_append;
|
||||
const size_t n_elem_needed = n_char_total + 1;
|
||||
if (wl->n_elem_word_alloc < n_elem_needed) {
|
||||
const size_t n_elem_alloc = 2 * n_elem_needed;
|
||||
wl->wl.wl_word = TREALLOC(char, wl->wl.wl_word,
|
||||
n_elem_alloc);
|
||||
wl->n_elem_word_alloc = n_elem_alloc;
|
||||
}
|
||||
char *p_dst = wl->wl.wl_word + wl->n_char_word;
|
||||
(void) memcpy(p_dst, p_start, n_char_append);
|
||||
p_dst += n_char_append;
|
||||
*p_dst = '\0';
|
||||
wl->n_char_word = n_char_total;
|
||||
}
|
||||
}
|
||||
} /* end of characters after braced expression */
|
||||
} /* end of loop over braced expressions + following chars in string */
|
||||
|
||||
return words;
|
||||
} /* end of function brac1 */
|
||||
|
||||
|
||||
|
||||
/* Given a string starting with a {, return a wordlist of the expansions
|
||||
* for the text until the matching }.
|
||||
* for the text until the matching }. A vaild input string must have both
|
||||
* an opening brace and a closing brace. If an error occurs, NULL is
|
||||
* returned. On a successful return, *p_n_char_processed will contain the
|
||||
* number of characters processed by brac2 up to and including the closing
|
||||
* outermost brace
|
||||
*/
|
||||
|
||||
static wordlist *
|
||||
brac2(char *string)
|
||||
static wordlist_l *brac2(const char *string,
|
||||
size_t *p_n_char_processed)
|
||||
{
|
||||
wordlist *wlist = NULL, *nwl;
|
||||
char buf[BSIZE_SP], *s;
|
||||
int nb;
|
||||
bool eflag = FALSE;
|
||||
wordlist_l *wlist = (wordlist_l *) NULL;
|
||||
char buf_fixed[BSIZE_SP]; /* default work buffer */
|
||||
char *buf = buf_fixed; /* actual work buffer */
|
||||
bool eflag = FALSE; /* end-of-processing flag */
|
||||
|
||||
/* Required buffer size. Note that 1st char of string is not copied,
|
||||
* so strlen(string) includes the length of the null at the end */
|
||||
const size_t n_elem_needed = strlen(string);
|
||||
|
||||
/* Allocate and use a larger buffer if required */
|
||||
if (n_elem_needed > BSIZE_SP) { /* will not fit in stack buffer */
|
||||
buf = TMALLOC(char, n_elem_needed);
|
||||
}
|
||||
|
||||
string++; /* Get past the first open brace... */
|
||||
for (;;) {
|
||||
(void) strcpy(buf, string);
|
||||
nb = 0;
|
||||
s = buf;
|
||||
for (;;) {
|
||||
if ((*s == cp_ccurl) && (nb == 0)) {
|
||||
eflag = TRUE;
|
||||
break;
|
||||
}
|
||||
if ((*s == cp_comma) && (nb == 0))
|
||||
break;
|
||||
if (*s == cp_ocurl)
|
||||
nb++;
|
||||
if (*s == cp_ccurl)
|
||||
(void) strcpy(buf, string); /* make a copy of string */
|
||||
char *buf_cur = buf; /* current position in buffer */
|
||||
|
||||
/* Each iteration of the outer loop processes one comma-separated
|
||||
* expression of the top-level brace-enclosed list */
|
||||
for ( ; ; ) {
|
||||
int nb = 0; /* number of braces **inside 1st brace** */
|
||||
size_t offset_ocurl1 = SIZE_MAX; /* Offset to 1st '{' */
|
||||
|
||||
/* Start processing at start of next top-level term */
|
||||
char *s = buf_cur;
|
||||
|
||||
/* Scan the string until the next comma at the top level is found,
|
||||
* the closing brace at the top level is found or the string ends
|
||||
* with a missing brace. If another term is found, it is processed
|
||||
* as a null-terminated string by calling brac1() */
|
||||
for ( ; ; ) {
|
||||
const char ch_cur = *s;
|
||||
if (ch_cur == cp_ccurl) { /* closing brace found */
|
||||
if (nb == 0) {
|
||||
/* A closing brace found without any internal opening
|
||||
* braces, so this one is the outermost brace */
|
||||
eflag = TRUE; /* done -- set end flag */
|
||||
break;
|
||||
}
|
||||
/* Else closing brace of internal level */
|
||||
nb--;
|
||||
if (*s == '\0') {
|
||||
fprintf(cp_err, "Error: missing }.\n");
|
||||
return (NULL);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
else if (ch_cur == cp_ocurl) { /* another brace level started */
|
||||
if (nb++ == 0) { /* Inc count. If 1st '{', save offset */
|
||||
offset_ocurl1 = s - buf_cur;
|
||||
}
|
||||
}
|
||||
else if ((ch_cur == cp_comma) && (nb == 0)) {
|
||||
/* Comma found outside of any internal braced
|
||||
* expression */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if reached end of string. If so, the closing
|
||||
* brace was not present. */
|
||||
if (ch_cur == '\0') {
|
||||
fprintf(cp_err, "Error: missing }.\n");
|
||||
if (buf != buf_fixed) { /* free allocation if made */
|
||||
txfree(buf);
|
||||
}
|
||||
if (wlist != (wordlist_l *) NULL) {
|
||||
wll_free(wlist);
|
||||
}
|
||||
|
||||
return (wordlist_l *) NULL;
|
||||
}
|
||||
s++; /* process next char */
|
||||
} /* end of loop finding end of braces */
|
||||
|
||||
/* The above loop exits without returning from the function if either
|
||||
* a comma at the top level or the closing top level brace is reached.
|
||||
* Variable s points to this location. By setting it to null, a string
|
||||
* is created for one of the comma-separated expressions at the top
|
||||
* level */
|
||||
*s = '\0';
|
||||
nwl = brac1(buf);
|
||||
wlist = wl_append(wlist, nwl);
|
||||
string += s - buf + 1;
|
||||
if (eflag)
|
||||
return (wlist);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the top-level expression found and append to the
|
||||
* wordlist being built */
|
||||
{
|
||||
wordlist_l *nwl = brac1(
|
||||
offset_ocurl1 == SIZE_MAX ? s - buf_cur : offset_ocurl1,
|
||||
buf_cur);
|
||||
wlist = wll_append(wlist, nwl);
|
||||
}
|
||||
|
||||
/* Check for competion of processing */
|
||||
if (eflag) { /* done -- normal function exit */
|
||||
if (buf != buf_fixed) { /* free allocation if made */
|
||||
txfree(buf);
|
||||
}
|
||||
|
||||
/* When the loop is exited, s is at a brace or comma, which
|
||||
* is also considered to be processed. Hence +2 not +1. */
|
||||
*p_n_char_processed = s - buf + 2;
|
||||
return wlist;
|
||||
}
|
||||
|
||||
buf_cur = s + 1; /* go to next term after comma */
|
||||
} /* end of loop over top-level comma-separated expressions */
|
||||
} /* end of function brac2 */
|
||||
|
||||
|
||||
|
||||
/* Expand tildes. */
|
||||
|
||||
char *
|
||||
cp_tildexpand(char *string)
|
||||
char *cp_tildexpand(char *string)
|
||||
{
|
||||
char *result;
|
||||
/* Attempt to do the tilde expansion */
|
||||
char * const result = tildexpand(string);
|
||||
|
||||
result = tildexpand(string);
|
||||
|
||||
if (!result) {
|
||||
if (cp_nonomatch)
|
||||
if (!result) { /* expansion failed */
|
||||
if (cp_nonomatch) { /* If set, should return the original string */
|
||||
return copy(string);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
/* Else should return NULL to indiciate failure */
|
||||
return (char *) NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result; /* successful expansion returned */
|
||||
} /* end of function cp_tildexpand */
|
||||
|
||||
|
||||
|
||||
/* Say whether the pattern p can match the string s. */
|
||||
|
||||
/* MW. Now simply compare strings */
|
||||
|
||||
bool
|
||||
cp_globmatch(char *p, char *s)
|
||||
bool cp_globmatch(char *p, char *s)
|
||||
{
|
||||
return (!(strcmp(p, s)));
|
||||
}
|
||||
return !(strcmp(p, s));
|
||||
} /* end of function cp_globmatch */
|
||||
|
||||
|
||||
|
||||
/* This function expands the leading ~ of wl_node. */
|
||||
static void tilde_expand_word(wordlist *wl_node)
|
||||
{
|
||||
char *word = wl_node->wl_word;
|
||||
char *p_char_cur = ++word;
|
||||
char ch = *p_char_cur;
|
||||
if (ch == '\0' || ch == DIR_TERM) {
|
||||
char *sz_home;
|
||||
const int n_char_home = get_local_home(0, &sz_home);
|
||||
if (n_char_home < 0) { /* expansion failed */
|
||||
/* Strip the ~ and return the rest */
|
||||
strip_1st_char(wl_node);
|
||||
return;
|
||||
}
|
||||
merge_home_with_rest(wl_node, (size_t) n_char_home, sz_home, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
/* ~bob -- Get name of user and find home for that user */
|
||||
{
|
||||
char * const usr_start = wl_node->wl_word + 1;
|
||||
char *usr_end = usr_start;
|
||||
char c;
|
||||
while ((c = *usr_end) != '\0' && c != DIR_TERM) {
|
||||
++usr_end;
|
||||
}
|
||||
const size_t n_char_usr = usr_end - usr_start;
|
||||
const size_t n_byte_usr = n_char_usr + 1;
|
||||
const char c_orig = c; /* save char to be overwritten by '\0' */
|
||||
*usr_end = '\0';
|
||||
|
||||
char *sz_home;
|
||||
const int n_char_home = get_usr_home(usr_start, 0, &sz_home);
|
||||
*usr_end = c_orig; /* restore char overwritten by '\0' */
|
||||
if (n_char_home < 0) {
|
||||
strip_1st_char(wl_node);
|
||||
return; /* Strip the ~ and return the rest */
|
||||
}
|
||||
merge_home_with_rest(wl_node, (size_t) n_char_home, sz_home,
|
||||
n_char_usr + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
/* ~bob is meaningless. Strip the ~ and return the rest */
|
||||
strip_1st_char(wl_node);
|
||||
return;
|
||||
#endif
|
||||
} /* end of function tilde_expand_word */
|
||||
|
||||
|
||||
|
||||
/* Strip the 1st char. Equivalent to merging an empty HOME string with the
|
||||
* chars after the 1st char. Assumes string is at least 1 char long
|
||||
* excluding trailing NULL */
|
||||
static inline void strip_1st_char(wordlist *wl_node)
|
||||
{
|
||||
merge_home_with_rest(wl_node, 0, (char *) NULL, 1);
|
||||
return;
|
||||
} /* end of function strip_1st_char */
|
||||
|
||||
|
||||
|
||||
/* This function modifies the wordlist node to consist of <home> +
|
||||
* rest of string after n_char_skip. It is assumed that the string
|
||||
* is at least n_char_skip characters long excluding the trailing null */
|
||||
static inline void merge_home_with_rest(wordlist *wl_node,
|
||||
size_t n_char_home, const char *sz_home, size_t n_char_skip)
|
||||
{
|
||||
size_t p_n_char_word[2];
|
||||
p_n_char_word[0] = n_char_home;
|
||||
p_n_char_word[1] = strlen(wl_node->wl_word) - n_char_skip;
|
||||
|
||||
char *pp_word[2];
|
||||
pp_word[0] = (char *) sz_home;
|
||||
pp_word[1] = wl_node->wl_word + n_char_skip;
|
||||
|
||||
wl_modify_word(wl_node, 2u, p_n_char_word, pp_word);
|
||||
return;
|
||||
} /* end of function merge_home_with_rest */
|
||||
|
||||
|
||||
|
||||
|
||||
/*** Long-form wordlist functions ***/
|
||||
|
||||
/* This function converts long-form wordlist wll to a standard wordlist.
|
||||
* The input long-form list is not modified. */
|
||||
static wordlist *wll_to_wl(const wordlist_l *wll)
|
||||
{
|
||||
/* Handle degnerate case of NULL input */
|
||||
if (wll == (wordlist_l *) NULL) {
|
||||
return (wordlist *) NULL;
|
||||
}
|
||||
|
||||
/* There is at least one node in the long-form wordlist. */
|
||||
/* Convert it to a standard wordlist node, which is the node to
|
||||
* return */
|
||||
wordlist * const wl_start = wll_node_to_wl_node(wll);
|
||||
wordlist * wl_dst_prev = wl_start;
|
||||
wl_start->wl_prev = (wordlist *) NULL;
|
||||
|
||||
/* Continue adding nodes */
|
||||
for (wll = (wordlist_l *) wll->wl.wl_next ; wll != (wordlist_l *) NULL;
|
||||
wll = (wordlist_l *) wll->wl.wl_next) {
|
||||
/* Convert a single long-form node to a standard for node */
|
||||
wordlist *wl_dst_cur = wll_node_to_wl_node(wll);
|
||||
wl_dst_prev->wl_next = wl_dst_cur;
|
||||
wl_dst_cur->wl_prev = wl_dst_prev;
|
||||
wl_dst_prev = wl_dst_cur;
|
||||
} /* end of loop over nodes in input long-form wordlist */
|
||||
|
||||
/* Terminate the list of words */
|
||||
wl_dst_prev->wl_next = (wordlist *) NULL;
|
||||
return wl_start;
|
||||
} /* end of function wll_to_wl */
|
||||
|
||||
|
||||
|
||||
/* This function creates word data for a standard list from word data of
|
||||
* a long-form list. Both structures must be allocated on input, and the
|
||||
* long-form data is not change */
|
||||
static wordlist *wll_node_to_wl_node(const wordlist_l *wll)
|
||||
{
|
||||
/* Allocate node being returned */
|
||||
wordlist * const wl_dst = TMALLOC(wordlist, 1);
|
||||
|
||||
/* Find required size of allocation and save lengths of arrays */
|
||||
const size_t n_char_word = wll->n_char_word;
|
||||
const size_t n_byte_alloc = n_char_word + 1;
|
||||
|
||||
/* Allocate buffer */
|
||||
char * p_dst_cur = wl_dst->wl_word = TMALLOC(char, n_byte_alloc);
|
||||
|
||||
/* Word data */
|
||||
wl_dst->wl_word = p_dst_cur;
|
||||
(void) memcpy(p_dst_cur, wll->wl.wl_word, n_char_word);
|
||||
p_dst_cur += n_char_word;
|
||||
*p_dst_cur++ = '\0';
|
||||
|
||||
return wl_dst;
|
||||
} /* end of function wll_node_to_wl_node */
|
||||
|
||||
|
||||
|
||||
/* Free a long-form wordlist */
|
||||
void wll_free(wordlist_l *wll)
|
||||
{
|
||||
while (wll != (wordlist_l *) NULL) {
|
||||
wordlist_l * const next = (wordlist_l *) wll->wl.wl_next;
|
||||
void *p;
|
||||
if ((p = (void *) wll->wl.wl_word) != NULL) {
|
||||
txfree(p);
|
||||
}
|
||||
txfree(wll);
|
||||
wll = next;
|
||||
} /* end of loop over wordlist nodes */
|
||||
} /* end of function wll_free */
|
||||
|
||||
|
||||
|
||||
/* This function prepends a wordlist_l node to the existing list.
|
||||
*
|
||||
* Parameters
|
||||
* n_char_word: Length of word, excluding trailing NULL
|
||||
* p_word: Address of word, or NULL if none. A null terminiation is
|
||||
* not required if the word will be duplicated.
|
||||
* opt: OPT_WLL_COPY_ALL -- create copy instead of resuing word allocation
|
||||
* tail: Address of wordlist having this word prepended. May be null.
|
||||
*
|
||||
* Return value
|
||||
* New wordlist node which is the start of the list
|
||||
*/
|
||||
wordlist_l *wll_cons(
|
||||
size_t n_elem_word_alloc, size_t n_char_word, const char *p_word,
|
||||
unsigned int opt, wordlist_l *tail)
|
||||
{
|
||||
/* Create a new node and link with the existing wordlist */
|
||||
wordlist_l *w = TMALLOC(wordlist_l, 1);
|
||||
w->wl.wl_next = (wordlist *) tail;
|
||||
w->wl.wl_prev = (wordlist *) NULL;
|
||||
|
||||
w->n_char_word = n_char_word;
|
||||
w->n_elem_word_alloc = n_elem_word_alloc;
|
||||
|
||||
if (opt & OPT_WLL_COPY_ALL) {
|
||||
char *p_dst = w->wl.wl_word = TMALLOC(char, n_elem_word_alloc);
|
||||
(void) memcpy(p_dst, p_word, n_char_word);
|
||||
p_dst += n_char_word;
|
||||
*p_dst = '\0';
|
||||
}
|
||||
else {
|
||||
w->wl.wl_word = (char *) p_word;
|
||||
}
|
||||
|
||||
/* Link to front of rest of nodes, if present */
|
||||
if (tail) {
|
||||
/* The new word goes in the front */
|
||||
tail->wl.wl_prev = (wordlist *) w;
|
||||
}
|
||||
|
||||
return w;
|
||||
} /* end of function wl_cons */
|
||||
|
||||
|
||||
|
||||
/* This function appends wl_to_append to the end of wl_dst and returns the
|
||||
* start of the combined wordlist */
|
||||
static wordlist_l *wll_append(wordlist_l *wl_dst, wordlist_l *wl_to_append)
|
||||
{
|
||||
/* Handle degenerate cases where both of the input wordlists
|
||||
* are not non-NULL */
|
||||
if (wl_dst == (wordlist_l *) NULL) {
|
||||
return wl_to_append;
|
||||
}
|
||||
if (wl_to_append == (wordlist_l *) NULL) {
|
||||
return wl_dst;
|
||||
}
|
||||
|
||||
/* Locate last node of wl_dst */
|
||||
{
|
||||
wordlist_l *wl;
|
||||
for (wl = wl_dst; wl->wl.wl_next;
|
||||
wl = (wordlist_l *) wl->wl.wl_next) {
|
||||
;
|
||||
}
|
||||
|
||||
/* Link nwl to end */
|
||||
wl->wl.wl_next = (wordlist *) wl_to_append;
|
||||
wl_to_append->wl.wl_prev = (wordlist *) wl;
|
||||
}
|
||||
|
||||
return wl_dst; /* Return combined wordlist */
|
||||
} /* end of function wll_append */
|
||||
|
||||
|
||||
|
||||
/* This function appends word data, of the wordlist_l node "to_append" to
|
||||
* the existing values at wordlist_l node "dst".
|
||||
*/
|
||||
void wll_append_to_node(wordlist_l *dst, const wordlist_l *to_append)
|
||||
{
|
||||
/* Get sizes */
|
||||
const size_t n_old = dst->n_char_word;
|
||||
const size_t n_new = to_append->n_char_word;
|
||||
const size_t n_total = n_old + n_new;
|
||||
const size_t n_elem_needed = n_total + 1;
|
||||
|
||||
/* Resize if needed */
|
||||
if (dst->n_elem_word_alloc < n_elem_needed) {
|
||||
const size_t n_elem_alloc = 2 * n_elem_needed;
|
||||
dst->wl.wl_word = TREALLOC(
|
||||
char, dst->wl.wl_word, n_elem_alloc);
|
||||
dst->n_elem_word_alloc = n_elem_alloc;
|
||||
}
|
||||
|
||||
/* Do append */
|
||||
{
|
||||
char *p_dst = dst->wl.wl_word + n_old;
|
||||
char * const p_src = to_append->wl.wl_word;
|
||||
(void) memcpy(p_dst, p_src, n_new);
|
||||
p_dst += n_new;
|
||||
*p_dst = '\0';
|
||||
}
|
||||
dst->n_char_word = n_total;
|
||||
} /* end of function wll_append_to_node */
|
||||
|
||||
|
||||
|
||||
/* This function modifies word data in a word list node by building a new word
|
||||
* from the arrays supplied. These arrays may contain pieces of the word
|
||||
* being modified, with overlap and duplication of intervals allowed. Null
|
||||
* terminiations are not required on the input data.
|
||||
*
|
||||
* Parameters
|
||||
* wl_node: wordlist node being modified. Cannot be NULL.
|
||||
* n_input: Number of inputs
|
||||
* p_n_char_word: Array of length n_input of lengths of input strings,
|
||||
excluding trailing nulls
|
||||
* pp_word: Array of pointers to input character data. An entry may be NULL
|
||||
* iff the corrseponding value of p_n_char_word is 0.
|
||||
*/
|
||||
static void wl_modify_word(wordlist *wl_node, unsigned int n_input,
|
||||
const size_t *p_n_char_word, char **pp_word)
|
||||
{
|
||||
/* Find the number of chars of word data */
|
||||
size_t n_char_word_new = 0;
|
||||
{ /* have array */
|
||||
/* Accumulate count of chars */
|
||||
const size_t *p_n_char_word_cur = p_n_char_word;
|
||||
const size_t * const p_n_char_word_end = p_n_char_word + n_input;
|
||||
for ( ; p_n_char_word_cur != p_n_char_word_end;
|
||||
++p_n_char_word_cur) {
|
||||
n_char_word_new += *p_n_char_word_cur;
|
||||
}
|
||||
}
|
||||
|
||||
/* New allocation */
|
||||
char *p_word_new;
|
||||
|
||||
/* Process the segments. */
|
||||
{ /* no escapes */
|
||||
/* + 1 for null after word */
|
||||
const size_t n_byte_alloc = n_char_word_new + 1;
|
||||
|
||||
/* New allocation */
|
||||
p_word_new = TMALLOC(char, n_byte_alloc);
|
||||
|
||||
/* New word. Build from input pieces */
|
||||
{
|
||||
const size_t *p_n_char_word_cur = p_n_char_word;
|
||||
const size_t * const p_n_char_word_end = p_n_char_word + n_input;
|
||||
char **pp_word_cur = pp_word;
|
||||
char *p_dst = p_word_new;
|
||||
for ( ; p_n_char_word_cur < p_n_char_word_end;
|
||||
++p_n_char_word_cur, ++pp_word_cur) {
|
||||
const size_t n_char_word_cur = *p_n_char_word_cur;
|
||||
(void) memcpy(p_dst, *pp_word_cur, n_char_word_cur);
|
||||
p_dst += n_char_word_cur;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Free old and assign new */
|
||||
txfree(wl_node->wl_word);
|
||||
wl_node->wl_word = p_word_new;
|
||||
} /* end of function wl_modify_word */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
/*************
|
||||
* streams.c
|
||||
************/
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/wordlist.h"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
|
||||
/* Externs defined in std.c */
|
||||
|
||||
extern char *tildexpand(char *string);
|
||||
extern char *tildexpand(const char *string);
|
||||
extern void printnum(char *buf, double num);
|
||||
int printnum_ds(DSTRING *p_ds, double num);
|
||||
extern int cp_numdgt;
|
||||
|
|
|
|||
267
src/misc/tilde.c
267
src/misc/tilde.c
|
|
@ -3,20 +3,24 @@ Copyright 1991 Regents of the University of California. All rights reserved.
|
|||
Modified: 2002 R. Oktas, <roktas@omu.edu.tr>
|
||||
**********/
|
||||
|
||||
#include "ngspice/defines.h"
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "tilde.h"
|
||||
#include "ngspice/stringskip.h"
|
||||
#include "tilde.h"
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||
#ifdef _WIN32
|
||||
#undef BOOLEAN
|
||||
#include <windows.h> /* win32 functions */
|
||||
#include "shlobj.h" /* SHGetFolderPath */
|
||||
#endif
|
||||
|
||||
static inline int copy_home_to_buf(size_t n_byte_dst, char **p_dst,
|
||||
const char *src);
|
||||
|
||||
/* XXX To prevent a name collision with `readline's `tilde_expand',
|
||||
the original name: `tilde_expand' has changed to `tildexpand'. This
|
||||
situation naturally brings to mind that `tilde_expand' could be used
|
||||
|
|
@ -26,83 +30,196 @@ Modified: 2002 R. Oktas, <roktas@omu.edu.tr>
|
|||
reason why it should be replaced: eg. it returns NULL which should
|
||||
not behave this way, IMHO. Anyway... Don't care for the moment, may
|
||||
be in the future. -- ro */
|
||||
|
||||
|
||||
char *
|
||||
tildexpand(char *string)
|
||||
char *tildexpand(const char *string)
|
||||
{
|
||||
#ifdef HAVE_PWD_H
|
||||
char buf[BSIZE_SP];
|
||||
char *k, c;
|
||||
#endif
|
||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||
char buf2[BSIZE_SP];
|
||||
#endif
|
||||
char *result = NULL;
|
||||
|
||||
if (!string)
|
||||
return NULL;
|
||||
|
||||
string = skip_ws(string);
|
||||
|
||||
if (*string != '~')
|
||||
return copy(string);
|
||||
|
||||
string += 1;
|
||||
|
||||
if (!*string || *string == '/') {
|
||||
/* First try the environment setting. May also make life easier
|
||||
for non-unix platforms, eg. MS-DOS. -- ro */
|
||||
result = getenv("HOME");
|
||||
#ifdef HAVE_PWD_H
|
||||
/* Can't find a result from the environment, let's try
|
||||
the other stuff. -- ro */
|
||||
if (!result) {
|
||||
struct passwd *pw;
|
||||
pw = getpwuid(getuid());
|
||||
if (pw)
|
||||
result = pw->pw_dir;
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
} else {
|
||||
struct passwd *pw;
|
||||
k = buf;
|
||||
while ((c = *string) && c != '/')
|
||||
*k++ = c, string++;
|
||||
*k = '\0';
|
||||
pw = getpwnam(buf);
|
||||
if (pw)
|
||||
result = pw->pw_dir;
|
||||
#endif
|
||||
/* If no string passed, return NULL */
|
||||
if (!string) {
|
||||
return NULL;
|
||||
}
|
||||
if (result) {
|
||||
#ifdef HAVE_PWD_H
|
||||
strcpy(buf, result);
|
||||
if (*string)
|
||||
strcat(buf, string);
|
||||
return copy(buf);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
string = skip_ws(string); /* step past leading whitespace */
|
||||
|
||||
/* If the string does not begin with a tilde, there is no ~ to expand */
|
||||
if (*string != '~') {
|
||||
return copy(string);
|
||||
}
|
||||
|
||||
++string; /* step past tilde */
|
||||
|
||||
/* Test for home of current user */
|
||||
if (*string == '\0' || *string == DIR_TERM) {
|
||||
char *sz_home;
|
||||
const int n_char_home = get_local_home(0, &sz_home);
|
||||
if (n_char_home < 0) {
|
||||
return copy(string); /* Strip the ~ and return the rest */
|
||||
}
|
||||
const size_t n_char_rest = strlen(string);
|
||||
TREALLOC(char, sz_home, (size_t) n_char_home + n_char_rest + 1);
|
||||
strcpy(sz_home + n_char_home, string);
|
||||
return sz_home;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
/* ~bob -- Get name of user and find home for that user */
|
||||
{
|
||||
char buf_fixed[100];
|
||||
char *buf = buf_fixed;
|
||||
const char * const usr_start = string;
|
||||
char c;
|
||||
while ((c = *string) && c != '/') {
|
||||
string++;
|
||||
}
|
||||
const char * const usr_end = string;
|
||||
const size_t n_char_usr = usr_end - usr_start;
|
||||
const size_t n_byte_usr = n_char_usr + 1;
|
||||
if (n_byte_usr > sizeof buf_fixed) {
|
||||
buf = TMALLOC(char, n_byte_usr);
|
||||
}
|
||||
(void) memcpy(buf, usr_start, n_char_usr);
|
||||
buf[n_char_usr] = '\0';
|
||||
|
||||
|
||||
char *sz_home;
|
||||
const int n_char_home = get_usr_home(buf, 0, &sz_home);
|
||||
if (buf != buf_fixed) { /* free allocated buffer for user name */
|
||||
txfree(buf);
|
||||
}
|
||||
if (n_char_home < 0) {
|
||||
return copy(usr_start); /* Strip the ~ and return the rest */
|
||||
}
|
||||
const size_t n_char_rest = strlen(string);
|
||||
TREALLOC(char, sz_home, (size_t) n_char_home + n_char_rest + 1);
|
||||
strcpy(sz_home + n_char_home, string);
|
||||
return sz_home;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Emulate the old behavior to prevent side effects. -- ro */
|
||||
return copy(string);
|
||||
}
|
||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||
else if(SUCCEEDED(SHGetFolderPath(NULL,
|
||||
CSIDL_PERSONAL,
|
||||
NULL,
|
||||
0,
|
||||
buf2)))
|
||||
{
|
||||
if (*string)
|
||||
strcat(buf2, string);
|
||||
return copy(buf2);
|
||||
}
|
||||
/* ~abc is meaningless */
|
||||
return copy(string); /* Again strip ~ and return rest */
|
||||
#endif
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
} /* end of function tildexpand */
|
||||
|
||||
|
||||
|
||||
|
||||
/* Get value of "HOME" for the current user and copy to *p_buf if
|
||||
* the value is less than n_byte_buf characters long. Otherwise
|
||||
* allocate a buffer of the minimum required size.
|
||||
*
|
||||
* Return values
|
||||
* >0: Number of characters copied to *p_buf, excluding the trailing null
|
||||
* -1: A value for HOME could not be obtained.
|
||||
*
|
||||
* Remarks:
|
||||
* This function does not free any allocation at *p_buf, allowing a
|
||||
* fixed buffer to be passed to it.
|
||||
*/
|
||||
int get_local_home(size_t n_byte_buf, char **p_buf)
|
||||
{
|
||||
char *sz_home = (char *) NULL;
|
||||
#ifdef _WIN32
|
||||
char buf_sh_path[MAX_PATH];
|
||||
#endif
|
||||
|
||||
do {
|
||||
/* First thing to try is an environment variable HOME */
|
||||
if ((sz_home = getenv("HOME")) != (char *) NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* If Windows, try an env var USERPROFILE next */
|
||||
if ((sz_home = getenv("USERPROFILE")) != (char *) NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* For Windows, the folder path CSIDL_PERSONAL is tried next */
|
||||
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0,
|
||||
buf_sh_path))) {
|
||||
sz_home = buf_sh_path;
|
||||
break;
|
||||
}
|
||||
#elif defined(HAVE_PWD_H) /* _WIN32 and HAVE_PWD_H are mutually exclusive */
|
||||
/* Get home information for the current user */
|
||||
{
|
||||
struct passwd *pw;
|
||||
pw = getpwuid(getuid());
|
||||
if (pw) {
|
||||
sz_home = pw->pw_dir;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} while (0);
|
||||
|
||||
if (sz_home == (char *) NULL) { /* did not find a HOME value */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy home value to buffer */
|
||||
return copy_home_to_buf(n_byte_buf, p_buf, sz_home);
|
||||
} /* end of function get_local_home */
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
/* Get value of "HOME" for usr and copy to *p_buf if
|
||||
* the value is less than n_byte_buf characters long. Otherwise
|
||||
* allocate a buffer of the minimum required size.
|
||||
*
|
||||
* Return values
|
||||
* >0: Number of characters copied to *pp_buf, excluding the trailing null
|
||||
* -1: A value for HOME could not be obtained.
|
||||
*
|
||||
* Remarks:
|
||||
* This function does not free any allocation at *p_buf, allowing a
|
||||
* fixed buffer to be passed to it.
|
||||
*/
|
||||
int get_usr_home(const char *usr, size_t n_byte_buf, char **p_buf)
|
||||
{
|
||||
struct passwd * const pw = getpwnam(usr);
|
||||
if (pw) {
|
||||
/* Copy home value to buffer */
|
||||
return copy_home_to_buf(n_byte_buf, p_buf, pw->pw_dir);
|
||||
}
|
||||
|
||||
return -1;
|
||||
} /* end of function get_usr_home */
|
||||
#endif /* HAVE_PWD_H */
|
||||
|
||||
|
||||
|
||||
/* This function copies home value src to the buffer at *p_dst, allocating
|
||||
* a larger buffer if required.
|
||||
*
|
||||
* Parameters
|
||||
* n_byte_dst: Size of supplied destination buffer
|
||||
* p_dst: Address containing address of supplied buffer on input. May be
|
||||
* given the address of a larger buffer allocation if the input buffer
|
||||
* is too small.
|
||||
* src: Address of HOME value
|
||||
*
|
||||
* Return values
|
||||
* number of characters copied excluding terminating null
|
||||
*
|
||||
* Remarks:
|
||||
* This function does not free any allocation at *p_dst, allowing a
|
||||
* fixed buffer to be passed to it.
|
||||
*/
|
||||
static inline int copy_home_to_buf(size_t n_byte_dst, char **p_dst,
|
||||
const char *src)
|
||||
{
|
||||
const size_t n_char_src = strlen(src); /* Size of HOME value */
|
||||
const size_t n_byte_src = n_char_src + 1;
|
||||
|
||||
/* Allocate dst if input buffer too small */
|
||||
if (n_byte_src > n_byte_dst) { /* too big */
|
||||
*p_dst = TMALLOC(char, n_byte_src);
|
||||
}
|
||||
|
||||
(void) memcpy(*p_dst, src, n_byte_src);
|
||||
|
||||
return (int) n_char_src;
|
||||
} /* end of function copy_home_to_buf */
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@
|
|||
#ifndef ngspice_TILDE_H
|
||||
#define ngspice_TILDE_H
|
||||
|
||||
char * tildexpand(char *string);
|
||||
char * tildexpand(const char *string);
|
||||
|
||||
int get_local_home(size_t n_byte_buf, char **p_buf);
|
||||
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
int get_usr_home(const char *usr, size_t n_byte_buf, char **p_buf);
|
||||
#endif
|
||||
|
||||
#endif /* include guard */
|
||||
|
|
|
|||
Loading…
Reference in New Issue