Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
f4e4082a
...
f4e4082ae1da285ec7abe072a945d606f2f79056
authored
2003-03-10 13:44:37 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
New file. Source for the sortm utility.
1 parent
1157f827
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
563 additions
and
0 deletions
mh/sortm.c
mh/sortm.c
0 → 100644
View file @
f4e4082
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003 Free Software Foundation, Inc.
GNU Mailutils 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, or (at your option)
any later version.
GNU Mailutils 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 GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* MH sortm command */
#include <mh.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
const
char
*
argp_program_version
=
"sortm ("
PACKAGE_STRING
")"
;
static
char
doc
[]
=
N_
(
"GNU MH sortm
\v
"
"Use -help to obtain the list of traditional MH options."
);
static
char
args_doc
[]
=
N_
(
"[msgs]"
);
#define ARG_QUICKSORT 1024
#define ARG_SHELL 1025
/* GNU options */
static
struct
argp_option
options
[]
=
{
{
"folder"
,
ARG_FOLDER
,
N_
(
"FOLDER"
),
0
,
N_
(
"Specify folder to operate upon"
)},
{
N_
(
"Setting sort keys:"
),
0
,
NULL
,
OPTION_DOC
,
NULL
,
0
},
{
"datefield"
,
ARG_DATEFIELD
,
N_
(
"STRING"
),
0
,
N_
(
"Sort on the date field (default `Date:')"
),
10
},
{
"nodatefield"
,
ARG_NODATEFIELD
,
NULL
,
0
,
N_
(
"Undo the effect of the last --datefield option"
),
10
},
{
"limit"
,
ARG_LIMIT
,
N_
(
"DAYS"
),
0
,
N_
(
"Consider two datefields equal if their difference lies within the given nuber of DAYS."
),
11
},
{
"nolimit"
,
ARG_NOLIMIT
,
NULL
,
0
,
N_
(
"Undo the effect of the last --limit option"
),
11
},
{
"textfield"
,
ARG_TEXTFIELD
,
N_
(
"STRING"
),
15
,
N_
(
"Sort on the text field"
),
1
},
{
"notextfield"
,
ARG_NOTEXTFIELD
,
NULL
,
0
,
N_
(
"Undo the effect of the last --textfield option"
),
15
},
{
"numfield"
,
ARG_NUMFIELD
,
N_
(
"STRING"
),
0
,
N_
(
"Sort on the numeric field"
),
16
},
{
N_
(
"Actions:"
),
0
,
NULL
,
OPTION_DOC
,
NULL
,
16
},
{
"reorder"
,
ARG_REORDER
,
0
,
0
,
N_
(
"Reorder the messages (default)"
),
20
},
{
"dry-run"
,
ARG_DRY_RUN
,
0
,
0
,
N_
(
"Do not do anything, only show what would have been done"
),
20
},
{
"list"
,
ARG_LIST
,
0
,
0
,
N_
(
"List the sorted messages"
),
20
},
{
"form"
,
ARG_FORM
,
N_
(
"FILE"
),
0
,
N_
(
"Read format from given file"
),
23
},
{
"format"
,
ARG_FORMAT
,
N_
(
"FORMAT"
),
0
,
N_
(
"Use this format string"
),
23
},
{
"verbose"
,
ARG_VERBOSE
,
N_
(
"BOOL"
),
OPTION_ARG_OPTIONAL
,
N_
(
"Verbosely list executed actions"
),
30
},
{
"noverbose"
,
ARG_NOVERBOSE
,
NULL
,
OPTION_HIDDEN
,
""
},
{
N_
(
"Select sort algorithm:"
),
0
,
NULL
,
OPTION_DOC
,
NULL
,
30
},
{
"shell"
,
ARG_SHELL
,
0
,
0
,
N_
(
"Use shell algorithm"
),
40
},
{
"quicksort"
,
ARG_QUICKSORT
,
0
,
0
,
N_
(
"Use quicksort algorithm (default)"
),
40
},
{
NULL
},
};
/* Traditional MH options */
struct
mh_option
mh_option
[]
=
{
{
"datefield"
,
1
,
0
,
"field"
},
{
"nodatefield"
,
3
,
0
,
0
},
{
"textfield"
,
1
,
0
,
"field"
},
{
"notextfield"
,
3
,
0
,
0
},
{
"limit"
,
1
,
0
,
"days"
},
{
"nolimit"
,
3
,
0
,
0
},
{
"verbose"
,
1
,
MH_OPT_BOOL
,
NULL
},
{
NULL
},
};
static
int
limit
;
static
int
verbose
;
static
mailbox_t
mbox
;
static
const
char
*
mbox_path
;
static
mh_msgset_t
msgset
;
#define ACTION_REORDER 0
#define ACTION_DRY_RUN 1
#define ACTION_LIST 2
static
int
algorithm
=
ARG_QUICKSORT
;
static
int
action
=
ACTION_REORDER
;
static
char
*
format_str
=
mh_list_format
;
static
mh_format_t
format
;
typedef
int
(
*
compfun
)
__PMT
((
void
*
,
void
*
));
static
void
addop
__P
((
char
*
field
,
compfun
comp
));
static
void
remop
__P
((
compfun
comp
));
static
int
comp_text
__P
((
void
*
a
,
void
*
b
));
static
int
comp_date
__P
((
void
*
a
,
void
*
b
));
static
int
comp_number
__P
((
void
*
a
,
void
*
b
));
static
int
opt_handler
(
int
key
,
char
*
arg
,
void
*
unused
,
struct
argp_state
*
state
)
{
switch
(
key
)
{
case
ARG_FOLDER
:
current_folder
=
arg
;
break
;
case
ARG_DATEFIELD
:
addop
(
arg
,
comp_date
);
break
;
case
ARG_NUMFIELD
:
addop
(
arg
,
comp_number
);
break
;
case
ARG_NODATEFIELD
:
remop
(
comp_date
);
break
;
case
ARG_TEXTFIELD
:
addop
(
arg
,
comp_text
);
break
;
case
ARG_NOTEXTFIELD
:
remop
(
comp_text
);
break
;
case
ARG_LIMIT
:
limit
=
strtoul
(
arg
,
NULL
,
0
);
break
;
case
ARG_NOLIMIT
:
limit
=
-
1
;
break
;
case
ARG_VERBOSE
:
if
(
!
arg
||
isalpha
(
arg
[
0
]))
verbose
=
is_true
(
arg
);
else
verbose
=
arg
[
0
]
-
'0'
;
break
;
case
ARG_NOVERBOSE
:
verbose
=
0
;
break
;
case
ARG_FORM
:
mh_read_formfile
(
arg
,
&
format_str
);
break
;
case
ARG_FORMAT
:
format_str
=
arg
;
break
;
case
ARG_REORDER
:
action
=
ACTION_REORDER
;
break
;
case
ARG_LIST
:
action
=
ACTION_LIST
;
break
;
case
ARG_DRY_RUN
:
action
=
ACTION_DRY_RUN
;
if
(
!
verbose
)
verbose
=
1
;
break
;
case
ARG_SHELL
:
case
ARG_QUICKSORT
:
algorithm
=
key
;
break
;
default:
return
1
;
}
return
0
;
}
/* *********************** Comparison functions **************************** */
struct
comp_op
{
char
*
field
;
compfun
comp
;
};
static
list_t
oplist
;
static
void
addop
(
char
*
field
,
compfun
comp
)
{
struct
comp_op
*
op
=
xmalloc
(
sizeof
(
*
op
));
if
(
!
oplist
&&
list_create
(
&
oplist
))
{
mh_error
(
_
(
"can't create operation list"
));
exit
(
1
);
}
op
->
field
=
field
;
op
->
comp
=
comp
;
list_append
(
oplist
,
op
);
}
struct
rem_data
{
struct
comp_op
*
op
;
compfun
comp
;
};
static
int
rem_action
(
void
*
item
,
void
*
data
)
{
struct
comp_op
*
op
=
item
;
struct
rem_data
*
d
=
data
;
if
(
d
->
comp
==
op
->
comp
)
d
->
op
=
op
;
return
0
;
}
static
void
remop
(
compfun
comp
)
{
struct
rem_data
d
;
d
.
comp
=
comp
;
d
.
op
=
NULL
;
list_do
(
oplist
,
rem_action
,
&
d
);
list_remove
(
oplist
,
d
.
op
);
free
(
d
.
op
);
}
struct
comp_data
{
int
r
;
message_t
m
[
2
];
};
static
int
compare_action
(
void
*
item
,
void
*
data
)
{
struct
comp_op
*
op
=
item
;
struct
comp_data
*
dp
=
data
;
char
*
a
,
*
ap
,
*
b
,
*
bp
;
header_t
h
;
if
(
message_get_header
(
dp
->
m
[
0
],
&
h
)
||
header_aget_value
(
h
,
op
->
field
,
&
a
))
return
0
;
if
(
message_get_header
(
dp
->
m
[
1
],
&
h
)
||
header_aget_value
(
h
,
op
->
field
,
&
b
))
{
free
(
a
);
return
0
;
}
ap
=
a
;
bp
=
b
;
if
(
strcasecmp
(
op
->
field
,
MU_HEADER_SUBJECT
)
==
0
)
{
if
(
strncasecmp
(
ap
,
"re:"
,
3
)
==
0
)
ap
+=
3
;
if
(
strncasecmp
(
b
,
"re:"
,
3
)
==
0
)
bp
+=
3
;
}
dp
->
r
=
op
->
comp
(
ap
,
bp
);
free
(
a
);
free
(
b
);
return
dp
->
r
;
/* go on until the difference is found */
}
static
int
compare_messages
(
message_t
a
,
message_t
b
)
{
struct
comp_data
d
;
d
.
r
=
0
;
d
.
m
[
0
]
=
a
;
d
.
m
[
1
]
=
b
;
list_do
(
oplist
,
compare_action
,
&
d
);
if
(
verbose
>
1
)
fprintf
(
stderr
,
"%d
\n
"
,
d
.
r
);
return
d
.
r
;
}
static
int
comp_text
(
void
*
a
,
void
*
b
)
{
return
strcasecmp
(
a
,
b
);
}
static
int
comp_number
(
void
*
a
,
void
*
b
)
{
long
na
,
nb
;
na
=
strtol
(
a
,
NULL
,
0
);
nb
=
strtol
(
b
,
NULL
,
0
);
if
(
na
>
nb
)
return
1
;
else
if
(
na
<
nb
)
return
-
1
;
return
0
;
}
/*FIXME: Also used in imap4d*/
static
int
_parse_822_date
(
char
*
date
,
time_t
*
timep
)
{
struct
tm
tm
;
mu_timezone
tz
;
const
char
*
p
=
date
;
if
(
parse822_date_time
(
&
p
,
date
+
strlen
(
date
),
&
tm
,
&
tz
)
==
0
)
{
*
timep
=
mu_tm2time
(
&
tm
,
&
tz
);
return
0
;
}
return
1
;
}
static
int
comp_date
(
void
*
a
,
void
*
b
)
{
time_t
ta
,
tb
;
if
(
_parse_822_date
(
a
,
&
ta
)
||
_parse_822_date
(
b
,
&
tb
))
return
0
;
if
(
ta
<
tb
)
{
if
(
limit
&&
tb
-
ta
<=
limit
)
return
0
;
return
-
1
;
}
else
if
(
ta
>
tb
)
{
if
(
limit
&&
ta
-
tb
<=
limit
)
return
0
;
return
1
;
}
return
0
;
}
/* *********************** Sorting routines ***************************** */
static
int
comp0
(
size_t
na
,
size_t
nb
)
{
message_t
a
,
b
;
if
(
mailbox_get_message
(
mbox
,
na
,
&
a
)
||
mailbox_get_message
(
mbox
,
nb
,
&
b
))
return
0
;
if
(
verbose
>
1
)
fprintf
(
stderr
,
_
(
"comparing messages %lu and %lu: "
),
(
unsigned
long
)
na
,
(
unsigned
long
)
nb
);
return
compare_messages
(
a
,
b
);
}
int
comp
(
const
void
*
a
,
const
void
*
b
)
{
return
comp0
(
*
(
size_t
*
)
a
,
*
(
size_t
*
)
b
);
}
/* ****************************** Shell sort ****************************** */
#define prevdst(h) ((h)-1)/3
static
int
startdst
(
unsigned
count
,
int
*
num
)
{
int
i
,
h
;
for
(
i
=
h
=
1
;
9
*
h
+
4
<
count
;
i
++
,
h
=
3
*
h
+
1
)
;
*
num
=
i
;
return
h
;
}
void
shell_sort
()
{
int
h
,
s
,
i
,
j
;
size_t
hold
;
for
(
h
=
startdst
(
msgset
.
count
,
&
s
);
s
>
0
;
s
--
,
h
=
prevdst
(
h
))
{
if
(
verbose
>
1
)
fprintf
(
stderr
,
_
(
"distance %d
\n
"
),
h
);
for
(
j
=
h
;
j
<
msgset
.
count
;
j
++
)
{
hold
=
msgset
.
list
[
j
];
for
(
i
=
j
-
h
;
i
>=
0
&&
comp0
(
hold
,
msgset
.
list
[
i
])
<
0
;
i
-=
h
)
msgset
.
list
[
i
+
h
]
=
msgset
.
list
[
i
];
msgset
.
list
[
i
+
h
]
=
hold
;
}
}
}
/* ****************************** Actions ********************************* */
void
list_message
(
size_t
num
)
{
message_t
msg
=
NULL
;
char
*
buffer
;
mailbox_get_message
(
mbox
,
num
,
&
msg
);
mh_format
(
&
format
,
msg
,
num
,
76
,
&
buffer
);
printf
(
"%s
\n
"
,
buffer
);
free
(
buffer
);
}
void
swap_message
(
size_t
a
,
size_t
b
)
{
char
*
path_a
,
*
path_b
;
char
*
tmp
;
asprintf
(
&
path_a
,
"%s/%lu"
,
mbox_path
,
(
unsigned
long
)
a
);
asprintf
(
&
path_b
,
"%s/%lu"
,
mbox_path
,
(
unsigned
long
)
b
);
tmp
=
mu_tempname
(
mbox_path
);
rename
(
path_a
,
tmp
);
unlink
(
path_a
);
rename
(
path_b
,
path_a
);
unlink
(
path_b
);
rename
(
tmp
,
path_b
);
free
(
tmp
);
}
void
transpose
(
size_t
i
,
size_t
n
)
{
size_t
j
;
for
(
j
=
i
+
1
;
j
<
msgset
.
count
;
j
++
)
if
(
msgset
.
list
[
j
]
==
n
)
{
size_t
t
=
msgset
.
list
[
i
];
msgset
.
list
[
i
]
=
msgset
.
list
[
j
];
msgset
.
list
[
j
]
=
t
;
break
;
}
}
static
int
got_signal
;
RETSIGTYPE
sighandler
(
int
sig
)
{
got_signal
=
1
;
}
void
sort
()
{
size_t
*
oldlist
,
i
;
oldlist
=
xmalloc
(
msgset
.
count
*
sizeof
(
*
oldlist
));
memcpy
(
oldlist
,
msgset
.
list
,
msgset
.
count
*
sizeof
(
*
oldlist
));
switch
(
algorithm
)
{
case
ARG_QUICKSORT
:
qsort
(
msgset
.
list
,
msgset
.
count
,
sizeof
(
msgset
.
list
[
0
]),
comp
);
break
;
case
ARG_SHELL
:
shell_sort
();
break
;
}
switch
(
action
)
{
case
ACTION_LIST
:
for
(
i
=
0
;
i
<
msgset
.
count
;
i
++
)
list_message
(
msgset
.
list
[
i
]);
break
;
default:
/* Install signal handlers */
signal
(
SIGINT
,
sighandler
);
signal
(
SIGQUIT
,
sighandler
);
signal
(
SIGTERM
,
sighandler
);
if
(
verbose
)
fprintf
(
stderr
,
_
(
"Transpositions:
\n
"
));
for
(
i
=
0
,
got_signal
=
0
;
!
got_signal
&&
i
<
msgset
.
count
;
i
++
)
{
if
(
msgset
.
list
[
i
]
!=
oldlist
[
i
])
{
size_t
old_num
,
new_num
;
message_t
msg
;
mailbox_get_message
(
mbox
,
oldlist
[
i
],
&
msg
);
mh_message_number
(
msg
,
&
old_num
);
mailbox_get_message
(
mbox
,
msgset
.
list
[
i
],
&
msg
);
mh_message_number
(
msg
,
&
new_num
);
transpose
(
i
,
oldlist
[
i
]);
if
(
verbose
)
fprintf
(
stderr
,
"{%lu, %lu}
\n
"
,
(
unsigned
long
)
old_num
,
(
unsigned
long
)
new_num
);
if
(
action
==
ACTION_REORDER
)
swap_message
(
old_num
,
new_num
);
}
}
}
}
/* Main */
int
main
(
int
argc
,
char
**
argv
)
{
int
index
;
url_t
url
;
mu_init_nls
();
mh_argp_parse
(
argc
,
argv
,
0
,
options
,
mh_option
,
args_doc
,
doc
,
opt_handler
,
NULL
,
&
index
);
if
(
!
oplist
)
addop
(
"date"
,
comp_date
);
if
(
action
==
ACTION_LIST
&&
mh_format_parse
(
format_str
,
&
format
))
{
mh_error
(
_
(
"Bad format string"
));
exit
(
1
);
}
mbox
=
mh_open_folder
(
current_folder
,
0
);
mailbox_get_url
(
mbox
,
&
url
);
mbox_path
=
url_to_string
(
url
);
if
(
memcmp
(
mbox_path
,
"mh:"
,
3
)
==
0
)
mbox_path
+=
3
;
argc
-=
index
;
argv
+=
index
;
mh_msgset_parse
(
mbox
,
&
msgset
,
argc
,
argv
,
"all"
);
sort
(
mbox
,
msgset
);
return
0
;
}
Please
register
or
sign in
to post a comment