very old code commited, ymmv
This commit is contained in:
parent
4fa31cb790
commit
c653852ee2
60
CheckResolv/Makefile
Normal file
60
CheckResolv/Makefile
Normal file
@ -0,0 +1,60 @@
|
||||
#-------------------------------------------------------------------
|
||||
#
|
||||
# CheckResolv
|
||||
#
|
||||
# editable configuration variables:
|
||||
|
||||
DESTDIR = /usr/local
|
||||
COPT = -g -ansi -Wall
|
||||
|
||||
#
|
||||
# you can now compile with "make checkresolv" and install it
|
||||
# with "su -c 'make install'"
|
||||
#
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
VERSION=0.25
|
||||
|
||||
all:
|
||||
@echo
|
||||
@echo " may be you can read (and edit) the Makefile before"
|
||||
@echo " trying to compile and run that kludge..."
|
||||
@echo
|
||||
@echo " for impatients: try \"make checkresolv\""
|
||||
@echo
|
||||
|
||||
checkresolv.o: checkresolv.c Makefile fonctions.h
|
||||
gcc $(COPT) -c -DVERSION=\"$(VERSION)\" -DTRACE=0 $<
|
||||
|
||||
fonctions.o: fonctions.c Makefile fonctions.h
|
||||
gcc $(COPT) -c -DVERSION=\"$(VERSION)\" -DTRACE=0 $<
|
||||
|
||||
checkresolv: checkresolv.o fonctions.o
|
||||
gcc $(COPT) $^ -o $@
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#
|
||||
# install procedure is _also_ quick and dirty
|
||||
#
|
||||
install:
|
||||
install --strip checkresolv $(DESTDIR)/bin
|
||||
install checkresolv.man $(DESTDIR)/man/man1/checkresolv.1
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
FILES=*.c *.h Makefile CHANGELOG README TODO checkresolv.man *.html
|
||||
|
||||
TARNAME=checkresolv-$(VERSION).tar.gz
|
||||
|
||||
tarball: $(FILES)
|
||||
@echo "Tarball is" $(TARNAME)
|
||||
@ls $^ > MANIFEST ; \
|
||||
( cd .. ; \
|
||||
tar zcvf $(TARNAME) `sed 's/^/CheckResolv\//' CheckResolv/MANIFEST` )
|
||||
@date >> tarball
|
||||
@wc -c ../$(TARNAME)
|
||||
|
||||
lines: $(FILES)
|
||||
wc $(FILES) | sort -n
|
||||
|
||||
#-------------------------------------------------------------------
|
21
CheckResolv/README.md
Normal file
21
CheckResolv/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
```
|
||||
CheckResolv
|
||||
===========
|
||||
|
||||
This is a quick and dirty hack, built for chasing
|
||||
a LPRng latency problem. Usage is very simple:
|
||||
you give a hostname or an IP addr, and the soft
|
||||
try a few lookup and/or reverse lookup.
|
||||
|
||||
|
||||
Options are:
|
||||
-V display version
|
||||
-r do a reverse lookup
|
||||
-v increase verbosity
|
||||
-e print relateds env vars
|
||||
-t display time op operations
|
||||
|
||||
|
||||
Have a good life, don't release CO2 in the Ternet...
|
||||
|
||||
```
|
12
CheckResolv/TODO
Normal file
12
CheckResolv/TODO
Normal file
@ -0,0 +1,12 @@
|
||||
This is the TODO file for CheckResolv
|
||||
-------------------------------------
|
||||
|
||||
- virer les GNUismes du Makefile
|
||||
- check for potentials buffers overflows
|
||||
- write a really cut manpage
|
||||
|
||||
- add a function to analyze /etc/resolv.conf
|
||||
- add a function to check /etc/hosts
|
||||
|
||||
- build a fonction for detect DNS used by the resolver.
|
||||
|
238
CheckResolv/checkresolv.c
Normal file
238
CheckResolv/checkresolv.c
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* CheckResolv
|
||||
* ===========
|
||||
*
|
||||
* quick and dirty debugging hack.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#define __USE_BSD
|
||||
#include <string.h>
|
||||
/* #undef __USE_BSD */
|
||||
#include <sys/time.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#define __USE_MISC
|
||||
#include <netdb.h> /* herror ? */
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "fonctions.h"
|
||||
|
||||
char * strdup(char *); /* DIRTY HACK */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* quick and dirty global variables */
|
||||
|
||||
int verbose = 0;
|
||||
int do_reverse = 0;
|
||||
int do_environ = 0;
|
||||
int do_timing = 0;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* parameter '*txt' is not used */
|
||||
int print_hostent(struct hostent *ph, char *txt)
|
||||
{
|
||||
char *ptr, **pptr;
|
||||
|
||||
printf("h_name: %s\n", ph->h_name);
|
||||
|
||||
pptr = ph->h_aliases;
|
||||
if (verbose) {
|
||||
printf("h_aliases: %p -> %p\n", pptr, *pptr);
|
||||
}
|
||||
|
||||
while ( (ptr = *(pptr)) != NULL ) {
|
||||
printf(" alias: %s\n", ptr);
|
||||
pptr++;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("h_addrtype: %d\n", ph->h_addrtype);
|
||||
printf("h_length: %d\n", ph->h_length);
|
||||
}
|
||||
|
||||
print_ip((struct in_addr **)ph->h_addr_list); /* strange cast */
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* If we have a list of IP addr, we can try a
|
||||
* reverse lookup, no ?
|
||||
*/
|
||||
int check_reverse(struct hostent *ph)
|
||||
{
|
||||
struct in_addr **liste;
|
||||
struct in_addr *addr;
|
||||
struct in_addr l_addr; /* Jules */
|
||||
struct hostent *revph;
|
||||
int nbre;
|
||||
double t1 , t2;
|
||||
char *ptmp;
|
||||
|
||||
if (do_timing) t1 = chronometre();
|
||||
|
||||
nbre = 0;
|
||||
liste = (struct in_addr **)ph->h_addr_list;
|
||||
|
||||
while (NULL != (addr = *liste++)) {
|
||||
l_addr = *addr; /* Jules */
|
||||
#if TRACE
|
||||
fprintf(stderr, "---> %p %p\n", addr, l_addr);
|
||||
#endif
|
||||
revph = gethostbyaddr(&l_addr, ph->h_length, ph->h_addrtype);
|
||||
if (NULL != revph) {
|
||||
/* taking over hidden string vars */
|
||||
ptmp = strdup(inet_ntoa(l_addr));
|
||||
if (NULL == ptmp) {
|
||||
fprintf(stderr, "no memory in %s, line %d\n",
|
||||
__FILE__, __LINE__);
|
||||
abort();
|
||||
}
|
||||
#if TRACE
|
||||
fprintf(stderr, "%s:%d %p %p\n", __func__, __LINE__,
|
||||
ptmp, revph->h_name);
|
||||
#endif
|
||||
printf("reverse %-16s -> %s\n", ptmp, revph->h_name);
|
||||
free(ptmp);
|
||||
}
|
||||
else {
|
||||
/* fprintf(stderr, "reverse ? wtf ?\n"); */
|
||||
herror("reverse lookup"); /* this func is obsolete ! */
|
||||
}
|
||||
nbre++;
|
||||
}
|
||||
|
||||
if (do_timing) {
|
||||
t2 = chronometre();
|
||||
if (nbre > 1)
|
||||
printf("reverse take %.3f s (%.3f s)\n", t2-t1, (t2-t1)/nbre);
|
||||
else
|
||||
printf("reverse take %.3f s.\n", t2-t1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
struct hostent *direct_lookup(char *hostname)
|
||||
{
|
||||
struct hostent *p_host;
|
||||
double t1 , t2;
|
||||
int foo;
|
||||
|
||||
if (do_timing) t1 = chronometre();
|
||||
p_host = gethostbyname(hostname);
|
||||
if (do_timing) t2 = chronometre();
|
||||
|
||||
if (p_host==NULL)
|
||||
{
|
||||
fprintf(stderr, "error %d on '%s'", h_errno, hostname);
|
||||
herror(" ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
foo = print_hostent(p_host, NULL);
|
||||
|
||||
if (do_timing) printf("gethostbyname take %.3f s.\n", t2 - t1);
|
||||
|
||||
return p_host;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
int analyse(char *nom, int flag)
|
||||
{
|
||||
struct hostent *p_host;
|
||||
|
||||
p_host = direct_lookup(nom);
|
||||
|
||||
/*
|
||||
* new, 31 jan 2005, v 0.19
|
||||
* if the requested 'hostname' seems to be an ip address, can we
|
||||
* force a valid reverse lookup ?
|
||||
*/
|
||||
if (is_IP_addr(nom) && !do_reverse)
|
||||
{
|
||||
fprintf(stderr, "* if %s is a valid ip addr, try the '-r' switch.\n",
|
||||
nom);
|
||||
}
|
||||
|
||||
if (do_reverse && (p_host!=NULL))
|
||||
check_reverse(p_host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* Set some global flags, based on our environment
|
||||
* variable.
|
||||
*/
|
||||
void analyze_environ(void)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr = getenv("CHECKRESOLV");
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
if ( ! strcmp("tech", ptr) ) {
|
||||
do_reverse = 1;
|
||||
do_timing = 1;
|
||||
}
|
||||
if ( ! strcmp("all", ptr) ) {
|
||||
do_reverse = 1;
|
||||
do_timing = 1;
|
||||
verbose = 1;
|
||||
do_environ = 1;
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int foo;
|
||||
|
||||
char * liste_opt = "vrhteV";
|
||||
int option;
|
||||
|
||||
if (argc == 1) help_options();
|
||||
|
||||
while ((option=getopt(argc, argv, liste_opt)) != -1)
|
||||
{
|
||||
switch(option)
|
||||
{
|
||||
case 'v': verbose++; break;
|
||||
case 'r': do_reverse=1; break;
|
||||
case 'e': do_environ=1; break;
|
||||
case 't': do_timing=1; break;
|
||||
case 'h': usage(); break;
|
||||
case 'V': version(); break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "argc %d optind %d\n", argc, optind);
|
||||
for (foo=optind; foo<argc; foo++)
|
||||
{
|
||||
fprintf(stderr, " %4d %s\n", foo, argv[foo]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* env vars can override command line options.
|
||||
*/
|
||||
analyze_environ();
|
||||
|
||||
for (foo=optind; foo<argc; foo++)
|
||||
{
|
||||
printf("------------( %s \n", argv[foo]);
|
||||
analyse(argv[foo], 0);
|
||||
}
|
||||
|
||||
if (do_environ) print_envvars(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
44
CheckResolv/checkresolv.html
Normal file
44
CheckResolv/checkresolv.html
Normal file
@ -0,0 +1,44 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>CheckResolv</title>
|
||||
<meta name="keywords" content="resolver, BIND, DNS, resolv.conf">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>CheckResolv</h1>
|
||||
|
||||
<p>
|
||||
This is a <i>quick'n'dirty</i> tool for checking the configuration
|
||||
of your local resolver and/or DNS configuration. See the
|
||||
included manpage and source code for more explanations.
|
||||
</p>
|
||||
|
||||
<h2>options</h2>
|
||||
|
||||
<dl> <dt>-V <dd>display version number and exit.
|
||||
<dt>-h <dd>brief help on the command-line options.
|
||||
<dt>-v <dd>display various useless messages.
|
||||
<dt>-r <dd>do reverse lookup on IP address discovered.
|
||||
<dt>-e <dd>show content of a few environment var resolver-related.
|
||||
<dt>-t <dd>compute elapsed time of operation, not really accurate.
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
This software use only basic functions like <i>gethostbyname(3)</i>
|
||||
or <i>gethostbyaddr(3)</i>. Checkresolv use the more low-level
|
||||
of the resolver galaxy, so it works like any "lambda"
|
||||
application. Really nice when you have to catch a mysterious
|
||||
failure in a <small>LAMBDA</small> software.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The environmemt variable <tt>CHECKRESOLV</tt> control the verbosity.
|
||||
A value of <tt>tech</tt> add the display of reverse lookup and timings.
|
||||
And setting to <tt>all</tt> give you all the bells'n'whistles needed
|
||||
by geeks.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
80
CheckResolv/checkresolv.man
Normal file
80
CheckResolv/checkresolv.man
Normal file
@ -0,0 +1,80 @@
|
||||
.TH CheckResolv 1 "2005 September" "various OS" "Tonton Th"
|
||||
|
||||
.SH NAME
|
||||
checkresolv \- quick & dirty tool for checking sanity of resolver.
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBcheckresolv\fP -V
|
||||
.br
|
||||
\fBcheckresolv\fP [options] host.name
|
||||
.br
|
||||
\fBcheckresolv\fP [options] 42.51.69.406
|
||||
|
||||
.SH DESCRIPTION
|
||||
CheckResolv is a (not so) q'n'd tool for checking basic capacities and
|
||||
potentials bugs of your resolver configuration.
|
||||
I have started the dev of this thing when I was working hard on a remote
|
||||
nasty printing problems.
|
||||
It use only \fBgethostbyname\fP and \fBgethostbyaddr\fP functions,
|
||||
like any lambda applications.
|
||||
CheckResolv can also display environment variables who can modify the behaviour
|
||||
of this damned resolver, or give you some problems.
|
||||
|
||||
.SH OPTIONS
|
||||
.B -V
|
||||
display version number and exit.
|
||||
.br
|
||||
.B -h
|
||||
brief help on the command-line options.
|
||||
.br
|
||||
.B -v
|
||||
display various useless messages.
|
||||
.br
|
||||
.B -r
|
||||
do reverse lookup on IP address discovered.
|
||||
.br
|
||||
.B -e
|
||||
show content of a few environment vars resolver-related.
|
||||
.br
|
||||
.B -t
|
||||
compute elapsed time of operation, not really accurate.
|
||||
|
||||
.SH TIPS
|
||||
If you have a strange problem between two hosts, "don't panic". Take the time
|
||||
to compil CheckResolv on the two hosts, and run it with the -r option, first
|
||||
with the hostname, and after that, with the IP address.
|
||||
And do this two runs on the two hosts. So, you get four results.
|
||||
Now, use your brain...
|
||||
|
||||
.SH CONFIG FILE
|
||||
All your config files are belong to us. In the futur, may be you can
|
||||
put a list of env vars to display in a file.
|
||||
|
||||
.SH ENV VARS
|
||||
If the environment variable CHECKRESOLV is set to "tech", reverse lookup
|
||||
and timing are activated, very nice when your pop3 server take 42 seconds
|
||||
before you can get some silly answer.
|
||||
And "all" give you all the bells & whistles.
|
||||
This variable override command lines options.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR resolver (5),
|
||||
.BR host (1),
|
||||
.BR dig (1),
|
||||
.BR nslookup (1)
|
||||
|
||||
.SH BUGS
|
||||
Some are here, some are waiting in the dark. Hidden static storage is a pain.
|
||||
No IPv6 support. No Slackware package, no Debian package...
|
||||
|
||||
.SH COMPILATION
|
||||
Currently (2005 march), this software was only tested on Slackware 10.0 and
|
||||
Debian Sarge, but it can
|
||||
compile 'fine' on others Linux or *BSD flavors. IRIX is also a valuable target,
|
||||
because my troll-master use it...
|
||||
|
||||
.SH AUTHOR(S)
|
||||
Thierry (aka tth) Boudet, with help from @donis, Miod, Reynerie...
|
||||
|
||||
|
||||
|
167
CheckResolv/fonctions.c
Normal file
167
CheckResolv/fonctions.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* CheckResolv
|
||||
* ===========
|
||||
* quick and dirty debugging hack.
|
||||
*
|
||||
* a bunch of various undocumented functions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "fonctions.h"
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* return !0 if str seems to be a quadnumber ip address.
|
||||
*/
|
||||
int is_IP_addr(char *str)
|
||||
{
|
||||
int nbrdots, length, foo, flag;
|
||||
/* int o[4]; */
|
||||
|
||||
length = strlen(str);
|
||||
flag = nbrdots = 0;
|
||||
for (foo=0; foo<length; foo++)
|
||||
{
|
||||
if (str[foo]=='.') nbrdots++;
|
||||
else if ( ! isdigit(str[foo]) )
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nbrdots==3;
|
||||
}
|
||||
/*
|
||||
* warning, this func is a kludge.
|
||||
*/
|
||||
/* ------------------------------------------------------------ */
|
||||
double chronometre(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
int foo;
|
||||
double ftemps;
|
||||
|
||||
foo = gettimeofday(&tv, NULL);
|
||||
if (foo) perror("get time of day");
|
||||
|
||||
ftemps = (double)tv.tv_sec + ((double)tv.tv_usec/1e6);
|
||||
return ftemps;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
int print_ip(struct in_addr **liste)
|
||||
{
|
||||
struct in_addr *addr;
|
||||
|
||||
if (liste==NULL)
|
||||
{
|
||||
fprintf(stderr, "print addrip (%s:%d): liste is NULL\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(5);
|
||||
}
|
||||
|
||||
while ((addr = *liste++)!=NULL)
|
||||
{
|
||||
printf("ip: %s", inet_ntoa(*addr));
|
||||
/*
|
||||
* mmmm, must resolve globals vars...
|
||||
if (verbose)
|
||||
printf(" %8x", *addr);
|
||||
*/
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
static void print_onevar(char *name)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if ((ptr=getenv(name)) == NULL)
|
||||
printf("%-29s is not defined\n", name);
|
||||
else
|
||||
printf("%-27s = '%s'\n", name, ptr);
|
||||
}
|
||||
|
||||
struct envvars
|
||||
{
|
||||
char *name;
|
||||
char *comment;
|
||||
} envvars[] =
|
||||
{
|
||||
{ "HOSTNAME", NULL },
|
||||
{ "HOSTALIASES", NULL },
|
||||
{ "http_proxy", NULL },
|
||||
{ "ftp_proxy", NULL },
|
||||
{ "PRINTER", NULL },
|
||||
{ "RESOLV_HOST_CONF", NULL },
|
||||
{ "RESOLV_SERV_ORDER", NULL },
|
||||
{ "RESOLV_SPOOF_CHECK", NULL },
|
||||
{ "RESOLV_MULTI", NULL },
|
||||
{ "RESOLV_REORDER", NULL },
|
||||
{ "CHECKRESOLV", NULL },
|
||||
{ "TONTON_TH", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* by the way, if you know another interesting env vars in
|
||||
* the resolver context...
|
||||
*/
|
||||
|
||||
int print_envvars(int flags)
|
||||
{
|
||||
struct envvars *pev;
|
||||
|
||||
puts("");
|
||||
pev = envvars;
|
||||
while (pev->name != NULL)
|
||||
{
|
||||
print_onevar(pev->name);
|
||||
pev++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
void help_options(void)
|
||||
{
|
||||
fputs("checkresolv [-v] [-r] [-e] [-t] hostname|ipaddr\n", stderr);
|
||||
fputs("checkresolv -h : more help\n", stderr);
|
||||
fputs("checkresolv -V : print version\n", stderr);
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "*** CheckResolv v %s *** by tth ***\n", VERSION);
|
||||
fputs("Usage:\n", stderr);
|
||||
fputs("\tcheckresolv [options] hostname | @ip\n", stderr);
|
||||
fputs("\n", stderr);
|
||||
fputs("options:\n", stderr);
|
||||
fputs("\t-V: display version number\n", stderr);
|
||||
fputs("\t-v: increase verbosity\n", stderr);
|
||||
fputs("\t-r: try a reverse lookup\n", stderr);
|
||||
fputs("\t-e: print some env vars\n", stderr);
|
||||
fputs("\t-t: print elapsed time\n", stderr);
|
||||
fputs("\n", stderr);
|
||||
fputs("environmemt variable:\n", stderr);
|
||||
fputs("\tname: CHECKRESOLV\n", stderr);
|
||||
fputs("\tvalue: \"tech\" reverse-lookup and timing\n", stderr);
|
||||
fputs("\tvalue: \"all\" all the bells & whistles\n", stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(0);
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
void version(void)
|
||||
{
|
||||
printf("CheckResolv v %s by tth\n", VERSION);
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
17
CheckResolv/fonctions.h
Normal file
17
CheckResolv/fonctions.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* CheckResolv
|
||||
* ===========
|
||||
* quick and dirty debugging hack.
|
||||
*
|
||||
*/
|
||||
|
||||
int is_IP_addr(char *str);
|
||||
double chronometre(void);
|
||||
|
||||
int print_ip(struct in_addr **liste);
|
||||
|
||||
void help_options(void);
|
||||
void usage(void);
|
||||
void version(void);
|
||||
|
||||
int print_envvars(int flag);
|
1
DumpGDBM/.gitignore
vendored
Normal file
1
DumpGDBM/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
MANIFEST
|
91
DumpGDBM/Makefile
Normal file
91
DumpGDBM/Makefile
Normal file
@ -0,0 +1,91 @@
|
||||
# ----------------------------------------------------
|
||||
# this is the Makefile for the 'dumpgdbm' utility
|
||||
# ----------------------------------------------------
|
||||
#
|
||||
# Pour plus d'information, le mieux, c'est de m'ecrire
|
||||
# <oulala@chez.com> ou de me faire parvenir une caisse
|
||||
# de vin australien. Ou chilien, ils font du bon vin
|
||||
# au Chili: du Cabernet-Sauvignon de premiere bourre.
|
||||
#
|
||||
# ----------------------------------------------------
|
||||
#
|
||||
|
||||
OU_LE_METTRE = /usr/local
|
||||
|
||||
#
|
||||
# Positionner TRACE a 42 pour avoir un binaire
|
||||
# qui raconte sa vie, son oeuvre, ses trolls...
|
||||
#
|
||||
# you can safely remove the -g (debug) options.
|
||||
#
|
||||
|
||||
TRACE = 0
|
||||
C_OPT = -Wall -DTRACE=$(TRACE)
|
||||
|
||||
# ----------------------------------------------------
|
||||
|
||||
all: dumpgdbm cleargdbm
|
||||
|
||||
dump_funcs.o: dump_funcs.c dumpgdbm.h Makefile
|
||||
cc $(C_OPT) -c dump_funcs.c
|
||||
|
||||
dumpgdbm.o: dumpgdbm.c dumpgdbm.h Makefile
|
||||
cc $(C_OPT) -c dumpgdbm.c
|
||||
|
||||
dumpgdbm: dumpgdbm.o dump_funcs.o Makefile
|
||||
cc $(C_OPT) dumpgdbm.o dump_funcs.o -lgdbm -lreadline -ltermcap -o dumpgdbm
|
||||
|
||||
exemple.gdbm: exemple.pl Makefile
|
||||
-rm exemple.gdbm
|
||||
perl ./exemple.pl
|
||||
|
||||
cleargdbm: cleargdbm.c Makefile
|
||||
cc $(C_OPT) cleargdbm.c -lgdbm -o cleargdbm
|
||||
|
||||
love:
|
||||
@echo "--------- No War --------"
|
||||
@echo "install -> " $(OU_LE_METTRE)/
|
||||
@echo "trace -> " $(TRACE)
|
||||
|
||||
#
|
||||
# Bon, OK, ma methode d'installation est rudimentaire,
|
||||
# mais fallait lire la doc avant, si votre systeme est
|
||||
# tout detruit, c'est pas de ma faute. Ymmv.
|
||||
#
|
||||
|
||||
install:
|
||||
cp dumpgdbm dumpgdbm.install
|
||||
strip dumpgdbm.install
|
||||
cp dumpgdbm.install $(OU_LE_METTRE)/bin/dumpgdbm
|
||||
rm dumpgdbm.install
|
||||
cp dumpgdbm.1 $(OU_LE_METTRE)/man/man1/dumpgdbm.1
|
||||
cp cleargdbm.1 $(OU_LE_METTRE)/man/man1/cleargdbm.1
|
||||
@echo
|
||||
@echo "configuration modified, you have to reboot now."
|
||||
@echo " [YES] [NO] [MAY BE] [DON'T KNOW]"
|
||||
@echo
|
||||
@sleep 1
|
||||
@echo "arf, arf, trop drole, on s'y croirait..."
|
||||
@echo
|
||||
|
||||
#
|
||||
# Rah, mais qu'est ce qu'est Gruiik, ce truc !
|
||||
#
|
||||
|
||||
tarball: dumpgdbm.c dumpgdbm.1 Makefile README TODO MANIFEST BUGS \
|
||||
cleargdbm.c cleargdbm.1 INSTALL dump_funcs.c \
|
||||
dumpgdbm.h exemple.pl
|
||||
( cd .. ; \
|
||||
tar zcvf dumpgdbm.tar.gz `sed 's/^/DumpGDBM\//' DumpGDBM/MANIFEST` )
|
||||
date >> tarball
|
||||
|
||||
|
||||
#
|
||||
# merci de votre attention.
|
||||
#
|
||||
# http://la.buvette.org/ego/
|
||||
# http://krabulator.free.fr/devel/
|
||||
#
|
||||
#
|
||||
#-- end of Makefile --
|
||||
|
2
DumpGDBM/README.md
Normal file
2
DumpGDBM/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# DumpGDBM
|
||||
|
BIN
DumpGDBM/cleargdbm
Executable file
BIN
DumpGDBM/cleargdbm
Executable file
Binary file not shown.
59
DumpGDBM/cleargdbm.1
Normal file
59
DumpGDBM/cleargdbm.1
Normal file
@ -0,0 +1,59 @@
|
||||
.TH ClearGDBM 1 "Juillet 2002" "GNU/Linux" "tontonTh tools"
|
||||
|
||||
.SH NAME
|
||||
cleargdbm \- Videur de fichiers GDBM
|
||||
|
||||
.SH SYNOPSYS
|
||||
\fBcleargdbm\fP -V
|
||||
.br
|
||||
\fBcleargdbm\fP -h|-?
|
||||
.br
|
||||
\fBcleargdbm\fP [-v] fichier.gdbm
|
||||
|
||||
.SH DESCRIPTION
|
||||
Les fichiers GDBM permettent de stocker des 'tables associatives'
|
||||
sur mémoire permanente. La rapidité de lecture de ces tables est
|
||||
impressionante. Je les utilise parfois comme cache de bases de
|
||||
données dans des applications Web.
|
||||
.br
|
||||
|
||||
\fBcleargdbm\fP permet de 'vider' une table gdbm, en fait de l'effacer
|
||||
physiquement du disque, puis de la re-créer sans rien y mettre dedans.
|
||||
Accessoirement, on peut aussi mesurer la vitesse d'utilisation, de
|
||||
manière totalement arbitraire (à la BogoMIPS, en fait).
|
||||
.br
|
||||
|
||||
Le programme tente de préserver certaines caractéristiques du fichier
|
||||
destroyé: les droits d'accès uniquement à l'heure actuelle.
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
.B -V
|
||||
pour connaitre la version du machin-bidule.
|
||||
.br
|
||||
.B -v
|
||||
pour avoir du bavardage (fmbl roulaize) sur ce que fait ce kludge.
|
||||
.br
|
||||
.B -h -?
|
||||
Ah, il y a un peu de l'aide. On va en avoir besoin.
|
||||
.br
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR gdbm (3)
|
||||
.BR GDBM_File (3pm)
|
||||
.BR dumpgdbm (1)
|
||||
|
||||
.SH BUGS
|
||||
Il y en a probablement quelques uns qui trainent...
|
||||
Au lieu de raler, il faut signaler les problêmes à l'auteur.
|
||||
Toutes les idées d'amélioration sont les bienvenues.
|
||||
De bonnes bouteilles aussi.
|
||||
Bières anglo/saxonnes (Guinness roulaize) ou vins languedociens.
|
||||
|
||||
.SH AUTHOR
|
||||
Thierry Boudet (oulala@chez.com) depuis Juillet 1999.
|
||||
Pour en savoir plus: http://krabulator.free.fr/devel/ ou La.Buvette.Org.
|
||||
|
||||
.SH DEDICACE
|
||||
Ce logiciel est dédié à Florence D. qui est le soleil de ma vie.
|
||||
|
167
DumpGDBM/cleargdbm.c
Normal file
167
DumpGDBM/cleargdbm.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
cleargdbm.c
|
||||
===========
|
||||
|
||||
very old homepage = http://krabulator.free.fr/devel/
|
||||
|
||||
=====================================================
|
||||
WARNING! this program is _not_ secure! don't use it
|
||||
with a setuid root setting.
|
||||
=====================================================
|
||||
|
||||
(g) 2003 Thierry Boudet - aka TontonTh
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <gdbm.h>
|
||||
|
||||
#define VERSION "0.0.12"
|
||||
|
||||
#define MAX_FILENAME_LENGTH 4242 // 63 bytes for a filename is enough
|
||||
// for all. -imaginary BG-
|
||||
|
||||
char filename[MAX_FILENAME_LENGTH+2];
|
||||
int verbosity = 0;
|
||||
int block_size = 512;
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static void
|
||||
print_version(int totale)
|
||||
{
|
||||
printf ("\n");
|
||||
printf ("*** ClearGDBM version %s (g) 2003 TontonTh Useless Soft.\n", VERSION);
|
||||
printf ("\n");
|
||||
if (totale)
|
||||
{
|
||||
printf (" file " __FILE__ " compiled " __DATE__ " at " __TIME__ "\n");
|
||||
printf (" %s\n", gdbm_version);
|
||||
printf ("\n");
|
||||
}
|
||||
#if TRACE
|
||||
printf (" WARNING: compiled with TRACE option. May be _bogus_ !\n\n");
|
||||
#endif
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
static void
|
||||
help(void)
|
||||
{
|
||||
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int
|
||||
clear_gdbm(char *name, int flag)
|
||||
{
|
||||
int foo;
|
||||
GDBM_FILE file;
|
||||
struct stat infos;
|
||||
int mode;
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "TRACE: try to clear gdbm file '%s', flag=%d\n", name, flag);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* on va vérifier si c'est bien un fichier GDBM qu'on va niquer, là.
|
||||
*/
|
||||
file = gdbm_open(name, 512, GDBM_READER, 0444, NULL);
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Hu, Ho, '%s' is not a GDBM file, err: %s\n",
|
||||
name, gdbm_strerror(gdbm_errno));
|
||||
exit(1);
|
||||
}
|
||||
gdbm_close(file);
|
||||
|
||||
/*
|
||||
* nous allons récuperer quelques infos sur le fichier à n*q**r.
|
||||
*/
|
||||
foo = stat(name, &infos);
|
||||
#if TRACE
|
||||
fprintf(stderr, "TRACE: retour stat = %d\n", foo);
|
||||
#endif
|
||||
mode = infos.st_mode & 0777;
|
||||
fprintf(stderr, "protection = 0%03o\n", mode);
|
||||
|
||||
/*
|
||||
* bon, maintenant, on y va --force
|
||||
*/
|
||||
foo = unlink(name);
|
||||
if (foo)
|
||||
{
|
||||
perror ("unlink file");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
file = gdbm_open(name, 512, GDBM_WRCREAT, mode, NULL);
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Ho, désolé, pas pu créer %s (%s)\n",
|
||||
name, gdbm_strerror(gdbm_errno));
|
||||
exit(1);
|
||||
}
|
||||
gdbm_close(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
/*
|
||||
* let's go for the destroy :)
|
||||
*/
|
||||
|
||||
static char *optstring = "Vvhb:?";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int option_retour;
|
||||
int foo;
|
||||
char *nomfichier;
|
||||
|
||||
while ( (option_retour = getopt(argc, argv, optstring)) >= 0)
|
||||
{
|
||||
#if TRACE
|
||||
fprintf(stderr, "TRACE: getopt = %d, argc = %d, optind = %d\n",
|
||||
option_retour, argc, optind);
|
||||
#endif
|
||||
switch (option_retour)
|
||||
{
|
||||
case 'V':
|
||||
print_version(1);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
|
||||
case 'h': case '?':
|
||||
help();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "TRACE: fin traitement options argc=%d, optind=%d\n",
|
||||
argc, optind);
|
||||
fprintf(stderr, "TRACE: next arg %s\n", argv[argc-1]);
|
||||
#endif
|
||||
|
||||
nomfichier = argv[argc-1];
|
||||
|
||||
/*
|
||||
* WARNING!
|
||||
*
|
||||
* this programme is not secure. carefully read the sources
|
||||
* before use. you have be warned.
|
||||
*/
|
||||
|
||||
clear_gdbm(nomfichier, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
165
DumpGDBM/dump_funcs.c
Normal file
165
DumpGDBM/dump_funcs.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
various functions for dumpgdbm
|
||||
==============================
|
||||
|
||||
--------------------------------------------------------------------
|
||||
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
|
||||
--------------------------------------------------------------------
|
||||
|
||||
(g) 2003 Thierry Boudet - aka TontonTh
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gdbm.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
#include "dumpgdbm.h"
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
void
|
||||
print_version(int totale)
|
||||
{
|
||||
printf ("\n");
|
||||
printf ("*** DumpGDBM version %s (g) 2003 TontonTh Useless Soft.\n", VERSION);
|
||||
printf ("\n");
|
||||
if (totale)
|
||||
{
|
||||
printf (" more info -> http://krabulator.free.fr/devel/\n");
|
||||
printf (" this software is released under the 'Gnu Public License'\n");
|
||||
printf (" %s\n", gdbm_version);
|
||||
printf ("\n");
|
||||
}
|
||||
#if TRACE
|
||||
printf (" WARNING: compiled with TRACE option. May be _bogus_ !\n\n");
|
||||
#endif
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
void
|
||||
print_options(void)
|
||||
{
|
||||
printf ("command-line options:\n");
|
||||
printf ("\t-V\tprint version and infos.\n");
|
||||
printf ("\t-x\thexadecimal display.\n");
|
||||
printf ("\t-o\toctal display.\n");
|
||||
printf ("\t-a\tascii display.\n");
|
||||
printf ("\t-v\tbe verbose. more tchatche.\n");
|
||||
printf ("\t-w\twarn if key empty. [todo]\n");
|
||||
printf ("\t-W\tsilent search empty key. [todo]\n");
|
||||
printf ("\t-m 42\tset the qty of bytes displayed.\n");
|
||||
printf ("\t-8\tdisplay chars with ascii>127\n");
|
||||
printf ("\t-i\tstart in interactive mode\n");
|
||||
printf ("\n");
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
void init_global_vars(void)
|
||||
{
|
||||
verbosity = 0;
|
||||
maxoctets = 75;
|
||||
hexadecimal = 0;
|
||||
octal = 0;
|
||||
ok_for_8_bits = 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
hexadump(void *ptr, int count)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char *cptr;
|
||||
|
||||
cptr = (unsigned char *)ptr;
|
||||
if (count > maxoctets) count = maxoctets;
|
||||
|
||||
j = 0;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
printf(" %02x", cptr[i]);
|
||||
if (j++ > 22 && i!=(count-1))
|
||||
{
|
||||
printf("\n ");
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
octaldump(void *ptr, int count)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char *cptr;
|
||||
|
||||
cptr = (unsigned char *)ptr;
|
||||
if (count > maxoctets) count = maxoctets;
|
||||
|
||||
j = 0;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
printf(" %03o", cptr[i]);
|
||||
if (j++ > 16 && i!=(count-1))
|
||||
{
|
||||
printf("\n ");
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
asciidump(void *ptr, int count)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char *cptr;
|
||||
|
||||
cptr = (unsigned char *)ptr;
|
||||
if (count > maxoctets) count = maxoctets;
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "ok_for_8_bits %d\n", ok_for_8_bits);
|
||||
#endif
|
||||
|
||||
j = 0;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
if ( ok_for_8_bits )
|
||||
{
|
||||
if (isprint(cptr[i]) || cptr[i]>127)
|
||||
printf("%c", cptr[i]);
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isprint(cptr[i]))
|
||||
printf("%c", cptr[i]);
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
if (j++ > 70 && i!=(count-1))
|
||||
{
|
||||
printf("\n ");
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
BIN
DumpGDBM/dumpgdbm
Executable file
BIN
DumpGDBM/dumpgdbm
Executable file
Binary file not shown.
110
DumpGDBM/dumpgdbm.1
Normal file
110
DumpGDBM/dumpgdbm.1
Normal file
@ -0,0 +1,110 @@
|
||||
.TH DumpGDBM 1 "Fevrier 2003" "GNU/Linux" "Oulala tools"
|
||||
|
||||
.SH NAME
|
||||
dumpgdbm \- Dumpeur de fichiers GDBM
|
||||
|
||||
.SH SYNOPSYS
|
||||
\fBdumpgdbm\fP -V
|
||||
.br
|
||||
\fBdumpgdbm\fP -h
|
||||
.br
|
||||
\fBdumpgdbm\fP [-vxoa8] [-m 42] [-i] fichier.gdbm
|
||||
|
||||
.SH DESCRIPTION
|
||||
Les fichiers GDBM permettent de stocker des 'tables associatives'
|
||||
sur mémoire permanente. La rapidité de lecture de ces tables est
|
||||
impressionante. Mais leur utilisation est parfois surprenante.
|
||||
Par exemple, la présence ou non d'un '\\0' en fin de chaine...
|
||||
.br
|
||||
|
||||
\fBdumpgdbm\fP affiche en ascii, en octal, ou en hexadécimal les
|
||||
couples (clef/valeur) contenus dans un fichier GDBM.
|
||||
Il devrait contenir bientôt (ymmv) un mécanisme de détection des clefs nulles,
|
||||
réputées pour créer des problèmes dans des langages à typage faible,
|
||||
comme Perl ou PHP. Suggestions attendues...
|
||||
|
||||
.SH OPTIONS
|
||||
.B -V
|
||||
pour connaitre la version du machin-bidule.
|
||||
.br
|
||||
.B -x
|
||||
affichage des octets en hexadecimal.
|
||||
.br
|
||||
.B -o
|
||||
affichage en octal (pdp11 roulaize).
|
||||
.br
|
||||
.B -a
|
||||
affichage en ascii (voir aussi -8)
|
||||
.br
|
||||
.B -v
|
||||
pour avoir du bavardage (fmbl roulaize)
|
||||
.br
|
||||
.B -h
|
||||
ah, il y a un peu de l'aide.
|
||||
.br
|
||||
.B -8
|
||||
C'est OK pour afficher les caractères dont le code ascii > 128.
|
||||
.br
|
||||
.B -m 42
|
||||
détermine le nombre maximum d'octets affichés.
|
||||
.br
|
||||
.B -i
|
||||
démarrage en mode interactif.
|
||||
|
||||
Les options -x, -a et -o sont exclusives et c'est la dernière rencontrée
|
||||
sur la ligne de commande qui a la priorité.
|
||||
L'option -8 n'a de sens qu'en mode ascii.
|
||||
|
||||
.SH INTERACTIF
|
||||
Pour le mettre en oeuvre, c'est l'option
|
||||
.B -i
|
||||
au lancement, et ensuite, au prompt, un
|
||||
.B ?
|
||||
pour une liste abrégée des commandes. Puis taper:
|
||||
.B help command
|
||||
ou
|
||||
.B listcom
|
||||
pour en savoir un peu plus. Désolé, mais mon interpréteur de commandes n'est
|
||||
pas (encore) parfait. Il utilise readline, mais ne sauvegarde pas (encore)
|
||||
l'historique des commandes.
|
||||
|
||||
Les commandes de recherche,
|
||||
.B ds
|
||||
et
|
||||
.B ks
|
||||
, utilisent les expressions régulières POSIX.
|
||||
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR gdbm (3)
|
||||
.BR GDBM_File (3pm)
|
||||
.BR cleargdbm (1)
|
||||
.BR regex(3)
|
||||
|
||||
.SH BUGS
|
||||
Il y en a probablement quelques uns qui trainent...
|
||||
Par exemple, rien n'est encore prévu pour l'EBCDIC (Flo?).
|
||||
Mais bon, au lieu de raler, il faut signaler les problêmes à l'auteur.
|
||||
Toutes les idées d'amélioration sont les bienvenues.
|
||||
De bonnes bouteilles aussi.
|
||||
Bières anglo/saxonnes (Guinness roulaize) ou vins languedociens.
|
||||
|
||||
.SH SORRY
|
||||
I have to rewrite this man page in english, but my english is very poor.
|
||||
|
||||
.SH LICENSE
|
||||
Ce logiciel est distribué sous la bienveillante protection de la
|
||||
GNU GENERAL PUBLIC LICENSE, version 2. J'en profite pour remercier
|
||||
.B RMS
|
||||
sans qui rien de tout ça ne serait arrivé.
|
||||
|
||||
.SH AUTHOR
|
||||
Thierry Boudet (oulala@chez.com) depuis Juillet 1999.
|
||||
Pour en savoir plus: http://krabulator.free.fr/devel/ ou
|
||||
http://tboudet.free.fr/
|
||||
|
||||
.SH DEDICACE
|
||||
Euh, donc ce logiciel est dédié à Jennifer Mack, dont je suis un fervent
|
||||
admirateur depuis très longtemps. Merci également à Joshua, qui m'a fait
|
||||
découvrir que tout cela n'est qu'un jeu.
|
||||
|
808
DumpGDBM/dumpgdbm.c
Normal file
808
DumpGDBM/dumpgdbm.c
Normal file
@ -0,0 +1,808 @@
|
||||
/*
|
||||
dumpgdbm.c
|
||||
==========
|
||||
|
||||
Very old Homepage = http://tboudet.free.fr/dumpgdbm/
|
||||
|
||||
|
||||
(g) 2003 Thierry Boudet - aka TontonTh
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <gdbm.h>
|
||||
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
#define MAIN 1
|
||||
|
||||
#include "dumpgdbm.h"
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* global variables */
|
||||
|
||||
int warn_if_key_empty = 0;
|
||||
int found_an_empty_key = 0;
|
||||
int interactive = 0;
|
||||
int leading_zero = 1;
|
||||
|
||||
#define MAX_FILENAME_LENGTH 4242 /* 63 bytes for a filename is enough
|
||||
for all. -imaginary BG- */
|
||||
|
||||
char filename[MAX_FILENAME_LENGTH+2];
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static void
|
||||
dump_entry(datum key, datum data, int maxsize)
|
||||
{
|
||||
|
||||
#if TRACE
|
||||
printf("@,L: %p,%d %p,%d\n", key.dptr, key.dsize, data.dptr, data.dsize);
|
||||
#endif
|
||||
|
||||
printf("K: ");
|
||||
if (hexadecimal) hexadump(key.dptr, key.dsize);
|
||||
else if (octal) octaldump(key.dptr, key.dsize);
|
||||
else asciidump(key.dptr, key.dsize);
|
||||
|
||||
printf("D: ");
|
||||
if (hexadecimal) hexadump(data.dptr, data.dsize);
|
||||
else if (octal) octaldump(data.dptr, data.dsize);
|
||||
else asciidump(data.dptr, data.dsize);
|
||||
|
||||
free(data.dptr); /* XXX XXX */
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
/*
|
||||
* here we have the main loop for batches dumps.
|
||||
*/
|
||||
static int
|
||||
dump_gdbm_file(char *name)
|
||||
{
|
||||
GDBM_FILE file;
|
||||
datum entry, datas;
|
||||
|
||||
file = gdbm_open(name, 512, GDBM_READER, 0444, NULL);
|
||||
#if TRACE
|
||||
fprintf(stderr, "retour gdbm_open = %08lx\n", (unsigned long)file);
|
||||
#endif
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "can't open %s\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry = gdbm_firstkey(file);
|
||||
if (entry.dptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "database %s is empty\n", name);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
datas = gdbm_fetch(file, entry);
|
||||
if (entry.dsize == 0)
|
||||
{
|
||||
found_an_empty_key = 1;
|
||||
}
|
||||
dump_entry(entry, datas, maxoctets);
|
||||
/*
|
||||
* XXX may be we must free the data memory here ?
|
||||
*/
|
||||
entry = gdbm_nextkey(file, entry);
|
||||
} while ( entry.dptr != NULL);
|
||||
|
||||
gdbm_close(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
/*
|
||||
* Oct 17 2002: use of regular expressions.
|
||||
*/
|
||||
int search_key(GDBM_FILE gf, char * pattern)
|
||||
{
|
||||
datum entry, datas;
|
||||
char *bufptr, *cptr;
|
||||
int foo;
|
||||
regex_t reg;
|
||||
regmatch_t match[1];
|
||||
|
||||
if (pattern == NULL)
|
||||
{
|
||||
fprintf(stderr, "no pattern ??\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
foo = strlen(pattern);
|
||||
if (pattern[foo-1] == '\n')
|
||||
pattern[foo-1] = '\0';
|
||||
#if TRACE
|
||||
fprintf(stderr, "Search Key: cleaned pattern [%s]\n", pattern);
|
||||
#endif
|
||||
|
||||
foo = regcomp(®, pattern, REG_EXTENDED);
|
||||
#if TRACE
|
||||
printf("regcomp ---> %d\n", foo);
|
||||
#endif
|
||||
|
||||
entry = gdbm_firstkey(gf);
|
||||
if (entry.dptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "database is empty or bugged\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
bufptr = (char *)malloc(entry.dsize+2);
|
||||
if (bufptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "in Search Key: no memory, sorry\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
strncpy(bufptr, entry.dptr, entry.dsize);
|
||||
bufptr[entry.dsize] = '\0';
|
||||
#if TRACE
|
||||
fprintf(stderr, "Search Key: bufptr is [%s]\n", bufptr);
|
||||
#endif
|
||||
|
||||
foo = regexec(®, bufptr, 1, match, 0);
|
||||
if (foo==0)
|
||||
{
|
||||
datas = gdbm_fetch(gf, entry);
|
||||
dump_entry(entry, datas, maxoctets);
|
||||
}
|
||||
|
||||
free(bufptr); /* 26 Jul 2002 */
|
||||
|
||||
entry = gdbm_nextkey(gf, entry);
|
||||
|
||||
} while ( entry.dptr != NULL);
|
||||
|
||||
regfree(®);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
/*
|
||||
* Oct 16 2002: use of regular expressions.
|
||||
*/
|
||||
int search_data(GDBM_FILE gf, char * pattern)
|
||||
{
|
||||
datum entry, datas;
|
||||
char *bufptr;
|
||||
int foo;
|
||||
regex_t reg;
|
||||
regmatch_t match[1];
|
||||
|
||||
if (pattern == NULL)
|
||||
{
|
||||
fprintf(stderr, "no pattern ??\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
foo = strlen(pattern);
|
||||
if (pattern[foo-1] == '\n')
|
||||
pattern[foo-1] = '\0';
|
||||
#if TRACE
|
||||
fprintf(stderr, "\nSearch Data: cleaned pattern [%s]\n", pattern);
|
||||
#endif
|
||||
|
||||
foo = regcomp(®, pattern, REG_EXTENDED);
|
||||
#if TRACE
|
||||
printf("regcomp ---> %d\n", foo);
|
||||
#endif
|
||||
|
||||
entry = gdbm_firstkey(gf);
|
||||
if (entry.dptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "database is empty or bugged\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
datas = gdbm_fetch(gf, entry);
|
||||
|
||||
if (datas.dsize > 0)
|
||||
{
|
||||
bufptr = (char *)malloc(datas.dsize+2);
|
||||
if (bufptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "in Search Data: no memory, sorry\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
strncpy(bufptr, datas.dptr, datas.dsize);
|
||||
bufptr[datas.dsize] = '\0';
|
||||
#if TRACE
|
||||
// fprintf(stderr, "Search Data: bufptr [%s]\n", bufptr);
|
||||
#endif
|
||||
|
||||
foo = regexec(®, bufptr, 1, match, 0);
|
||||
if (foo==0)
|
||||
{
|
||||
dump_entry(entry, datas, maxoctets);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "data size is 0 ?\n");
|
||||
}
|
||||
entry = gdbm_nextkey(gf, entry);
|
||||
} while ( entry.dptr != NULL);
|
||||
|
||||
regfree(®);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define CMDLINE_LENGTH 80
|
||||
|
||||
#define CMD_QUIT 1
|
||||
#define CMD_HEX 2
|
||||
#define CMD_ASCII 3
|
||||
#define CMD_OCTAL 4
|
||||
#define CMD_FIRST 5
|
||||
#define CMD_NEXT 6
|
||||
#define CMD_SEVEN 7
|
||||
#define CMD_HEIGHT 8
|
||||
|
||||
#define CMD_PRINT 10
|
||||
#define CMD_KEYSEARCH 12
|
||||
#define CMD_DATASEARCH 13
|
||||
#define CMD_MAXOCT 14
|
||||
#define CMD_FMBL 15
|
||||
#define CMD_EMPTY 16
|
||||
|
||||
#define CMD_HELP 42
|
||||
#define CMD_LISTCOM 43
|
||||
#define CMD_VERSION 51
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *keyw;
|
||||
int code;
|
||||
} Commande;
|
||||
|
||||
Commande commandes[] =
|
||||
{
|
||||
{ "q", CMD_QUIT },
|
||||
{ "ZZ", CMD_QUIT },
|
||||
{ ":q", CMD_QUIT },
|
||||
{ ":q!", CMD_QUIT },
|
||||
{ "exit", CMD_QUIT },
|
||||
{ "quit", CMD_QUIT },
|
||||
{ "bye", CMD_QUIT },
|
||||
|
||||
{ "x", CMD_HEX },
|
||||
{ "hex", CMD_HEX },
|
||||
{ "hexa", CMD_HEX },
|
||||
|
||||
{ "a", CMD_ASCII },
|
||||
{ "ascii", CMD_ASCII },
|
||||
|
||||
{ "o", CMD_OCTAL },
|
||||
{ "octal", CMD_OCTAL },
|
||||
|
||||
{ "h", CMD_HELP },
|
||||
{ "help", CMD_HELP },
|
||||
{ "?", CMD_HELP },
|
||||
|
||||
{ "f", CMD_FIRST },
|
||||
{ "first", CMD_FIRST },
|
||||
|
||||
{ "m", CMD_MAXOCT },
|
||||
{ "maxoctets", CMD_MAXOCT },
|
||||
{ "maxbytes", CMD_MAXOCT },
|
||||
|
||||
{ "n", CMD_NEXT },
|
||||
{ "next", CMD_NEXT },
|
||||
|
||||
{ "p", CMD_PRINT },
|
||||
{ "print", CMD_PRINT },
|
||||
|
||||
{ "ks", CMD_KEYSEARCH },
|
||||
{ "keysearch", CMD_KEYSEARCH },
|
||||
|
||||
{ "ds", CMD_DATASEARCH },
|
||||
{ "datasearch", CMD_DATASEARCH },
|
||||
|
||||
{ "empty", CMD_EMPTY },
|
||||
|
||||
{ "7", CMD_SEVEN },
|
||||
{ "8", CMD_HEIGHT },
|
||||
|
||||
{ "V", CMD_VERSION },
|
||||
{ "version", CMD_VERSION },
|
||||
|
||||
{ "commands", CMD_LISTCOM },
|
||||
{ "listcom", CMD_LISTCOM },
|
||||
|
||||
{ "sux", 0 }
|
||||
};
|
||||
|
||||
#define NBRE_CMD (sizeof(commandes)/sizeof(Commande))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int number;
|
||||
char *text;
|
||||
} Help;
|
||||
|
||||
|
||||
char Help_version[] =
|
||||
"If you send me a bug report at <oulala@chez.com>, you must give me\n"
|
||||
" this information, with the output of 'uname -a' command.";
|
||||
char Help_maxoctet[] =
|
||||
"change the number of bytes displayed for key & data field.\n"
|
||||
" can be modified with the -m NN command line option.";
|
||||
char Help_print[] =
|
||||
"re-print the current record, so you can see it with different 'base':\n"
|
||||
" ascii, hexadecimal or octal. use '? [a|x|o]' for more info.";
|
||||
char Help_first[] =
|
||||
"JUMPTO the first record. you have to understand this. man gdbm.";
|
||||
char Help_next[] =
|
||||
"GOTO the next record. you have to understand this. 'man gdbm' is a must.";
|
||||
char Help_seven[] =
|
||||
"only true ASCII chars are printed. others are displayed as '.'";
|
||||
char Help_height[] =
|
||||
"display all chars. beware of differences in charset between Os !";
|
||||
char Help_KS[] = "Search a posix regex pattern in all the key fields.";
|
||||
char Help_DS[] = "POSIX extended regex search in all the data fields.";
|
||||
char No_Help_Text[] = "this help text need to be written...";
|
||||
|
||||
Help help[] =
|
||||
{
|
||||
{ 0, "just a joke for my friend tnemeth :)" },
|
||||
{ CMD_QUIT, "good bye, cruel world." },
|
||||
{ CMD_VERSION, Help_version },
|
||||
{ CMD_HEX, "switch to hexadecimal display." },
|
||||
{ CMD_OCTAL, "switch to octal display, you own a pdp11 ???" },
|
||||
{ CMD_ASCII, "switch to ascii display, see 7 & 8 commands." },
|
||||
{ CMD_MAXOCT, Help_maxoctet },
|
||||
{ CMD_PRINT, Help_print },
|
||||
{ CMD_FIRST, Help_first },
|
||||
{ CMD_NEXT, Help_next },
|
||||
{ CMD_SEVEN, Help_seven },
|
||||
{ CMD_HEIGHT, Help_height },
|
||||
|
||||
{ CMD_KEYSEARCH, Help_KS },
|
||||
{ CMD_DATASEARCH, Help_DS },
|
||||
|
||||
{ CMD_HELP, "sure, 42 is the ultimate answer !" }
|
||||
};
|
||||
|
||||
#define NBRE_HELP (sizeof(help)/sizeof(Help))
|
||||
|
||||
// -------------------------
|
||||
|
||||
static int
|
||||
lookup_cmd(char *cmd)
|
||||
{
|
||||
int foo;
|
||||
|
||||
/*
|
||||
* bon, la, c'est un hack un peu crade... mais je pense
|
||||
* que c'est qu'on rec,oit un parametre foireux...
|
||||
*/
|
||||
if ( cmd[strlen(cmd)-1] == '\n') cmd[strlen(cmd)-1] = '\0';
|
||||
|
||||
#if TRACE
|
||||
printf("lookup cmd [%s]\n", cmd);
|
||||
#endif
|
||||
|
||||
for (foo=0; foo<NBRE_CMD; foo++)
|
||||
{
|
||||
|
||||
#if TRACE
|
||||
// printf("try cmd #%d %s\n", foo, commandes[foo].keyw);
|
||||
#endif
|
||||
|
||||
if ( ! strcmp(commandes[foo].keyw, cmd) )
|
||||
return commandes[foo].code;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
static void
|
||||
help_cli(void)
|
||||
{
|
||||
int foo, bar;
|
||||
|
||||
printf("----------------( Help me Obi Wan ! )---------------\n");
|
||||
for (foo=bar=0; foo<NBRE_CMD; foo++)
|
||||
{
|
||||
bar += printf("%s ", commandes[foo].keyw);
|
||||
if (bar > 69) /* sex number ? */
|
||||
{
|
||||
bar = 0; puts("");
|
||||
}
|
||||
}
|
||||
printf("\n-----------( use '? command' for details )----------\n");
|
||||
}
|
||||
|
||||
static void
|
||||
full_help(char *keyword)
|
||||
{
|
||||
int num_keyword, foo;
|
||||
|
||||
num_keyword = lookup_cmd(keyword);
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "%s -> %d\n", keyword, num_keyword);
|
||||
#endif
|
||||
|
||||
if (num_keyword == -1)
|
||||
{
|
||||
printf("%s: no such command\n", keyword);
|
||||
return;
|
||||
}
|
||||
|
||||
for (foo=0; foo<NBRE_HELP; foo++)
|
||||
{
|
||||
#if TRACE
|
||||
fprintf(stderr, "%4d %4d %s\n", foo, help[foo].number, help[foo].text);
|
||||
#endif
|
||||
if (help[foo].number == num_keyword)
|
||||
{
|
||||
printf("\ncommand [%s]\n %s\n\n", keyword, help[foo].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int list_commands(int foo)
|
||||
{
|
||||
|
||||
puts("q ZZ exit : quit Dumpgdbm.");
|
||||
puts("x hex : hexadecimal display");
|
||||
puts("a ascii : ascii display");
|
||||
puts("o octal : octal display");
|
||||
// puts("h help | help");
|
||||
puts("f first : jump to first record");
|
||||
puts("n next : next record");
|
||||
puts("m maxbytes : set number of displayed bytes");
|
||||
puts("p print : redisplay the current record");
|
||||
puts("ks : key search");
|
||||
puts("ds | data search");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// Interpreteur de commandes
|
||||
// -------------------------
|
||||
static void
|
||||
shell(void)
|
||||
{
|
||||
char *cptr, *pline;
|
||||
int code_cmd, flag_exit, value;
|
||||
GDBM_FILE gdbm_file;
|
||||
datum entry, datas;
|
||||
int first_ok = 0;
|
||||
|
||||
flag_exit = 0; // on va pas s'arreter maintenant ?
|
||||
|
||||
printf("working on [%s]\n", filename);
|
||||
|
||||
gdbm_file = gdbm_open(filename, 512, GDBM_READER, 0444, NULL);
|
||||
if (gdbm_file == NULL)
|
||||
{
|
||||
fprintf(stderr, "can't open %s\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* init of readline behaviour
|
||||
*/
|
||||
rl_bind_key('\t', rl_insert); /* no filename completion, silly here :) */
|
||||
|
||||
do
|
||||
{
|
||||
pline = readline("dumpgdbm > ");
|
||||
if (pline == NULL)
|
||||
{
|
||||
printf("\nEOF ?\n");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* if the line is not empty, add it to the history
|
||||
*/
|
||||
if ( pline && *pline )
|
||||
add_history(pline);
|
||||
|
||||
#if TRACE
|
||||
printf("[%s]\n", pligne);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* search the first token on the line
|
||||
*/
|
||||
cptr = strtok(pline, " \t");
|
||||
#if TRACE
|
||||
fprintf(stderr, "pline %p cptr %p\n", pline, cptr);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* is there a text on this command-line ?
|
||||
*/
|
||||
if ( cptr==NULL || !strcmp("\n", cptr) ) continue;
|
||||
|
||||
#if TRACE
|
||||
printf("token = %s\n", cptr);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ok, la commande est pointee par cptr, on va tenter
|
||||
* de la comprendre...
|
||||
*/
|
||||
code_cmd = lookup_cmd(cptr);
|
||||
|
||||
switch (code_cmd)
|
||||
{
|
||||
case CMD_QUIT: flag_exit = 1; break;
|
||||
|
||||
case CMD_HEX:
|
||||
hexadecimal = 1;
|
||||
octal = 0;
|
||||
break;
|
||||
|
||||
case CMD_OCTAL:
|
||||
octal = 1;
|
||||
hexadecimal = 0;
|
||||
break;
|
||||
|
||||
case CMD_ASCII:
|
||||
octal = hexadecimal = 0;
|
||||
break;
|
||||
|
||||
case CMD_HELP:
|
||||
cptr = strtok(NULL, " \t");
|
||||
if (cptr == NULL || *cptr == '\0')
|
||||
help_cli();
|
||||
else
|
||||
full_help(cptr);
|
||||
break;
|
||||
|
||||
case CMD_VERSION: print_version(1); break;
|
||||
|
||||
case CMD_FIRST:
|
||||
entry = gdbm_firstkey(gdbm_file);
|
||||
if (entry.dptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "database is empty\n");
|
||||
break;
|
||||
}
|
||||
datas = gdbm_fetch(gdbm_file, entry);
|
||||
dump_entry(entry, datas, maxoctets);
|
||||
first_ok = 1;
|
||||
break;
|
||||
|
||||
case CMD_NEXT:
|
||||
if (first_ok)
|
||||
entry = gdbm_nextkey(gdbm_file, entry);
|
||||
else
|
||||
entry = gdbm_firstkey(gdbm_file);
|
||||
first_ok = 1;
|
||||
if (entry.dptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "end of database\n");
|
||||
break;
|
||||
}
|
||||
datas = gdbm_fetch(gdbm_file, entry);
|
||||
dump_entry(entry, datas, maxoctets);
|
||||
break;
|
||||
|
||||
case CMD_PRINT:
|
||||
if ( ! first_ok )
|
||||
entry = gdbm_firstkey(gdbm_file);
|
||||
first_ok = 42;
|
||||
if (entry.dptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "Print: no entry\n");
|
||||
break;
|
||||
}
|
||||
datas = gdbm_fetch(gdbm_file, entry);
|
||||
dump_entry(entry, datas, maxoctets);
|
||||
break;
|
||||
|
||||
case CMD_KEYSEARCH:
|
||||
cptr = strtok(NULL, " \t");
|
||||
if (cptr != NULL)
|
||||
{
|
||||
search_key(gdbm_file, cptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "keysearch need an argument\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_DATASEARCH:
|
||||
#if TRACE
|
||||
fprintf(stderr, "==== DATA SEARCH ====\n");
|
||||
#endif
|
||||
search_data(gdbm_file, strtok(NULL, " \t"));
|
||||
break;
|
||||
|
||||
case CMD_MAXOCT:
|
||||
|
||||
cptr = strtok(NULL, " \t");
|
||||
if (cptr != NULL)
|
||||
{
|
||||
#if TRACE
|
||||
fprintf(stderr, "MAXOCT: cptr %s\n", cptr);
|
||||
#endif
|
||||
if ( sscanf(cptr, "%d", &value) == 1 )
|
||||
{
|
||||
printf("maxoctets = %d\n", value);
|
||||
maxoctets = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "need a numeric argument\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case CMD_SEVEN:
|
||||
ok_for_8_bits = 0;
|
||||
break;
|
||||
|
||||
case CMD_HEIGHT:
|
||||
ok_for_8_bits = 1;
|
||||
break;
|
||||
|
||||
case CMD_LISTCOM:
|
||||
list_commands(0);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
fprintf(stderr, "\t\tChimera roulaize grave a donf\n");
|
||||
fprintf(stderr, "\t\tAthena widgets are so nice !!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "command %s : huho ?\n", cptr);
|
||||
break;
|
||||
}
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "freeing command line %p\n", pline);
|
||||
#endif
|
||||
free(pline);
|
||||
|
||||
} while ( ! flag_exit );
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static char *optstring = "VvxohwW8m:ia";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int option_retour;
|
||||
int foo;
|
||||
|
||||
init_global_vars();
|
||||
|
||||
while ( (option_retour = getopt(argc, argv, optstring)) >= 0)
|
||||
{
|
||||
#if TRACE
|
||||
fprintf(stderr, "getopt = %d, argc = %d, optind = %d\n",
|
||||
option_retour, argc, optind);
|
||||
#endif
|
||||
switch (option_retour)
|
||||
{
|
||||
case 'V':
|
||||
print_version(1);
|
||||
exit(1);
|
||||
break;
|
||||
case 'v':
|
||||
verbosity++;
|
||||
if (verbosity > 5)
|
||||
{
|
||||
fprintf(stderr, "Higher verbosity !\n");
|
||||
fprintf(stderr, "now dumping kernel...\n");
|
||||
sleep(5);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
hexadecimal = octal = 0;
|
||||
break;
|
||||
case 'x':
|
||||
hexadecimal = 1;
|
||||
octal = 0;
|
||||
break;
|
||||
case 'o':
|
||||
octal = 1;
|
||||
hexadecimal = 0;
|
||||
break;
|
||||
case 'h':
|
||||
print_version(0);
|
||||
print_options();
|
||||
exit(2);
|
||||
break;
|
||||
case 'w':
|
||||
warn_if_key_empty = 1;
|
||||
break;
|
||||
case '8':
|
||||
ok_for_8_bits = 1;
|
||||
break;
|
||||
case 'i':
|
||||
interactive = 1;
|
||||
break;
|
||||
case 'm':
|
||||
if (sscanf(optarg, "%d", &foo) == 1)
|
||||
{
|
||||
maxoctets = foo;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"opt 'm' need a numeric arg\n");
|
||||
exit(5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "fin traitement options argc=%d, optind=%d\n",
|
||||
argc, optind);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* a cet endroit il est probable qu'on puisse memoriser
|
||||
* le nom du fichier GDBM dans une variable globale.
|
||||
*/
|
||||
if (optind != argc)
|
||||
{
|
||||
strncpy(filename, argv[optind], MAX_FILENAME_LENGTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "WARNING: dumpgdbm: missing filename\n");
|
||||
print_options();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
shell();
|
||||
}
|
||||
else
|
||||
{
|
||||
dump_gdbm_file(argv[optind]);
|
||||
}
|
||||
|
||||
if (found_an_empty_key && warn_if_key_empty)
|
||||
{
|
||||
fprintf(stderr, "YO! A KEY IS EMPTY\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- the end ----- */
|
26
DumpGDBM/dumpgdbm.h
Normal file
26
DumpGDBM/dumpgdbm.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifdef MAIN
|
||||
#define EXTERN
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#define VERSION "0.2.27"
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* global variables */
|
||||
|
||||
EXTERN int verbosity;
|
||||
EXTERN int maxoctets;
|
||||
EXTERN int hexadecimal;
|
||||
EXTERN int octal;
|
||||
EXTERN int ok_for_8_bits;
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
void print_version(int);
|
||||
void print_options(void);
|
||||
void init_global_vars(void);
|
||||
|
||||
int hexadump(void *ptr, int count);
|
||||
int octaldump(void *ptr, int count);
|
||||
int asciidump(void *ptr, int count);
|
23
DumpGDBM/exemple.pl
Executable file
23
DumpGDBM/exemple.pl
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use GDBM_File;
|
||||
|
||||
my $nomdb = "exemple.gdbm";
|
||||
my (%DB, @champs);
|
||||
my ($user, $gecos);
|
||||
|
||||
open(SOURCE, "< /etc/passwd") or die "source $!";
|
||||
tie(%DB, "GDBM_File", $nomdb, GDBM_WRCREAT, 0666) or die "gdbm $!";
|
||||
|
||||
while (<SOURCE>)
|
||||
{
|
||||
@champs = split ":", $_;
|
||||
$user = $champs[0]."\0";
|
||||
$gecos = $champs[4]."\0";
|
||||
$DB{$user} = $gecos;
|
||||
}
|
||||
|
||||
untie %DB;
|
||||
close SOURCE;
|
||||
0;
|
3
Hexdiff/.gitignore
vendored
Normal file
3
Hexdiff/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
hexdiff
|
||||
|
71
Hexdiff/Makefile
Normal file
71
Hexdiff/Makefile
Normal file
@ -0,0 +1,71 @@
|
||||
#
|
||||
# VISUEL HEXDIFF
|
||||
# --------------
|
||||
#
|
||||
# old site : http://tboudet.free.fr/hexdiff/
|
||||
#
|
||||
|
||||
OU_LE_METTRE = /usr/local
|
||||
VERSION=0.0.50
|
||||
|
||||
TARNAME="hexdiff-$(VERSION).tar.gz"
|
||||
|
||||
all: hexdiff
|
||||
|
||||
#
|
||||
# if you define TRACE to a non zero value, you get a
|
||||
# lot of debugging trace on _stderr_
|
||||
#
|
||||
|
||||
COMP=gcc
|
||||
COPT=-g -DVERSION=\"$(VERSION)\" -DTRACE=0 -ansi
|
||||
LOPT=-lncurses
|
||||
|
||||
hexdiff.o: hexdiff.c Makefile hexdiff.h
|
||||
$(COMP) $(COPT) -Wall -O2 -c hexdiff.c
|
||||
|
||||
fonctions.o: fonctions.c Makefile hexdiff.h
|
||||
$(COMP) $(COPT) -Wall -O2 -c fonctions.c
|
||||
|
||||
parse_rc.o: parse_rc.c Makefile hexdiff.h
|
||||
$(COMP) $(COPT) -Wall -O2 -c parse_rc.c
|
||||
|
||||
fileinfo.o: fileinfo.c Makefile hexdiff.h
|
||||
$(COMP) $(COPT) -Wall -O2 -c fileinfo.c
|
||||
|
||||
sel_file.o: sel_file.c Makefile hexdiff.h
|
||||
$(COMP) $(COPT) -Wall -O2 -c sel_file.c
|
||||
|
||||
asciiview.o: asciiview.c Makefile hexdiff.h
|
||||
$(COMP) $(COPT) -Wall -O2 -c asciiview.c
|
||||
|
||||
OBJECTS=hexdiff.o fonctions.o fileinfo.o parse_rc.o sel_file.o \
|
||||
asciiview.o
|
||||
|
||||
hexdiff: Makefile $(OBJECTS)
|
||||
$(COMP) $(OBJECTS) -o $@ $(LOPT)
|
||||
|
||||
#
|
||||
# this install procedure is very crude.
|
||||
#
|
||||
install:
|
||||
cp hexdiff hexdiff.install
|
||||
strip hexdiff.install
|
||||
cp hexdiff.install $(OU_LE_METTRE)/bin/hexdiff
|
||||
rm hexdiff.install
|
||||
cp hexdiff.1 $(OU_LE_METTRE)/man/man1/hexdiff.1
|
||||
@echo "you can copy hexdiff.rc in your HOME as .hexdiffrc"
|
||||
|
||||
FILES=hexdiff.c hexdiff.1 Makefile README TODO BUGS fonctions.c CHANGES \
|
||||
hexdiff.h parse_rc.c hexdiff.rc fileinfo.c sel_file.c \
|
||||
asciiview.c memcheck.sh
|
||||
|
||||
tarball: $(FILES)
|
||||
@echo $(TARNAME)
|
||||
ls $^ > MANIFEST ; \
|
||||
( cd .. ; \
|
||||
tar zcvf $(TARNAME) `sed 's/^/HexDiff\//' HexDiff/MANIFEST` )
|
||||
date >> tarball
|
||||
|
||||
lines: $(FILES)
|
||||
wc $(FILES) | sort -n
|
19
Hexdiff/README.md
Normal file
19
Hexdiff/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Hexdiff
|
||||
|
||||
Un truc en ncurses pour voir les différences entre deux fichiers binaires.
|
||||
|
||||
```
|
||||
look at:
|
||||
- the Makefile
|
||||
- the man page
|
||||
- the source code
|
||||
|
||||
old website:
|
||||
http://tboudet.free.fr/hexdiff/
|
||||
|
||||
installation:
|
||||
1) run make
|
||||
2) patch
|
||||
3) goto 1
|
||||
|
||||
```
|
14
Hexdiff/TODO
Normal file
14
Hexdiff/TODO
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
add a '/' keystroke for searching a byte sequence in
|
||||
the current file.
|
||||
|
||||
drink a beer ? or, better, eat a Guinness ?
|
||||
|
||||
write a better english. write a better doc. write a
|
||||
better manpage. write a better code.
|
||||
|
||||
make a Slackware package. Mmmeee.
|
||||
|
||||
move the config file from $HOME/.hexdiffrc to
|
||||
$HOME/.tth/hexdiff.rc
|
||||
|
202
Hexdiff/asciiview.c
Normal file
202
Hexdiff/asciiview.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
+----------------+
|
||||
| Ascii View |
|
||||
+----------------+
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hexdiff.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static void av_sauve_contexte(void)
|
||||
{ /* code to be defined ? */ }
|
||||
/*----------------------------------------------------------------*/
|
||||
static void av_restaure_contexte(void)
|
||||
{ /* code to be defined ? */ }
|
||||
/*----------------------------------------------------------------*/
|
||||
static char * ascii_name(int code)
|
||||
{
|
||||
static char static_buffer[20];
|
||||
|
||||
/* XXX this big switch must be audited.... */
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case 0: return "NUL";
|
||||
case 1: return "SOH ^a";
|
||||
case 2: return "STX ^b";
|
||||
case 3: return "ETX ^c";
|
||||
case 4: return "EOT ^d";
|
||||
case 5: return "ENQ ^e";
|
||||
case 6: return "ACQ ^f";
|
||||
case 7: return "BEL ^g";
|
||||
case 8: return "BS ^h";
|
||||
case 9: return "HT ^i";
|
||||
case 10: return "LF ^j";
|
||||
case 11: return "VT ^k";
|
||||
case 12: return "FF ^l";
|
||||
case 13: return "CR ^m";
|
||||
case 14: return "SO ^n";
|
||||
case 15: return "SI ^o";
|
||||
case 16: return "DLE ^p";
|
||||
case 17: return "DC1 ^q";
|
||||
case 18: return "DC2 ^r";
|
||||
case 19: return "DC3 ^s";
|
||||
case 20: return "DC4 ^t";
|
||||
case 21: return "NAK ^u";
|
||||
case 22: return "SYN ^v";
|
||||
case 23: return "ETB ^w";
|
||||
case 24: return "CAN ^x";
|
||||
case 25: return "EM ^y";
|
||||
case 26: return "SUB ^z";
|
||||
case 27: return "ESC";
|
||||
case 28: return "FS ";
|
||||
case 29: return "GS ";
|
||||
case 30: return "RS ";
|
||||
case 31: return "US ";
|
||||
case 32: return "SPACE";
|
||||
case 127: return "DEL";
|
||||
}
|
||||
|
||||
if (code < 128)
|
||||
{
|
||||
sprintf(static_buffer, "'%c'", code);
|
||||
return static_buffer;
|
||||
}
|
||||
|
||||
/* may be for code > 127, we can put the "html" code &blabla; ? */
|
||||
|
||||
return "";
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
#define ASCV_I2LIG(idx) ((idx)>>6)
|
||||
#define ASCV_I2COL(idx) ((idx)&63)
|
||||
|
||||
static int av_affiche(Fichier *fic, WINDOW *pop, int clig, int ccol)
|
||||
{
|
||||
int foo, lig, col, car;
|
||||
char chaine[100];
|
||||
long depl;
|
||||
unsigned char octet;
|
||||
|
||||
wstandout(pop);
|
||||
for (foo=1; foo<65; foo++)
|
||||
mvwaddch(pop, 1, foo, ' ');
|
||||
mvwaddstr(pop, 1, 2, fic->nom);
|
||||
|
||||
depl = (clig*64)+ccol;
|
||||
octet = fic->buffer[depl];
|
||||
sprintf(chaine, "%7ld : %3d 0x%02x 0%03o",
|
||||
fic->offset+depl, octet, octet, octet);
|
||||
mvwaddstr(pop, 18, 1, chaine);
|
||||
mvwaddstr(pop, 18, 33, " ");
|
||||
mvwaddstr(pop, 18, 33, ascii_name(fic->buffer[depl]));
|
||||
wstandend(pop);
|
||||
|
||||
for (foo=0; foo<16*64; foo++)
|
||||
{
|
||||
lig = ASCV_I2LIG(foo);
|
||||
col = ASCV_I2COL(foo);
|
||||
car = fic->buffer[foo];
|
||||
car = is_printable(car) ? car : ' ';
|
||||
if (clig==lig && ccol==col)
|
||||
wstandout(pop);
|
||||
mvwaddch(pop, lig+2, col+1, car);
|
||||
if (clig==lig && ccol==col)
|
||||
wstandend(pop);
|
||||
}
|
||||
|
||||
/* put the cursor at the current location */
|
||||
/* this was a really bad idea for Xterm users, because
|
||||
* current pos char was written in "standout", and the
|
||||
* text cursor of xterm re-reverse it.
|
||||
* XXX wmove(pop, clig+2, ccol+1);
|
||||
*/
|
||||
wmove(pop,1,64);
|
||||
|
||||
wrefresh(pop);
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/* new: 2004 Nov.
|
||||
* still in developement.
|
||||
*/
|
||||
int asciiview(void)
|
||||
{
|
||||
WINDOW * popup;
|
||||
int foo, key, flag_exit;
|
||||
int clig, ccol; /* position du curseur */
|
||||
Fichier * fic;
|
||||
|
||||
av_sauve_contexte();
|
||||
|
||||
popup = newwin(21, 66, 3, 5);
|
||||
bordure(popup);
|
||||
|
||||
wstandout(popup);
|
||||
for (foo=1; foo<65; foo++)
|
||||
mvwaddch(popup, 19, foo, ' ');
|
||||
mvwaddstr(popup, 19, 1, " 'Q' quit, <tab> see other file");
|
||||
for (foo=1; foo<65; foo++)
|
||||
mvwaddch(popup, 18, foo, ' ');
|
||||
wstandend(popup);
|
||||
wrefresh(popup);
|
||||
|
||||
flag_exit = 0;
|
||||
clig = ccol = 0;
|
||||
do
|
||||
{
|
||||
if (fenetre_active==0) fic = &f1;
|
||||
else fic = &f2;
|
||||
|
||||
av_affiche(fic, popup, clig, ccol);
|
||||
key = getch();
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case 'q': case 'Q':
|
||||
flag_exit = 1;
|
||||
break;
|
||||
case '\t':
|
||||
fenetre_active ^= 1;
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (clig>0) clig--; break;
|
||||
case KEY_DOWN:
|
||||
if (clig<15) clig++; break;
|
||||
case KEY_LEFT:
|
||||
if (ccol>0) ccol--;
|
||||
else if (clig>0)
|
||||
{
|
||||
/* go to the previous line */
|
||||
ccol=63; clig--;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
if (ccol<63) ccol++;
|
||||
else if (clig<15)
|
||||
{
|
||||
/* go to the next line */
|
||||
ccol=0; clig++;
|
||||
}
|
||||
break;
|
||||
case KEY_HOME:
|
||||
ccol = clig = 0; break;
|
||||
case KEY_END:
|
||||
ccol = 63; clig = 15; break;
|
||||
default:
|
||||
flash();
|
||||
break;
|
||||
}
|
||||
|
||||
} while ( ! flag_exit );
|
||||
|
||||
delwin(popup);
|
||||
|
||||
av_restaure_contexte();
|
||||
return 42;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
138
Hexdiff/fileinfo.c
Normal file
138
Hexdiff/fileinfo.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
fileinfo.c
|
||||
----------
|
||||
|
||||
More infos --> http://tboudet.free.fr/hexdiff/
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "hexdiff.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/* private vars of this module */
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* this func need more "configurability"
|
||||
*/
|
||||
static void prtime(time_t t, char *pstr)
|
||||
{
|
||||
struct tm *ptm;
|
||||
int foo;
|
||||
ptm = gmtime(&t);
|
||||
foo = strftime(pstr, 99, "%Y-%m-%d %H:%M:%S", ptm);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
#define W_FILEINFO 48
|
||||
WINDOW * do_fileinfo(int fd, int ligne)
|
||||
{
|
||||
WINDOW * popup;
|
||||
int foo, lig, hpopup;
|
||||
struct stat stat_buf;
|
||||
char buffer[100];
|
||||
struct passwd *pass;
|
||||
struct group *grp;
|
||||
|
||||
if (config.ext_fileinfo) hpopup = 13;
|
||||
else hpopup = 12;
|
||||
|
||||
popup = newwin(hpopup, W_FILEINFO, ligne, 15);
|
||||
if ( popup==NULL ) return NULL;
|
||||
bordure(popup);
|
||||
|
||||
#if TRACE
|
||||
sprintf(buffer, " fileinfos fd %d ", fd);
|
||||
mvwaddstr(popup, 0, 10, buffer);
|
||||
#endif
|
||||
|
||||
foo = fstat(fd, &stat_buf);
|
||||
if (foo==0)
|
||||
{
|
||||
lig = 2;
|
||||
sprintf(buffer, "dev: %ld", (long)(stat_buf.st_dev));
|
||||
mvwaddstr(popup, lig, 2, buffer);
|
||||
sprintf(buffer, "inode: %ld", stat_buf.st_ino);
|
||||
mvwaddstr(popup, lig, 22, buffer);
|
||||
lig += 2;
|
||||
|
||||
sprintf(buffer, "uid: %d", stat_buf.st_uid);
|
||||
mvwaddstr(popup, lig, 2, buffer);
|
||||
sprintf(buffer, "gid: %d", stat_buf.st_gid);
|
||||
mvwaddstr(popup, lig, 22, buffer);
|
||||
if (config.ext_fileinfo)
|
||||
{
|
||||
lig++;
|
||||
|
||||
pass = getpwuid(stat_buf.st_uid);
|
||||
if (pass==NULL) strcpy(buffer, "unknow user");
|
||||
else sprintf(buffer, "user: %s", pass->pw_name);
|
||||
mvwaddstr(popup, lig, 2, buffer);
|
||||
|
||||
grp = getgrgid(stat_buf.st_gid);
|
||||
if (grp==NULL) strcpy(buffer, "unknow group");
|
||||
else sprintf(buffer, "group: %s", grp->gr_name);
|
||||
mvwaddstr(popup, lig, 22, buffer);
|
||||
}
|
||||
lig+=2;
|
||||
|
||||
/* Nov 2004: may be, here, we need a 'ls-like' display ,
|
||||
with "-rwxr-x---" look'n'feel ? */
|
||||
sprintf(buffer, "rwx: %05o", stat_buf.st_mode & 01777);
|
||||
mvwaddstr(popup, lig, 2, buffer);
|
||||
sprintf(buffer, "size: %ld", stat_buf.st_size);
|
||||
mvwaddstr(popup, lig, 22, buffer);
|
||||
lig+=2;
|
||||
|
||||
/* we don't display the atime, because, after all,
|
||||
hexdiff _is_ reading the file :) */
|
||||
prtime(stat_buf.st_mtime, buffer);
|
||||
mvwaddstr(popup, lig, 4, "mtime:");
|
||||
mvwaddstr(popup, lig, 14, buffer);
|
||||
lig++;
|
||||
|
||||
prtime(stat_buf.st_ctime, buffer);
|
||||
mvwaddstr(popup, lig, 4, "ctime:");
|
||||
mvwaddstr(popup, lig, 14, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(buffer, "fstat error = %d", foo);
|
||||
mvwaddstr(popup, 6, 2, buffer);
|
||||
}
|
||||
|
||||
wrefresh(popup);
|
||||
return popup;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int fileinfo(int fd, int ligne)
|
||||
{
|
||||
WINDOW * pop;
|
||||
|
||||
pop = do_fileinfo(fd, ligne);
|
||||
getch();
|
||||
delwin(pop);
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int double_fileinfo(int fd1, int ligne1, int fd2, int ligne2)
|
||||
{
|
||||
WINDOW * pop1, * pop2;
|
||||
|
||||
pop1 = do_fileinfo(fd1, ligne1);
|
||||
pop2 = do_fileinfo(fd2, ligne2);
|
||||
getch();
|
||||
delwin(pop1);
|
||||
delwin(pop2);
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
331
Hexdiff/fonctions.c
Normal file
331
Hexdiff/fonctions.c
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
fonctions.c
|
||||
-----------
|
||||
|
||||
Old site --> http://tboudet.free.fr/hexdiff/
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "hexdiff.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
int is_printable(int octet)
|
||||
{
|
||||
if (config.show_8bits)
|
||||
return isprint(octet & 0x7f);
|
||||
|
||||
return isprint(octet);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int ouvre_fichier(char *nom)
|
||||
{
|
||||
int fd, foo;
|
||||
struct stat statbuf;
|
||||
Fichier *fichier;
|
||||
long offset;
|
||||
|
||||
if ( (fd=open(nom, O_RDONLY)) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fenetre_active==0)
|
||||
{
|
||||
fichier = &f1; offset = f2.offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
fichier = &f2; offset = f1.offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* close the old file
|
||||
*/
|
||||
close(fichier->fd);
|
||||
|
||||
/*
|
||||
* store information on newly open file
|
||||
*/
|
||||
strncpy(fichier->nom, nom, T_NOM);
|
||||
foo = fstat(fd, &statbuf);
|
||||
fichier->fd = fd;
|
||||
fichier->taille = statbuf.st_size;
|
||||
fichier->offset = offset;
|
||||
fichier->lus = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
void barre_inverse(char c, int ligne)
|
||||
{
|
||||
int foo;
|
||||
standout();
|
||||
for (foo=0; foo<80; foo++)
|
||||
mvaddch(ligne, foo, c);
|
||||
standend();
|
||||
/* refresh(); */
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/* new 28 juillet 2007 */
|
||||
static int calcul_pourcent(Fichier *f)
|
||||
{
|
||||
float foo;
|
||||
if (f->taille < 16) return 0;
|
||||
foo = ((float)f->offset * 100.0) / (float)f->taille;
|
||||
return (int)foo;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int
|
||||
ecrire_barres_fichiers(void)
|
||||
{
|
||||
char buffer[150];
|
||||
int pourcent;
|
||||
|
||||
barre_inverse(' ', BARRE_1);
|
||||
barre_inverse(' ', BARRE_2);
|
||||
|
||||
standout();
|
||||
|
||||
mvaddstr(BARRE_1, 0, fenetre_active ? " " : "**");
|
||||
mvaddstr(BARRE_1, 3, f1.nom);
|
||||
pourcent = calcul_pourcent(&f1);
|
||||
sprintf(buffer, "%8ld %8ld %3d%%", f1.taille, f1.offset, pourcent);
|
||||
/*sprintf(buffer, "%8ld %8ld %8ld", f1.taille, f1.offset, f1.lus);*/
|
||||
mvaddstr(BARRE_1, 52, buffer);
|
||||
|
||||
mvaddstr(BARRE_2, 0, fenetre_active ? "**" : " ");
|
||||
mvaddstr(BARRE_2, 3, f2.nom);
|
||||
pourcent = calcul_pourcent(&f2);
|
||||
sprintf(buffer, "%8ld %8ld %3d%%", f2.taille, f2.offset, pourcent);
|
||||
mvaddstr(BARRE_2, 52, buffer);
|
||||
|
||||
if (config.show_8bits) mvaddstr(0, 72, " 8bits ");
|
||||
else mvaddstr(0, 72, " 7bits ");
|
||||
if (config.offsets_in_hex) mvaddstr(0, 66, " hex ");
|
||||
else mvaddstr(0, 66, " dec ");
|
||||
standend();
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int
|
||||
fond_ecran(void)
|
||||
{
|
||||
#if TRACE
|
||||
int foo;
|
||||
char buffer[200];
|
||||
#endif
|
||||
|
||||
barre_inverse(' ', 0);
|
||||
standout();
|
||||
mvaddstr(0, 2, " Visuel HexDiff v " VERSION " by tTh 2007 ");
|
||||
#if TRACE
|
||||
sprintf(buffer, " screen size %dx%d ", COLS, LINES);
|
||||
foo = strlen(buffer);
|
||||
mvaddstr(0, COLS-2-foo, buffer);
|
||||
#endif
|
||||
standend();
|
||||
refresh();
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "HAUT %3d\n", HAUT);
|
||||
fprintf(stderr, "HAUT_1 %3d BARRE_1 %3d\n", HAUT_1, BARRE_1);
|
||||
fprintf(stderr, "HAUT_2 %3d BARRE_2 %3d\n", HAUT_2, BARRE_2);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
void bordure(WINDOW * w)
|
||||
{
|
||||
if (config.nice_border)
|
||||
box(w, 0, 0);
|
||||
else
|
||||
wborder(w, '|', '|', '-', '-', '+', '+', '+', '+');
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
int ligne;
|
||||
char * texte;
|
||||
} ligne_aide;
|
||||
|
||||
ligne_aide lignes[] =
|
||||
{
|
||||
{ 2, "x q : quit now, 'tfatf'" },
|
||||
{ 4, "u j (U) : go up one (4) lines" },
|
||||
{ 5, "d k (D) : go down one (4) lines" },
|
||||
{ 6, "<spc> : go down one full page" },
|
||||
{ 7, "0 : back to begin of files" },
|
||||
{ 8, "$ : goto end of shortest file" },
|
||||
{ 9, "<tab> : toggle the active window" },
|
||||
{ 10, "g : input a new file offset" },
|
||||
/* { 11, "= : synchronize the two offsets" }, */
|
||||
{ 12, "H : 'toogle' hex/dec offset display" },
|
||||
{ 13, "7 8 : display control of bit 7" },
|
||||
{ 14, "i (I) : info about file(s)" },
|
||||
{ 15, "n : jump to the next difference" },
|
||||
{ 16, "^O : open new file in current win" },
|
||||
{ 17, "A : Ascii View (new feature :)" }
|
||||
};
|
||||
|
||||
#define NB_LIG (sizeof(lignes)/sizeof(ligne_aide))
|
||||
|
||||
#define L_POPUP 2
|
||||
#define C_POPUP 11
|
||||
|
||||
void popup_aide(void)
|
||||
{
|
||||
WINDOW * popup;
|
||||
int foo, bar, ligmax, largmax;
|
||||
|
||||
ligmax = largmax = 0;
|
||||
for (foo=0; foo<NB_LIG; foo++)
|
||||
{
|
||||
if ((bar=lignes[foo].ligne) > ligmax) ligmax = bar;
|
||||
if ((bar=strlen(lignes[foo].texte)) > largmax) largmax = bar;
|
||||
}
|
||||
|
||||
ligmax += 3;
|
||||
largmax += 7;
|
||||
popup = newwin(ligmax, largmax, L_POPUP, C_POPUP);
|
||||
bordure(popup);
|
||||
|
||||
for (foo=0; foo<NB_LIG; foo++)
|
||||
{
|
||||
mvwaddstr(popup, lignes[foo].ligne, 3, lignes[foo].texte);
|
||||
}
|
||||
|
||||
wrefresh(popup);
|
||||
getch();
|
||||
delwin(popup);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
static char *about_texte[] =
|
||||
{
|
||||
"Visuel Hexdiff - version " VERSION,
|
||||
"(c) 2007 by Thierry [tth] Boudet",
|
||||
"http://tboudet.free.fr/hexdiff/",
|
||||
"send bugs reports: tontonth@free.fr",
|
||||
"binary build: " __DATE__ "/" __TIME__,
|
||||
};
|
||||
|
||||
void about(void)
|
||||
{
|
||||
WINDOW * popup;
|
||||
int nblignes = sizeof(about_texte) / sizeof(char *);
|
||||
int foo;
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "boite about: %d lignes\n", nblignes);
|
||||
#endif
|
||||
|
||||
popup = newwin((nblignes*2)+3, 43, L_POPUP, C_POPUP);
|
||||
bordure(popup);
|
||||
|
||||
for (foo=0; foo<nblignes; foo++)
|
||||
{
|
||||
#if TRACE
|
||||
fprintf(stderr, "%d '%s'\n", foo, about_texte[foo]);
|
||||
#endif
|
||||
mvwaddstr(popup, (foo*2)+2, 4, about_texte[foo]);
|
||||
}
|
||||
wrefresh(popup);
|
||||
getch();
|
||||
delwin(popup);
|
||||
/* pourquoi, quand je fait le 'delwin', ncurses
|
||||
ne rafraichit pas la zone qui etait masquee ?
|
||||
*/
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
void aide_cl(int flag)
|
||||
{
|
||||
int foo;
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
fputs("\tusage:\n", stderr);
|
||||
fputs("\t\thexdiff -h\n", stderr);
|
||||
fputs("\t\thexdiff -V\n", stderr);
|
||||
fputs("\t\thexdiff -X\n", stderr);
|
||||
fputs("\t\thexdiff file.A file.B\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fputs("\n", stderr);
|
||||
fputs("\t+------------------------------------------------+\n", stderr);
|
||||
fputs("\t| commandes clavier |\n", stderr);
|
||||
fputs("\t+------------------------------------------------+\n", stderr);
|
||||
for (foo=0; foo<NB_LIG; foo++)
|
||||
{
|
||||
fprintf(stderr, "\t| %-46s |\n", lignes[foo].texte);
|
||||
}
|
||||
fputs("\t+------------------------------------------------+\n", stderr);
|
||||
fputs("\t| Pour le reste: 'man hexdiff', hein... |\n", stderr);
|
||||
fputs("\t+------------------------------------------------+\n", stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* cette fonction de saisie est codee a la "GRUIK" (aka "rache method")
|
||||
*/
|
||||
#define W_FEN_SL 40
|
||||
#define H_FEN_SL 5
|
||||
|
||||
long saisir_un_long(char *txt)
|
||||
{
|
||||
WINDOW * saisie;
|
||||
int l, c, foo;
|
||||
long valeur;
|
||||
|
||||
saisie = newwin(H_FEN_SL, W_FEN_SL, 5, 20);
|
||||
wstandout(saisie);
|
||||
|
||||
/*
|
||||
* la, je me demande pourquoi je suis oblige de 'poker' des espaces
|
||||
* au lieu d'appeler une fonction de base. par exemple, wclear() ne
|
||||
* semble pas prendre en compte le wstandout() ?
|
||||
*/
|
||||
for (l=0; l<H_FEN_SL; l++)
|
||||
for (c=0; c<W_FEN_SL; c++)
|
||||
mvwaddch(saisie, l, c, ' ');
|
||||
|
||||
bordure(saisie);
|
||||
|
||||
mvwaddstr(saisie, 2, 3, txt);
|
||||
wstandend(saisie);
|
||||
mvwaddstr(saisie, 2, 25, " ");
|
||||
wrefresh(saisie);
|
||||
|
||||
echo();
|
||||
foo = mvwscanw(saisie, 2, 25, "%ld", &valeur);
|
||||
noecho();
|
||||
|
||||
/* wrefresh(saisie); */
|
||||
delwin(saisie);
|
||||
if (foo == 1)
|
||||
return valeur;
|
||||
return -1;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
void version(void)
|
||||
{
|
||||
fprintf(stderr, "\nThis is 'hexdiff' v "VERSION", made by tontonTh in 2007\n");
|
||||
fprintf(stderr, "homepage: http://tboudet.free.fr/hexdiff/\n");
|
||||
#if TRACE
|
||||
fprintf(stderr, "Warning ! compiled with active TRACE !\n");
|
||||
#endif
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
129
Hexdiff/hexdiff.1
Normal file
129
Hexdiff/hexdiff.1
Normal file
@ -0,0 +1,129 @@
|
||||
.TH HexDiff 1 "November 1905" "Divers Un*ces" "TontonTh tools"
|
||||
|
||||
.SH NAME
|
||||
hexdiff \- un 'visuel diff' pour les fichiers binaires
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBhexdiff\fP -V
|
||||
.br
|
||||
\fBhexdiff\fP -h|-?
|
||||
.br
|
||||
\fBhexdiff\fP file1 file2
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBhexdiff\fP a été crée pour faciliter le débuggage de routines d'écriture
|
||||
de fichiers images (PCX et BMP, comme par hasard). En comparant un fichier
|
||||
kimarche et un fichier que je fabrique, ça va aider :)
|
||||
.br
|
||||
\fBhexdiff\fP affiche, après le lancement, deux fenètres montrant un dump
|
||||
hexadécimal et ascii du début des deux fichiers. Deux barres d'état
|
||||
donnent le nom du fichier, sa taille et l'offset courant.
|
||||
La fenêtre courante est marquée par '**' à gauche de l'écran.
|
||||
A l'aide de diverses touches du clavier, vous pouvez vous déplacer
|
||||
simultanément dans les deux fichiers, et le dump vous montrera alors,
|
||||
en vidéo inverse, les octets qui sont différents entre les deux fichiers.
|
||||
Après, hein, c'est à vous d'interpréter...
|
||||
|
||||
.SH OPTIONS
|
||||
.B -V
|
||||
Pour connaitre la version du machin-bidule.
|
||||
.br
|
||||
.B -h | -?
|
||||
Ah, il y a un peu de l'aide. Bon à savoir.
|
||||
.br
|
||||
.B -X
|
||||
Help for debugging your ~/.hexdiffrc, or the rc file parser.
|
||||
|
||||
.SH KEYBOARD COMMANDS
|
||||
.B x q
|
||||
Quitte le programme. Parfois...
|
||||
.br
|
||||
.B u j U
|
||||
Remonte d'une ligne (de 16 octets), ou de quatre, dans les deux fichiers.
|
||||
.br
|
||||
.B d k D
|
||||
Descend d'une ou quatre lignes dans les deux fichiers.
|
||||
.br
|
||||
.B <space>
|
||||
Descend de plusieurs lignes dans les deux fichiers. Ce nombre étant calculé
|
||||
selon la taille de l'écran, je ne peux le révéler ici.
|
||||
.br
|
||||
.B 0 <home>
|
||||
Reprend au début des deux fichiers.
|
||||
.br
|
||||
.B $
|
||||
Vous emmène aux environs de juste avant la fin du plus petit des deux fichiers.
|
||||
.br
|
||||
.B g
|
||||
Propose de saisir un nouvel offset pour les deux fichiers. Attention, cette
|
||||
fonctions a été écrite à la 'Gruik' et n'est donc pas fiable.
|
||||
.br
|
||||
.B H
|
||||
Bascule l'affichage des offsets entre le décimal et l'hexadécimal. Le mode
|
||||
initial est configurable.
|
||||
.br
|
||||
.B i
|
||||
Affichage des informations 'fstat' sur le fichier sélectionné.
|
||||
.br
|
||||
.B I
|
||||
Affiche les mêmes informations, mais pour les deux fichiers simultanément.
|
||||
.br
|
||||
.B A
|
||||
Open the (currently) experimental AsciiViewer.
|
||||
Maybe coredump with no request. <tab> switch as usual.
|
||||
.br
|
||||
.B ^O
|
||||
Ouverture d'un nouveau fichier dans la fenêtre courante. Le "selecteur de
|
||||
fichier" est encore rudimentaire. Utiliser 'Q' pour annuler, <Enter> pour
|
||||
valider, et '?' pour l'aide.
|
||||
.br
|
||||
.B n
|
||||
Part à la recherche de la prochaine différence entre les deux fichiers.
|
||||
.br
|
||||
.B <tab>
|
||||
Change la fenètre active. Pour le moment, ça ne sert presque à rien.
|
||||
Ah, non, il parait que ça joue sur le contexte d'autres fonctions.
|
||||
Personne ne m'en a parlé, je ne suis au courant de rien, alors
|
||||
je --->[]
|
||||
.br
|
||||
.B ?
|
||||
"Popupe" une fenètre d'aide reprenant les principales commandes. Pour
|
||||
les autres commandes: un seul slogan, Utsl.
|
||||
|
||||
.SH CONFIG FILE
|
||||
Le fichier de configuration est
|
||||
.B .hexdiffrc
|
||||
et doit se trouver dans le
|
||||
.B $HOME
|
||||
de l'utilisateur.
|
||||
Une ligne commençant par un
|
||||
.B '#'
|
||||
est un commentaire. Les lignes vides sont ignorées. Pour plus de détails,
|
||||
consulter le fichier 'hexdiff.rc' qui devrait se trouver dans l'archive.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR diff (1),
|
||||
.BR cmp (1)
|
||||
|
||||
.SH BUGS
|
||||
Si vous redimensionnez votre xterm, \fBhexdiff\fP se prend un SIGWINCH,
|
||||
et s'en va probablement visiter le pays des Slashies. Dans la pratique,
|
||||
il en revient très vite.
|
||||
.br
|
||||
L'affichage en fin de fichier, si les tailles sont différentes, est
|
||||
parfois un peu déglingué. Mais je vais réparer ça.
|
||||
.br
|
||||
Cette page de man n'est pas synchrone avec la réalité virtuelle du code.
|
||||
Car le code évolue plus vite que la réalité. Parfois.
|
||||
|
||||
.SH AUTHOR
|
||||
Thierry Boudet aka
|
||||
.B tTh
|
||||
qui 'spleytise' avec vigueur ce petit programme depuis Mars 2002.
|
||||
Pour en savoir un peu plus sur ce logiciel:
|
||||
http://tboudet.free.fr/hexdiff/ et sur moi: http://tontonth.free.fr/plop/
|
||||
|
||||
.SH DEDICACE
|
||||
Ce logiciel est dédié aux kamarades trolleurs de l'équipe HardStory du
|
||||
CULTe, sans qui rien n'est pas faisable. <http://www.culte.org/>
|
||||
|
394
Hexdiff/hexdiff.c
Normal file
394
Hexdiff/hexdiff.c
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
Visuel Hexdiff
|
||||
--------------
|
||||
|
||||
More infos --> http://tboudet.free.fr/hexdiff/
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAIN
|
||||
|
||||
#include "hexdiff.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static void finish(int signal)
|
||||
{
|
||||
endwin(); exit(0);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int
|
||||
affiche_les_dumps(void)
|
||||
{
|
||||
int foo, bar, idx, flag;
|
||||
char buff[50];
|
||||
char *format_offset;
|
||||
|
||||
memset(f1.buffer, 0, T_BUFF);
|
||||
memset(f2.buffer, 0, T_BUFF);
|
||||
|
||||
/*
|
||||
* lire les deux fichiers...
|
||||
*/
|
||||
lseek(f1.fd, f1.offset, SEEK_SET);
|
||||
f1.lus = read(f1.fd, f1.buffer, T_BUFF);
|
||||
lseek(f2.fd, f2.offset, SEEK_SET);
|
||||
f2.lus = read(f2.fd, f2.buffer, T_BUFF);
|
||||
|
||||
ecrire_barres_fichiers();
|
||||
|
||||
/*
|
||||
* afficher les offsets
|
||||
*/
|
||||
format_offset = config.offsets_in_hex ? "%08lx" : "%8ld";
|
||||
|
||||
for (foo=0; foo<HAUT; foo++)
|
||||
{
|
||||
move(HAUT_1+foo, 0); clrtoeol();
|
||||
move(HAUT_2+foo, 0); clrtoeol();
|
||||
sprintf(buff, format_offset, foo*16+f1.offset);
|
||||
mvaddstr(HAUT_1+foo, 0, buff);
|
||||
sprintf(buff, format_offset, foo*16+f2.offset);
|
||||
mvaddstr(HAUT_2+foo, 0, buff);
|
||||
}
|
||||
|
||||
/*
|
||||
* afficher les octets
|
||||
*/
|
||||
for (foo=0; foo<HAUT; foo++)
|
||||
{
|
||||
for (bar=0; bar<16; bar++)
|
||||
{
|
||||
idx = foo*16 + bar;
|
||||
|
||||
/*
|
||||
* il faut prendre en compte le cas ou la taille
|
||||
* des fichiers n'est pas la meme, pour ne pas mettre
|
||||
* en evidence les octets qui debordent.
|
||||
*/
|
||||
flag = f1.buffer[idx]!=f2.buffer[idx];
|
||||
|
||||
/*
|
||||
* fenetre du haut
|
||||
*/
|
||||
if (flag && !fenetre_active) standout();
|
||||
if (idx < f1.lus)
|
||||
{
|
||||
sprintf(buff, "%02x", f1.buffer[idx]);
|
||||
mvaddstr(HAUT_1+foo, bar*3+11, buff);
|
||||
if (is_printable(f1.buffer[idx]))
|
||||
mvaddch(HAUT_1+foo, bar+62, f1.buffer[idx]);
|
||||
else
|
||||
mvaddch(HAUT_1+foo, bar+62, ' ');
|
||||
}
|
||||
if (flag && !fenetre_active) standend();
|
||||
|
||||
/*
|
||||
* fenetre du bas
|
||||
*/
|
||||
if (flag && fenetre_active) standout();
|
||||
if (idx < f2.lus)
|
||||
{
|
||||
sprintf(buff, "%02x", f2.buffer[idx]);
|
||||
mvaddstr(HAUT_2+foo, bar*3+11, buff);
|
||||
if (is_printable(f2.buffer[idx]))
|
||||
mvaddch(HAUT_2+foo, bar+62, f2.buffer[idx]);
|
||||
else
|
||||
mvaddch(HAUT_2+foo, bar+62, ' ');
|
||||
}
|
||||
|
||||
if (flag && fenetre_active) standend();
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* la boucle principale. tant qu'on a pas presse une touche
|
||||
* kifaiquitter, on reste dedans.
|
||||
*/
|
||||
int
|
||||
interactive(void)
|
||||
{
|
||||
int clef; /* la touche en question */
|
||||
int flag_exit = 0; /* devient 1 si on doit quitter la boucle */
|
||||
int pas_a_la_fin;
|
||||
int foo;
|
||||
long lfoo;
|
||||
char chaine[T_NOM+1];
|
||||
#if TRACE
|
||||
char buff[100];
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
affiche_les_dumps();
|
||||
|
||||
pas_a_la_fin = (f1.offset<f1.taille) && (f2.offset<f2.taille);
|
||||
|
||||
clef = getch();
|
||||
|
||||
#if TRACE
|
||||
sprintf(buff, "%c %04x %d ", clef, clef, pas_a_la_fin);
|
||||
mvaddstr(0, 0, buff); refresh();
|
||||
#endif
|
||||
|
||||
switch (clef)
|
||||
{
|
||||
case 'x': case 'q':
|
||||
flag_exit = 1;
|
||||
break;
|
||||
|
||||
case 'u': case 'j':
|
||||
case KEY_UP:
|
||||
if (f1.offset>15) f1.offset -= 16;
|
||||
if (f2.offset>15) f2.offset -= 16;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
f1.offset -= 64;
|
||||
if (f1.offset<0) f1.offset=0;
|
||||
f2.offset -= 64;
|
||||
if (f2.offset<0) f2.offset=0;
|
||||
break;
|
||||
|
||||
|
||||
case 'd': case 'k':
|
||||
case KEY_DOWN:
|
||||
if (pas_a_la_fin)
|
||||
{
|
||||
f1.offset += 16;
|
||||
f2.offset += 16;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if (pas_a_la_fin)
|
||||
{
|
||||
f1.offset += 64;
|
||||
f2.offset += 64;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
config.offsets_in_hex ^= 1;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case KEY_NPAGE:
|
||||
if (pas_a_la_fin)
|
||||
{
|
||||
f1.offset += (HAUT-1)*16;
|
||||
f2.offset += (HAUT-1)*16;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_PPAGE:
|
||||
lfoo = f1.offset - (HAUT-1)*16;
|
||||
if (lfoo<0) lfoo = 0;
|
||||
f1.offset = f2.offset = lfoo;
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case KEY_HOME:
|
||||
f1.offset = f2.offset = 0;
|
||||
break;
|
||||
|
||||
case '7':
|
||||
config.show_8bits = 0;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
config.show_8bits = 1;
|
||||
break;
|
||||
|
||||
case '$':
|
||||
/* jump to the end of the smallest file */
|
||||
lfoo = (f1.taille<f2.taille) ? f1.taille : f2.taille;
|
||||
f1.offset = f2.offset = (lfoo-16) & 0xffffff0;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
lfoo = (f1.offset<f2.offset) ? f1.offset : f2.offset;
|
||||
f1.offset = f2.offset = lfoo & 0xffffff0;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
lfoo = saisir_un_long("nouvel offset");
|
||||
if (lfoo != -1)
|
||||
f1.offset = f2.offset = lfoo & 0xffffff0;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if (fenetre_active == 0)
|
||||
fileinfo(f1.fd, HAUT_1);
|
||||
else
|
||||
fileinfo(f2.fd, HAUT_2);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
double_fileinfo(f1.fd, HAUT_1, f2.fd, HAUT_2);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
/**** asciiview ****/
|
||||
asciiview();
|
||||
break;
|
||||
/*
|
||||
* a patch from Mark Glines:
|
||||
* key 'n' search for the next difference
|
||||
*/
|
||||
case 'n': /* next */
|
||||
for(lfoo = f1.offset + 16;
|
||||
lfoo < f1.taille && (lfoo+f2.offset-f1.offset) < f2.taille;
|
||||
lfoo += 16) {
|
||||
|
||||
char buf1[16], buf2[16];
|
||||
int diff = f2.offset - f1.offset;
|
||||
lseek(f1.fd, lfoo, SEEK_SET);
|
||||
lseek(f2.fd, lfoo+diff, SEEK_SET);
|
||||
if(read(f1.fd,buf1,16) == 16)
|
||||
if(read(f2.fd,buf2,16) == 16)
|
||||
if(memcmp(buf1,buf2,16)) {
|
||||
f1.offset = lfoo;
|
||||
f2.offset = lfoo + diff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
popup_aide();
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
about();
|
||||
break;
|
||||
|
||||
case 0x0f: /* CTRL O */
|
||||
foo = select_new_file(chaine, T_NOM, 0);
|
||||
if (foo)
|
||||
ouvre_fichier(chaine);
|
||||
break;
|
||||
|
||||
case '\t': /* TAB */
|
||||
fenetre_active ^= 1;
|
||||
break;
|
||||
|
||||
case '\f': /* CTRL L */
|
||||
wrefresh(curscr);
|
||||
break;
|
||||
|
||||
case 'V': /* plugin viewers ? */
|
||||
break;
|
||||
|
||||
default: /* this key was not used */
|
||||
flash();
|
||||
break;
|
||||
}
|
||||
} while ( ! flag_exit );
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* HERE WE GO, FAST AND FURIOUS !
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int foo;
|
||||
struct stat statbuf;
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "\n------ trace de %s ------\n", argv[0]);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
|
||||
if (argc == 1) aide_cl(0);
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
if (!strcmp(argv[1], "-?") || !strcmp(argv[1], "-h"))
|
||||
aide_cl(1);
|
||||
|
||||
if (!strcmp(argv[1], "-V")) version();
|
||||
|
||||
if (!strcmp(argv[1], "-X"))
|
||||
{
|
||||
foo = lire_configuration(1);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != 3) aide_cl(0);
|
||||
|
||||
/*
|
||||
* initialisation des variables globales
|
||||
*/
|
||||
fenetre_active = 0;
|
||||
|
||||
/*
|
||||
* on va essayer d'ouvrir les fichiers.
|
||||
*/
|
||||
if ( (f1.fd=open(argv[1], O_RDONLY)) < 0)
|
||||
{
|
||||
perror(argv[1]); exit(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(f1.nom, argv[1], T_NOM);
|
||||
foo = fstat(f1.fd, &statbuf);
|
||||
f1.taille = statbuf.st_size;
|
||||
f1.offset = 0;
|
||||
f1.lus = 0;
|
||||
}
|
||||
|
||||
if ( (f2.fd=open(argv[2], O_RDONLY)) < 0)
|
||||
{
|
||||
perror(argv[2]); exit(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(f2.nom, argv[2], T_NOM);
|
||||
foo = fstat(f2.fd, &statbuf);
|
||||
f2.taille = statbuf.st_size;
|
||||
f2.offset = 0;
|
||||
f2.lus = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* si on arrive ici, c'est que les deux fichiers sont ouverts,
|
||||
* donc on peut tenter de lire le fichier de configuration...
|
||||
*/
|
||||
foo = lire_configuration(0);
|
||||
|
||||
/*
|
||||
* ... et ensuite, on peut passer en mode 'Vizzual'.
|
||||
*/
|
||||
initscr();
|
||||
nonl(); cbreak(); noecho();
|
||||
|
||||
keypad(stdscr, TRUE); /* acces aux touches 'curseur' */
|
||||
|
||||
foo = fond_ecran();
|
||||
|
||||
interactive(); /* GOTO LOOP */
|
||||
|
||||
/*
|
||||
* plop, on a fini, restaurer la console
|
||||
*/
|
||||
finish(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
99
Hexdiff/hexdiff.h
Normal file
99
Hexdiff/hexdiff.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* global .h file for hexdiff
|
||||
* --------------------------
|
||||
*/
|
||||
|
||||
#include <ncurses.h>
|
||||
|
||||
/* "#define VERSION" is now in the Makefile */
|
||||
|
||||
#define T_BUFF 4242
|
||||
#define T_NOM 360
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fd;
|
||||
long taille;
|
||||
long offset;
|
||||
long lus;
|
||||
char nom[T_NOM+1]; /* buffer overflow ? */
|
||||
unsigned char buffer[T_BUFF];
|
||||
} Fichier;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int nice_border;
|
||||
int show_8bits;
|
||||
char *language;
|
||||
int offsets_in_hex;
|
||||
int ext_fileinfo;
|
||||
int show_hidden;
|
||||
int sf_flag;
|
||||
int explique; /* not used */
|
||||
int zoom;
|
||||
int asciiview; /* not used */
|
||||
} configuration;
|
||||
|
||||
/*
|
||||
* declaration of globals vars
|
||||
*/
|
||||
|
||||
#ifdef MAIN
|
||||
#define EXTERN
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
EXTERN Fichier f1, f2;
|
||||
EXTERN int fenetre_active;
|
||||
EXTERN configuration config;
|
||||
|
||||
/*
|
||||
* macros de positionnement en hauteur
|
||||
*/
|
||||
#define HAUT ((LINES-3)/2)
|
||||
#define HAUT_1 1
|
||||
#define BARRE_1 (HAUT_1+HAUT)
|
||||
#define HAUT_2 (HAUT_1+(HAUT)+1)
|
||||
#define BARRE_2 (HAUT_2+HAUT)
|
||||
|
||||
/*
|
||||
* prototype des fonctions
|
||||
*/
|
||||
void barre_inverse(char c, int ligne);
|
||||
int ecrire_barres_fichiers(void);
|
||||
int fond_ecran(void);
|
||||
void about(void);
|
||||
void aide_cl(int flag);
|
||||
void bordure(WINDOW * w);
|
||||
void popup_aide(void);
|
||||
long saisir_un_long(char *txt);
|
||||
void version(void);
|
||||
int is_printable(int octet);
|
||||
int ouvre_fichier(char *nom);
|
||||
|
||||
/*
|
||||
* file parse_rc.c
|
||||
*/
|
||||
#define HEXDIFF_RC ".hexdiffrc"
|
||||
int init_configuration(void);
|
||||
int lire_configuration(int flag);
|
||||
|
||||
/*
|
||||
* file fileinfo.c
|
||||
*/
|
||||
int fileinfo(int fd, int ligne);
|
||||
int double_fileinfo(int, int, int, int);
|
||||
|
||||
/*
|
||||
* file sel_file.c
|
||||
*/
|
||||
int select_new_file(char *, int, int);
|
||||
int select_set_opt(int flg);
|
||||
|
||||
/*
|
||||
* file asciiview.c
|
||||
*/
|
||||
int asciiview(void);
|
||||
int octalview(void); /* not urgent */
|
||||
|
31
Hexdiff/hexdiff.rc
Normal file
31
Hexdiff/hexdiff.rc
Normal file
@ -0,0 +1,31 @@
|
||||
#
|
||||
# fichier de configuration pour Hexdiff
|
||||
# http://tboudet.free.fr/hexdiff/
|
||||
#
|
||||
|
||||
# enable (1) or disable (0) display of chars
|
||||
# with a code > 127. charset dependant.
|
||||
# you can toogle this flag with the 7 and 8 keys
|
||||
show_8bits 1
|
||||
|
||||
# enable or disable usage of semi-graphic chars
|
||||
# around the various popup windows.
|
||||
nice_border 0
|
||||
|
||||
# select decimal or hexa display of file offset.
|
||||
# the key 'H' switch interactively beetwen the two modes.
|
||||
offsets_in_hex 0
|
||||
# sorry, at this time, no octal offset display...
|
||||
|
||||
# if set to 1, display the id of user and group
|
||||
# in the fileinfo popup (access by 'i' or 'I' key
|
||||
ext_fileinfo 1
|
||||
|
||||
# those flags is not yet used...
|
||||
language fr
|
||||
asciiview 0
|
||||
|
||||
# is the file selector display hidden file ?
|
||||
show_hidden 0
|
||||
|
||||
|
15
Hexdiff/memcheck.sh
Normal file
15
Hexdiff/memcheck.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# seek for memory leaks
|
||||
# ---------------------
|
||||
# you need a recent version of http://www.valgrind.org/
|
||||
#
|
||||
make hexdiff
|
||||
|
||||
rm valgr-plop*
|
||||
|
||||
valgrind --tool=memcheck --log-file=valgr-plop \
|
||||
--leak-check=yes --show-reachable=yes \
|
||||
./hexdiff hexdiff.o fonctions.o
|
||||
|
259
Hexdiff/parse_rc.c
Normal file
259
Hexdiff/parse_rc.c
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
|
||||
HEXDIFF - lecture du fichier de configuration
|
||||
---------------------------------------------
|
||||
|
||||
Attention, programmation a la "Gruiik" !-)
|
||||
Il y a plein de GOTO dans cette fonction, mais je
|
||||
les daguisent habilement en fortranisme.
|
||||
-- tTh --
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* pour strtok */
|
||||
/* certaines mauvaises langues pratendent
|
||||
* que 'strtok' est obsolete, insecure et
|
||||
* pas elegant. moi, je veux bien, mais
|
||||
* alors,il faut me montrer par quoi le
|
||||
* remplacer...
|
||||
*/
|
||||
#include "hexdiff.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* positionner a des valeurs connues toutes les options de
|
||||
* configuration.
|
||||
*
|
||||
* 18juin2002: euh, on ne pourrait pas faire ce truc a la
|
||||
* declaration de la variable ?
|
||||
*/
|
||||
int
|
||||
init_configuration(void)
|
||||
{
|
||||
config.nice_border = 0;
|
||||
config.show_8bits = 0;
|
||||
config.language = "fr";
|
||||
config.offsets_in_hex = 0;
|
||||
config.ext_fileinfo = 0;
|
||||
config.show_hidden = 1;
|
||||
config.sf_flag = 0;
|
||||
config.explique = 0;
|
||||
config.zoom = 0;
|
||||
config.asciiview = 0;
|
||||
|
||||
return 51; /* have a Pastis ? */
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#define DO_NICE_BORDER 1
|
||||
#define DO_LANGUAGE 2
|
||||
#define DO_SHOW_8BITS 3
|
||||
#define DO_OFFSET_HEX 4
|
||||
#define DO_EXT_FILEINFO 5
|
||||
#define DO_SHOW_HIDDEN 20
|
||||
#define DO_FS_FLAG 21
|
||||
#define DO_EXPLIQUE 24
|
||||
#define DO_START_ZOOM 25
|
||||
#define DO_ASCIIVIEW 26
|
||||
|
||||
#define FLAG 1
|
||||
#define TEXTE 2
|
||||
#define NOMBRE 3
|
||||
#define KEY_ALIAS 4
|
||||
|
||||
struct conf_var
|
||||
{
|
||||
char *nom;
|
||||
int code;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct conf_var conf_vars[] =
|
||||
{
|
||||
{ "nice_border", DO_NICE_BORDER, FLAG },
|
||||
{ "language", DO_LANGUAGE, TEXTE },
|
||||
{ "show_8bits", DO_SHOW_8BITS, FLAG },
|
||||
{ "offsets_in_hex", DO_OFFSET_HEX, FLAG },
|
||||
{ "ext_fileinfo", DO_EXT_FILEINFO, FLAG },
|
||||
{ "show_hidden", DO_SHOW_HIDDEN, FLAG },
|
||||
{ "fs_flag", DO_FS_FLAG, NOMBRE },
|
||||
{ "explique", DO_EXPLIQUE, FLAG },
|
||||
{ "start_zoom", DO_START_ZOOM, FLAG },
|
||||
{ "asciiview", DO_ASCIIVIEW, NOMBRE }
|
||||
} ;
|
||||
|
||||
#define NB_TOKEN ( sizeof(conf_vars) / sizeof(struct conf_var) )
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static int lookup_token(char *token)
|
||||
{
|
||||
int foo;
|
||||
|
||||
for (foo=0; foo<NB_TOKEN; foo++)
|
||||
if ( !strcmp(token, conf_vars[foo].nom) )
|
||||
return foo;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
#define LIGNE_RC 442
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* If 'flag' is set to a non-zero value:
|
||||
* - the configfile name is set to './hexdiff.rc'
|
||||
* - parsing trace is displayed
|
||||
*/
|
||||
int
|
||||
lire_configuration(int flag)
|
||||
{
|
||||
FILE *fp;
|
||||
char ligne[LIGNE_RC+3];
|
||||
int line_number, foo;
|
||||
int numtok;
|
||||
char *machin, *valeur;
|
||||
char *delim = " \t=";
|
||||
char *home;
|
||||
|
||||
#if TRACE
|
||||
fprintf(stderr, "*** lecture fichier de conf, flag=%d\n", flag);
|
||||
#endif
|
||||
|
||||
if ( (home=getenv("HOME")) != NULL )
|
||||
{
|
||||
/*
|
||||
* XXX - WARNING BUFFER OVERFLOW HERE !!!
|
||||
*/
|
||||
foo = strlen(home) + strlen(HEXDIFF_RC);
|
||||
if (foo > LIGNE_RC)
|
||||
{
|
||||
fprintf(stderr, ".hexdiffrc buff overflow %d, bad $HOME ?\n",
|
||||
foo);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(ligne, home); strcat(ligne, "/");
|
||||
strcat(ligne, HEXDIFF_RC);
|
||||
}
|
||||
else
|
||||
/*
|
||||
* oui, bon, c'est pas trop coherent, mais je ne
|
||||
* savais pas trop quoi faire en cas de 'homeless',
|
||||
* alors je me suis permis de supposer un contexte
|
||||
* msdos/djgpp ...
|
||||
*/
|
||||
{
|
||||
strcpy(ligne, "c:\\hexdiff.rc");
|
||||
}
|
||||
|
||||
#if TRACE
|
||||
if (flag) /* we are in .rc debug context */
|
||||
{
|
||||
strcpy(ligne, "hexdiff.rc");
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( (fp = fopen(ligne, "r")) == NULL )
|
||||
{
|
||||
perror("hexdiff config file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
line_number = 1;
|
||||
|
||||
while ( fgets(ligne, LIGNE_RC, fp) != NULL )
|
||||
{
|
||||
/*
|
||||
* virer le caractere de fin de ligne (Gruiikage)
|
||||
*/
|
||||
foo=strlen(ligne);
|
||||
if (foo>0)
|
||||
ligne[foo-1] = '\0';
|
||||
#if TRACE
|
||||
fprintf(stderr, "%4d %4d : %s\n",
|
||||
line_number, foo, ligne);
|
||||
#endif
|
||||
line_number++;
|
||||
|
||||
/*
|
||||
* decomposition de la ligne en machins
|
||||
*/
|
||||
machin = strtok(ligne, delim);
|
||||
|
||||
if (machin == NULL) /* ya pas de token */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( machin[0] == '#' ) /* c'est un commentaire */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numtok = lookup_token(machin);
|
||||
|
||||
if (flag)
|
||||
fprintf(stderr, "TOKEN = [%s] code=%d\n", machin, numtok);
|
||||
|
||||
if ( numtok < 0 ) { continue; }
|
||||
|
||||
valeur = strtok(NULL, delim); /* is strtok() usable in 2007 ? */
|
||||
|
||||
if ( valeur != NULL )
|
||||
{
|
||||
if (flag)
|
||||
fprintf(stderr, "VALUE = [%s]\n", valeur);
|
||||
|
||||
switch(conf_vars[numtok].code)
|
||||
{
|
||||
case DO_NICE_BORDER:
|
||||
config.nice_border = atoi(valeur);
|
||||
break;
|
||||
|
||||
case DO_SHOW_8BITS:
|
||||
config.show_8bits = atoi(valeur);
|
||||
break;
|
||||
|
||||
case DO_LANGUAGE:
|
||||
#if TRACE
|
||||
fprintf(stderr, "lang=%s\n", valeur);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DO_OFFSET_HEX:
|
||||
config.offsets_in_hex = atoi(valeur);
|
||||
break;
|
||||
|
||||
case DO_EXT_FILEINFO:
|
||||
config.ext_fileinfo = atoi(valeur);
|
||||
break;
|
||||
|
||||
case DO_SHOW_HIDDEN:
|
||||
config.show_hidden = atoi(valeur);
|
||||
break;
|
||||
|
||||
case DO_FS_FLAG:
|
||||
break;
|
||||
|
||||
case DO_EXPLIQUE:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else /* valeur == NULL */
|
||||
{
|
||||
#if TRACE
|
||||
fprintf(stderr, "null value ?\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return 42; /* thx for all the fishes, Douglas */
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
352
Hexdiff/sel_file.c
Normal file
352
Hexdiff/sel_file.c
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
sel_file.c
|
||||
----------
|
||||
|
||||
old site --> http://tboudet.free.fr/hexdiff/
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
/* nasty hack */
|
||||
char *strdup(char *);
|
||||
/* end of hack */
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "hexdiff.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/* private vars of this module */
|
||||
|
||||
typedef struct {
|
||||
long taille;
|
||||
char *nom;
|
||||
int idx;
|
||||
} FICH;
|
||||
|
||||
static FICH *liste;
|
||||
static int taille; /* taille de la liste */
|
||||
static int nombre; /* nbre d'entrees dans la liste */
|
||||
|
||||
#define TCHONK 42
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static int teste_dirent(const struct dirent *de, struct stat *pstat)
|
||||
{
|
||||
int foo;
|
||||
|
||||
foo = stat(de->d_name, pstat);
|
||||
|
||||
if (S_ISDIR(pstat->st_mode))
|
||||
return 0;
|
||||
|
||||
if (config.show_hidden==0 && de->d_name[0]=='.')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
static int compare_nom_asc(const void *pa, const void *pb)
|
||||
{
|
||||
return strcmp( ((FICH *)pa)->nom, ((FICH *)pb)->nom);
|
||||
}
|
||||
static int compare_nom_desc(const void *pa, const void *pb)
|
||||
{
|
||||
return strcmp( ((FICH *)pb)->nom, ((FICH *)pa)->nom);
|
||||
}
|
||||
static int compare_taille_asc(const void *pa, const void *pb)
|
||||
{
|
||||
return ((FICH *)pa)->taille - ((FICH *)pb)->taille;
|
||||
}
|
||||
static int compare_taille_desc(const void *pa, const void *pb)
|
||||
{
|
||||
return ((FICH *)pb)->taille - ((FICH *)pa)->taille;
|
||||
}
|
||||
static int compare_idx(const void *pa, const void *pb)
|
||||
{
|
||||
return ((FICH *)pa)->idx - ((FICH *)pb)->idx;
|
||||
}
|
||||
#define PAR_NOM_ASC 1
|
||||
#define PAR_NOM_DESC 2
|
||||
#define PAR_TAILLE_ASC 3
|
||||
#define PAR_TAILLE_DESC 4
|
||||
#define PAR_IDX 5
|
||||
#define PAR_PLOP 6
|
||||
static int trier_la_liste(int comment)
|
||||
{
|
||||
switch (comment)
|
||||
{
|
||||
case PAR_NOM_ASC:
|
||||
qsort(liste, nombre, sizeof(FICH), compare_nom_asc);
|
||||
break;
|
||||
case PAR_NOM_DESC:
|
||||
qsort(liste, nombre, sizeof(FICH), compare_nom_desc);
|
||||
break;
|
||||
case PAR_TAILLE_ASC:
|
||||
qsort(liste, nombre, sizeof(FICH), compare_taille_asc);
|
||||
break;
|
||||
case PAR_TAILLE_DESC:
|
||||
qsort(liste, nombre, sizeof(FICH), compare_taille_desc);
|
||||
break;
|
||||
case PAR_IDX:
|
||||
qsort(liste, nombre, sizeof(FICH), compare_idx);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
static int liste_fichiers(WINDOW *win, int flag)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
struct stat statbuf;
|
||||
int foo;
|
||||
|
||||
/*
|
||||
* initializing local vars, for list-of-files
|
||||
*/
|
||||
if ( NULL == (liste = malloc(TCHONK*sizeof(FICH))) )
|
||||
{
|
||||
wprintw(win, "no mem for file list");
|
||||
wrefresh(win);
|
||||
return 1;
|
||||
}
|
||||
taille = TCHONK;
|
||||
|
||||
dir = opendir(".");
|
||||
if (dir == NULL)
|
||||
{
|
||||
wprintw(win, "error on 'opendir'");
|
||||
wrefresh(win);
|
||||
return 1;
|
||||
}
|
||||
|
||||
nombre = 0;
|
||||
while ( (de=readdir(dir)) != NULL)
|
||||
{
|
||||
if ( ! teste_dirent(de, &statbuf) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* strdup is a 'non-portable' function ? */
|
||||
liste[nombre].nom = strdup(de->d_name);
|
||||
liste[nombre].taille = statbuf.st_size;
|
||||
liste[nombre].idx = nombre;
|
||||
nombre++;
|
||||
wrefresh(win);
|
||||
|
||||
/*
|
||||
* if needed, increase the size of the list
|
||||
*/
|
||||
if (nombre >= taille)
|
||||
{
|
||||
liste = realloc(liste, sizeof(FICH)*(taille+TCHONK));
|
||||
taille += TCHONK;
|
||||
}
|
||||
}
|
||||
|
||||
foo = closedir(dir);
|
||||
|
||||
return nombre;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
char *txt_aide_fs[] =
|
||||
{
|
||||
"\n WARNING !\n\n",
|
||||
" this file selector is a 'quick and dirty' hack\n",
|
||||
" and code was written with a 'Spleyt' spirit :)\n\n",
|
||||
"\n",
|
||||
" smart keys are:\n\n",
|
||||
" a -> sort by name ascending\n",
|
||||
" A -> sort by name reversing\n",
|
||||
" s -> sort by size\n",
|
||||
" S -> sort reverse by size\n",
|
||||
" n -> no sort\n",
|
||||
"",
|
||||
"sort by date is a work in progress..."
|
||||
};
|
||||
int help_on_file_selector(WINDOW *win, int flag)
|
||||
{
|
||||
int foo;
|
||||
|
||||
werase(win);
|
||||
for (foo=0; foo<(sizeof(txt_aide_fs)/sizeof(char *)); foo++)
|
||||
{
|
||||
wprintw(win, txt_aide_fs[foo]);
|
||||
wrefresh(win);
|
||||
}
|
||||
foo = getch();
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
/*
|
||||
* new, 2005 June: now, we get the max usable length for *nomfich.
|
||||
*/
|
||||
int select_new_file(char *nomfich, int t_nom, int flags)
|
||||
{
|
||||
int ligmax, largmax, affh, idx = -1;
|
||||
WINDOW *fen_1, *fen_2;
|
||||
int foo, first, curseur, flag_exit, key;
|
||||
char chaine[T_NOM];
|
||||
|
||||
/*
|
||||
* quick'n'dirty security check, need more work.
|
||||
*/
|
||||
if (t_nom > T_NOM)
|
||||
{
|
||||
fprintf(stderr, "\n%s:%d possible buffer overflow\n", __FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ligmax = LINES-8; /* taille verticale de la popup */
|
||||
largmax = 62;
|
||||
|
||||
fen_1 = newwin(ligmax, largmax, 2, 12);
|
||||
bordure(fen_1); wrefresh(fen_1);
|
||||
|
||||
/*
|
||||
* first line of popup display active win number
|
||||
* and current win directory. as this time, we can't
|
||||
* select another directory ;-(
|
||||
*/
|
||||
wstandout(fen_1);
|
||||
for (foo=1; foo<largmax-1; foo++)
|
||||
{
|
||||
mvwaddch(fen_1, 1, foo, ' ');
|
||||
mvwaddch(fen_1, ligmax-2, foo, ' ');
|
||||
}
|
||||
/* XXX display the number of the active window
|
||||
XXX in this file selector.
|
||||
sprintf(chaine, "<%d>", fenetre_active);
|
||||
mvwaddstr(fen_1, 1, 2, chaine);
|
||||
*/
|
||||
|
||||
if (getcwd(chaine,99)!=NULL)
|
||||
mvwaddstr(fen_1, 1, 3, chaine);
|
||||
else
|
||||
mvwaddstr(fen_1, 1, 9, " can't get cwd, sorry... ");
|
||||
|
||||
mvwaddstr(fen_1, ligmax-2, 4, "'Q' to abort, <Enter> to select, '?' for help");
|
||||
wstandend(fen_1);
|
||||
wrefresh(fen_1);
|
||||
|
||||
/*
|
||||
* create a subwindow for the scrolling selector
|
||||
*/
|
||||
fen_2 = derwin(fen_1, ligmax-4, largmax-2, 2, 1);
|
||||
scrollok(fen_2, 1);
|
||||
|
||||
affh = ligmax-4; /* XXX need a valid value :) */
|
||||
|
||||
foo = liste_fichiers(fen_2, 0);
|
||||
#if TRACE
|
||||
wprintw(fen_2, "ret liste fichiers = %d\n", foo);
|
||||
wrefresh(fen_2);
|
||||
getch();
|
||||
#endif
|
||||
|
||||
trier_la_liste(PAR_NOM_ASC);
|
||||
|
||||
/*
|
||||
* now, the file list is built, so display the selector.
|
||||
*/
|
||||
first = curseur = 0;
|
||||
flag_exit = 0;
|
||||
|
||||
do
|
||||
{
|
||||
werase(fen_2);
|
||||
for (foo=0; foo<affh; foo++)
|
||||
{
|
||||
idx = foo+first;
|
||||
if (idx >= nombre)
|
||||
break;
|
||||
|
||||
if (curseur==foo) wstandout(fen_2);
|
||||
mvwprintw(fen_2, foo, 1, " %-46s %9ld ",
|
||||
liste[idx].nom, liste[idx].taille);
|
||||
if (curseur==foo) wstandend(fen_2);
|
||||
}
|
||||
wrefresh(fen_2);
|
||||
|
||||
#if TRACE
|
||||
mvwprintw(fen_1, 1, 2, "curs %3d first %3d ", curseur, first);
|
||||
wrefresh(fen_1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* user interaction
|
||||
*/
|
||||
key = getch();
|
||||
switch (key)
|
||||
{
|
||||
case KEY_UP:
|
||||
if (curseur) curseur--;
|
||||
else if (first>0) first--;
|
||||
break;
|
||||
|
||||
case KEY_DOWN:
|
||||
if ((curseur+first) >= (nombre-1)) break;
|
||||
|
||||
if (curseur < affh-1) curseur++;
|
||||
else if (first<(nombre-affh)) first++;
|
||||
break;
|
||||
|
||||
/* SORT operations */
|
||||
case 'a':
|
||||
trier_la_liste(PAR_NOM_ASC); break;
|
||||
case 'A':
|
||||
trier_la_liste(PAR_NOM_DESC); break;
|
||||
case 's':
|
||||
trier_la_liste(PAR_TAILLE_ASC); break;
|
||||
case 'S':
|
||||
trier_la_liste(PAR_TAILLE_DESC); break;
|
||||
|
||||
case '?':
|
||||
help_on_file_selector(fen_2, 0);
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
idx = curseur+first;
|
||||
flag_exit = 1;
|
||||
break;
|
||||
|
||||
case 'Q': flag_exit = -1; break;
|
||||
}
|
||||
} while ( ! flag_exit );
|
||||
|
||||
delwin(fen_1);
|
||||
|
||||
if (flag_exit == 1)
|
||||
{
|
||||
strcpy(nomfich, liste[idx].nom);
|
||||
}
|
||||
|
||||
/*
|
||||
* free the memory used by our list
|
||||
*/
|
||||
for (foo=0; foo<nombre; foo++)
|
||||
free(liste[foo].nom);
|
||||
free(liste);
|
||||
|
||||
return flag_exit==1;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int select_set_opt(int flg)
|
||||
{
|
||||
#if TRACE
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
Loading…
Reference in New Issue
Block a user