Merge branch 'jc/mailinfo' into next

* jc/mailinfo:
  mailinfo: skip bogus UNIX From line inside body
  tutorial-2: typofix in examples.
  tutorial: add discussion of index file, object database
  tutorial: expanded discussion of commit history
  tutorial: replace "whatchanged" by "log"
  NO_INET_NTOP and compat/inet_ntop.c for some systems (e.g. old Cygwin).
  remove superflous "const"
  checkdiff_consume: strtol parameter fix.
  Elaborate on why ':' is a bad idea in a ref name.
  Reference git-check-ref-format in git-branch.
This commit is contained in:
Junio C Hamano 2006-05-21 17:37:54 -07:00
commit 7b8e4ab07c
11 changed files with 755 additions and 70 deletions

View File

@ -7,6 +7,7 @@ MAN7_TXT=git.txt
DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT)) DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT))
ARTICLES = tutorial ARTICLES = tutorial
ARTICLES += tutorial-2
ARTICLES += core-tutorial ARTICLES += core-tutorial
ARTICLES += cvs-migration ARTICLES += cvs-migration
ARTICLES += diffcore ARTICLES += diffcore

View File

@ -43,6 +43,9 @@ OPTIONS
<branchname>:: <branchname>::
The name of the branch to create or delete. The name of the branch to create or delete.
The new branch name must pass all checks defined by
gitlink:git-check-ref-format[1]. Some of these checks
may restrict the characters allowed in a branch name.
<start-point>:: <start-point>::
The new branch will be created with a HEAD equal to this. It may The new branch will be created with a HEAD equal to this. It may

View File

@ -45,6 +45,8 @@ refname expressions (see gitlink:git-rev-parse[1]). Namely:
. colon `:` is used as in `srcref:dstref` to mean "use srcref\'s . colon `:` is used as in `srcref:dstref` to mean "use srcref\'s
value and store it in dstref" in fetch and push operations. value and store it in dstref" in fetch and push operations.
It may also be used to select a specific object such as with
gitlink:git-cat-file[1] "git-cat-file blob v1.3.3:refs.c".
GIT GIT

View File

@ -35,7 +35,10 @@ OPTIONS
Force a re-read of everything. Force a re-read of everything.
-b:: -b::
Create a new branch and start it at <branch>. Create a new branch named <new_branch> and start it at
<branch>. The new branch name must pass all checks defined
by gitlink:git-check-ref-format[1]. Some of these checks
may restrict the characters allowed in a branch name.
-m:: -m::
If you have local modifications to one or more files that If you have local modifications to one or more files that

View File

