📄 pathdup.c
字号:
/* pathdup.c - reproduces a path stripping /../ /./ and resolving symlinks Copyright (C) 1996-2000 Paul Sheer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include "global.h"#include "pipe-headers.h"#include <my_string.h>#include "mad.h"struct comp { struct comp *prev; struct comp *next; char name[2];};static struct comp *comp_last (struct comp *p){ while (p->next) p = p->next; return p;}static struct comp *comp_first (struct comp *p){ while (p->prev) p = p->prev; return p;}static inline struct comp *comp_cat (struct comp *s, struct comp *t){ s = comp_last (s); t = comp_first (t); s->next = t; t->prev = s; return comp_first (s);}static inline struct comp *comp_insert (struct comp *p, struct comp *s){ struct comp *t; t = comp_last (s); s = comp_first (s); if (p->prev) p->prev->next = s; if (p->next) p->next->prev = t; t->next = p->next; s->prev = p->prev; memset (p, 0, sizeof (*p)); free (p); return t;}static inline struct comp *comp_replace (struct comp *p, struct comp *s){ struct comp *t, *prev, *r; t = comp_last (s); if (p->next) p->next->prev = t; t->next = p->next; for (r = p; r; r = prev) { prev = r->prev; memset (r, 0, sizeof (*r)); free (r); } return t;}static inline void comp_free (struct comp *p){ struct comp *next; p = comp_first (p); for (; p; p = next) { next = p->next; memset (p, 0, sizeof (*p)); free (p); }}#define COMP_DUMP(p) \ if (u == p) \ u = p->next; \ if (p->next) \ p->next->prev = p->prev; \ if (p->prev) \ p->prev->next = p->next; \ memset (p, 0, sizeof (*p)); \ free (p);/* dump .. . and nothings, but remember the place in the list of p */static struct comp *comp_strip (struct comp *p){ struct comp *u = p, *next; for (p = comp_first (p); p; p = next) { next = p->next; if (!*p->name || !strcmp (p->name, ".")) { COMP_DUMP (p); } else if (!strcmp (p->name, "..")) { struct comp *t; if ((t = p->prev)) { COMP_DUMP (t); } COMP_DUMP (p); } } if (!u) {/* mustn't strip everything */ u = malloc (sizeof (struct comp)); memset (u, 0, sizeof (struct comp)); } return u;}/* split into a list along / */#ifdef HAVE_MADstatic char *mad_comp_combine (struct comp *s, char *file, int line)#define comp_combine(s) mad_comp_combine(s, __FILE__, __LINE__)#elsestatic char *comp_combine (struct comp *s)#endif{ int n; struct comp *t, *f; char *p, *r; f = comp_first (s); for (n = 0, t = f; t != s->next; t = t->next) n += strlen (t->name) + 1;#ifdef HAVE_MAD r = mad_alloc (n + 2, file, line);#else r = malloc (n + 2);#endif for (p = r, t = f; t != s->next; t = t->next) { *p++ = '/'; strcpy (p, t->name); p += strlen (p); } return r;}/* split into a list along / */static struct comp *comp_tize (char *s){ struct comp *u, *p = 0; char *t; int done = 0; while (!done) { int l; t = (char *) strchr (s, '/'); if (!t) { t = s + strlen (s); done = 1; } l = (unsigned long) t - (unsigned long) s; u = malloc (sizeof (struct comp) + l); u->prev = p; u->next = 0; if (p) p->next = u; p = u; memcpy (u->name, s, l); u->name[l] = '\0'; s = t + 1; } return p;}static inline char *comp_readlink (struct comp *p){ char *s; int r; static char buf[2048]; s = comp_combine (p); r = readlink (s, buf, 2047); if (r == -1 && errno == EINVAL) { free (s); return ""; } if (r == -1) { free (s); return 0; } buf[r] = '\0'; free (s); return buf;}/* if there is an error, this just returns as far as it got */static inline struct comp *resolve_symlink (struct comp *path){ int i; struct comp *t; path = comp_strip (comp_first (path)); path = comp_last (path); for (i = 0;; i++) { char *l; if (i >= 1000) break; l = comp_readlink (path); if (!l) break; if (l[0] == '/') {/* absolute symlink */ t = comp_tize (l); path = comp_replace (path, t); path = comp_strip (path); continue; } else if (*l) {/* relative symlink */ t = comp_tize (l); path = comp_insert (path, t); path = comp_strip (path); continue; } else if (path->prev) {/* not a symlink */ path = path->prev; continue; } break; } return path;}extern char *home_dir;#ifdef HAVE_MADchar *mad_pathdup (char *p, char *file, int line)#elsechar *pathdup (char *p)#endif{ struct comp *s; s = comp_tize (p); if (!strcmp (comp_first (s)->name, "~")) { s = comp_replace (comp_first (s), comp_tize (home_dir)); } else if (*p != '/') { char *cwd; cwd = malloc (2048);#ifdef HAVE_GETCWD getcwd (cwd, 2047);#else getwd (cwd);#endif s = comp_cat (comp_tize (cwd), comp_tize (p)); free (cwd); } s = resolve_symlink (s);#ifdef HAVE_MAD p = mad_comp_combine (comp_last (s), file, line);#else p = comp_combine (comp_last (s));#endif comp_free (s); return p;}#if 0int main (int argc, char **argv){ printf ("%s\n", pathdup (argv[1])); return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -