File: pathfun.c

package info (click to toggle)
yorick 1.5.08-1
  • links: PTS
  • area: main
  • in suites: woody
  • size: 7,508 kB
  • ctags: 7,937
  • sloc: ansic: 75,604; cpp: 1,282; lisp: 1,217; sh: 1,026; makefile: 616; fortran: 19
file content (179 lines) | stat: -rw-r--r-- 4,235 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
    PATHFUN.C
    Implement path name expansion and utility functions required by Yorick.

    $Id: sysdep.c,v 1.1 1993/08/27 18:32:09 munro Exp munro $
 */
/*    Copyright (c) 2001.  The Regents of the University of California.
                    All rights reserved.  */

#include "yio.h"
#include "pstdlib.h"
#include <string.h>

#define DIR_SEP '/'
#define DIR_SEP_S "/"

char *yCWD = 0;
char *yHOME = "~/";

/* YSetCWD returns non-0 if operation fails, resets yCWD on success.  */
int
YSetCWD(const char *name)
{
  int notOK = name? p_chdir(name) : 0;
  if (!notOK) {
    p_free(yCWD);
    yCWD = p_strcpy(p_getcwd());
    if (yCWD) YNameToHead(&yCWD);
    else notOK = 1;
  }
  return notOK;
}

void
YGetHOME(void)
{
  char *hnm = Ygetenv("HOME");
  if (hnm && hnm[0]) {
    yHOME = p_strcpy(hnm);
    YNameToHead(&yHOME);
  } else {
    yHOME = p_strcpy(ySiteDir);
  }
}

/* convert path name which may be relative, or begin with ., .., ~, or
 * an environment variable, into an absolute pathname */
char *
YExpandName(const char *name)
{
  char *path, *head = 0, *tail0 = 0;
  char *tail = (char *)name;  /* I promise not to write to the original... */
  int freeHead = 0;
  int nRemove = 0;   /* count number of leading ..s */

  if (!name) return 0;

  /* try to take care of simple environment variable in first position */
  if (tail[0]=='$') {
    char *env;
    char delim = *(++tail);
    if (delim=='(') { delim = ')'; tail++; }
    else if (delim=='{') { delim='}'; tail++; }
    else delim = DIR_SEP;
    env = tail;
    while (*tail && *tail!=delim) tail++;
    if (*tail && delim!=DIR_SEP) tail++;
    head = Ygetenv( (env = p_strncat(0, env, tail-env)) );
    p_free(env);
    tail = tail0 = p_strncat(head, tail, 0);
    p_free(head);
    head = 0;
  }

  /* handle paths beginning with . or ~ or relative pathnames */
  if (tail[0]=='.') {
    head = yCWD;
    if (!tail[1]) tail++;
    else if (tail[1]==DIR_SEP) tail += 2;
  } else if (!YIsAbsolute(tail)) {
    head = yCWD;
  }

  /* count number of leading ..s */
  while (tail[0]=='.') {
    if (tail[1]=='.') {
      if (!tail[2]) {
	tail += 2;
	nRemove++;
      } else if (tail[2]==DIR_SEP) {
	tail += 3;
	nRemove++;
      }
    } else if (tail[1]==DIR_SEP) {
      tail += 2;
    } else if (!tail[1]) {
      tail++;
    } else {
      break;
    }
  }

  /* strip nRemove parent directories (but stop at root) */
  if (nRemove && head) {
    char *old = head;
    head = p_strcpy(head);
    if (freeHead) p_free(old);
    else freeHead = 1;
    path = head+strlen(head)-1;   /* guaranteed to point to DIR_SEP */
    do {
      while (path>head && *(--path)!=DIR_SEP);
    } while (--nRemove);
    path[1] = '\0';
  }

  path = p_strncat(head, tail, 0);
  if (freeHead) p_free(head);
  if (tail0) p_free(tail0);
  return path;
}

/* strip leading directory names from a pathname */
char *
YNameTail(const char *name)
{
  const char *nm = name;
  if (!nm) return 0;
  nm += strlen(nm);
  while (nm>name && *nm!=DIR_SEP) nm--;
  if (*nm!=DIR_SEP) return p_strcpy(nm);
  else return p_strcpy(nm+1);
}

/* return leading directory names of a pathname, including trailing /
 * returns 0 if no occurrences of / in pathname */
char *
YNameHead(const char *name)
{
  const char *nm = name;
  if (!nm) return 0;
  nm += strlen(nm);
  while (nm>name && *nm!=DIR_SEP) nm--;
  if (*nm!=DIR_SEP) return 0;
  else return p_strncat(0, name, nm-name+1);
}

/* ensure that a name ends in /, so it can be used as a path prefix */
void
YNameToHead(char **name)
{
  char *head = *name;
  long n = head? strlen(head) : 0;
  if (n<1 || head[n-1]!=DIR_SEP) {
    head = p_strncat(head, DIR_SEP_S, 0);
    p_free(*name);
    *name = head;
  }
}

int
YIsAbsolute(const char *name)
{
  if (name[0]==DIR_SEP || name[0]=='~') return 1;
  /* handle MS Windows a:/blahblah */
  if (name[0] && name[1]==':' && name[2]==DIR_SEP &&
      ((name[0]>='A' && name[0]<='Z') || (name[0]>='a' && name[0]<='z')))
    return 1;
  /* handle MS Windows \\server\path */
  if (name[0]=='\\' && name[1]=='\\') return 1;
  return 0;
}

int
YIsDotRelative(const char *name)
{
  return name[0]=='.' &&
    (!name[1] || (name[1]==DIR_SEP ||
		  (name[1]=='.' && (!name[2] || name[2]==DIR_SEP))));
}