1 /**********
2 Copyright 1991 Regents of the University of California. All rights reserved.
3 Modified: 2002 R. Oktas, <roktas@omu.edu.tr>
4 **********/
5
6 #include "ngspice/defines.h"
7 #include "ngspice/ngspice.h"
8 #include "ngspice/stringskip.h"
9 #include "tilde.h"
10
11 #ifdef HAVE_PWD_H
12 #include <pwd.h>
13 #endif
14
15 #ifdef _WIN32
16 #undef BOOLEAN
17 #include <windows.h> /* win32 functions */
18 #include "shlobj.h" /* SHGetFolderPath */
19 #endif
20
21 static inline int copy_home_to_buf(size_t n_byte_dst, char **p_dst,
22 const char *src);
23
24 /* XXX To prevent a name collision with `readline's `tilde_expand',
25 the original name: `tilde_expand' has changed to `tildexpand'. This
26 situation naturally brings to mind that `tilde_expand' could be used
27 directly from `readline' (since it will already be included if we
28 wish to activate the `readline' support). Following implementation of
29 'tilde expanding' has some problems which constitutes another good
30 reason why it should be replaced: eg. it returns NULL which should
31 not behave this way, IMHO. Anyway... Don't care for the moment, may
32 be in the future. -- ro */
tildexpand(const char * string)33 char *tildexpand(const char *string)
34 {
35 /* If no string passed, return NULL */
36 if (!string) {
37 return NULL;
38 }
39
40 string = skip_ws(string); /* step past leading whitespace */
41
42 /* If the string does not begin with a tilde, there is no ~ to expand */
43 if (*string != '~') {
44 return copy(string);
45 }
46
47 ++string; /* step past tilde */
48
49 /* Test for home of current user */
50 if (*string == '\0' || *string == DIR_TERM) {
51 char *sz_home;
52 const int n_char_home = get_local_home(0, &sz_home);
53 if (n_char_home < 0) {
54 return copy(string); /* Strip the ~ and return the rest */
55 }
56 const size_t n_char_rest = strlen(string);
57 sz_home = TREALLOC(char, sz_home, (size_t) n_char_home + n_char_rest + 1);
58 strcpy(sz_home + n_char_home, string);
59 return sz_home;
60 }
61
62 #ifdef HAVE_PWD_H
63 /* ~bob -- Get name of user and find home for that user */
64 {
65 char buf_fixed[100];
66 char *buf = buf_fixed;
67 const char * const usr_start = string;
68 char c;
69 while ((c = *string) && c != '/') {
70 string++;
71 }
72 const char * const usr_end = string;
73 const size_t n_char_usr = (size_t) (usr_end - usr_start);
74 const size_t n_byte_usr = n_char_usr + 1;
75 if (n_byte_usr > sizeof buf_fixed) {
76 buf = TMALLOC(char, n_byte_usr);
77 }
78 (void) memcpy(buf, usr_start, n_char_usr);
79 buf[n_char_usr] = '\0';
80
81
82 char *sz_home;
83 const int n_char_home = get_usr_home(buf, 0, &sz_home);
84 if (buf != buf_fixed) { /* free allocated buffer for user name */
85 txfree(buf);
86 }
87 if (n_char_home < 0) {
88 return copy(usr_start); /* Strip the ~ and return the rest */
89 }
90 const size_t n_char_rest = strlen(string);
91 sz_home = TREALLOC(char, sz_home, (size_t) n_char_home + n_char_rest + 1);
92 strcpy(sz_home + n_char_home, string);
93 return sz_home;
94 }
95
96 #else
97 /* ~abc is meaningless */
98 return copy(string); /* Again strip ~ and return rest */
99 #endif
100 } /* end of function tildexpand */
101
102
103
104
105 /* Get value of "HOME" for the current user and copy to *p_buf if
106 * the value is less than n_byte_buf characters long. Otherwise
107 * allocate a buffer of the minimum required size.
108 *
109 * Return values
110 * >0: Number of characters copied to *p_buf, excluding the trailing null
111 * -1: A value for HOME could not be obtained.
112 *
113 * Remarks:
114 * This function does not free any allocation at *p_buf, allowing a
115 * fixed buffer to be passed to it.
116 */
get_local_home(size_t n_byte_buf,char ** p_buf)117 int get_local_home(size_t n_byte_buf, char **p_buf)
118 {
119 char *sz_home = (char *) NULL;
120 #ifdef _WIN32
121 char buf_sh_path[MAX_PATH];
122 #endif
123
124 do {
125 /* First thing to try is an environment variable HOME */
126 if ((sz_home = getenv("HOME")) != (char *) NULL) {
127 break;
128 }
129
130 #if defined(_WIN32)
131 /* If Windows, try an env var USERPROFILE next */
132 if ((sz_home = getenv("USERPROFILE")) != (char *) NULL) {
133 break;
134 }
135
136 /* For Windows, the folder path CSIDL_PERSONAL is tried next */
137 if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0,
138 buf_sh_path))) {
139 sz_home = buf_sh_path;
140 break;
141 }
142 #elif defined(HAVE_PWD_H) /* _WIN32 and HAVE_PWD_H are mutually exclusive */
143 /* Get home information for the current user */
144 {
145 struct passwd *pw;
146 pw = getpwuid(getuid());
147 if (pw) {
148 sz_home = pw->pw_dir;
149 }
150 }
151 #endif
152 } while (0);
153
154 if (sz_home == (char *) NULL) { /* did not find a HOME value */
155 return -1;
156 }
157
158 /* Copy home value to buffer */
159 return copy_home_to_buf(n_byte_buf, p_buf, sz_home);
160 } /* end of function get_local_home */
161
162
163
164 #ifdef HAVE_PWD_H
165 /* Get value of "HOME" for usr and copy to *p_buf if
166 * the value is less than n_byte_buf characters long. Otherwise
167 * allocate a buffer of the minimum required size.
168 *
169 * Return values
170 * >0: Number of characters copied to *pp_buf, excluding the trailing null
171 * -1: A value for HOME could not be obtained.
172 *
173 * Remarks:
174 * This function does not free any allocation at *p_buf, allowing a
175 * fixed buffer to be passed to it.
176 */
get_usr_home(const char * usr,size_t n_byte_buf,char ** p_buf)177 int get_usr_home(const char *usr, size_t n_byte_buf, char **p_buf)
178 {
179 struct passwd * const pw = getpwnam(usr);
180 if (pw) {
181 /* Copy home value to buffer */
182 return copy_home_to_buf(n_byte_buf, p_buf, pw->pw_dir);
183 }
184
185 return -1;
186 } /* end of function get_usr_home */
187 #endif /* HAVE_PWD_H */
188
189
190
191 /* This function copies home value src to the buffer at *p_dst, allocating
192 * a larger buffer if required.
193 *
194 * Parameters
195 * n_byte_dst: Size of supplied destination buffer
196 * p_dst: Address containing address of supplied buffer on input. May be
197 * given the address of a larger buffer allocation if the input buffer
198 * is too small.
199 * src: Address of HOME value
200 *
201 * Return values
202 * number of characters copied excluding terminating null
203 *
204 * Remarks:
205 * This function does not free any allocation at *p_dst, allowing a
206 * fixed buffer to be passed to it.
207 */
copy_home_to_buf(size_t n_byte_dst,char ** p_dst,const char * src)208 static inline int copy_home_to_buf(size_t n_byte_dst, char **p_dst,
209 const char *src)
210 {
211 const size_t n_char_src = strlen(src); /* Size of HOME value */
212 const size_t n_byte_src = n_char_src + 1;
213
214 /* Allocate dst if input buffer too small */
215 if (n_byte_src > n_byte_dst) { /* too big */
216 *p_dst = TMALLOC(char, n_byte_src);
217 }
218
219 (void) memcpy(*p_dst, src, n_byte_src);
220
221 return (int) n_char_src;
222 } /* end of function copy_home_to_buf */
223
224
225
226