@ -0,0 +1,391 @@
A tutorial introduction to git: part two
========================================
You should work through link:tutorial.html[A tutorial introduction to
git] before reading this tutorial.
The goal of this tutorial is to introduce two fundamental pieces of
git's architecture--the object database and the index file--and to
provide the reader with everything necessary to understand the rest
of the git documentation.
The git object database
-----------------------
Let's start a new project and create a small amount of history:
------------------------------------------------
$ mkdir test-project
$ cd test-project
$ git init-db
defaulting to local storage area
$ echo 'hello world' > file.txt
$ git add .
$ git commit -a -m "initial commit"
Committing initial tree 92b8b694ffb1675e5975148e1121810081dbdffe
$ echo 'hello world!' >file.txt
$ git commit -a -m "add emphasis"
------------------------------------------------
What are the 40 digits of hex that git responded to the first commit
with?
We saw in part one of the tutorial that commits have names like this.
It turns out that every object in the git history is stored under
such a 40-digit hex name. That name is the SHA1 hash of the object's
contents; among other things, this ensures that git will never store
the same data twice (since identical data is given an identical SHA1
name), and that the contents of a git object will never change (since
that would change the object's name as well).
We can ask git about this particular object with the cat-file
command--just cut-and-paste from the reply to the initial commit, to
save yourself typing all 40 hex digits:
------------------------------------------------
$ git cat-file -t 92b8b694ffb1675e5975148e1121810081dbdffe
tree
------------------------------------------------
A tree can refer to one or more "blob" objects, each corresponding to
a file. In addition, a tree can also refer to other tree objects,
thus creating a directory heirarchy. You can examine the contents of
any tree using ls-tree (remember that a long enough initial portion
of the SHA1 will also work):
------------------------------------------------
$ git ls-tree 92b8b694
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad file.txt
------------------------------------------------
Thus we see that this tree has one file in it. The SHA1 hash is a
reference to that file's data:
------------------------------------------------
$ git cat-file -t 3b18e512
blob
------------------------------------------------
A "blob" is just file data, which we can also examine with cat-file:
------------------------------------------------
$ git cat-file blob 3b18e512
hello world
------------------------------------------------
Note that this is the old file data; so the object that git named in
its response to the initial tree was a tree with a snapshot of the
directory state that was recorded by the first commit.
All of these objects are stored under their SHA1 names inside the git
directory:
------------------------------------------------
$ find .git/objects/
.git/objects/
.git/objects/pack
.git/objects/info
.git/objects/3b
.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
.git/objects/92
.git/objects/92/b8b694ffb1675e5975148e1121810081dbdffe
.git/objects/54
.git/objects/54/196cc2703dc165cbd373a65a4dcf22d50ae7f7
.git/objects/a0
.git/objects/a0/423896973644771497bdc03eb99d5281615b51
.git/objects/d0
.git/objects/d0/492b368b66bdabf2ac1fd8c92b39d3db916e59
.git/objects/c4
.git/objects/c4/d59f390b9cfd4318117afde11d601c1085f241
------------------------------------------------
and the contents of these files is just the compressed data plus a
header identifying their length and their type. The type is either a
blob, a tree, a commit, or a tag. We've seen a blob and a tree now,
so next we should look at a commit.
The simplest commit to find is the HEAD commit, which we can find
from .git/HEAD:
------------------------------------------------
$ cat .git/HEAD
ref: refs/heads/master
------------------------------------------------
As you can see, this tells us which branch we're currently on, and it
tells us this by naming a file under the .git directory, which itself
contains a SHA1 name referring to a commit object, which we can
examine with cat-file:
------------------------------------------------
$ cat .git/refs/heads/master
c4d59f390b9cfd4318117afde11d601c1085f241
$ git cat-file -t c4d59f39
commit
$ git cat-file commit c4d59f39
tree d0492b368b66bdabf2ac1fd8c92b39d3db916e59
parent 54196cc2703dc165cbd373a65a4dcf22d50ae7f7
author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500
committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500
add emphasis
------------------------------------------------
The "tree" object here refers to the new state of the tree:
------------------------------------------------
$ git ls-tree d0492b36
100644 blob a0423896973644771497bdc03eb99d5281615b51 file.txt
$ git cat-file commit a0423896
hello world!
------------------------------------------------
and the "parent" object refers to the previous commit:
------------------------------------------------
$ git-cat-file commit 54196cc2
tree 92b8b694ffb1675e5975148e1121810081dbdffe
author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500
committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500
initial commit
------------------------------------------------
The tree object is the tree we examined first, and this commit is
unusual in that it lacks any parent.
Most commits have only one parent, but it is also common for a commit
to have multiple parents. In that case the commit represents a
merge, with the parent references pointing to the heads of the merged
branches.
Besides blobs, trees, and commits, the only remaining type of object
is a "tag", which we won't discuss here; refer to gitlink:git-tag[1]
for details.
So now we know how git uses the object database to represent a
project's history:
* "commit" objects refer to "tree" objects representing the
snapshot of a directory tree at a particular point in the
history, and refer to "parent" commits to show how they're
connected into the project history.
* "tree" objects represent the state of a single directory,
associating directory names to "blob" objects containing file
data and "tree" objects containing subdirectory information.
* "blob" objects contain file data without any other structure.
* References to commit objects at the head of each branch are
stored in files under .git/refs/heads/.
* The name of the current branch is stored in .git/HEAD.
Note, by the way, that lots of commands take a tree as an argument.
But as we can see above, a tree can be referred to in many different
ways--by the SHA1 name for that tree, by the name of a commit that
refers to the tree, by the name of a branch whose head refers to that
tree, etc.--and most such commands can accept any of these names.
In command synopses, the word "tree-ish" is sometimes used to
designate such an argument.
The index file
--------------
The primary tool we've been using to create commits is "git commit
-a", which creates a commit including every change you've made to
your working tree. But what if you want to commit changes only to
certain files? Or only certain changes to certain files?
If we look at the way commits are created under the cover, we'll see
that there are more flexible ways creating commits.
Continuing with our test-project, let's modify file.txt again:
------------------------------------------------
$ echo "hello world, again" >>file.txt
------------------------------------------------
but this time instead of immediately making the commit, let's take an
intermediate step, and ask for diffs along the way to keep track of
what's happening:
------------------------------------------------
$ git diff
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
hello world!
+hello world, again
$ git update-index file.txt
$ git diff
------------------------------------------------
The last diff is empty, but no new commits have been made, and the
head still doesn't contain the new line:
------------------------------------------------
$ git-diff HEAD
diff --git a/file.txt b/file.txt
index a042389..513feba 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
hello world!
+hello world, again
------------------------------------------------
So "git diff" is comparing against something other than the head.
The thing that it's comparing against is actually the index file,
which is stored in .git/index in a binary format, but whose contents
we can examine with ls-files:
------------------------------------------------
$ git ls-files --stage
100644 513feba2e53ebbd2532419ded848ba19de88ba00 0 file.txt
$ git cat-file -t 513feba2
blob
$ git cat-file blob 513feba2
hello world, again
------------------------------------------------
So what our "git update-index" did was store a new blob and then put
a reference to it in the index file. If we modify the file again,
we'll see that the new modifications are reflected in the "git-diff"
output:
------------------------------------------------
$ echo 'again?' >>file.txt
$ git diff
index 513feba..ba3da7b 100644
--- a/file.txt
+++ b/file.txt
@@ -1,2 +1,3 @@
hello world!
hello world, again
+again?
------------------------------------------------
With the right arguments, git diff can also show us the difference
between the working directory and the last commit, or between the
index and the last commit:
------------------------------------------------
$ git diff HEAD
diff --git a/file.txt b/file.txt
index a042389..ba3da7b 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,3 @@
hello world!
+hello world, again
+again?
$ git diff --cached
diff --git a/file.txt b/file.txt
index a042389..513feba 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
hello world!
+hello world, again
------------------------------------------------
At any time, we can create a new commit using "git commit" (without
the -a option), and verify that the state committed only includes the
changes stored in the index file, not the additional change that is
still only in our working tree:
------------------------------------------------
$ git commit -m "repeat"
$ git diff HEAD
diff --git a/file.txt b/file.txt
index 513feba..ba3da7b 100644
--- a/file.txt
+++ b/file.txt
@@ -1,2 +1,3 @@
hello world!
hello world, again
+again?
------------------------------------------------
So by default "git commit" uses the index to create the commit, not
the working tree; the -a option to commit tells it to first update
the index with all changes in the working tree.
Finally, it's worth looking at the effect of "git add" on the index
file:
------------------------------------------------
$ echo "goodbye, world" >closing.txt
$ git add closing.txt
------------------------------------------------
The effect of the "git add" was to add one entry to the index file:
------------------------------------------------
$ git ls-files --stage
100644 8b9743b20d4b15be3955fc8d5cd2b09cd2336138 0 closing.txt
100644 513feba2e53ebbd2532419ded848ba19de88ba00 0 file.txt
------------------------------------------------
And, as you can see with cat-file, this new entry refers to the
current contents of the file:
------------------------------------------------
$ git cat-file blob a6b11f7a
goodbye, word
------------------------------------------------
The "status" command is a useful way to get a quick summary of the
situation:
------------------------------------------------
$ git status
#
# Updated but not checked in:
# (will commit)
#
# new file: closing.txt
#
#
# Changed but not updated:
# (use git-update-index to mark for commit)
#
# modified: file.txt
#
------------------------------------------------
Since the current state of closing.txt is cached in the index file,
it is listed as "updated but not checked in". Since file.txt has
changes in the working directory that aren't reflected in the index,
it is marked "changed but not updated". At this point, running "git
commit" would create a commit that added closing.txt (with its new
contents), but that didn't modify file.txt.
Also, note that a bare "git diff" shows the changes to file.txt, but
not the addition of closing.txt, because the version of closing.txt
in the index file is identical to the one in the working directory.
In addition to being the staging area for new commits, the index file
is also populated from the object database when checking out a
branch, and is used to hold the trees involved in a merge operation.
See the link:core-tutorial.txt[core tutorial] and the relevant man
pages for details.
What next?
----------
At this point you should know everything necessary to read the man
pages for any of the git commands; one good place to start would be
with the commands mentioned in link:everday.html[Everyday git]. You
should be able to find any unknown jargon in the
link:glossary.html[Glosssay].
The link:cvs-migration.html[CVS migration] document explains how to
import a CVS repository into git, and shows how to use git in a
CVS-like way.
For some interesting examples of git use, see the
link:howto-index.html[howtos].
For git developers, the link:core-tutorial.html[Core tutorial] goes
into detail on the lower-level git mechanisms involved in, for
example, creating a new commit.

