Always define ExecutableName variable
[geany-mirror.git] / ctags / main / routines.c
blob49e46219c699da218c8fa315e4bd90d89182c5f7
1 /*
2 * Copyright (c) 2002-2003, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains a lose assortment of shared functions.
8 */
11 * INCLUDE FILES
13 #include "general.h" /* must always come first */
15 #include <glib.h>
16 #include <glib/gstdio.h>
18 #include <errno.h>
20 #ifdef HAVE_STDLIB_H
21 # include <stdlib.h> /* to declare malloc (), realloc () */
22 #endif
23 #include <ctype.h>
24 #include <string.h>
25 #include <stdio.h> /* to declare tempnam(), and SEEK_SET (hopefully) */
27 #ifdef HAVE_FCNTL_H
28 # include <fcntl.h> /* to declare O_RDWR, O_CREAT, O_EXCL */
29 #endif
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h> /* to declare mkstemp () */
32 #endif
34 #ifdef HAVE_LIMITS_H
35 # include <limits.h> /* to declare MB_LEN_MAX */
36 #endif
37 #ifndef MB_LEN_MAX
38 # define MB_LEN_MAX 6
39 #endif
41 /* To declare "struct stat" and stat ().
43 #if defined (HAVE_SYS_TYPES_H)
44 # include <sys/types.h>
45 #else
46 # if defined (HAVE_TYPES_H)
47 # include <types.h>
48 # endif
49 #endif
50 #ifdef HAVE_SYS_STAT_H
51 # include <sys/stat.h>
52 #else
53 # ifdef HAVE_STAT_H
54 # include <stat.h>
55 # endif
56 #endif
58 #ifdef HAVE_DIRECT_H
59 # include <direct.h> /* to _getcwd */
60 #endif
61 #ifdef HAVE_DIR_H
62 # include <dir.h> /* to declare findfirst() and findnext() */
63 #endif
64 #ifdef HAVE_IO_H
65 # include <io.h> /* to declare open() */
66 #endif
67 #include "debug.h"
68 #include "routines.h"
69 #ifdef HAVE_ICONV
70 # include "mbcs.h"
71 #endif
72 #ifdef HAVE_ERRNO_H
73 # include <errno.h>
74 #endif
76 #include "options.h"
79 * MACROS
81 #ifndef TMPDIR
82 # define TMPDIR "/tmp"
83 #endif
85 /* File type tests.
87 #ifndef S_ISREG
88 # if defined (S_IFREG)
89 # define S_ISREG(mode) ((mode) & S_IFREG)
90 # endif
91 #endif
93 #ifndef S_ISLNK
94 # ifdef S_IFLNK
95 # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
96 # else
97 # define S_ISLNK(mode) FALSE /* assume no soft links */
98 # endif
99 #endif
101 #ifndef S_ISDIR
102 # ifdef S_IFDIR
103 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
104 # else
105 # define S_ISDIR(mode) FALSE /* assume no soft links */
106 # endif
107 #endif
109 #ifndef S_IFMT
110 # define S_IFMT 0
111 #endif
113 #ifndef S_IXUSR
114 # define S_IXUSR 0
115 #endif
116 #ifndef S_IXGRP
117 # define S_IXGRP 0
118 #endif
119 #ifndef S_IXOTH
120 # define S_IXOTH 0
121 #endif
123 #ifndef S_IRUSR
124 # define S_IRUSR 0400
125 #endif
126 #ifndef S_IWUSR
127 # define S_IWUSR 0200
128 #endif
130 #ifndef S_ISUID
131 # define S_ISUID 0
132 #endif
134 #ifndef S_ISGID
135 # define S_ISGID 0
136 #endif
138 /* Hack for ridiculous practice of Microsoft Visual C++.
140 #if defined (WIN32)
141 # if defined (_MSC_VER)
142 # define stat _stat
143 # define getcwd _getcwd
144 # define PATH_MAX _MAX_PATH
145 # endif
146 #endif
148 #ifndef PATH_MAX
149 # define PATH_MAX 256
150 #endif
152 #define selected(var,feature) (((int)(var) & (int)(feature)) == (int)feature)
155 * Miscellaneous macros
160 * DATA DEFINITIONS
162 #if defined (MSDOS_STYLE_PATH)
163 const char *const PathDelimiters = ":/\\";
164 #endif
166 char *CurrentDirectory;
168 static const char *ExecutableProgram = NULL;
169 static const char *ExecutableName = "geany";
172 * FUNCTION PROTOTYPES
174 #ifdef NEED_PROTO_STAT
175 extern int stat (const char *, struct stat *);
176 #endif
177 #ifdef NEED_PROTO_LSTAT
178 extern int lstat (const char *, struct stat *);
179 #endif
183 * FUNCTION DEFINITIONS
187 extern void setExecutableName (const char *const path)
189 ExecutableProgram = path;
190 ExecutableName = baseFilename (path);
193 extern const char *getExecutableName (void)
195 return ExecutableName;
199 extern void *eMalloc (const size_t size)
201 void *buffer = g_malloc (size);
203 if (buffer == NULL)
204 error (FATAL, "out of memory");
206 return buffer;
209 extern void *eCalloc (const size_t count, const size_t size)
211 void *buffer = calloc (count, size);
213 if (buffer == NULL)
214 error (FATAL, "out of memory");
216 return buffer;
219 extern void *eRealloc (void *const ptr, const size_t size)
221 void *buffer;
222 if (ptr == NULL)
223 buffer = eMalloc (size);
224 else
226 buffer = g_realloc (ptr, size);
227 if (buffer == NULL)
228 error (FATAL, "out of memory");
230 return buffer;
233 extern void eFree (void *const ptr)
235 if (ptr != NULL)
236 free (ptr);
239 #ifndef HAVE_STRSTR
240 extern char* strstr (const char *str, const char *substr)
242 const size_t length = strlen (substr);
243 const char *match = NULL;
244 const char *p;
246 for (p = str ; *p != '\0' && match == NULL ; ++p)
247 if (strncmp (p, substr, length) == 0)
248 match = p;
249 return (char*) match;
251 #endif
253 extern char* eStrdup (const char* str)
255 char* result = xMalloc (strlen (str) + 1, char);
256 strcpy (result, str);
257 return result;
260 extern void toLowerString (char* str)
262 while (*str != '\0')
264 *str = tolower ((int) *str);
265 ++str;
269 extern void toUpperString (char* str)
271 while (*str != '\0')
273 *str = toupper ((int) *str);
274 ++str;
278 /* Newly allocated string containing lower case conversion of a string.
280 extern char* newLowerString (const char* str)
282 char* const result = xMalloc (strlen (str) + 1, char);
283 int i = 0;
285 result [i] = tolower ((int) str [i]);
286 while (str [i++] != '\0');
287 return result;
290 /* Newly allocated string containing upper case conversion of a string.
292 extern char* newUpperString (const char* str)
294 char* const result = xMalloc (strlen (str) + 1, char);
295 int i = 0;
297 result [i] = toupper ((int) str [i]);
298 while (str [i++] != '\0');
299 return result;
303 #if 0
304 static void setCurrentDirectory (void)
306 char* const cwd = getcwd (NULL, PATH_MAX);
307 CurrentDirectory = xMalloc (strlen (cwd) + 2, char);
308 if (cwd [strlen (cwd) - (size_t) 1] == PATH_SEPARATOR)
309 strcpy (CurrentDirectory, cwd);
310 else
311 sprintf (CurrentDirectory, "%s%c", cwd, OUTPUT_PATH_SEPARATOR);
312 free (cwd);
314 #endif
317 extern boolean doesFileExist (const char *const fileName)
319 GStatBuf fileStatus;
321 return (boolean) (g_stat (fileName, &fileStatus) == 0);
324 extern boolean isRecursiveLink (const char* const dirName)
326 boolean result = FALSE;
327 char* const path = absoluteFilename (dirName);
328 while (path [strlen (path) - 1] == PATH_SEPARATOR)
329 path [strlen (path) - 1] = '\0';
330 while (! result && strlen (path) > (size_t) 1)
332 char *const separator = strrchr (path, PATH_SEPARATOR);
333 if (separator == NULL)
334 break;
335 else if (separator == path) /* backed up to root directory */
336 *(separator + 1) = '\0';
337 else
338 *separator = '\0';
339 result = isSameFile (path, dirName);
341 eFree (path);
342 return result;
345 extern boolean isSameFile (const char *const name1, const char *const name2)
347 boolean result = FALSE;
348 #ifdef HAVE_STAT_ST_INO
349 GStatBuf stat1, stat2;
351 if (g_stat (name1, &stat1) == 0 && g_stat (name2, &stat2) == 0)
352 result = (boolean) (stat1.st_ino == stat2.st_ino);
353 #endif
354 return result;
358 * Pathname manipulation (O/S dependent!!!)
361 extern const char *baseFilename (const char *const filePath)
363 #if defined (MSDOS_STYLE_PATH)
364 const char *tail = NULL;
365 unsigned int i;
367 /* Find whichever of the path delimiters is last.
369 for (i = 0 ; i < strlen (PathDelimiters) ; ++i)
371 const char *sep = strrchr (filePath, PathDelimiters [i]);
373 if (sep > tail)
374 tail = sep;
376 #else
377 const char *tail = strrchr (filePath, PATH_SEPARATOR);
378 #endif
379 if (tail == NULL)
380 tail = filePath;
381 else
382 ++tail; /* step past last delimiter */
384 return tail;
388 * File extension and language mapping
390 extern const char *fileExtension (const char *const fileName)
392 const char *extension;
393 const char *pDelimiter = NULL;
395 pDelimiter = strrchr (fileName, '.');
397 if (pDelimiter == NULL)
398 extension = "";
399 else
400 extension = pDelimiter + 1; /* skip to first char of extension */
402 return extension;
405 extern boolean isAbsolutePath (const char *const path)
407 boolean result = FALSE;
408 #if defined (MSDOS_STYLE_PATH)
409 if (strchr (PathDelimiters, path [0]) != NULL)
410 result = TRUE;
411 else if (isalpha (path [0]) && path [1] == ':')
413 if (strchr (PathDelimiters, path [2]) != NULL)
414 result = TRUE;
415 else
416 /* We don't support non-absolute file names with a drive
417 * letter, like `d:NAME' (it's too much hassle).
419 error (FATAL,
420 "%s: relative file names with drive letters not supported",
421 path);
423 #else
424 result = (boolean) (path [0] == PATH_SEPARATOR);
425 #endif
426 return result;
429 extern vString *combinePathAndFile (const char *const path,
430 const char *const file)
432 vString *const filePath = vStringNew ();
433 const int lastChar = path [strlen (path) - 1];
434 # ifdef MSDOS_STYLE_PATH
435 boolean terminated = (boolean) (strchr (PathDelimiters, lastChar) != NULL);
436 # else
437 boolean terminated = (boolean) (lastChar == PATH_SEPARATOR);
438 # endif
440 vStringCopyS (filePath, path);
441 if (! terminated)
443 vStringPut (filePath, OUTPUT_PATH_SEPARATOR);
444 vStringTerminate (filePath);
446 vStringCatS (filePath, file);
448 return filePath;
451 /* Return a newly-allocated string whose contents concatenate those of
452 * s1, s2, s3.
453 * Routine adapted from Gnu etags.
455 static char* concat (const char *s1, const char *s2, const char *s3)
457 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
458 char *result = xMalloc (len1 + len2 + len3 + 1, char);
460 strcpy (result, s1);
461 strcpy (result + len1, s2);
462 strcpy (result + len1 + len2, s3);
463 result [len1 + len2 + len3] = '\0';
465 return result;
468 /* Return a newly allocated string containing the absolute file name of FILE
469 * given CWD (which should end with a slash).
470 * Routine adapted from Gnu etags.
472 extern char* absoluteFilename (const char *file)
474 char *slashp, *cp;
475 char *res = NULL;
477 if (isAbsolutePath (file))
478 res = eStrdup (file);
479 else
480 res = concat (CurrentDirectory, file, "");
482 /* Delete the "/dirname/.." and "/." substrings. */
483 slashp = strchr (res, '/');
484 while (slashp != NULL && slashp [0] != '\0')
486 if (slashp[1] == '.')
488 if (slashp [2] == '.' && (slashp [3] == '/' || slashp [3] == '\0'))
490 cp = slashp;
492 cp--;
493 while (cp >= res && ! isAbsolutePath (cp));
494 if (cp < res)
495 cp = slashp;/* the absolute name begins with "/.." */
496 #ifdef MSDOS_STYLE_PATH
497 /* Under MSDOS and NT we get `d:/NAME' as absolute file name,
498 * so the luser could say `d:/../NAME'. We silently treat this
499 * as `d:/NAME'.
501 else if (cp [0] != '/')
502 cp = slashp;
503 #endif
504 memmove (cp, slashp + 3, strlen (slashp + 3) + 1);
505 slashp = cp;
506 continue;
508 else if (slashp [2] == '/' || slashp [2] == '\0')
510 memmove (slashp, slashp + 2, strlen (slashp + 2) + 1);
511 continue;
514 slashp = strchr (slashp + 1, '/');
517 if (res [0] == '\0')
518 return eStrdup ("/");
519 else
521 #ifdef MSDOS_STYLE_PATH
522 /* Canonicalize drive letter case. */
523 if (res [1] == ':' && islower (res [0]))
524 res [0] = toupper (res [0]);
525 #endif
527 return res;
531 /* Return a newly allocated string containing the absolute file name of dir
532 * where FILE resides given CWD (which should end with a slash).
533 * Routine adapted from Gnu etags.
535 extern char* absoluteDirname (char *file)
537 char *slashp, *res;
538 char save;
539 #ifdef MSDOS_STYLE_PATH
540 char *p;
541 for (p = file ; *p != '\0' ; p++)
542 if (*p == '\\')
543 *p = '/';
544 #endif
545 slashp = strrchr (file, '/');
546 if (slashp == NULL)
547 res = eStrdup (CurrentDirectory);
548 else
550 save = slashp [1];
551 slashp [1] = '\0';
552 res = absoluteFilename (file);
553 slashp [1] = save;
555 return res;
558 /* Return a newly allocated string containing the file name of FILE relative
559 * to the absolute directory DIR (which should end with a slash).
560 * Routine adapted from Gnu etags.
562 extern char* relativeFilename (const char *file, const char *dir)
564 const char *fp, *dp;
565 char *absdir, *res;
566 int i;
568 /* Find the common root of file and dir (with a trailing slash). */
569 absdir = absoluteFilename (file);
570 fp = absdir;
571 dp = dir;
572 while (*fp++ == *dp++)
573 continue;
574 fp--;
575 dp--; /* back to the first differing char */
577 { /* look at the equal chars until '/' */
578 if (fp == absdir)
579 return absdir; /* first char differs, give up */
580 fp--;
581 dp--;
582 } while (*fp != '/');
584 /* Build a sequence of "../" strings for the resulting relative file name.
586 i = 0;
587 while ((dp = strchr (dp + 1, '/')) != NULL)
588 i += 1;
589 res = xMalloc (3 * i + strlen (fp + 1) + 1, char);
590 res [0] = '\0';
591 while (i-- > 0)
592 strcat (res, "../");
594 /* Add the file name relative to the common root of file and dir. */
595 strcat (res, fp + 1);
596 free (absdir);
598 return res;
601 extern long unsigned int getFileSize (const char *const name)
603 GStatBuf fileStatus;
604 unsigned long size = 0;
606 if (g_stat (name, &fileStatus) == 0)
607 size = fileStatus.st_size;
609 return size;
612 #if 0
613 static boolean isSymbolicLink (const char *const name)
615 #if defined (WIN32)
616 return FALSE;
617 #else
618 GStatBuf fileStatus;
619 boolean result = FALSE;
621 if (g_lstat (name, &fileStatus) == 0)
622 result = (boolean) (S_ISLNK (fileStatus.st_mode));
624 return result;
625 #endif
628 static boolean isNormalFile (const char *const name)
630 GStatBuf fileStatus;
631 boolean result = FALSE;
633 if (g_stat (name, &fileStatus) == 0)
634 result = (boolean) (S_ISREG (fileStatus.st_mode));
636 return result;
638 #endif
640 extern boolean isExecutable (const char *const name)
642 GStatBuf fileStatus;
643 boolean result = FALSE;
645 if (g_stat (name, &fileStatus) == 0)
646 result = (boolean) ((fileStatus.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) != 0);
648 return result;
651 #ifdef HAVE_MKSTEMP
653 static boolean isSetUID (const char *const name)
655 #if defined (WIN32)
656 return FALSE;
657 #else
658 GStatBuf fileStatus;
659 boolean result = FALSE;
661 if (g_stat (name, &fileStatus) == 0)
662 result = (boolean) ((fileStatus.st_mode & S_ISUID) != 0);
664 return result;
665 #endif
668 #endif
670 #if 0
671 static boolean isDirectory (const char *const name)
673 boolean result = FALSE;
674 GStatBuf fileStatus;
676 if (g_stat (name, &fileStatus) == 0)
677 result = (boolean) S_ISDIR (fileStatus.st_mode);
678 return result;
680 #endif
682 /*#ifndef HAVE_FGETPOS*/
684 extern int fgetpos ( stream, pos )
685 FILE *const stream;
686 fpos_t *const pos;
688 int result = 0;
690 *pos = ftell (stream);
691 if (*pos == -1L)
692 result = -1;
694 return result;
697 extern int fsetpos ( stream, pos )
698 FILE *const stream;
699 fpos_t *const pos;
701 return fseek (stream, *pos, SEEK_SET);
704 /*#endif*/
706 extern FILE *tempFile (const char *const mode, char **const pName)
708 char *name;
709 FILE *fp;
710 int fd;
711 #ifdef HAVE_MKSTEMP
712 const char *const template = "tags.XXXXXX";
713 const char *tmpdir = NULL;
714 if (! isSetUID (ExecutableProgram))
715 tmpdir = getenv ("TMPDIR");
716 if (tmpdir == NULL)
717 tmpdir = TMPDIR;
718 name = xMalloc (strlen (tmpdir) + 1 + strlen (template) + 1, char);
719 sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, template);
720 fd = mkstemp(name);
721 #else
722 name = xMalloc (L_tmpnam, char);
723 if (tmpnam (name) != name)
724 error (FATAL | PERROR, "cannot assign temporary file name");
725 fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
726 #endif
727 if (fd == -1)
728 error (FATAL | PERROR, "cannot open temporary file");
729 fp = fdopen (fd, mode);
730 if (fp == NULL)
731 error (FATAL | PERROR, "cannot open temporary file");
732 DebugStatement (
733 debugPrintf (DEBUG_STATUS, "opened temporary file %s\n", name); )
734 Assert (*pName == NULL);
735 *pName = name;
736 return fp;
739 extern void error (const errorSelection selection,
740 const char *const format, ...)
742 va_list ap;
744 va_start (ap, format);
745 fprintf (errout, "%s: %s", getExecutableName (),
746 selected (selection, WARNING) ? "Warning: " : "");
747 vfprintf (errout, format, ap);
748 if (selected (selection, PERROR))
749 fprintf (errout, " : %s", g_strerror (errno));
750 fputs ("\n", errout);
751 va_end (ap);
752 if (selected (selection, FATAL))
753 exit (1);
756 #ifndef HAVE_STRICMP
757 extern int stricmp (const char *s1, const char *s2)
759 int result;
762 result = toupper ((int) *s1) - toupper ((int) *s2);
763 } while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
764 return result;
766 #endif
768 #ifndef HAVE_STRNICMP
769 extern int strnicmp (const char *s1, const char *s2, size_t n)
771 int result;
774 result = toupper ((int) *s1) - toupper ((int) *s2);
775 } while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
776 return result;
778 #endif
781 /* vi:set tabstop=4 shiftwidth=4: */