blob: 8618c929e2454955e25b6e72ddb61a6e62e364d9 [file] [log] [blame]
/* --COPYRIGHT--,EPL
*Copyright (c) 2008 Texas Instruments and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
/*
* ======== xdcrmp.c ========
* Remove all package files in the specified base directories _except_ any
* "nested packages".
*
* usage: xdcrmp [-help] [-k] [-n] [base-directory ...]
*/
#include <xdc/std.h>
#include <xdc/services/host/lib/xutl.h>
#include <xdc/services/host/lib/lst.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXPATHLEN 1024
static Char pathBuf[MAXPATHLEN + 1];
static String usage = "%s: [-help] [-k] [-n] [package-base-directory ...]\n"
" -help display this message\n"
" -k keep all underlying packages. Without this flag,\n"
" only packages with the same repository are retained; \n"
" normally, packages contained in subdirectories are\n"
" removed unless they have exactly the same repository as\n"
" the package being removed.\n"
" -n don't actually remove any files; just show the commands\n"
" that would be executed.\n";
static String progName = NULL;
static LST_Seq curDirList = NULL;
static LST_Seq curPkgBaseList = NULL;
static String curRepo = NULL;
static String curBase = NULL;
static String curName = NULL;
static Int curBaseLen = 0;
static Bool kflag = FALSE;
static Bool nflag = FALSE;
static int exitStatus = 0;
static Int compare(const void *a, const void *b);
static Void deleteList(LST_Seq list);
static Bool filter(IArg arg, String baseName, String dirName, Char *end);
static Void rmDirs(LST_Seq dirs, LST_Seq pkgs);
static Int scanFile(IArg arg, IArg *cookie, String baseName, String dirName);
/*
* ======== main ========
*/
Int main(Int argc, String argv[])
{
Int i;
XUTL_init();
LST_init();
progName = argv[0];
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'k': {
kflag = TRUE;
break;
}
case 'n': {
nflag = TRUE;
break;
}
case 'h': {
printf(usage, progName);
return (0);
}
default: {
fprintf(stderr, usage, progName);
return (1);
}
}
}
else {
break;
}
}
if (i >= argc) {
fprintf(stderr, usage, progName);
return (1);
}
for (; i < argc; i++) {
if (XUTL_isPackageBase(argv[i], FALSE)) {
curDirList = LST_create(sizeof(String));
curPkgBaseList = LST_create(sizeof(String));
if (curDirList == NULL || curPkgBaseList == NULL) {
fprintf(stderr, "%s: output memory\n", progName);
exit(1);
}
curRepo = NULL;
curBase = argv[i];
curBaseLen = strlen(curBase);
/* if argv[i] is a package base, find it's files */
if ((curName = XUTL_getPackageName(curBase, FALSE)) != NULL) {
Char *cp;
/* replace '.'s with '/'s in curName */
for (cp = curName; *cp != '\0'; cp++) {
if (*cp == '.') {
*cp = '/';
}
}
/* if we only keep pkgs with the same repo, compute it now */
if (kflag == FALSE) {
curRepo = XUTL_getPackageRep(curBase);
}
/* now scan the file system and remove pkg files */
XUTL_scanFS(curBase, scanFile, filter, 0, XUTL_FSALL);
free(curName);
if (curRepo != NULL) {
free(curRepo);
}
/* remove the now empty directories */
rmDirs(curDirList, curPkgBaseList);
deleteList(curDirList);
deleteList(curPkgBaseList);
}
}
else {
fprintf(stderr, "%s: %s is not a package base directory\n",
progName, argv[i]);
}
}
return (exitStatus);
}
/*
* ======== compare ========
* Sort array so that prefixes appear later; this allows one to
* remove directories in order from 0 to N.
*/
static Int compare(const void *a, const void *b)
{
String dirA = *(String *)a;
String dirB = *(String *)b;
return (strcmp(dirB, dirA));
}
/*
* ======== deleteList ========
*/
static void deleteList(LST_Seq list)
{
String name;
for (LST_scan(list, &name); LST_next(list);) {
free(name);
}
LST_delete(list);
}
/*
* ======== filter ========
* skip nested package directories
*
* Return TRUE to skip dirName/baseName (and not remove it), FALSE to
* scan it (i.e, remove it).
*/
static Bool filter(IArg arg, String baseName, String dirName, Char *end)
{
Int len = end - dirName;
Int baseLen = strlen(baseName);
Bool result = TRUE;
Bool isDir = FALSE;
/* append baseName and dirName to determine if it's a package */
if ((len + 1 + baseLen + 1) < MAXPATHLEN) {
sprintf(pathBuf, "%s/%s", dirName, baseName);
result = XUTL_isPackageBase(pathBuf, FALSE);
isDir = result ? TRUE : XUTL_isDir(pathBuf);
/* if -k is not set, check curRepo against pathBuf pkg's repository */
if (result && curRepo != NULL) {
String rname = XUTL_getPackageRep(pathBuf);
result = FALSE; /* only skip if curRepo matches pathBuf's repo */
if (rname != NULL) {
if (strcmp(rname, curRepo) == 0) {
result = TRUE;
}
free(rname);
}
}
}
else {
fprintf(stderr, "%s: error: path too long (%s/%s)\n",
progName, dirName, baseName);
}
#if 0
printf("%s/%s: %s\n", dirName, baseName,
result == TRUE ? "TRUE" : "FALSE");
#endif
if (isDir) {
String tmp = strdup(pathBuf);
if (tmp == NULL
|| LST_append(result ? curPkgBaseList:curDirList, &tmp) == FALSE) {
fprintf(stderr, "%s: error: out of memory\n", progName);
exit(1);
}
/* printf("appending %s (%s) ...\n", tmp, result ? "TRUE" : "FALSE");*/
}
return (result);
}
/*
* ======== rmDirs ========
*/
static Void rmDirs(LST_Seq dirs, LST_Seq pkgs)
{
Int dirTabLen = LST_length(dirs);
if (dirTabLen > 0) {
String pkg;
String dir;
Bool remove = TRUE;
Int dirIndex = 0;
Int i;
String *dirTab = (String *)malloc(dirTabLen * sizeof(String));
if (dirTab == NULL) {
fprintf(stderr, "%s: error: out of memory\n", progName);
exit(1);
}
for (LST_scan(dirs, &dir); LST_next(dirs);) {
/* if any pkg is under dir, don't remove it */
for (LST_scan(pkgs, &pkg); LST_next(pkgs);) {
if (strncmp(dir, pkg, strlen(dir)) == 0) {
/* printf("preserving %s\n", dir); */
remove = FALSE;
}
}
if (remove == TRUE) {
dirTab[dirIndex++] = dir;
}
}
/* sort directories so we can remove them from the bottom up */
qsort(dirTab, dirIndex, sizeof(String), compare);
for (i = 0; i < dirIndex; i++) {
if (nflag == TRUE) {
printf("rmdir %s\n", dirTab[i]);
}
else {
if (!XUTL_rm(dirTab[i])) {
fprintf(stderr, "%s: can't remove '%s'\n",
progName, dirTab[i]);
exitStatus = 1;
}
}
}
free(dirTab);
}
}
/*
* ======== scanFile ========
* remove file visited
*/
static Int scanFile(IArg arg, IArg *cookie, String baseName, String dirName)
{
if ((strlen(dirName) + strlen(baseName) + 1) < MAXPATHLEN) {
sprintf(pathBuf, "%s/%s", dirName, baseName);
if (nflag == TRUE) {
printf("rm %s\n", pathBuf);
}
else {
if (!XUTL_rm(pathBuf)) {
fprintf(stderr, "%s: can't remove '%s'\n",
progName, pathBuf);
exitStatus = 1;
}
}
}
return (0);
}