View File

@ -80,13 +80,13 @@ file; just remove it, then commit.
At any point you can view the history of your changes using At any point you can view the history of your changes using
------------------------------------------------ ------------------------------------------------
$ git whatchanged $ git log
------------------------------------------------ ------------------------------------------------
If you also want to see complete diffs at each step, use If you also want to see complete diffs at each step, use
------------------------------------------------ ------------------------------------------------
$ git whatchanged -p $ git log -p
------------------------------------------------ ------------------------------------------------
Managing branches Managing branches
@ -216,7 +216,7 @@ This actually pulls changes from the branch in Bob's repository named
"master". Alice could request a different branch by adding the name "master". Alice could request a different branch by adding the name
of the branch to the end of the git pull command line. of the branch to the end of the git pull command line.
This merges Bob's changes into her repository; "git whatchanged" will This merges Bob's changes into her repository; "git log" will
now show the new commits. If Alice has made her own changes in the now show the new commits. If Alice has made her own changes in the
meantime, then Bob's changes will be merged in, and she will need to meantime, then Bob's changes will be merged in, and she will need to
manually fix any conflicts. manually fix any conflicts.
@ -234,7 +234,7 @@ named bob-incoming. (Unlike git pull, git fetch just fetches a copy
of Bob's line of development without doing any merging). Then of Bob's line of development without doing any merging). Then
------------------------------------- -------------------------------------
$ git whatchanged -p master..bob-incoming $ git log -p master..bob-incoming
------------------------------------- -------------------------------------
shows a list of all the changes that Bob made since he branched from shows a list of all the changes that Bob made since he branched from
@ -288,102 +288,179 @@ Git can also be used in a CVS-like mode, with a central repository
that various users push changes to; see gitlink:git-push[1] and that various users push changes to; see gitlink:git-push[1] and
link:cvs-migration.html[git for CVS users]. link:cvs-migration.html[git for CVS users].
Keeping track of history Exploring history
------------------------ -----------------
Git history is represented as a series of interrelated commits. The Git history is represented as a series of interrelated commits. We
most recent commit in the currently checked-out branch can always be have already seen that the git log command can list those commits.
referred to as HEAD, and the "parent" of any commit can always be Note that first line of each git log entry also gives a name for the
referred to by appending a caret, "^", to the end of the name of the commit:
commit. So, for example,
------------------------------------- -------------------------------------
git diff HEAD^ HEAD $ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date: Tue May 16 17:18:22 2006 -0700
merge-base: Clarify the comments on post processing.
------------------------------------- -------------------------------------
shows the difference between the most-recently checked-in state of We can give this name to git show to see the details about this
the tree and the previous state, and commit.
------------------------------------- -------------------------------------
git diff HEAD^^ HEAD^ $ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
------------------------------------- -------------------------------------
shows the difference between that previous state and the state two But there other ways to refer to commits. You can use any initial
commits ago. Also, HEAD~5 can be used as a shorthand for HEAD{caret}{caret}{caret}{caret}{caret}, part of the name that is long enough to uniquely identify the commit:
and more generally HEAD~n can refer to the nth previous commit.
Commits representing merges have more than one parent, and you can
specify which parent to follow in that case; see
gitlink:git-rev-parse[1].
The name of a branch can also be used to refer to the most recent
commit on that branch; so you can also say things like
------------------------------------- -------------------------------------
git diff HEAD experimental $ git show c82a22c39c # the first few characters of the name are
# usually enough
$ git show HEAD # the tip of the current branch
$ git show experimental # the tip of the "experimental" branch
------------------------------------- -------------------------------------
to see the difference between the most-recently committed tree in Every commit has at least one "parent" commit, which points to the
the current branch and the most-recently committed tree in the previous state of the project:
experimental branch.
But you may find it more useful to see the list of commits made in
the experimental branch but not in the current branch, and
------------------------------------- -------------------------------------
git whatchanged HEAD..experimental $ git show HEAD^ # to see the parent of HEAD
$ git show HEAD^^ # to see the grandparent of HEAD
$ git show HEAD~4 # to see the great-great grandparent of HEAD
------------------------------------- -------------------------------------
will do that, just as Note that merge commits may have more than one parent:
------------------------------------- -------------------------------------
git whatchanged experimental..HEAD $ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
$ git show HEAD^2 # show the second parent of HEAD
------------------------------------- -------------------------------------
will show the list of commits made on the HEAD but not included in You can also give commits names of your own; after running
experimental.
You can also give commits convenient names of your own: after running
------------------------------------- -------------------------------------
$ git-tag v2.5 HEAD^^ $ git-tag v2.5 1b2e1d63ff
------------------------------------- -------------------------------------
you can refer to HEAD^^ by the name "v2.5". If you intend to share you can refer to 1b2e1d63ff by the name "v2.5". If you intend to
this name with other people (for example, to identify a release share this name with other people (for example, to identify a release
version), you should create a "tag" object, and perhaps sign it; see version), you should create a "tag" object, and perhaps sign it; see
gitlink:git-tag[1] for details. gitlink:git-tag[1] for details.
You can revisit the old state of a tree, and make further Any git command that needs to know a commit can take any of these
modifications if you wish, using git branch: the command names. For example:
------------------------------------- -------------------------------------
$ git branch stable-release v2.5 $ git diff v2.5 HEAD # compare the current HEAD to v2.5
$ git branch stable v2.5 # start a new branch named "stable" based
# at v2.5
$ git reset --hard HEAD^ # reset your current branch and working
# directory its state at HEAD^
------------------------------------- -------------------------------------
will create a new branch named "stable-release" starting from the Be careful with that last command: in addition to losing any changes
commit which you tagged with the name v2.5. in the working directory, it will also remove all later commits from
this branch. If this branch is the only branch containing those
You can reset the state of any branch to an earlier commit at any commits, they will be lost. (Also, don't use "git reset" on a
time with
-------------------------------------
$ git reset --hard v2.5
-------------------------------------
This will remove all later commits from this branch and reset the
working tree to the state it had when the given commit was made. If
this branch is the only branch containing the later commits, those
later changes will be lost. Don't use "git reset" on a
publicly-visible branch that other developers pull from, as git will publicly-visible branch that other developers pull from, as git will
be confused by history that disappears in this way. be confused by history that disappears in this way.)
The git grep command can search for strings in any version of your
project, so
-------------------------------------
$ git grep "hello" v2.5
-------------------------------------
searches for all occurences of "hello" in v2.5.
If you leave out the commit name, git grep will search any of the
files it manages in your current directory. So
-------------------------------------
$ git grep "hello"
-------------------------------------
is a quick way to search just the files that are tracked by git.
Many git commands also take sets of commits, which can be specified
in a number of ways. Here are some examples with git log:
-------------------------------------
$ git log v2.5..v2.6 # commits between v2.5 and v2.6
$ git log v2.5.. # commits since v2.5
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log v2.5.. Makefile # commits since v2.5 which modify
# Makefile
-------------------------------------
You can also give git log a "range" of commits where the first is not
necessarily an ancestor of the second; for example, if the tips of
the branches "stable-release" and "master" diverged from a common
commit some time ago, then
-------------------------------------
$ git log stable..experimental
-------------------------------------
will list commits made in the experimental branch but not in the
stable branch, while
-------------------------------------
$ git log experimental..stable
-------------------------------------
will show the list of commits made on the stable branch but not
the experimental branch.
The "git log" command has a weakness: it must present commits in a
list. When the history has lines of development that diverged and
then merged back together, the order in which "git log" presents
those commits is meaningless.
Most projects with multiple contributors (such as the linux kernel,
or git itself) have frequent merges, and gitk does a better job of
visualizing their history. For example,
-------------------------------------
$ gitk --since="2 weeks ago" drivers/
-------------------------------------
allows you to browse any commits from the last 2 weeks of commits
that modified files under the "drivers" directory.
Finally, most commands that take filenames will optionally allow you
to precede any filename by a commit, to specify a particular version
fo the file:
-------------------------------------
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------
Next Steps Next Steps
---------- ----------
Some good commands to explore next: This tutorial should be enough to perform basic distributed revision
control for your projects. However, to fully understand the depth
and power of git you need to understand two simple ideas on which it
is based:
* gitlink:git-diff[1]: This flexible command does much more than * The object database is the rather elegant system used to
we've seen in the few examples above. store the history of your project--files, directories, and
commits.
* The index file is a cache of the state of a directory tree,
used to create commits, check out working directories, and
hold the various trees involved in a merge.
link:tutorial-2.html[Part two of this tutorial] explains the object
database, the index file, and a few other odds and ends that you'll
need to make the most of git.
If you don't want to consider with that right away, a few other
digressions that may be interesting at this point are:
* gitlink:git-format-patch[1], gitlink:git-am[1]: These convert * gitlink:git-format-patch[1], gitlink:git-am[1]: These convert
series of git commits into emailed patches, and vice versa, series of git commits into emailed patches, and vice versa,
@ -397,8 +474,6 @@ Some good commands to explore next:
smart enough to perform a close-to-optimal search even in the smart enough to perform a close-to-optimal search even in the
case of complex non-linear history with lots of merged branches. case of complex non-linear history with lots of merged branches.
Other good starting points include link:everyday.html[Everday GIT * link:everyday.html[Everday GIT with 20 Commands Or So]
with 20 Commands Or So] and link:cvs-migration.html[git for CVS
users]. Also, link:core-tutorial.html[A short git tutorial] gives an * link:cvs-migration.html[git for CVS users].
introduction to lower-level git commands for advanced users and
developers.

