/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
* Copyright (c) 2001, Tony Hoyle
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS source distribution.
*
* Query CVS/Entries from server
*/
#include "cvs.h"
// Horrid hack for legacy servers
unsigned global_ls_response_hack;
static int ls_proc (int argc, char **argv, const char *xwhere, const char *mwhere, const char *mfile, int shorten, int local, const char *mname, const char *msg);
static int ls_fileproc(void *callerdat, struct file_info *finfo);
static Dtype ls_direntproc(void *callerdat, char *dir,
char *repos, char *update_dir,
List *entries, const char *virtual_repository, Dtype hint);
static const char *const ls_usage[] =
{
"Usage: %s %s [-q] [-e] [-l] [-R] [-r rev] [-D date] [-t] [modules...]\n",
"\t-D date\tShow files from date.\n",
"\t-e\tDisplay in CVS/Entries format.\n",
"\t-l\tDisplay all details.\n",
"\t-P\tIgnore empty directories.\n",
"\t-q\tQuieter output.\n",
"\t-R\tList recursively.\n",
"\t-r rev\tShow files with revision or tag.\n",
"\t-T\tShow time in local time instead of GMT.\n",
"(Specify the --help global option for a list of other help options)\n",
NULL
};
static int entries_format;
static int long_format;
static char *show_tag;
static char *show_date;
static int tag_validated;
static int recurse;
static char *regexp_match;
static int local_time;
static int local_time_offset;
static int prune;
int ls(int argc, char **argv)
{
int c;
int err = 0;
std::vector<cvs::filename> args;
if (argc == -1)
usage (ls_usage);
entries_format = 0;
long_format = 0;
show_tag = NULL;
show_date = NULL;
tag_validated = 0;
quiet = 0;
recurse = 0;
local_time_offset = get_local_time_offset();
optind = 0;
while ((c = getopt (argc, argv, "+qelr:D:RTo:P")) != -1)
{
switch (c)
{
case 'q':
quiet = 1;
break;
case 'e':
entries_format = 1;
break;
case 'l':
long_format = 1;
break;
case 'r':
show_tag = optarg;
break;
case 'D':
show_date = Make_Date (optarg);
break;
case 'R':
recurse = 1;
break;
case 'T':
local_time = 1;
break;
case 'o':
local_time_offset = atoi(optarg);
break;
case 'P':
prune = 1;
break;
case '?':
default:
usage (ls_usage);
break;
}
}
argc -= optind;
argv += optind;
if (current_parsed_root->isremote)
{
char *req;
for(int i=0; i<argc; i++)
args.push_back(argv[i]);
if(supported_request("rls"))
req="rls\n";
else if(supported_request("ls"))
req="ls\n";
else
{
req = NULL;
if(recurse || prune || long_format)
{
error(1,0,"Remote server does not support rls. Requested options not available.");
}
local_time = 0;
send_to_server("Global_option -n\n",0);
if(argc==1 && !strcmp(argv[0],"/"))
argc=0;
if(supported_request("expand-modules"))
{
send_file_names(argc,argv,SEND_EXPAND_WILD);
client_module_expansion.clear();
send_to_server("expand-modules\n",0);
err = get_server_responses();
if(err)
return err;
args=client_module_expansion;
if(!args.size())
args.push_back(".");
}
send_arg("-N");
}
if(quiet)
send_arg("-q");
if(req && entries_format)
send_arg("-e");
if(long_format)
send_arg("-l");
if(recurse)
send_arg("-R");
if(prune)
send_arg("-P");
if(local_time)
{
char tmp[64];
send_arg("-T");
sprintf(tmp,"%d",local_time_offset);
option_with_arg("-o",tmp);
}
if(show_tag)
option_with_arg("-r",show_tag);
if(show_date)
option_with_arg("-D",show_date);
send_arg("--");
for (size_t i = 0; i < args.size(); ++i)
{
send_arg (args[i].c_str());
if(!req)
{
if(strcmp(args[i].c_str(),"."))
{
cvs::string tmp;
send_to_server("Directory ",0);
send_to_server(args[i].c_str(),0);
send_to_server("\n",0);
tmp = current_parsed_root->directory;
tmp+="/";
tmp+=args[i].c_str();
send_to_server(tmp.c_str(),0);
send_to_server("\n",0);
}
}
}
if(!req)
{
send_to_server("Directory .\n",0);
send_to_server(current_parsed_root->directory,0);
send_to_server("\n",0);
}
send_to_server (req?req:"co\n", 0);
if(!req)
{
if(entries_format)
global_ls_response_hack |= 2;
if(quiet)
global_ls_response_hack |= 4;
global_ls_response_hack |= 1;
}
err = get_responses_and_close ();
return err;
}
{
DBM *db;
int i;
db = open_module ();
if(argc)
{
for (i = 0; i < argc; i++)
{
char *mod = xstrdup(argv[i]);
char *p;
for(p=strchr(mod,'\\'); p; p=strchr(p,'\\'))
*p='/';
p = strrchr(mod,'/');
if(p && (strchr(p,'?') || strchr(p,'*')))
{
*p='\0';
regexp_match = p+1;
}
else
regexp_match = NULL;
/* Frontends like to do 'ls -q /', so we support it explicitly */
if(!strcmp(mod,"/"))
{
*mod='\0';
}
err += do_module (db, mod, MISC,
"Listing",
ls_proc, (char *) NULL, 0, 0, 0, 0, (char*)NULL);
xfree(mod);
}
}
else
{
err += do_module (db, ".", MISC,
"Listing",
ls_proc, (char *) NULL, 0, 0, 0, 0, (char*)NULL);
}
close_module (db);
}
return (err);
}
static int ls_proc (int argc, char **argv, const char *xwhere, const char *mwhere, const char *mfile, int shorten, int local, const char *mname, const char *msg)
{
/* Begin section which is identical to patch_proc--should this
be abstracted out somehow? */
char *myargv[2];
int err = 0;
int which;
char *repository, *mapped_repository;
char *where;
if(!quiet)
{
if(strcmp(mname,"."))
{
cvs_outerr("Listing module: ", 0);
cvs_outerr(mname, 0);
cvs_outerr("\n\n", 0);
}
else
cvs_outerr("Listing modules on server\n\n", 0);
}
repository = (char*)xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
+ (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
(void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
where = (char*)xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ 1);
(void) strcpy (where, argv[0]);
/* if mfile isn't null, we need to set up to do only part of the module */
if (mfile != NULL)
{
char *cp;
char *path;
/* if the portion of the module is a path, put the dir part on repos */
if ((cp = strrchr (mfile, '/')) != NULL)
{
*cp = '\0';
(void) strcat (repository, "/");
(void) strcat (repository, mfile);
(void) strcat (where, "/");
(void) strcat (where, mfile);
mfile = cp + 1;
}
/* take care of the rest */
path = (char*)xmalloc (strlen (repository) + strlen (mfile) + 5);
(void) sprintf (path, "%s/%s", repository, mfile);
if (isdir (path))
{
/* directory means repository gets the dir tacked on */
(void) strcpy (repository, path);
(void) strcat (where, "/");
(void) strcat (where, mfile);
}
else
{
myargv[0] = argv[0];
myargv[1] = (char*)mfile;
argc = 2;
argv = myargv;
}
xfree (path);
}
mapped_repository = map_repository(repository);
/* cd to the starting repository */
if ( CVS_CHDIR (mapped_repository) < 0)
{
error (0, errno, "cannot chdir to %s", fn_root(repository));
xfree (repository);
xfree (mapped_repository);
return (1);
}
xfree (repository);
xfree (mapped_repository);
/* End section which is identical to patch_proc. */
which = W_REPOS;
repository = NULL;
if (show_tag != NULL && !tag_validated)
{
tag_check_valid (show_tag, argc - 1, argv + 1, local, 0, repository);
tag_validated = 1;
}
err = start_recursion (ls_fileproc, (FILESDONEPROC) NULL,(PREDIRENTPROC) NULL,
ls_direntproc, (DIRLEAVEPROC) NULL, NULL,
argc - 1, argv + 1, local, which, 0, 1,
where, repository, 1, verify_read);
if(!strcmp(mname,"."))
{
DBM *db;
if ((db = open_module ())!=NULL)
{
datum key = dbm_firstkey(db);
if(key.dptr)
{
cvs_output("\n",1);
if(!quiet)
cvs_outerr("Virtual modules on server (CVSROOT/modules file)\n\n",0);
cat_module(0);
}
close_module(db);
}
}
return err;
}
/*
* display the status of a file
*/
/* ARGSUSED */
static int
ls_fileproc(void *callerdat, struct file_info *finfo)
{
Vers_TS *vers;
char outdate[32],tag[64];
time_t t;
if(regexp_match && !regex_filename_match(regexp_match,finfo->file))
return 0;
vers = Version_TS (finfo, NULL, show_tag, show_date, 1, 0, 0);
if(!vers->vn_rcs)
{
freevers_ts(&vers);
return 0;
}
if(RCS_isdead(finfo->rcs, vers->vn_rcs))
{
freevers_ts(&vers);
return 0;
}
t=RCS_getrevtime (finfo->rcs, vers->vn_rcs, 0, 0);
if(local_time)
t+=local_time_offset;
strcpy(outdate,asctime(gmtime(&t)));
outdate[strlen(outdate)-1]='\0';
if(entries_format)
{
tag[0]='\0';
if(show_tag)
sprintf(tag,"T%s",show_tag);
printf("/%s/%s/%s/%s/%s\n",finfo->file,vers->vn_rcs,outdate,vers->options,tag);
}
else if(long_format)
{
printf("%-32.32s%-8.8s%s %s\n",finfo->file,vers->vn_rcs,outdate,vers->options);
}
else
printf("%s\n",finfo->file);
freevers_ts(&vers);
return 0;
}
Dtype ls_direntproc(void *callerdat, char *dir,
char *repos, char *update_dir,
List *entries, const char *virtual_repository, Dtype hint)
{
if(hint!=R_PROCESS)
return hint;
if(prune && (!entries || list_isempty(entries)))
return R_SKIP_ALL;
if(!strcasecmp(dir,"."))
return R_PROCESS;
if(recurse)
{
printf("\nDirectory %s\n\n",update_dir);
return R_PROCESS;
}
if(entries_format)
{
printf("D/%s////\n",dir);
}
else if(long_format)
{
printf("%-32.32s(directory)\n",dir);
}
else
printf("%s\n",dir);
return R_SKIP_ALL;
}
syntax highlighted by Code2HTML, v. 0.9.1