1 static const char CVSID
[] = "$Id: utils.c,v 1.23 2004/10/18 19:27:26 arnef Exp $";
2 /*******************************************************************************
4 * utils.c -- miscellaneous non-GUI routines *
6 * Copyright (C) 2002 Mark Edel *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. In addition, you may distribute versions of this program linked to *
12 * Motif or Open Motif. See README for details. *
14 * This software is distributed in the hope that it will be useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * for more details.* *
19 * You should have received a copy of the GNU General Public License along with *
20 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
21 * Place, Suite 330, Boston, MA 02111-1307 USA *
23 *******************************************************************************/
26 #include "../config.h"
36 #include <lib$routines.h>
39 #include "../util/VMSparam.h"
40 #include "../util/VMSutils.h"
42 #include <sys/types.h>
46 /* just to get 'Boolean' types defined: */
47 #include <X11/Intrinsic.h>
53 #define DEFAULT_NEDIT_HOME ".nedit"
55 static char* hiddenFileNames
[N_FILE_TYPES
] = {".nedit", ".neditmacro", ".neditdb;1"};
56 static char* plainFileNames
[N_FILE_TYPES
] = {"nedit.rc", "autoload.nm", "nedit.history;1"};
58 static char* hiddenFileNames
[N_FILE_TYPES
] = {".nedit", ".neditmacro", ".neditdb"};
59 static char* plainFileNames
[N_FILE_TYPES
] = {"nedit.rc", "autoload.nm", "nedit.history"};
62 static void buildFilePath(char* fullPath
, const char* dir
, const char* file
);
63 static Boolean
isDir(const char* file
);
64 static Boolean
isRegFile(const char* file
);
68 /* return non-NULL value for the current working directory.
69 If system call fails, provide a fallback value */
71 static char curdir
[MAXPATHLEN
];
73 if (!getcwd(curdir
, MAXPATHLEN
)) {
74 perror("nedit: getcwd() fails");
83 /* return a non-NULL value for the user's home directory,
84 without trailing slash.
85 We try the environment var and the system user database. */
88 static char homedir
[MAXPATHLEN
]="";
89 struct passwd
*passwdEntry
;
97 passwdEntry
= getpwuid(getuid());
98 if (passwdEntry
&& *(passwdEntry
->pw_dir
)) {
99 ptr
= passwdEntry
->pw_dir
;
101 /* This is really serious, so just exit. */
102 perror("nedit: getpwuid() failed ");
106 strncpy(homedir
, ptr
, sizeof(homedir
)-1);
107 homedir
[sizeof(homedir
)-1]='\0';
108 /* Fix trailing slash */
110 if (len
>1 && homedir
[len
-1]=='/') {
117 ** Return a pointer to the username of the current user in a statically
124 return cuserid(NULL
);
126 /* cuserid has apparently been dropped from the ansi C standard, and if
127 strict ansi compliance is turned on (on Sun anyhow, maybe others), calls
128 to cuserid fail to compile. Older versions of nedit try to use the
129 getlogin call first, then if that fails, use getpwuid and getuid. This
130 results in the user-name of the original terminal being used, which is
131 not correct when the user uses the su command. Now, getpwuid only: */
133 const struct passwd
*passwdEntry
;
134 static char *userName
=NULL
;
139 passwdEntry
= getpwuid(getuid());
141 /* This is really serious, but sometimes username service
142 is misconfigured through no fault of the user. Be nice
143 and let the user start nc anyway. */
144 perror("nedit: getpwuid() failed - reverting to $USER");
145 return getenv("USER");
148 userName
=malloc(strlen(passwdEntry
->pw_name
)+1);
149 strcpy(userName
, passwdEntry
->pw_name
);
157 ** Writes the hostname of the current system in string "hostname".
159 ** NOTE: This function used to be called "GetHostName" but that resulted in a
160 ** linking conflict on VMS with the standard gethostname function, because
161 ** VMS links case-insensitively.
166 static char hostname
[MAXNODENAMELEN
+1];
167 static int hostnameFound
= False
;
169 if (!hostnameFound
) {
171 /* This should be simple, but uname is not supported in the DEC C RTL and
172 gethostname on VMS depends either on Multinet or UCX. So use uname
173 on Unix, and use LIB$GETSYI on VMS. Note the VMS hostname will
174 be in DECNET format with trailing double colons, e.g. "FNALV1::". */
176 struct dsc$descriptor_s
*hostnameDesc
;
177 unsigned long int syiItemCode
= SYI$_NODENAME
; /* get Nodename */
178 unsigned long int unused
= 0;
179 unsigned short int hostnameLen
= MAXNODENAMELEN
+1;
181 hostnameDesc
= NulStrWrtDesc(hostname
, MAXNODENAMELEN
+1);
182 syi_status
= lib$
getsyi(&syiItemCode
, &unused
, hostnameDesc
, &hostnameLen
,
184 if (syi_status
!= SS$_NORMAL
) {
185 fprintf(stderr
, "nedit: Error return from lib$getsyi: %d", syi_status
);
186 strcpy(hostname
, "VMS");
188 hostname
[hostnameLen
] = '\0';
189 FreeStrDesc(hostnameDesc
);
191 struct utsname nameStruct
;
192 int rc
= uname(&nameStruct
);
194 /* Shouldn't ever happen, so we better exit() here */
195 perror("nedit: uname() failed ");
198 strcpy(hostname
, nameStruct
.nodename
);
200 hostnameFound
= True
;
207 ** Create a path: $HOME/filename
208 ** Return "" if it doesn't fit into the buffer
211 *PrependHome(const char *filename
, char *buf
, int buflen
)
214 int home_len
, file_len
;
216 homedir
=GetHomeDir();
217 home_len
=strlen(homedir
);
218 file_len
=strlen(filename
);
219 if ( (home_len
+1+file_len
)>=buflen
) {
223 strcpy(buf
, homedir
);
225 strcat(buf
, filename
);
230 extern int Max(int i1
, int i2
)
232 return i1
>= i2
? i1
: i2
;
235 extern int Min(int i1
, int i2
)
237 return i1
<= i2
? i1
: i2
;
240 extern int Min3(int i1
, int i2
, int i3
)
242 if (i1
<= i2
&& i1
<= i3
)
244 return i2
<= i3
? i2
: i3
;
247 extern int Max3(int i1
, int i2
, int i3
)
249 if (i1
>= i2
&& i1
>= i3
)
251 return i2
>= i3
? i2
: i3
;
255 ** Returns a pointer to the name of an rc file of the requested type.
258 ** - MAXPATHLEN is set to the max. allowed path length
259 ** - fullPath points to a buffer of at least MAXPATHLEN
262 ** - NULL if an error occurs while creating a directory
263 ** - Pointer to a static array containing the file name
266 const char* GetRCFileName(int type
)
268 static char rcFiles
[N_FILE_TYPES
][MAXPATHLEN
+ 1];
269 static int namesDetermined
= False
;
271 if (!namesDetermined
)
276 if ((nedit_home
= getenv("NEDIT_HOME")) == NULL
)
280 /* This is a default VMS setup */
281 for (i
= 0; i
< N_FILE_TYPES
; i
++)
283 buildFilePath(rcFiles
[i
], "SYS$LOGIN", hiddenFileNames
[i
]);
285 #else /* #ifdef VMS */
286 /* Let's try if ~/.nedit is a regular file or not. */
287 char legacyFile
[MAXPATHLEN
+ 1];
288 buildFilePath(legacyFile
, GetHomeDir(), hiddenFileNames
[NEDIT_RC
]);
289 if (isRegFile(legacyFile
))
291 /* This is a legacy setup with rc files in $HOME */
292 for (i
= 0; i
< N_FILE_TYPES
; i
++)
294 buildFilePath(rcFiles
[i
], GetHomeDir(), hiddenFileNames
[i
]);
298 /* ${HOME}/.nedit does not exist as a regular file. */
299 /* FIXME: Devices, sockets and fifos are ignored for now. */
300 char defaultNEditHome
[MAXPATHLEN
+ 1];
301 buildFilePath(defaultNEditHome
, GetHomeDir(), DEFAULT_NEDIT_HOME
);
302 if (!isDir(defaultNEditHome
))
304 /* Create DEFAULT_NEDIT_HOME */
305 if (mkdir(defaultNEditHome
, 0777) != 0)
307 perror("nedit: Error while creating rc file directory"
308 " $HOME/" DEFAULT_NEDIT_HOME
"\n"
309 " (Make sure all parent directories exist.)");
314 /* All set for DEFAULT_NEDIT_HOME, let's copy the names */
315 for (i
= 0; i
< N_FILE_TYPES
; i
++)
317 buildFilePath(rcFiles
[i
], defaultNEditHome
, plainFileNames
[i
]);
320 #endif /* #ifdef VMS */
323 /* $NEDIT_HOME is set. */
325 /* FIXME: Is this required? Does VMS know stat(), mkdir()? */
326 if (!isDir(nedit_home
))
328 /* Create $NEDIT_HOME */
329 if (mkdir(nedit_home
, 0777) != 0)
331 perror("nedit: Error while creating rc file directory $NEDIT_HOME\n"
332 "nedit: (Make sure all parent directories exist.)");
336 #endif /* #ifndef VMS */
338 /* All set for NEDIT_HOME, let's copy the names */
339 for (i
= 0; i
< N_FILE_TYPES
; i
++)
341 buildFilePath(rcFiles
[i
], nedit_home
, plainFileNames
[i
]);
345 namesDetermined
= True
;
348 return rcFiles
[type
];
352 ** Builds a file path from 'dir' and 'file', watching for buffer overruns.
355 ** - MAXPATHLEN is set to the max. allowed path length
356 ** - 'fullPath' points to a buffer of at least MAXPATHLEN
357 ** - 'dir' and 'file' are valid strings
360 ** - 'fullpath' will contain 'dir/file'
361 ** - Exits when the result would be greater than MAXPATHLEN
363 static void buildFilePath(char* fullPath
, const char* dir
, const char* file
)
365 if ((MAXPATHLEN
) < strlen(dir
) + strlen(file
) + 2)
367 /* We have no way to build the path. */
368 fprintf(stderr
, "nedit: rc file path too long for %s.\n", file
);
372 /* The length is already checked */
373 strcpy(fullPath
, dir
);
375 strcat(fullPath
, ":");
376 #else /* #ifdef VMS */
377 strcat(fullPath
, "/");
378 #endif /* #ifdef VMS */
379 strcat(fullPath
, file
);
383 ** Returns true if 'file' is a directory, false otherwise.
384 ** Links are followed.
390 ** - True for directories, false otherwise
392 static Boolean
isDir(const char* file
)
394 struct stat attribute
;
396 return ((stat(file
, &attribute
) == 0) && S_ISDIR(attribute
.st_mode
));
400 ** Returns true if 'file' is a regular file, false otherwise.
401 ** Links are followed.
407 ** - True for regular files, false otherwise
409 static Boolean
isRegFile(const char* file
)
411 struct stat attribute
;
413 return ((stat(file
, &attribute
) == 0) && S_ISREG(attribute
.st_mode
));