View File

@ -421,6 +421,9 @@ else
ALL_CFLAGS += -Dsockaddr_storage=sockaddr_in6 ALL_CFLAGS += -Dsockaddr_storage=sockaddr_in6
endif endif
endif endif
ifdef NO_INET_NTOP
LIB_OBJS += compat/inet_ntop.o
endif
ifdef NO_ICONV ifdef NO_ICONV
ALL_CFLAGS += -DNO_ICONV ALL_CFLAGS += -DNO_ICONV

View File

@ -518,7 +518,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
argc = nr; argc = nr;
for (i = 0; i < active_nr; i++) { for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i]; struct cache_entry *ce = active_cache[i];
const char *name; char *name;
if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode))) if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
continue; continue;
if (!pathspec_matches(paths, ce->name)) if (!pathspec_matches(paths, ce->name))

200
compat/inet_ntop.c Normal file
View File

@ -0,0 +1,200 @@
/*
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#ifndef NS_INADDRSZ
#define NS_INADDRSZ 4
#endif
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ 16
#endif
#ifndef NS_INT16SZ
#define NS_INT16SZ 2
#endif
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
/* const char *
* inet_ntop4(src, dst, size)
* format an IPv4 address
* return:
* `dst' (as a const)
* notes:
* (1) uses no statics
* (2) takes a u_char* not an in_addr as input
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop4(src, dst, size)
const u_char *src;
char *dst;
size_t size;
{
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
int nprinted;
nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
if (nprinted < 0)
return (NULL); /* we assume "errno" was set by "snprintf()" */
if ((size_t)nprinted > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
#ifndef NO_IPV6
/* const char *
* inet_ntop6(src, dst, size)
* convert IPv6 binary address into presentation (printable) format
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop6(src, dst, size)
const u_char *src;
char *dst;
size_t size;
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < NS_IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
cur.base = -1;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
return (NULL);
tp += strlen(tp);
break;
}
tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
(NS_IN6ADDRSZ / NS_INT16SZ))
*tp++ = ':';
*tp++ = '\0';
/*
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
#endif
/* char *
* inet_ntop(af, src, dst, size)
* convert a network format address to presentation format.
* return:
* pointer to presentation format address (`dst'), or NULL (see errno).
* author:
* Paul Vixie, 1996.
*/
const char *
inet_ntop(af, src, dst, size)
int af;
const void *src;
char *dst;
size_t size;
{
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
#ifndef NO_IPV6
case AF_INET6:
return (inet_ntop6(src, dst, size));
#endif
default:
errno = EAFNOSUPPORT;
return (NULL);
}
/* NOTREACHED */
}

