/* * PSP Software Development Kit - https://github.com/pspdev * ----------------------------------------------------------------------- * Licensed under the BSD license, see LICENSE in PSPSDK root for details. * * cwd.c - The global init/deinit code for our crt0. * * Copyright (c) 2005 Marcus R. Brown * Copyright (c) 2005 James Forshaw * Copyright (c) 2005 John Kelley * */ #include #include #include #include #include #include #ifdef F___cwd /* the present working directory variable. */ char __cwd[MAXNAMLEN + 1] = { 0 }; #else extern char __cwd[MAXNAMLEN + 1]; #endif #ifdef F___get_drive /* Return the number of bytes taken up by the "drive:" prefix, or -1 if it's not found */ int __get_drive(const char *d) { int i; for(i=0; d[i]; i++) { if(! ((d[i] >= 'a' && d[i] <= 'z') || (d[i] >= '0' && d[i] <= '9') )) break; } if(d[i] == ':') return i+1; return -1; } #else int __get_drive(const char *d); #endif #ifdef F_getcwd char *getcwd(char *buf, size_t size) { if(!buf) { errno = EINVAL; return NULL; } if(strlen(__cwd) >= size) { errno = ERANGE; return NULL; } strcpy(buf, __cwd); return buf; } #endif #ifdef F___path_absolute /* Like strcpy, but returns 0 if the string doesn't fit */ static int __safe_strcpy(char *out, const char *in, int maxlen) { for( ; maxlen > 0 && *in ; maxlen-- ) *(out++) = *(in++); if(maxlen < 1) return 0; *out = 0; return 1; } /* Like strcat, but returns 0 if the string doesn't fit */ static int __safe_strcat(char *out, const char *in, int maxlen) { for( ; *out ; out++,maxlen-- ) continue; return __safe_strcpy(out, in, maxlen); } /* Normalize a pathname (without leading "drive:") by removing . and .. components, duplicated /, etc. */ static int __path_normalize(char *out, int len) { int i, j; int first, next; /* First append "/" to make the rest easier */ if(!__safe_strcat(out,"/",len)) return -10; /* Convert "//" to "/" */ for(i=0; out[i+1]; i++) { if(out[i]=='/' && out[i+1]=='/') { for(j=i+1; out[j]; j++) out[j] = out[j+1]; i--; } } /* Convert "/./" to "/" */ for(i=0; out[i] && out[i+1] && out[i+2]; i++) { if(out[i]=='/' && out[i+1]=='.' && out[i+2]=='/') { for(j=i+1; out[j]; j++) out[j] = out[j+2]; i--; } } /* Convert "/asdf/../" to "/" until we can't anymore. Also * convert leading "/../" to "/" */ first = next = 0; while(1) { /* If a "../" follows, remove it and the parent */ if(out[next+1] && out[next+1]=='.' && out[next+2] && out[next+2]=='.' && out[next+3] && out[next+3]=='/') { for(j=0; out[first+j+1]; j++) out[first+j+1] = out[next+j+4]; first = next = 0; continue; } /* Find next slash */ first = next; for(next=first+1; out[next] && out[next] != '/'; next++) continue; if(!out[next]) break; } /* Remove trailing "/" */ for(i=1; out[i]; i++) continue; if(i >= 1 && out[i-1] == '/') out[i-1] = 0; return 0; } /* Convert relative path to absolute path. */ int __path_absolute(const char *in, char *out, int len) { int dr; /* See what the relative URL starts with */ dr = __get_drive(in); if(dr > 0 && in[dr] == '/') { /* It starts with "drive:/", so it's already absolute */ if(!__safe_strcpy(out, in, len)) return -1; } else if(in[0] == '/') { /* It's absolute, but missing the drive, so use cwd's drive */ if(strlen(__cwd) >= len) return -2; strcpy(out, __cwd); dr = __get_drive(out); out[dr] = 0; if(!__safe_strcat(out, in, len)) return -3; } else { /* It's not absolute, so append it to the current cwd */ if(strlen(__cwd) >= len) return -4; strcpy(out, __cwd); if(!__safe_strcat(out, "/", len)) return -6; if(!__safe_strcat(out, in, len)) return -7; } /* Now normalize the pathname portion */ dr = __get_drive(out); if(dr < 0) dr = 0; return __path_normalize(out + dr, len - dr); } #endif #ifdef F___init_cwd /* Set the current working directory (CWD) to the path where the module was launched. */ void __init_cwd(char *argv_0) { if (argv_0 != NULL) { char base_path[MAXPATHLEN + 1]; char *end; strncpy(base_path, argv_0, sizeof(base_path) - 1); base_path[sizeof(base_path) - 1] = '\0'; end = strrchr(base_path, '/'); if (end != NULL) { *(end + 1) = '\0'; chdir(base_path); } } } #endif