2
diff.c
View File

@ -432,7 +432,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
else if (line[0] == '@') { else if (line[0] == '@') {
char *plus = strchr(line, '+'); char *plus = strchr(line, '+');
if (plus) if (plus)
data->lineno = strtol(plus, line + len, 10); data->lineno = strtol(plus, NULL, 10);
else else
die("invalid diff"); die("invalid diff");
} }

View File

@ -237,10 +237,17 @@ static int eatspace(char *line)
#define SEEN_FROM 01 #define SEEN_FROM 01
#define SEEN_DATE 02 #define SEEN_DATE 02
#define SEEN_SUBJECT 04 #define SEEN_SUBJECT 04
#define SEEN_BOGUS_UNIX_FROM 010
/* First lines of body can have From:, Date:, and Subject: */ /* First lines of body can have From:, Date:, and Subject: */
static int handle_inbody_header(int *seen, char *line) static int handle_inbody_header(int *seen, char *line)
{ {
if (!memcmp(">From", line, 5) && isspace(line[5])) {
if (!(*seen & SEEN_BOGUS_UNIX_FROM)) {
*seen |= SEEN_BOGUS_UNIX_FROM;
return 1;
}
}
if (!memcmp("From:", line, 5) && isspace(line[5])) { if (!memcmp("From:", line, 5) && isspace(line[5])) {
if (!(*seen & SEEN_FROM) && handle_from(line+6)) { if (!(*seen & SEEN_FROM) && handle_from(line+6)) {
*seen |= SEEN_FROM; *seen |= SEEN_FROM;