Rename samples subdirectories

This commit is contained in:
Joshua Peek
2012-07-23 15:52:49 -05:00
parent 314f0e4852
commit 7b6caa0f6c
273 changed files with 2952 additions and 2955 deletions

25
samples/C/blob.c Normal file
View File

@@ -0,0 +1,25 @@
#include "cache.h"
#include "blob.h"
const char *blob_type = "blob";
struct blob *lookup_blob(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
if (!obj)
return create_object(sha1, OBJ_BLOB, alloc_blob_node());
if (!obj->type)
obj->type = OBJ_BLOB;
if (obj->type != OBJ_BLOB) {
error("Object %s is a %s, not a blob",
sha1_to_hex(sha1), typename(obj->type));
return NULL;
}
return (struct blob *) obj;
}
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
{
item->object.parsed = 1;
return 0;
}

25
samples/C/blob.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef BLOB_H
#define BLOB_H
#include "object.h"
extern const char *blob_type;
struct blob {
struct object object;
};
struct blob *lookup_blob(const unsigned char *sha1);
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
/**
* Blobs do not contain references to other objects and do not have
* structured data that needs parsing. However, code may use the
* "parsed" bit in the struct object for a blob to determine whether
* its content has been found to actually be available, so
* parse_blob_buffer() is used (by object.c) to flag that the object
* has been read successfully from the database.
**/
#endif /* BLOB_H */

99
samples/C/cache.c Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#include "repository.h"
#include "commit.h"
#include "thread-utils.h"
#include "util.h"
#include "cache.h"
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
{
if (size < 8)
size = 8;
size = git__size_t_powerof2(size);
cache->size_mask = size - 1;
cache->lru_count = 0;
cache->free_obj = free_ptr;
git_mutex_init(&cache->lock);
cache->nodes = git__malloc(size * sizeof(git_cached_obj *));
GITERR_CHECK_ALLOC(cache->nodes);
memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *));
return 0;
}
void git_cache_free(git_cache *cache)
{
size_t i;
for (i = 0; i < (cache->size_mask + 1); ++i) {
if (cache->nodes[i] != NULL)
git_cached_obj_decref(cache->nodes[i], cache->free_obj);
}
git__free(cache->nodes);
}
void *git_cache_get(git_cache *cache, const git_oid *oid)
{
uint32_t hash;
git_cached_obj *node = NULL, *result = NULL;
memcpy(&hash, oid->id, sizeof(hash));
git_mutex_lock(&cache->lock);
{
node = cache->nodes[hash & cache->size_mask];
if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) {
git_cached_obj_incref(node);
result = node;
}
}
git_mutex_unlock(&cache->lock);
return result;
}
void *git_cache_try_store(git_cache *cache, void *_entry)
{
git_cached_obj *entry = _entry;
uint32_t hash;
memcpy(&hash, &entry->oid, sizeof(uint32_t));
/* increase the refcount on this object, because
* the cache now owns it */
git_cached_obj_incref(entry);
git_mutex_lock(&cache->lock);
{
git_cached_obj *node = cache->nodes[hash & cache->size_mask];
if (node == NULL) {
cache->nodes[hash & cache->size_mask] = entry;
} else if (git_oid_cmp(&node->oid, &entry->oid) == 0) {
git_cached_obj_decref(entry, cache->free_obj);
entry = node;
} else {
git_cached_obj_decref(node, cache->free_obj);
cache->nodes[hash & cache->size_mask] = entry;
}
}
git_mutex_unlock(&cache->lock);
/* increase the refcount again, because we are
* returning it to the user */
git_cached_obj_incref(entry);
return entry;
}

1228
samples/C/commit.c Normal file

File diff suppressed because it is too large Load Diff

226
samples/C/commit.h Normal file
View File

@@ -0,0 +1,226 @@
#ifndef COMMIT_H
#define COMMIT_H
#include "object.h"
#include "tree.h"
#include "strbuf.h"
#include "decorate.h"
struct commit_list {
struct commit *item;
struct commit_list *next;
};
struct commit {
struct object object;
void *util;
unsigned int indegree;
unsigned long date;
struct commit_list *parents;
struct tree *tree;
char *buffer;
};
extern int save_commit_buffer;
extern const char *commit_type;
/* While we can decorate any object with a name, it's only used for commits.. */
extern struct decoration name_decoration;
struct name_decoration {
struct name_decoration *next;
int type;
char name[1];
};
struct commit *lookup_commit(const unsigned char *sha1);
struct commit *lookup_commit_reference(const unsigned char *sha1);
struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
int quiet);
struct commit *lookup_commit_reference_by_name(const char *name);
/*
* Look up object named by "sha1", dereference tag as necessary,
* get a commit and return it. If "sha1" does not dereference to
* a commit, use ref_name to report an error and die.
*/
struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name);
int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
int parse_commit(struct commit *item);
/* Find beginning and length of commit subject. */
int find_commit_subject(const char *commit_buffer, const char **subject);
struct commit_list *commit_list_insert(struct commit *item,
struct commit_list **list);
struct commit_list **commit_list_append(struct commit *commit,
struct commit_list **next);
unsigned commit_list_count(const struct commit_list *l);
struct commit_list *commit_list_insert_by_date(struct commit *item,
struct commit_list **list);
void commit_list_sort_by_date(struct commit_list **list);
void free_commit_list(struct commit_list *list);
/* Commit formats */
enum cmit_fmt {
CMIT_FMT_RAW,
CMIT_FMT_MEDIUM,
CMIT_FMT_DEFAULT = CMIT_FMT_MEDIUM,
CMIT_FMT_SHORT,
CMIT_FMT_FULL,
CMIT_FMT_FULLER,
CMIT_FMT_ONELINE,
CMIT_FMT_EMAIL,
CMIT_FMT_USERFORMAT,
CMIT_FMT_UNSPECIFIED
};
struct pretty_print_context {
enum cmit_fmt fmt;
int abbrev;
const char *subject;
const char *after_subject;
int preserve_subject;
enum date_mode date_mode;
unsigned date_mode_explicit:1;
int need_8bit_cte;
int show_notes;
struct reflog_walk_info *reflog_info;
const char *output_encoding;
};
struct userformat_want {
unsigned notes:1;
};
extern int has_non_ascii(const char *text);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
extern char *logmsg_reencode(const struct commit *commit,
const char *output_encoding);
extern char *reencode_commit_message(const struct commit *commit,
const char **encoding_p);
extern void get_commit_format(const char *arg, struct rev_info *);
extern const char *format_subject(struct strbuf *sb, const char *msg,
const char *line_separator);
extern void userformat_find_requirements(const char *fmt, struct userformat_want *w);
extern void format_commit_message(const struct commit *commit,
const char *format, struct strbuf *sb,
const struct pretty_print_context *context);
extern void pretty_print_commit(const struct pretty_print_context *pp,
const struct commit *commit,
struct strbuf *sb);
extern void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
struct strbuf *sb);
void pp_user_info(const struct pretty_print_context *pp,
const char *what, struct strbuf *sb,
const char *line, const char *encoding);
void pp_title_line(const struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
const char *encoding,
int need_8bit_cte);
void pp_remainder(const struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
int indent);
/** Removes the first commit from a list sorted by date, and adds all
* of its parents.
**/
struct commit *pop_most_recent_commit(struct commit_list **list,
unsigned int mark);
struct commit *pop_commit(struct commit_list **stack);
void clear_commit_marks(struct commit *commit, unsigned int mark);
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
/*
* Performs an in-place topological sort of list supplied.
*
* invariant of resulting list is:
* a reachable from b => ord(b) < ord(a)
* in addition, when lifo == 0, commits on parallel tracks are
* sorted in the dates order.
*/
void sort_in_topological_order(struct commit_list ** list, int lifo);
struct commit_graft {
unsigned char sha1[20];
int nr_parent; /* < 0 if shallow commit */
unsigned char parent[FLEX_ARRAY][20]; /* more */
};
typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
struct commit_graft *read_graft_line(char *buf, int len);
int register_commit_graft(struct commit_graft *, int);
struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
extern int register_shallow(const unsigned char *sha1);
extern int unregister_shallow(const unsigned char *sha1);
extern int for_each_commit_graft(each_commit_graft_fn, void *);
extern int is_repository_shallow(void);
extern struct commit_list *get_shallow_commits(struct object_array *heads,
int depth, int shallow_flag, int not_shallow_flag);
int is_descendant_of(struct commit *, struct commit_list *);
int in_merge_bases(struct commit *, struct commit **, int);
extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);
extern int run_add_interactive(const char *revision, const char *patch_mode,
const char **pathspec);
static inline int single_parent(struct commit *commit)
{
return commit->parents && !commit->parents->next;
}
struct commit_list *reduce_heads(struct commit_list *heads);
struct commit_extra_header {
struct commit_extra_header *next;
char *key;
char *value;
size_t len;
};
extern void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail);
extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit);
extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *);
extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
extern void free_commit_extra_headers(struct commit_extra_header *extra);
struct merge_remote_desc {
struct object *obj; /* the named object, could be a tag */
const char *name;
};
#define merge_remote_util(commit) ((struct merge_remote_desc *)((commit)->util))
/*
* Given "name" from the command line to merge, find the commit object
* and return it, while storing merge_remote_desc in its ->util field,
* to allow callers to tell if we are told to merge a tag.
*/
struct commit *get_merge_parent(const char *name);
extern int parse_signed_commit(const unsigned char *sha1,
struct strbuf *message, struct strbuf *signature);
#endif /* COMMIT_H */

725
samples/C/cpu.c Normal file
View File

@@ -0,0 +1,725 @@
/* CPU control.
* (C) 2001, 2002, 2003, 2004 Rusty Russell
*
* This code is licenced under the GPL.
*/
#include <linux/proc_fs.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/notifier.h>
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/cpu.h>
#include <linux/oom.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
#include <linux/bug.h>
#include <linux/kthread.h>
#include <linux/stop_machine.h>
#include <linux/mutex.h>
#include <linux/gfp.h>
#include <linux/suspend.h>
#include "smpboot.h"
#ifdef CONFIG_SMP
/* Serializes the updates to cpu_online_mask, cpu_present_mask */
static DEFINE_MUTEX(cpu_add_remove_lock);
/*
* The following two API's must be used when attempting
* to serialize the updates to cpu_online_mask, cpu_present_mask.
*/
void cpu_maps_update_begin(void)
{
mutex_lock(&cpu_add_remove_lock);
}
void cpu_maps_update_done(void)
{
mutex_unlock(&cpu_add_remove_lock);
}
static RAW_NOTIFIER_HEAD(cpu_chain);
/* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
* Should always be manipulated under cpu_add_remove_lock
*/
static int cpu_hotplug_disabled;
#ifdef CONFIG_HOTPLUG_CPU
static struct {
struct task_struct *active_writer;
struct mutex lock; /* Synchronizes accesses to refcount, */
/*
* Also blocks the new readers during
* an ongoing cpu hotplug operation.
*/
int refcount;
} cpu_hotplug = {
.active_writer = NULL,
.lock = __MUTEX_INITIALIZER(cpu_hotplug.lock),
.refcount = 0,
};
void get_online_cpus(void)
{
might_sleep();
if (cpu_hotplug.active_writer == current)
return;
mutex_lock(&cpu_hotplug.lock);
cpu_hotplug.refcount++;
mutex_unlock(&cpu_hotplug.lock);
}
EXPORT_SYMBOL_GPL(get_online_cpus);
void put_online_cpus(void)
{
if (cpu_hotplug.active_writer == current)
return;
mutex_lock(&cpu_hotplug.lock);
if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer))
wake_up_process(cpu_hotplug.active_writer);
mutex_unlock(&cpu_hotplug.lock);
}
EXPORT_SYMBOL_GPL(put_online_cpus);
/*
* This ensures that the hotplug operation can begin only when the
* refcount goes to zero.
*
* Note that during a cpu-hotplug operation, the new readers, if any,
* will be blocked by the cpu_hotplug.lock
*
* Since cpu_hotplug_begin() is always called after invoking
* cpu_maps_update_begin(), we can be sure that only one writer is active.
*
* Note that theoretically, there is a possibility of a livelock:
* - Refcount goes to zero, last reader wakes up the sleeping
* writer.
* - Last reader unlocks the cpu_hotplug.lock.
* - A new reader arrives at this moment, bumps up the refcount.
* - The writer acquires the cpu_hotplug.lock finds the refcount
* non zero and goes to sleep again.
*
* However, this is very difficult to achieve in practice since
* get_online_cpus() not an api which is called all that often.
*
*/
static void cpu_hotplug_begin(void)
{
cpu_hotplug.active_writer = current;
for (;;) {
mutex_lock(&cpu_hotplug.lock);
if (likely(!cpu_hotplug.refcount))
break;
__set_current_state(TASK_UNINTERRUPTIBLE);
mutex_unlock(&cpu_hotplug.lock);
schedule();
}
}
static void cpu_hotplug_done(void)
{
cpu_hotplug.active_writer = NULL;
mutex_unlock(&cpu_hotplug.lock);
}
#else /* #if CONFIG_HOTPLUG_CPU */
static void cpu_hotplug_begin(void) {}
static void cpu_hotplug_done(void) {}
#endif /* #else #if CONFIG_HOTPLUG_CPU */
/* Need to know about CPUs going up/down? */
int __ref register_cpu_notifier(struct notifier_block *nb)
{
int ret;
cpu_maps_update_begin();
ret = raw_notifier_chain_register(&cpu_chain, nb);
cpu_maps_update_done();
return ret;
}
static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
int *nr_calls)
{
int ret;
ret = __raw_notifier_call_chain(&cpu_chain, val, v, nr_to_call,
nr_calls);
return notifier_to_errno(ret);
}
static int cpu_notify(unsigned long val, void *v)
{
return __cpu_notify(val, v, -1, NULL);
}
#ifdef CONFIG_HOTPLUG_CPU
static void cpu_notify_nofail(unsigned long val, void *v)
{
BUG_ON(cpu_notify(val, v));
}
EXPORT_SYMBOL(register_cpu_notifier);
void __ref unregister_cpu_notifier(struct notifier_block *nb)
{
cpu_maps_update_begin();
raw_notifier_chain_unregister(&cpu_chain, nb);
cpu_maps_update_done();
}
EXPORT_SYMBOL(unregister_cpu_notifier);
/**
* clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU
* @cpu: a CPU id
*
* This function walks all processes, finds a valid mm struct for each one and
* then clears a corresponding bit in mm's cpumask. While this all sounds
* trivial, there are various non-obvious corner cases, which this function
* tries to solve in a safe manner.
*
* Also note that the function uses a somewhat relaxed locking scheme, so it may
* be called only for an already offlined CPU.
*/
void clear_tasks_mm_cpumask(int cpu)
{
struct task_struct *p;
/*
* This function is called after the cpu is taken down and marked
* offline, so its not like new tasks will ever get this cpu set in
* their mm mask. -- Peter Zijlstra
* Thus, we may use rcu_read_lock() here, instead of grabbing
* full-fledged tasklist_lock.
*/
WARN_ON(cpu_online(cpu));
rcu_read_lock();
for_each_process(p) {
struct task_struct *t;
/*
* Main thread might exit, but other threads may still have
* a valid mm. Find one.
*/
t = find_lock_task_mm(p);
if (!t)
continue;
cpumask_clear_cpu(cpu, mm_cpumask(t->mm));
task_unlock(t);
}
rcu_read_unlock();
}
static inline void check_for_tasks(int cpu)
{
struct task_struct *p;
write_lock_irq(&tasklist_lock);
for_each_process(p) {
if (task_cpu(p) == cpu && p->state == TASK_RUNNING &&
(p->utime || p->stime))
printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d "
"(state = %ld, flags = %x)\n",
p->comm, task_pid_nr(p), cpu,
p->state, p->flags);
}
write_unlock_irq(&tasklist_lock);
}
struct take_cpu_down_param {
unsigned long mod;
void *hcpu;
};
/* Take this CPU down. */
static int __ref take_cpu_down(void *_param)
{
struct take_cpu_down_param *param = _param;
int err;
/* Ensure this CPU doesn't handle any more interrupts. */
err = __cpu_disable();
if (err < 0)
return err;
cpu_notify(CPU_DYING | param->mod, param->hcpu);
return 0;
}
/* Requires cpu_add_remove_lock to be held */
static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
{
int err, nr_calls = 0;
void *hcpu = (void *)(long)cpu;
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
struct take_cpu_down_param tcd_param = {
.mod = mod,
.hcpu = hcpu,
};
if (num_online_cpus() == 1)
return -EBUSY;
if (!cpu_online(cpu))
return -EINVAL;
cpu_hotplug_begin();
err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
if (err) {
nr_calls--;
__cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL);
printk("%s: attempt to take down CPU %u failed\n",
__func__, cpu);
goto out_release;
}
err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
if (err) {
/* CPU didn't die: tell everyone. Can't complain. */
cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
goto out_release;
}
BUG_ON(cpu_online(cpu));
/*
* The migration_call() CPU_DYING callback will have removed all
* runnable tasks from the cpu, there's only the idle task left now
* that the migration thread is done doing the stop_machine thing.
*
* Wait for the stop thread to go away.
*/
while (!idle_cpu(cpu))
cpu_relax();
/* This actually kills the CPU. */
__cpu_die(cpu);
/* CPU is completely dead: tell everyone. Too late to complain. */
cpu_notify_nofail(CPU_DEAD | mod, hcpu);
check_for_tasks(cpu);
out_release:
cpu_hotplug_done();
if (!err)
cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
return err;
}
int __ref cpu_down(unsigned int cpu)
{
int err;
cpu_maps_update_begin();
if (cpu_hotplug_disabled) {
err = -EBUSY;
goto out;
}
err = _cpu_down(cpu, 0);
out:
cpu_maps_update_done();
return err;
}
EXPORT_SYMBOL(cpu_down);
#endif /*CONFIG_HOTPLUG_CPU*/
/* Requires cpu_add_remove_lock to be held */
static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
{
int ret, nr_calls = 0;
void *hcpu = (void *)(long)cpu;
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
struct task_struct *idle;
if (cpu_online(cpu) || !cpu_present(cpu))
return -EINVAL;
cpu_hotplug_begin();
idle = idle_thread_get(cpu);
if (IS_ERR(idle)) {
ret = PTR_ERR(idle);
goto out;
}
ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
if (ret) {
nr_calls--;
printk(KERN_WARNING "%s: attempt to bring up CPU %u failed\n",
__func__, cpu);
goto out_notify;
}
/* Arch-specific enabling code. */
ret = __cpu_up(cpu, idle);
if (ret != 0)
goto out_notify;
BUG_ON(!cpu_online(cpu));
/* Now call notifier in preparation. */
cpu_notify(CPU_ONLINE | mod, hcpu);
out_notify:
if (ret != 0)
__cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
out:
cpu_hotplug_done();
return ret;
}
int __cpuinit cpu_up(unsigned int cpu)
{
int err = 0;
#ifdef CONFIG_MEMORY_HOTPLUG
int nid;
pg_data_t *pgdat;
#endif
if (!cpu_possible(cpu)) {
printk(KERN_ERR "can't online cpu %d because it is not "
"configured as may-hotadd at boot time\n", cpu);
#if defined(CONFIG_IA64)
printk(KERN_ERR "please check additional_cpus= boot "
"parameter\n");
#endif
return -EINVAL;
}
#ifdef CONFIG_MEMORY_HOTPLUG
nid = cpu_to_node(cpu);
if (!node_online(nid)) {
err = mem_online_node(nid);
if (err)
return err;
}
pgdat = NODE_DATA(nid);
if (!pgdat) {
printk(KERN_ERR
"Can't online cpu %d due to NULL pgdat\n", cpu);
return -ENOMEM;
}
if (pgdat->node_zonelists->_zonerefs->zone == NULL) {
mutex_lock(&zonelists_mutex);
build_all_zonelists(NULL);
mutex_unlock(&zonelists_mutex);
}
#endif
cpu_maps_update_begin();
if (cpu_hotplug_disabled) {
err = -EBUSY;
goto out;
}
err = _cpu_up(cpu, 0);
out:
cpu_maps_update_done();
return err;
}
EXPORT_SYMBOL_GPL(cpu_up);
#ifdef CONFIG_PM_SLEEP_SMP
static cpumask_var_t frozen_cpus;
void __weak arch_disable_nonboot_cpus_begin(void)
{
}
void __weak arch_disable_nonboot_cpus_end(void)
{
}
int disable_nonboot_cpus(void)
{
int cpu, first_cpu, error = 0;
cpu_maps_update_begin();
first_cpu = cpumask_first(cpu_online_mask);
/*
* We take down all of the non-boot CPUs in one shot to avoid races
* with the userspace trying to use the CPU hotplug at the same time
*/
cpumask_clear(frozen_cpus);
arch_disable_nonboot_cpus_begin();
printk("Disabling non-boot CPUs ...\n");
for_each_online_cpu(cpu) {
if (cpu == first_cpu)
continue;
error = _cpu_down(cpu, 1);
if (!error)
cpumask_set_cpu(cpu, frozen_cpus);
else {
printk(KERN_ERR "Error taking CPU%d down: %d\n",
cpu, error);
break;
}
}
arch_disable_nonboot_cpus_end();
if (!error) {
BUG_ON(num_online_cpus() > 1);
/* Make sure the CPUs won't be enabled by someone else */
cpu_hotplug_disabled = 1;
} else {
printk(KERN_ERR "Non-boot CPUs are not disabled\n");
}
cpu_maps_update_done();
return error;
}
void __weak arch_enable_nonboot_cpus_begin(void)
{
}
void __weak arch_enable_nonboot_cpus_end(void)
{
}
void __ref enable_nonboot_cpus(void)
{
int cpu, error;
/* Allow everyone to use the CPU hotplug again */
cpu_maps_update_begin();
cpu_hotplug_disabled = 0;
if (cpumask_empty(frozen_cpus))
goto out;
printk(KERN_INFO "Enabling non-boot CPUs ...\n");
arch_enable_nonboot_cpus_begin();
for_each_cpu(cpu, frozen_cpus) {
error = _cpu_up(cpu, 1);
if (!error) {
printk(KERN_INFO "CPU%d is up\n", cpu);
continue;
}
printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
}
arch_enable_nonboot_cpus_end();
cpumask_clear(frozen_cpus);
out:
cpu_maps_update_done();
}
static int __init alloc_frozen_cpus(void)
{
if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO))
return -ENOMEM;
return 0;
}
core_initcall(alloc_frozen_cpus);
/*
* Prevent regular CPU hotplug from racing with the freezer, by disabling CPU
* hotplug when tasks are about to be frozen. Also, don't allow the freezer
* to continue until any currently running CPU hotplug operation gets
* completed.
* To modify the 'cpu_hotplug_disabled' flag, we need to acquire the
* 'cpu_add_remove_lock'. And this same lock is also taken by the regular
* CPU hotplug path and released only after it is complete. Thus, we
* (and hence the freezer) will block here until any currently running CPU
* hotplug operation gets completed.
*/
void cpu_hotplug_disable_before_freeze(void)
{
cpu_maps_update_begin();
cpu_hotplug_disabled = 1;
cpu_maps_update_done();
}
/*
* When tasks have been thawed, re-enable regular CPU hotplug (which had been
* disabled while beginning to freeze tasks).
*/
void cpu_hotplug_enable_after_thaw(void)
{
cpu_maps_update_begin();
cpu_hotplug_disabled = 0;
cpu_maps_update_done();
}
/*
* When callbacks for CPU hotplug notifications are being executed, we must
* ensure that the state of the system with respect to the tasks being frozen
* or not, as reported by the notification, remains unchanged *throughout the
* duration* of the execution of the callbacks.
* Hence we need to prevent the freezer from racing with regular CPU hotplug.
*
* This synchronization is implemented by mutually excluding regular CPU
* hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/
* Hibernate notifications.
*/
static int
cpu_hotplug_pm_callback(struct notifier_block *nb,
unsigned long action, void *ptr)
{
switch (action) {
case PM_SUSPEND_PREPARE:
case PM_HIBERNATION_PREPARE:
cpu_hotplug_disable_before_freeze();
break;
case PM_POST_SUSPEND:
case PM_POST_HIBERNATION:
cpu_hotplug_enable_after_thaw();
break;
default:
return NOTIFY_DONE;
}
return NOTIFY_OK;
}
static int __init cpu_hotplug_pm_sync_init(void)
{
pm_notifier(cpu_hotplug_pm_callback, 0);
return 0;
}
core_initcall(cpu_hotplug_pm_sync_init);
#endif /* CONFIG_PM_SLEEP_SMP */
/**
* notify_cpu_starting(cpu) - call the CPU_STARTING notifiers
* @cpu: cpu that just started
*
* This function calls the cpu_chain notifiers with CPU_STARTING.
* It must be called by the arch code on the new cpu, before the new cpu
* enables interrupts and before the "boot" cpu returns from __cpu_up().
*/
void __cpuinit notify_cpu_starting(unsigned int cpu)
{
unsigned long val = CPU_STARTING;
#ifdef CONFIG_PM_SLEEP_SMP
if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus))
val = CPU_STARTING_FROZEN;
#endif /* CONFIG_PM_SLEEP_SMP */
cpu_notify(val, (void *)(long)cpu);
}
#endif /* CONFIG_SMP */
/*
* cpu_bit_bitmap[] is a special, "compressed" data structure that
* represents all NR_CPUS bits binary values of 1<<nr.
*
* It is used by cpumask_of() to get a constant address to a CPU
* mask value that has a single bit set only.
*/
/* cpu_bit_bitmap[0] is empty - so we can back into it */
#define MASK_DECLARE_1(x) [x+1][0] = (1UL << (x))
#define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1)
#define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2)
#define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4)
const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = {
MASK_DECLARE_8(0), MASK_DECLARE_8(8),
MASK_DECLARE_8(16), MASK_DECLARE_8(24),
#if BITS_PER_LONG > 32
MASK_DECLARE_8(32), MASK_DECLARE_8(40),
MASK_DECLARE_8(48), MASK_DECLARE_8(56),
#endif
};
EXPORT_SYMBOL_GPL(cpu_bit_bitmap);
const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
EXPORT_SYMBOL(cpu_all_bits);
#ifdef CONFIG_INIT_ALL_POSSIBLE
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
= CPU_BITS_ALL;
#else
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
#endif
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
EXPORT_SYMBOL(cpu_possible_mask);
static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
EXPORT_SYMBOL(cpu_online_mask);
static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
EXPORT_SYMBOL(cpu_present_mask);
static DECLARE_BITMAP(cpu_active_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_active_mask = to_cpumask(cpu_active_bits);
EXPORT_SYMBOL(cpu_active_mask);
void set_cpu_possible(unsigned int cpu, bool possible)
{
if (possible)
cpumask_set_cpu(cpu, to_cpumask(cpu_possible_bits));
else
cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits));
}
void set_cpu_present(unsigned int cpu, bool present)
{
if (present)
cpumask_set_cpu(cpu, to_cpumask(cpu_present_bits));
else
cpumask_clear_cpu(cpu, to_cpumask(cpu_present_bits));
}
void set_cpu_online(unsigned int cpu, bool online)
{
if (online)
cpumask_set_cpu(cpu, to_cpumask(cpu_online_bits));
else
cpumask_clear_cpu(cpu, to_cpumask(cpu_online_bits));
}
void set_cpu_active(unsigned int cpu, bool active)
{
if (active)
cpumask_set_cpu(cpu, to_cpumask(cpu_active_bits));
else
cpumask_clear_cpu(cpu, to_cpumask(cpu_active_bits));
}
void init_cpu_present(const struct cpumask *src)
{
cpumask_copy(to_cpumask(cpu_present_bits), src);
}
void init_cpu_possible(const struct cpumask *src)
{
cpumask_copy(to_cpumask(cpu_possible_bits), src);
}
void init_cpu_online(const struct cpumask *src)
{
cpumask_copy(to_cpumask(cpu_online_bits), src);
}

784
samples/C/diff.c Normal file
View File

@@ -0,0 +1,784 @@
/*
* Copyright (C) 2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#include "git2/diff.h"
#include "diff.h"
#include "fileops.h"
#include "config.h"
#include "attr_file.h"
static char *diff_prefix_from_pathspec(const git_strarray *pathspec)
{
git_buf prefix = GIT_BUF_INIT;
const char *scan;
if (git_buf_common_prefix(&prefix, pathspec) < 0)
return NULL;
/* diff prefix will only be leading non-wildcards */
for (scan = prefix.ptr; *scan && !git__iswildcard(*scan); ++scan);
git_buf_truncate(&prefix, scan - prefix.ptr);
if (prefix.size > 0)
return git_buf_detach(&prefix);
git_buf_free(&prefix);
return NULL;
}
static bool diff_pathspec_is_interesting(const git_strarray *pathspec)
{
const char *str;
if (pathspec == NULL || pathspec->count == 0)
return false;
if (pathspec->count > 1)
return true;
str = pathspec->strings[0];
if (!str || !str[0] || (!str[1] && (str[0] == '*' || str[0] == '.')))
return false;
return true;
}
static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path)
{
unsigned int i;
git_attr_fnmatch *match;
if (!diff->pathspec.length)
return true;
git_vector_foreach(&diff->pathspec, i, match) {
int result = p_fnmatch(match->pattern, path, 0);
/* if we didn't match, look for exact dirname prefix match */
if (result == FNM_NOMATCH &&
(match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 &&
strncmp(path, match->pattern, match->length) == 0 &&
path[match->length] == '/')
result = 0;
if (result == 0)
return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? false : true;
}
return false;
}
static git_diff_delta *diff_delta__alloc(
git_diff_list *diff,
git_delta_t status,
const char *path)
{
git_diff_delta *delta = git__calloc(1, sizeof(git_diff_delta));
if (!delta)
return NULL;
delta->old_file.path = git_pool_strdup(&diff->pool, path);
if (delta->old_file.path == NULL) {
git__free(delta);
return NULL;
}
delta->new_file.path = delta->old_file.path;
if (diff->opts.flags & GIT_DIFF_REVERSE) {
switch (status) {
case GIT_DELTA_ADDED: status = GIT_DELTA_DELETED; break;
case GIT_DELTA_DELETED: status = GIT_DELTA_ADDED; break;
default: break; /* leave other status values alone */
}
}
delta->status = status;
return delta;
}
static git_diff_delta *diff_delta__dup(
const git_diff_delta *d, git_pool *pool)
{
git_diff_delta *delta = git__malloc(sizeof(git_diff_delta));
if (!delta)
return NULL;
memcpy(delta, d, sizeof(git_diff_delta));
delta->old_file.path = git_pool_strdup(pool, d->old_file.path);
if (delta->old_file.path == NULL)
goto fail;
if (d->new_file.path != d->old_file.path) {
delta->new_file.path = git_pool_strdup(pool, d->new_file.path);
if (delta->new_file.path == NULL)
goto fail;
} else {
delta->new_file.path = delta->old_file.path;
}
return delta;
fail:
git__free(delta);
return NULL;
}
static git_diff_delta *diff_delta__merge_like_cgit(
const git_diff_delta *a, const git_diff_delta *b, git_pool *pool)
{
git_diff_delta *dup = diff_delta__dup(a, pool);
if (!dup)
return NULL;
if (git_oid_cmp(&dup->new_file.oid, &b->new_file.oid) == 0)
return dup;
git_oid_cpy(&dup->new_file.oid, &b->new_file.oid);
dup->new_file.mode = b->new_file.mode;
dup->new_file.size = b->new_file.size;
dup->new_file.flags = b->new_file.flags;
/* Emulate C git for merging two diffs (a la 'git diff <sha>').
*
* When C git does a diff between the work dir and a tree, it actually
* diffs with the index but uses the workdir contents. This emulates
* those choices so we can emulate the type of diff.
*/
if (git_oid_cmp(&dup->old_file.oid, &dup->new_file.oid) == 0) {
if (dup->status == GIT_DELTA_DELETED)
/* preserve pending delete info */;
else if (b->status == GIT_DELTA_UNTRACKED ||
b->status == GIT_DELTA_IGNORED)
dup->status = b->status;
else
dup->status = GIT_DELTA_UNMODIFIED;
}
else if (dup->status == GIT_DELTA_UNMODIFIED ||
b->status == GIT_DELTA_DELETED)
dup->status = b->status;
return dup;
}
static int diff_delta__from_one(
git_diff_list *diff,
git_delta_t status,
const git_index_entry *entry)
{
git_diff_delta *delta;
if (status == GIT_DELTA_IGNORED &&
(diff->opts.flags & GIT_DIFF_INCLUDE_IGNORED) == 0)
return 0;
if (status == GIT_DELTA_UNTRACKED &&
(diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
return 0;
if (!diff_path_matches_pathspec(diff, entry->path))
return 0;
delta = diff_delta__alloc(diff, status, entry->path);
GITERR_CHECK_ALLOC(delta);
/* This fn is just for single-sided diffs */
assert(status != GIT_DELTA_MODIFIED);
if (delta->status == GIT_DELTA_DELETED) {
delta->old_file.mode = entry->mode;
delta->old_file.size = entry->file_size;
git_oid_cpy(&delta->old_file.oid, &entry->oid);
} else /* ADDED, IGNORED, UNTRACKED */ {
delta->new_file.mode = entry->mode;
delta->new_file.size = entry->file_size;
git_oid_cpy(&delta->new_file.oid, &entry->oid);
}
delta->old_file.flags |= GIT_DIFF_FILE_VALID_OID;
delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID;
if (git_vector_insert(&diff->deltas, delta) < 0) {
git__free(delta);
return -1;
}
return 0;
}
static int diff_delta__from_two(
git_diff_list *diff,
git_delta_t status,
const git_index_entry *old_entry,
const git_index_entry *new_entry,
git_oid *new_oid)
{
git_diff_delta *delta;
if (status == GIT_DELTA_UNMODIFIED &&
(diff->opts.flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
return 0;
if ((diff->opts.flags & GIT_DIFF_REVERSE) != 0) {
const git_index_entry *temp = old_entry;
old_entry = new_entry;
new_entry = temp;
}
delta = diff_delta__alloc(diff, status, old_entry->path);
GITERR_CHECK_ALLOC(delta);
delta->old_file.mode = old_entry->mode;
git_oid_cpy(&delta->old_file.oid, &old_entry->oid);
delta->old_file.flags |= GIT_DIFF_FILE_VALID_OID;
delta->new_file.mode = new_entry->mode;
git_oid_cpy(&delta->new_file.oid, new_oid ? new_oid : &new_entry->oid);
if (new_oid || !git_oid_iszero(&new_entry->oid))
delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID;
if (git_vector_insert(&diff->deltas, delta) < 0) {
git__free(delta);
return -1;
}
return 0;
}
static char *diff_strdup_prefix(git_pool *pool, const char *prefix)
{
size_t len = strlen(prefix);
/* append '/' at end if needed */
if (len > 0 && prefix[len - 1] != '/')
return git_pool_strcat(pool, prefix, "/");
else
return git_pool_strndup(pool, prefix, len + 1);
}
static int diff_delta__cmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
int val = strcmp(da->old_file.path, db->old_file.path);
return val ? val : ((int)da->status - (int)db->status);
}
static int config_bool(git_config *cfg, const char *name, int defvalue)
{
int val = defvalue;
if (git_config_get_bool(&val, cfg, name) < 0)
giterr_clear();
return val;
}
static git_diff_list *git_diff_list_alloc(
git_repository *repo, const git_diff_options *opts)
{
git_config *cfg;
size_t i;
git_diff_list *diff = git__calloc(1, sizeof(git_diff_list));
if (diff == NULL)
return NULL;
diff->repo = repo;
if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0 ||
git_pool_init(&diff->pool, 1, 0) < 0)
goto fail;
/* load config values that affect diff behavior */
if (git_repository_config__weakptr(&cfg, repo) < 0)
goto fail;
if (config_bool(cfg, "core.symlinks", 1))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS;
if (config_bool(cfg, "core.ignorestat", 0))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED;
if (config_bool(cfg, "core.filemode", 1))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_EXEC_BIT;
if (config_bool(cfg, "core.trustctime", 1))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME;
/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
if (opts == NULL)
return diff;
memcpy(&diff->opts, opts, sizeof(git_diff_options));
memset(&diff->opts.pathspec, 0, sizeof(diff->opts.pathspec));
diff->opts.old_prefix = diff_strdup_prefix(&diff->pool,
opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT);
diff->opts.new_prefix = diff_strdup_prefix(&diff->pool,
opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT);
if (!diff->opts.old_prefix || !diff->opts.new_prefix)
goto fail;
if (diff->opts.flags & GIT_DIFF_REVERSE) {
char *swap = diff->opts.old_prefix;
diff->opts.old_prefix = diff->opts.new_prefix;
diff->opts.new_prefix = swap;
}
/* only copy pathspec if it is "interesting" so we can test
* diff->pathspec.length > 0 to know if it is worth calling
* fnmatch as we iterate.
*/
if (!diff_pathspec_is_interesting(&opts->pathspec))
return diff;
if (git_vector_init(
&diff->pathspec, (unsigned int)opts->pathspec.count, NULL) < 0)
goto fail;
for (i = 0; i < opts->pathspec.count; ++i) {
int ret;
const char *pattern = opts->pathspec.strings[i];
git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch));
if (!match)
goto fail;
match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE;
ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern);
if (ret == GIT_ENOTFOUND) {
git__free(match);
continue;
} else if (ret < 0)
goto fail;
if (git_vector_insert(&diff->pathspec, match) < 0)
goto fail;
}
return diff;
fail:
git_diff_list_free(diff);
return NULL;
}
void git_diff_list_free(git_diff_list *diff)
{
git_diff_delta *delta;
git_attr_fnmatch *match;
unsigned int i;
if (!diff)
return;
git_vector_foreach(&diff->deltas, i, delta) {
git__free(delta);
diff->deltas.contents[i] = NULL;
}
git_vector_free(&diff->deltas);
git_vector_foreach(&diff->pathspec, i, match) {
git__free(match);
diff->pathspec.contents[i] = NULL;
}
git_vector_free(&diff->pathspec);
git_pool_clear(&diff->pool);
git__free(diff);
}
static int oid_for_workdir_item(
git_repository *repo,
const git_index_entry *item,
git_oid *oid)
{
int result;
git_buf full_path = GIT_BUF_INIT;
if (git_buf_joinpath(&full_path, git_repository_workdir(repo), item->path) < 0)
return -1;
/* calculate OID for file if possible*/
if (S_ISLNK(item->mode))
result = git_odb__hashlink(oid, full_path.ptr);
else if (!git__is_sizet(item->file_size)) {
giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
result = -1;
} else {
int fd = git_futils_open_ro(full_path.ptr);
if (fd < 0)
result = fd;
else {
result = git_odb__hashfd(
oid, fd, (size_t)item->file_size, GIT_OBJ_BLOB);
p_close(fd);
}
}
git_buf_free(&full_path);
return result;
}
#define EXEC_BIT_MASK 0000111
static int maybe_modified(
git_iterator *old_iter,
const git_index_entry *oitem,
git_iterator *new_iter,
const git_index_entry *nitem,
git_diff_list *diff)
{
git_oid noid, *use_noid = NULL;
git_delta_t status = GIT_DELTA_MODIFIED;
unsigned int omode = oitem->mode;
unsigned int nmode = nitem->mode;
GIT_UNUSED(old_iter);
if (!diff_path_matches_pathspec(diff, oitem->path))
return 0;
/* on platforms with no symlinks, promote plain files to symlinks */
if (S_ISLNK(omode) && S_ISREG(nmode) &&
!(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS))
nmode = GIT_MODE_TYPE(omode) | (nmode & GIT_MODE_PERMS_MASK);
/* on platforms with no execmode, clear exec bit from comparisons */
if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_EXEC_BIT)) {
omode = omode & ~EXEC_BIT_MASK;
nmode = nmode & ~EXEC_BIT_MASK;
}
/* support "assume unchanged" (badly, b/c we still stat everything) */
if ((diff->diffcaps & GIT_DIFFCAPS_ASSUME_UNCHANGED) != 0)
status = (oitem->flags_extended & GIT_IDXENTRY_INTENT_TO_ADD) ?
GIT_DELTA_MODIFIED : GIT_DELTA_UNMODIFIED;
/* support "skip worktree" index bit */
else if ((oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0)
status = GIT_DELTA_UNMODIFIED;
/* if basic type of file changed, then split into delete and add */
else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0)
return -1;
return 0;
}
/* if oids and modes match, then file is unmodified */
else if (git_oid_cmp(&oitem->oid, &nitem->oid) == 0 &&
omode == nmode)
status = GIT_DELTA_UNMODIFIED;
/* if we have a workdir item with an unknown oid, check deeper */
else if (git_oid_iszero(&nitem->oid) && new_iter->type == GIT_ITERATOR_WORKDIR) {
/* TODO: add check against index file st_mtime to avoid racy-git */
/* if they files look exactly alike, then we'll assume the same */
if (oitem->file_size == nitem->file_size &&
(!(diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) ||
(oitem->ctime.seconds == nitem->ctime.seconds)) &&
oitem->mtime.seconds == nitem->mtime.seconds &&
(!(diff->diffcaps & GIT_DIFFCAPS_USE_DEV) ||
(oitem->dev == nitem->dev)) &&
oitem->ino == nitem->ino &&
oitem->uid == nitem->uid &&
oitem->gid == nitem->gid)
status = GIT_DELTA_UNMODIFIED;
else if (S_ISGITLINK(nmode)) {
git_submodule *sub;
if ((diff->opts.flags & GIT_DIFF_IGNORE_SUBMODULES) != 0)
status = GIT_DELTA_UNMODIFIED;
else if (git_submodule_lookup(&sub, diff->repo, nitem->path) < 0)
return -1;
else if (sub->ignore == GIT_SUBMODULE_IGNORE_ALL)
status = GIT_DELTA_UNMODIFIED;
else {
/* TODO: support other GIT_SUBMODULE_IGNORE values */
status = GIT_DELTA_UNMODIFIED;
}
}
/* TODO: check git attributes so we will not have to read the file
* in if it is marked binary.
*/
else if (oid_for_workdir_item(diff->repo, nitem, &noid) < 0)
return -1;
else if (git_oid_cmp(&oitem->oid, &noid) == 0 &&
omode == nmode)
status = GIT_DELTA_UNMODIFIED;
/* store calculated oid so we don't have to recalc later */
use_noid = &noid;
}
return diff_delta__from_two(diff, status, oitem, nitem, use_noid);
}
static int diff_from_iterators(
git_repository *repo,
const git_diff_options *opts, /**< can be NULL for defaults */
git_iterator *old_iter,
git_iterator *new_iter,
git_diff_list **diff_ptr)
{
const git_index_entry *oitem, *nitem;
git_buf ignore_prefix = GIT_BUF_INIT;
git_diff_list *diff = git_diff_list_alloc(repo, opts);
if (!diff)
goto fail;
diff->old_src = old_iter->type;
diff->new_src = new_iter->type;
if (git_iterator_current(old_iter, &oitem) < 0 ||
git_iterator_current(new_iter, &nitem) < 0)
goto fail;
/* run iterators building diffs */
while (oitem || nitem) {
/* create DELETED records for old items not matched in new */
if (oitem && (!nitem || strcmp(oitem->path, nitem->path) < 0)) {
if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
git_iterator_advance(old_iter, &oitem) < 0)
goto fail;
}
/* create ADDED, TRACKED, or IGNORED records for new items not
* matched in old (and/or descend into directories as needed)
*/
else if (nitem && (!oitem || strcmp(oitem->path, nitem->path) > 0)) {
git_delta_t delta_type = GIT_DELTA_UNTRACKED;
/* check if contained in ignored parent directory */
if (git_buf_len(&ignore_prefix) &&
git__prefixcmp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0)
delta_type = GIT_DELTA_IGNORED;
if (S_ISDIR(nitem->mode)) {
/* recurse into directory only if there are tracked items in
* it or if the user requested the contents of untracked
* directories and it is not under an ignored directory.
*/
if ((oitem && git__prefixcmp(oitem->path, nitem->path) == 0) ||
(delta_type == GIT_DELTA_UNTRACKED &&
(diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0))
{
/* if this directory is ignored, remember it as the
* "ignore_prefix" for processing contained items
*/
if (delta_type == GIT_DELTA_UNTRACKED &&
git_iterator_current_is_ignored(new_iter))
git_buf_sets(&ignore_prefix, nitem->path);
if (git_iterator_advance_into_directory(new_iter, &nitem) < 0)
goto fail;
continue;
}
}
/* In core git, the next two "else if" clauses are effectively
* reversed -- i.e. when an untracked file contained in an
* ignored directory is individually ignored, it shows up as an
* ignored file in the diff list, even though other untracked
* files in the same directory are skipped completely.
*
* To me, this is odd. If the directory is ignored and the file
* is untracked, we should skip it consistently, regardless of
* whether it happens to match a pattern in the ignore file.
*
* To match the core git behavior, just reverse the following
* two "else if" cases so that individual file ignores are
* checked before container directory exclusions are used to
* skip the file.
*/
else if (delta_type == GIT_DELTA_IGNORED) {
if (git_iterator_advance(new_iter, &nitem) < 0)
goto fail;
continue; /* ignored parent directory, so skip completely */
}
else if (git_iterator_current_is_ignored(new_iter))
delta_type = GIT_DELTA_IGNORED;
else if (new_iter->type != GIT_ITERATOR_WORKDIR)
delta_type = GIT_DELTA_ADDED;
if (diff_delta__from_one(diff, delta_type, nitem) < 0 ||
git_iterator_advance(new_iter, &nitem) < 0)
goto fail;
}
/* otherwise item paths match, so create MODIFIED record
* (or ADDED and DELETED pair if type changed)
*/
else {
assert(oitem && nitem && strcmp(oitem->path, nitem->path) == 0);
if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 ||
git_iterator_advance(old_iter, &oitem) < 0 ||
git_iterator_advance(new_iter, &nitem) < 0)
goto fail;
}
}
git_iterator_free(old_iter);
git_iterator_free(new_iter);
git_buf_free(&ignore_prefix);
*diff_ptr = diff;
return 0;
fail:
git_iterator_free(old_iter);
git_iterator_free(new_iter);
git_buf_free(&ignore_prefix);
git_diff_list_free(diff);
*diff_ptr = NULL;
return -1;
}
int git_diff_tree_to_tree(
git_repository *repo,
const git_diff_options *opts, /**< can be NULL for defaults */
git_tree *old_tree,
git_tree *new_tree,
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && old_tree && new_tree && diff);
if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
git_iterator_for_tree_range(&b, repo, new_tree, prefix, prefix) < 0)
return -1;
git__free(prefix);
return diff_from_iterators(repo, opts, a, b, diff);
}
int git_diff_index_to_tree(
git_repository *repo,
const git_diff_options *opts,
git_tree *old_tree,
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && diff);
if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
git_iterator_for_index_range(&b, repo, prefix, prefix) < 0)
return -1;
git__free(prefix);
return diff_from_iterators(repo, opts, a, b, diff);
}
int git_diff_workdir_to_index(
git_repository *repo,
const git_diff_options *opts,
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && diff);
if (git_iterator_for_index_range(&a, repo, prefix, prefix) < 0 ||
git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0)
return -1;
git__free(prefix);
return diff_from_iterators(repo, opts, a, b, diff);
}
int git_diff_workdir_to_tree(
git_repository *repo,
const git_diff_options *opts,
git_tree *old_tree,
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && old_tree && diff);
if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0)
return -1;
git__free(prefix);
return diff_from_iterators(repo, opts, a, b, diff);
}
int git_diff_merge(
git_diff_list *onto,
const git_diff_list *from)
{
int error = 0;
git_pool onto_pool;
git_vector onto_new;
git_diff_delta *delta;
unsigned int i, j;
assert(onto && from);
if (!from->deltas.length)
return 0;
if (git_vector_init(&onto_new, onto->deltas.length, diff_delta__cmp) < 0 ||
git_pool_init(&onto_pool, 1, 0) < 0)
return -1;
for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) {
git_diff_delta *o = GIT_VECTOR_GET(&onto->deltas, i);
const git_diff_delta *f = GIT_VECTOR_GET(&from->deltas, j);
int cmp = !f ? -1 : !o ? 1 : strcmp(o->old_file.path, f->old_file.path);
if (cmp < 0) {
delta = diff_delta__dup(o, &onto_pool);
i++;
} else if (cmp > 0) {
delta = diff_delta__dup(f, &onto_pool);
j++;
} else {
delta = diff_delta__merge_like_cgit(o, f, &onto_pool);
i++;
j++;
}
if ((error = !delta ? -1 : git_vector_insert(&onto_new, delta)) < 0)
break;
}
if (!error) {
git_vector_swap(&onto->deltas, &onto_new);
git_pool_swap(&onto->pool, &onto_pool);
onto->new_src = from->new_src;
}
git_vector_foreach(&onto_new, i, delta)
git__free(delta);
git_vector_free(&onto_new);
git_pool_clear(&onto_pool);
return error;
}

609
samples/C/git.c Normal file
View File

@@ -0,0 +1,609 @@
#include "builtin.h"
#include "cache.h"
#include "exec_cmd.h"
#include "help.h"
#include "quote.h"
#include "run-command.h"
const char git_usage_string[] =
"git [--version] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
" [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
" [-c name=value] [--help]\n"
" <command> [<args>]";
const char git_more_info_string[] =
N_("See 'git help <command>' for more information on a specific command.");
static struct startup_info git_startup_info;
static int use_pager = -1;
struct pager_config {
const char *cmd;
int want;
char *value;
};
static int pager_command_config(const char *var, const char *value, void *data)
{
struct pager_config *c = data;
if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) {
int b = git_config_maybe_bool(var, value);
if (b >= 0)
c->want = b;
else {
c->want = 1;
c->value = xstrdup(value);
}
}
return 0;
}
/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
int check_pager_config(const char *cmd)
{
struct pager_config c;
c.cmd = cmd;
c.want = -1;
c.value = NULL;
git_config(pager_command_config, &c);
if (c.value)
pager_program = c.value;
return c.want;
}
static void commit_pager_choice(void) {
switch (use_pager) {
case 0:
setenv("GIT_PAGER", "cat", 1);
break;
case 1:
setup_pager();
break;
default:
break;
}
}
static int handle_options(const char ***argv, int *argc, int *envchanged)
{
const char **orig_argv = *argv;
while (*argc > 0) {
const char *cmd = (*argv)[0];
if (cmd[0] != '-')
break;
/*
* For legacy reasons, the "version" and "help"
* commands can be written with "--" prepended
* to make them look like flags.
*/
if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
break;
/*
* Check remaining flags.
*/
if (!prefixcmp(cmd, "--exec-path")) {
cmd += 11;
if (*cmd == '=')
git_set_argv_exec_path(cmd + 1);
else {
puts(git_exec_path());
exit(0);
}
} else if (!strcmp(cmd, "--html-path")) {
puts(system_path(GIT_HTML_PATH));
exit(0);
} else if (!strcmp(cmd, "--man-path")) {
puts(system_path(GIT_MAN_PATH));
exit(0);
} else if (!strcmp(cmd, "--info-path")) {
puts(system_path(GIT_INFO_PATH));
exit(0);
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
use_pager = 1;
} else if (!strcmp(cmd, "--no-pager")) {
use_pager = 0;
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--no-replace-objects")) {
read_replace_refs = 0;
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--git-dir")) {
if (*argc < 2) {
fprintf(stderr, "No directory given for --git-dir.\n" );
usage(git_usage_string);
}
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--git-dir=")) {
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--namespace")) {
if (*argc < 2) {
fprintf(stderr, "No namespace given for --namespace.\n" );
usage(git_usage_string);
}
setenv(GIT_NAMESPACE_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--namespace=")) {
setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) {
if (*argc < 2) {
fprintf(stderr, "No directory given for --work-tree.\n" );
usage(git_usage_string);
}
setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--work-tree=")) {
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
is_bare_repository_cfg = 1;
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "-c")) {
if (*argc < 2) {
fprintf(stderr, "-c expects a configuration string\n" );
usage(git_usage_string);
}
git_config_push_parameter((*argv)[1]);
(*argv)++;
(*argc)--;
} else {
fprintf(stderr, "Unknown option: %s\n", cmd);
usage(git_usage_string);
}
(*argv)++;
(*argc)--;
}
return (*argv) - orig_argv;
}
static int handle_alias(int *argcp, const char ***argv)
{
int envchanged = 0, ret = 0, saved_errno = errno;
const char *subdir;
int count, option_count;
const char **new_argv;
const char *alias_command;
char *alias_string;
int unused_nongit;
subdir = setup_git_directory_gently(&unused_nongit);
alias_command = (*argv)[0];
alias_string = alias_lookup(alias_command);
if (alias_string) {
if (alias_string[0] == '!') {
const char **alias_argv;
int argc = *argcp, i;
commit_pager_choice();
/* build alias_argv */
alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
alias_argv[0] = alias_string + 1;
for (i = 1; i < argc; ++i)
alias_argv[i] = (*argv)[i];
alias_argv[argc] = NULL;
ret = run_command_v_opt(alias_argv, RUN_USING_SHELL);
if (ret >= 0) /* normal exit */
exit(ret);
die_errno("While expanding alias '%s': '%s'",
alias_command, alias_string + 1);
}
count = split_cmdline(alias_string, &new_argv);
if (count < 0)
die("Bad alias.%s string: %s", alias_command,
split_cmdline_strerror(count));
option_count = handle_options(&new_argv, &count, &envchanged);
if (envchanged)
die("alias '%s' changes environment variables\n"
"You can use '!git' in the alias to do this.",
alias_command);
memmove(new_argv - option_count, new_argv,
count * sizeof(char *));
new_argv -= option_count;
if (count < 1)
die("empty alias for %s", alias_command);
if (!strcmp(alias_command, new_argv[0]))
die("recursive alias: %s", alias_command);
trace_argv_printf(new_argv,
"trace: alias expansion: %s =>",
alias_command);
new_argv = xrealloc(new_argv, sizeof(char *) *
(count + *argcp));
/* insert after command name */
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
*argv = new_argv;
*argcp += count - 1;
ret = 1;
}
if (subdir && chdir(subdir))
die_errno("Cannot change to '%s'", subdir);
errno = saved_errno;
return ret;
}
const char git_version_string[] = GIT_VERSION;
#define RUN_SETUP (1<<0)
#define RUN_SETUP_GENTLY (1<<1)
#define USE_PAGER (1<<2)
/*
* require working tree to be present -- anything uses this needs
* RUN_SETUP for reading from the configuration file.
*/
#define NEED_WORK_TREE (1<<3)
struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, const char *);
int option;
};
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
{
int status, help;
struct stat st;
const char *prefix;
prefix = NULL;
help = argc == 2 && !strcmp(argv[1], "-h");
if (!help) {
if (p->option & RUN_SETUP)
prefix = setup_git_directory();
if (p->option & RUN_SETUP_GENTLY) {
int nongit_ok;
prefix = setup_git_directory_gently(&nongit_ok);
}
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
use_pager = check_pager_config(p->cmd);
if (use_pager == -1 && p->option & USE_PAGER)
use_pager = 1;
if ((p->option & (RUN_SETUP | RUN_SETUP_GENTLY)) &&
startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */
trace_repo_setup(prefix);
}
commit_pager_choice();
if (!help && p->option & NEED_WORK_TREE)
setup_work_tree();
trace_argv_printf(argv, "trace: built-in: git");
status = p->fn(argc, argv, prefix);
if (status)
return status;
/* Somebody closed stdout? */
if (fstat(fileno(stdout), &st))
return 0;
/* Ignore write errors for pipes and sockets.. */
if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
return 0;
/* Check for ENOSPC and EIO errors.. */
if (fflush(stdout))
die_errno("write failure on standard output");
if (ferror(stdout))
die("unknown write failure on standard output");
if (fclose(stdout))
die_errno("close failed on standard output");
return 0;
}
static void handle_internal_command(int argc, const char **argv)
{
const char *cmd = argv[0];
static struct cmd_struct commands[] = {
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "annotate", cmd_annotate, RUN_SETUP },
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
{ "archive", cmd_archive },
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
{ "blame", cmd_blame, RUN_SETUP },
{ "branch", cmd_branch, RUN_SETUP },
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY },
{ "cat-file", cmd_cat_file, RUN_SETUP },
{ "check-attr", cmd_check_attr, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "checkout-index", cmd_checkout_index,
RUN_SETUP | NEED_WORK_TREE},
{ "cherry", cmd_cherry, RUN_SETUP },
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
{ "clone", cmd_clone },
{ "column", cmd_column, RUN_SETUP_GENTLY },
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "config", cmd_config, RUN_SETUP_GENTLY },
{ "count-objects", cmd_count_objects, RUN_SETUP },
{ "describe", cmd_describe, RUN_SETUP },
{ "diff", cmd_diff },
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
{ "diff-index", cmd_diff_index, RUN_SETUP },
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
{ "fast-export", cmd_fast_export, RUN_SETUP },
{ "fetch", cmd_fetch, RUN_SETUP },
{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
{ "format-patch", cmd_format_patch, RUN_SETUP },
{ "fsck", cmd_fsck, RUN_SETUP },
{ "fsck-objects", cmd_fsck, RUN_SETUP },
{ "gc", cmd_gc, RUN_SETUP },
{ "get-tar-commit-id", cmd_get_tar_commit_id },
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
{ "hash-object", cmd_hash_object },
{ "help", cmd_help },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
{ "log", cmd_log, RUN_SETUP },
{ "ls-files", cmd_ls_files, RUN_SETUP },
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
{ "mailinfo", cmd_mailinfo },
{ "mailsplit", cmd_mailsplit },
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
{ "merge-base", cmd_merge_base, RUN_SETUP },
{ "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
{ "merge-index", cmd_merge_index, RUN_SETUP },
{ "merge-ours", cmd_merge_ours, RUN_SETUP },
{ "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
{ "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
{ "merge-tree", cmd_merge_tree, RUN_SETUP },
{ "mktag", cmd_mktag, RUN_SETUP },
{ "mktree", cmd_mktree, RUN_SETUP },
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
{ "name-rev", cmd_name_rev, RUN_SETUP },
{ "notes", cmd_notes, RUN_SETUP },
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
{ "pack-redundant", cmd_pack_redundant, RUN_SETUP },
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
{ "patch-id", cmd_patch_id },
{ "peek-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
{ "pickaxe", cmd_blame, RUN_SETUP },
{ "prune", cmd_prune, RUN_SETUP },
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
{ "push", cmd_push, RUN_SETUP },
{ "read-tree", cmd_read_tree, RUN_SETUP },
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
{ "remote", cmd_remote, RUN_SETUP },
{ "remote-ext", cmd_remote_ext },
{ "remote-fd", cmd_remote_fd },
{ "replace", cmd_replace, RUN_SETUP },
{ "repo-config", cmd_repo_config, RUN_SETUP_GENTLY },
{ "rerere", cmd_rerere, RUN_SETUP },
{ "reset", cmd_reset, RUN_SETUP },
{ "rev-list", cmd_rev_list, RUN_SETUP },
{ "rev-parse", cmd_rev_parse },
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
{ "rm", cmd_rm, RUN_SETUP },
{ "send-pack", cmd_send_pack, RUN_SETUP },
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
{ "show", cmd_show, RUN_SETUP },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show-ref", cmd_show_ref, RUN_SETUP },
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
{ "stripspace", cmd_stripspace },
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
{ "tag", cmd_tag, RUN_SETUP },
{ "tar-tree", cmd_tar_tree },
{ "unpack-file", cmd_unpack_file, RUN_SETUP },
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
{ "update-index", cmd_update_index, RUN_SETUP },
{ "update-ref", cmd_update_ref, RUN_SETUP },
{ "update-server-info", cmd_update_server_info, RUN_SETUP },
{ "upload-archive", cmd_upload_archive },
{ "upload-archive--writer", cmd_upload_archive_writer },
{ "var", cmd_var, RUN_SETUP_GENTLY },
{ "verify-pack", cmd_verify_pack },
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
{ "version", cmd_version },
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
{ "write-tree", cmd_write_tree, RUN_SETUP },
};
int i;
static const char ext[] = STRIP_EXTENSION;
if (sizeof(ext) > 1) {
i = strlen(argv[0]) - strlen(ext);
if (i > 0 && !strcmp(argv[0] + i, ext)) {
char *argv0 = xstrdup(argv[0]);
argv[0] = cmd = argv0;
argv0[i] = '\0';
}
}
/* Turn "git cmd --help" into "git help cmd" */
if (argc > 1 && !strcmp(argv[1], "--help")) {
argv[1] = argv[0];
argv[0] = cmd = "help";
}
for (i = 0; i < ARRAY_SIZE(commands); i++) {
struct cmd_struct *p = commands+i;
if (strcmp(p->cmd, cmd))
continue;
exit(run_builtin(p, argc, argv));
}
}
static void execv_dashed_external(const char **argv)
{
struct strbuf cmd = STRBUF_INIT;
const char *tmp;
int status;
if (use_pager == -1)
use_pager = check_pager_config(argv[0]);
commit_pager_choice();
strbuf_addf(&cmd, "git-%s", argv[0]);
/*
* argv[0] must be the git command, but the argv array
* belongs to the caller, and may be reused in
* subsequent loop iterations. Save argv[0] and
* restore it on error.
*/
tmp = argv[0];
argv[0] = cmd.buf;
trace_argv_printf(argv, "trace: exec:");
/*
* if we fail because the command is not found, it is
* OK to return. Otherwise, we just pass along the status code.
*/
status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE | RUN_CLEAN_ON_EXIT);
if (status >= 0 || errno != ENOENT)
exit(status);
argv[0] = tmp;
strbuf_release(&cmd);
}
static int run_argv(int *argcp, const char ***argv)
{
int done_alias = 0;
while (1) {
/* See if it's an internal command */
handle_internal_command(*argcp, *argv);
/* .. then try the external ones */
execv_dashed_external(*argv);
/* It could be an alias -- this works around the insanity
* of overriding "git log" with "git show" by having
* alias.log = show
*/
if (done_alias || !handle_alias(argcp, argv))
break;
done_alias = 1;
}
return done_alias;
}
int main(int argc, const char **argv)
{
const char *cmd;
startup_info = &git_startup_info;
cmd = git_extract_argv0_path(argv[0]);
if (!cmd)
cmd = "git-help";
git_setup_gettext();
/*
* "git-xxxx" is the same as "git xxxx", but we obviously:
*
* - cannot take flags in between the "git" and the "xxxx".
* - cannot execute it externally (since it would just do
* the same thing over again)
*
* So we just directly call the internal command handler, and
* die if that one cannot handle it.
*/
if (!prefixcmp(cmd, "git-")) {
cmd += 4;
argv[0] = cmd;
handle_internal_command(argc, argv);
die("cannot handle %s internally", cmd);
}
/* Look for flags.. */
argv++;
argc--;
handle_options(&argv, &argc, NULL);
if (argc > 0) {
if (!prefixcmp(argv[0], "--"))
argv[0] += 2;
} else {
/* The user didn't specify a command; give them help */
commit_pager_choice();
printf("usage: %s\n\n", git_usage_string);
list_common_cmds_help();
printf("\n%s\n", git_more_info_string);
exit(1);
}
cmd = argv[0];
/*
* We use PATH to find git commands, but we prepend some higher
* precedence paths: the "--exec-path" option, the GIT_EXEC_PATH
* environment, and the $(gitexecdir) from the Makefile at build
* time.
*/
setup_path();
while (1) {
static int done_help = 0;
static int was_alias = 0;
was_alias = run_argv(&argc, &argv);
if (errno != ENOENT)
break;
if (was_alias) {
fprintf(stderr, "Expansion of alias '%s' failed; "
"'%s' is not a git command\n",
cmd, argv[0]);
exit(1);
}
if (!done_help) {
cmd = argv[0] = help_unknown_cmd(cmd);
done_help = 1;
} else
break;
}
fprintf(stderr, "Failed to run command '%s': %s\n",
cmd, strerror(errno));
return 1;
}

74
samples/C/hash.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#include "hash.h"
#if defined(PPC_SHA1)
# include "ppc/sha1.h"
#else
# include "sha1.h"
#endif
struct git_hash_ctx {
SHA_CTX c;
};
git_hash_ctx *git_hash_new_ctx(void)
{
git_hash_ctx *ctx = git__malloc(sizeof(*ctx));
if (!ctx)
return NULL;
SHA1_Init(&ctx->c);
return ctx;
}
void git_hash_free_ctx(git_hash_ctx *ctx)
{
git__free(ctx);
}
void git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
SHA1_Init(&ctx->c);
}
void git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{
assert(ctx);
SHA1_Update(&ctx->c, data, len);
}
void git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
SHA1_Final(out->id, &ctx->c);
}
void git_hash_buf(git_oid *out, const void *data, size_t len)
{
SHA_CTX c;
SHA1_Init(&c);
SHA1_Update(&c, data, len);
SHA1_Final(out->id, &c);
}
void git_hash_vec(git_oid *out, git_buf_vec *vec, size_t n)
{
SHA_CTX c;
size_t i;
SHA1_Init(&c);
for (i = 0; i < n; i++)
SHA1_Update(&c, vec[i].data, vec[i].len);
SHA1_Final(out->id, &c);
}

7
samples/C/hello.c Normal file
View File

@@ -0,0 +1,7 @@
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}

6
samples/C/hello.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef HELLO_H
#define HELLO_H
void hello();
#endif

2059
samples/C/http_parser.c Normal file

File diff suppressed because it is too large Load Diff

318
samples/C/http_parser.h Normal file
View File

@@ -0,0 +1,318 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef http_parser_h
#define http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
#define HTTP_PARSER_VERSION_MAJOR 1
#define HTTP_PARSER_VERSION_MINOR 0
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef unsigned int size_t;
typedef int ssize_t;
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#endif
/* Compile with -DHTTP_PARSER_DEBUG=1 to add extra debugging information to
* the error reporting facility.
*/
#ifndef HTTP_PARSER_DEBUG
# define HTTP_PARSER_DEBUG 0
#endif
/* Maximium header size allowed */
#define HTTP_MAX_HEADER_SIZE (80*1024)
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
* returning '1' from on_headers_complete will tell the parser that it
* should not expect a body. This is used when receiving a response to a
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body.
*
* http_data_cb does not return data chunks. It will be call arbitrarally
* many times for each string. E.G. you might get 10 callbacks for "on_path"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* webdav */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
/* subversion */ \
XX(16, REPORT, REPORT) \
XX(17, MKACTIVITY, MKACTIVITY) \
XX(18, CHECKOUT, CHECKOUT) \
XX(19, MERGE, MERGE) \
/* upnp */ \
XX(20, MSEARCH, M-SEARCH) \
XX(21, NOTIFY, NOTIFY) \
XX(22, SUBSCRIBE, SUBSCRIBE) \
XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(24, PATCH, PATCH) \
XX(25, PURGE, PURGE) \
enum http_method
{
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
#undef XX
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_TRAILING = 1 << 3
, F_UPGRADE = 1 << 4
, F_SKIPBODY = 1 << 5
};
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
/* Get the line number that generated the current error */
#if HTTP_PARSER_DEBUG
#define HTTP_PARSER_ERRNO_LINE(p) ((p)->error_lineno)
#else
#define HTTP_PARSER_ERRNO_LINE(p) 0
#endif
struct http_parser {
/** PRIVATE **/
unsigned char type : 2; /* enum http_parser_type */
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned char state; /* enum state from http_parser.c */
unsigned char header_state; /* enum header_state from http_parser.c */
unsigned char index; /* index into current matcher */
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned short status_code; /* responses only */
unsigned char method; /* requests only */
unsigned char http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned char upgrade : 1;
#if HTTP_PARSER_DEBUG
uint32_t error_lineno;
#endif
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_MAX = 6
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
void http_parser_init(http_parser *parser, enum http_parser_type type);
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns true, then this will be should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
#ifdef __cplusplus
}
#endif
#endif

2551
samples/C/markdown.c Normal file

File diff suppressed because it is too large Load Diff

462
samples/C/process.c Normal file
View File

@@ -0,0 +1,462 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <errno.h>
#include <sys/wait.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#ifdef __APPLE__
# include <TargetConditionals.h>
#endif
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
#else
extern char **environ;
#endif
static void uv__chld(EV_P_ ev_child* watcher, int revents) {
int status = watcher->rstatus;
int exit_status = 0;
int term_signal = 0;
uv_process_t *process = watcher->data;
assert(&process->child_watcher == watcher);
assert(revents & EV_CHILD);
ev_child_stop(EV_A_ &process->child_watcher);
if (WIFEXITED(status)) {
exit_status = WEXITSTATUS(status);
}
if (WIFSIGNALED(status)) {
term_signal = WTERMSIG(status);
}
if (process->exit_cb) {
process->exit_cb(process, exit_status, term_signal);
}
}
int uv__make_socketpair(int fds[2], int flags) {
#ifdef SOCK_NONBLOCK
int fl;
fl = SOCK_CLOEXEC;
if (flags & UV__F_NONBLOCK)
fl |= SOCK_NONBLOCK;
if (socketpair(AF_UNIX, SOCK_STREAM|fl, 0, fds) == 0)
return 0;
if (errno != EINVAL)
return -1;
/* errno == EINVAL so maybe the kernel headers lied about
* the availability of SOCK_NONBLOCK. This can happen if people
* build libuv against newer kernel headers than the kernel
* they actually run the software on.
*/
#endif
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return -1;
uv__cloexec(fds[0], 1);
uv__cloexec(fds[1], 1);
if (flags & UV__F_NONBLOCK) {
uv__nonblock(fds[0], 1);
uv__nonblock(fds[1], 1);
}
return 0;
}
int uv__make_pipe(int fds[2], int flags) {
#if __linux__
int fl;
fl = UV__O_CLOEXEC;
if (flags & UV__F_NONBLOCK)
fl |= UV__O_NONBLOCK;
if (uv__pipe2(fds, fl) == 0)
return 0;
if (errno != ENOSYS)
return -1;
#endif
if (pipe(fds))
return -1;
uv__cloexec(fds[0], 1);
uv__cloexec(fds[1], 1);
if (flags & UV__F_NONBLOCK) {
uv__nonblock(fds[0], 1);
uv__nonblock(fds[1], 1);
}
return 0;
}
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success.
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2],
int writable) {
int fd = -1;
switch (container->flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
UV_INHERIT_STREAM)) {
case UV_IGNORE:
return 0;
case UV_CREATE_PIPE:
assert(container->data.stream != NULL);
if (container->data.stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
return -1;
}
return uv__make_socketpair(fds, 0);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:
if (container->flags & UV_INHERIT_FD) {
fd = container->data.fd;
} else {
fd = container->data.stream->fd;
}
if (fd == -1) {
errno = EINVAL;
return -1;
}
fds[writable ? 1 : 0] = fd;
return 0;
default:
assert(0 && "Unexpected flags");
return -1;
}
}
static int uv__process_stdio_flags(uv_stdio_container_t* container,
int writable) {
if (container->data.stream->type == UV_NAMED_PIPE &&
((uv_pipe_t*)container->data.stream)->ipc) {
return UV_STREAM_READABLE | UV_STREAM_WRITABLE;
} else if (writable) {
return UV_STREAM_WRITABLE;
} else {
return UV_STREAM_READABLE;
}
}
static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2],
int writable) {
int fd = fds[writable ? 1 : 0];
int child_fd = fds[writable ? 0 : 1];
int flags;
/* No need to create stream */
if (!(container->flags & UV_CREATE_PIPE) || fd < 0) {
return 0;
}
assert(child_fd >= 0);
close(child_fd);
uv__nonblock(fd, 1);
flags = uv__process_stdio_flags(container, writable);
return uv__stream_open((uv_stream_t*)container->data.stream, fd, flags);
}
static void uv__process_close_stream(uv_stdio_container_t* container) {
if (!(container->flags & UV_CREATE_PIPE)) return;
uv__stream_close((uv_stream_t*)container->data.stream);
}
static void uv__process_child_init(uv_process_options_t options,
int stdio_count,
int* pipes) {
int i;
if (options.flags & UV_PROCESS_DETACHED) {
setsid();
}
/* Dup fds */
for (i = 0; i < stdio_count; i++) {
/*
* stdin has swapped ends of pipe
* (it's the only one readable stream)
*/
int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2];
int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1];
if (use_fd >= 0) {
close(close_fd);
} else if (i < 3) {
/* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */
use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR);
if (use_fd < 0) {
perror("failed to open stdio");
_exit(127);
}
} else {
continue;
}
if (i != use_fd) {
dup2(use_fd, i);
close(use_fd);
}
}
if (options.cwd && chdir(options.cwd)) {
perror("chdir()");
_exit(127);
}
if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
perror("setgid()");
_exit(127);
}
if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
perror("setuid()");
_exit(127);
}
environ = options.env;
execvp(options.file, options.args);
perror("execvp()");
_exit(127);
}
#ifndef SPAWN_WAIT_EXEC
# define SPAWN_WAIT_EXEC 1
#endif
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv_process_options_t options) {
/*
* Save environ in the case that we get it clobbered
* by the child process.
*/
char** save_our_env = environ;
int stdio_count = options.stdio_count < 3 ? 3 : options.stdio_count;
int* pipes = malloc(2 * stdio_count * sizeof(int));
#if SPAWN_WAIT_EXEC
int signal_pipe[2] = { -1, -1 };
struct pollfd pfd;
#endif
int status;
pid_t pid;
int i;
if (pipes == NULL) {
errno = ENOMEM;
goto error;
}
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
loop->counters.process_init++;
uv__handle_start(process);
process->exit_cb = options.exit_cb;
/* Init pipe pairs */
for (i = 0; i < stdio_count; i++) {
pipes[i * 2] = -1;
pipes[i * 2 + 1] = -1;
}
/* Create socketpairs/pipes, or use raw fd */
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_init_stdio(&options.stdio[i], pipes + i * 2, i != 0)) {
goto error;
}
}
/* This pipe is used by the parent to wait until
* the child has called `execve()`. We need this
* to avoid the following race condition:
*
* if ((pid = fork()) > 0) {
* kill(pid, SIGTERM);
* }
* else if (pid == 0) {
* execve("/bin/cat", argp, envp);
* }
*
* The parent sends a signal immediately after forking.
* Since the child may not have called `execve()` yet,
* there is no telling what process receives the signal,
* our fork or /bin/cat.
*
* To avoid ambiguity, we create a pipe with both ends
* marked close-on-exec. Then, after the call to `fork()`,
* the parent polls the read end until it sees POLLHUP.
*/
#if SPAWN_WAIT_EXEC
if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
goto error;
#endif
pid = fork();
if (pid == -1) {
#if SPAWN_WAIT_EXEC
close(signal_pipe[0]);
close(signal_pipe[1]);
#endif
environ = save_our_env;
goto error;
}
if (pid == 0) {
/* Child */
uv__process_child_init(options, stdio_count, pipes);
/* Execution never reaches here. */
}
/* Parent. */
/* Restore environment. */
environ = save_our_env;
#if SPAWN_WAIT_EXEC
/* POLLHUP signals child has exited or execve()'d. */
close(signal_pipe[1]);
do {
pfd.fd = signal_pipe[0];
pfd.events = POLLIN|POLLHUP;
pfd.revents = 0;
errno = 0, status = poll(&pfd, 1, -1);
}
while (status == -1 && (errno == EINTR || errno == ENOMEM));
assert((status == 1) && "poll() on pipe read end failed");
close(signal_pipe[0]);
#endif
process->pid = pid;
ev_child_init(&process->child_watcher, uv__chld, pid, 0);
ev_child_start(process->loop->ev, &process->child_watcher);
process->child_watcher.data = process;
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_open_stream(&options.stdio[i], pipes + i * 2, i == 0)) {
int j;
/* Close all opened streams */
for (j = 0; j < i; j++) {
uv__process_close_stream(&options.stdio[j]);
}
goto error;
}
}
free(pipes);
return 0;
error:
uv__set_sys_error(process->loop, errno);
for (i = 0; i < stdio_count; i++) {
close(pipes[i * 2]);
close(pipes[i * 2 + 1]);
}
free(pipes);
return -1;
}
int uv_process_kill(uv_process_t* process, int signum) {
int r = kill(process->pid, signum);
if (r) {
uv__set_sys_error(process->loop, errno);
return -1;
} else {
return 0;
}
}
uv_err_t uv_kill(int pid, int signum) {
int r = kill(pid, signum);
if (r) {
return uv__new_sys_error(errno);
} else {
return uv_ok_;
}
}
void uv__process_close(uv_process_t* handle) {
ev_child_stop(handle->loop->ev, &handle->child_watcher);
uv__handle_stop(handle);
}

129
samples/C/rdiscount.c Normal file
View File

@@ -0,0 +1,129 @@
#include <stdio.h>
#include "ruby.h"
#include "mkdio.h"
static VALUE rb_cRDiscount;
static VALUE
rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
{
/* grab char pointer to markdown input text */
char *res;
int szres;
VALUE encoding;
VALUE text = rb_funcall(self, rb_intern("text"), 0);
VALUE buf = rb_str_buf_new(1024);
Check_Type(text, T_STRING);
int flags = rb_rdiscount__get_flags(self);
MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
if ( mkd_compile(doc, flags) ) {
szres = mkd_document(doc, &res);
if ( szres != EOF ) {
rb_str_cat(buf, res, szres);
rb_str_cat(buf, "\n", 1);
}
}
mkd_cleanup(doc);
/* force the input encoding */
if ( rb_respond_to(text, rb_intern("encoding")) ) {
encoding = rb_funcall(text, rb_intern("encoding"), 0);
rb_funcall(buf, rb_intern("force_encoding"), 1, encoding);
}
return buf;
}
static VALUE
rb_rdiscount_toc_content(int argc, VALUE *argv, VALUE self)
{
char *res;
int szres;
int flags = rb_rdiscount__get_flags(self);
/* grab char pointer to markdown input text */
VALUE text = rb_funcall(self, rb_intern("text"), 0);
Check_Type(text, T_STRING);
/* allocate a ruby string buffer and wrap it in a stream */
VALUE buf = rb_str_buf_new(4096);
MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
if ( mkd_compile(doc, flags) ) {
szres = mkd_toc(doc, &res);
if ( szres != EOF ) {
rb_str_cat(buf, res, szres);
rb_str_cat(buf, "\n", 1);
}
}
mkd_cleanup(doc);
return buf;
}
int rb_rdiscount__get_flags(VALUE ruby_obj)
{
/* compile flags */
int flags = MKD_TABSTOP | MKD_NOHEADER;
/* smart */
if ( rb_funcall(ruby_obj, rb_intern("smart"), 0) != Qtrue )
flags = flags | MKD_NOPANTS;
/* filter_html */
if ( rb_funcall(ruby_obj, rb_intern("filter_html"), 0) == Qtrue )
flags = flags | MKD_NOHTML;
/* generate_toc */
if ( rb_funcall(ruby_obj, rb_intern("generate_toc"), 0) == Qtrue)
flags = flags | MKD_TOC;
/* no_image */
if ( rb_funcall(ruby_obj, rb_intern("no_image"), 0) == Qtrue)
flags = flags | MKD_NOIMAGE;
/* no_links */
if ( rb_funcall(ruby_obj, rb_intern("no_links"), 0) == Qtrue)
flags = flags | MKD_NOLINKS;
/* no_tables */
if ( rb_funcall(ruby_obj, rb_intern("no_tables"), 0) == Qtrue)
flags = flags | MKD_NOTABLES;
/* strict */
if ( rb_funcall(ruby_obj, rb_intern("strict"), 0) == Qtrue)
flags = flags | MKD_STRICT;
/* autolink */
if ( rb_funcall(ruby_obj, rb_intern("autolink"), 0) == Qtrue)
flags = flags | MKD_AUTOLINK;
/* safelink */
if ( rb_funcall(ruby_obj, rb_intern("safelink"), 0) == Qtrue)
flags = flags | MKD_SAFELINK;
/* no_pseudo_protocols */
if ( rb_funcall(ruby_obj, rb_intern("no_pseudo_protocols"), 0) == Qtrue)
flags = flags | MKD_NO_EXT;
return flags;
}
void Init_rdiscount()
{
rb_cRDiscount = rb_define_class("RDiscount", rb_cObject);
rb_define_method(rb_cRDiscount, "to_html", rb_rdiscount_to_html, -1);
rb_define_method(rb_cRDiscount, "toc_content", rb_rdiscount_toc_content, -1);
}
/* vim: set ts=4 sw=4: */

2538
samples/C/redis.c Normal file

File diff suppressed because it is too large Load Diff

164
samples/C/yajl.c Normal file
View File

@@ -0,0 +1,164 @@
/*
* Copyright 2010, Lloyd Hilaiel.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of Lloyd Hilaiel nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "api/yajl_parse.h"
#include "yajl_lex.h"
#include "yajl_parser.h"
#include "yajl_alloc.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
const char *
yajl_status_to_string(yajl_status stat)
{
const char * statStr = "unknown";
switch (stat) {
case yajl_status_ok:
statStr = "ok, no error";
break;
case yajl_status_client_canceled:
statStr = "client canceled parse";
break;
case yajl_status_insufficient_data:
statStr = "eof was met before the parse could complete";
break;
case yajl_status_error:
statStr = "parse error";
break;
}
return statStr;
}
yajl_handle
yajl_alloc(const yajl_callbacks * callbacks,
const yajl_parser_config * config,
const yajl_alloc_funcs * afs,
void * ctx)
{
unsigned int allowComments = 0;
unsigned int validateUTF8 = 0;
yajl_handle hand = NULL;
yajl_alloc_funcs afsBuffer;
/* first order of business is to set up memory allocation routines */
if (afs != NULL) {
if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
{
return NULL;
}
} else {
yajl_set_default_alloc_funcs(&afsBuffer);
afs = &afsBuffer;
}
hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
/* copy in pointers to allocation routines */
memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
if (config != NULL) {
allowComments = config->allowComments;
validateUTF8 = config->checkUTF8;
}
hand->callbacks = callbacks;
hand->ctx = ctx;
hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8);
hand->bytesConsumed = 0;
hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
yajl_bs_init(hand->stateStack, &(hand->alloc));
yajl_bs_push(hand->stateStack, yajl_state_start);
return hand;
}
void
yajl_reset_parser(yajl_handle hand) {
hand->lexer = yajl_lex_realloc(hand->lexer);
}
void
yajl_free(yajl_handle handle)
{
yajl_bs_free(handle->stateStack);
yajl_buf_free(handle->decodeBuf);
yajl_lex_free(handle->lexer);
YA_FREE(&(handle->alloc), handle);
}
yajl_status
yajl_parse(yajl_handle hand, const unsigned char * jsonText,
unsigned int jsonTextLen)
{
yajl_status status;
status = yajl_do_parse(hand, jsonText, jsonTextLen);
return status;
}
yajl_status
yajl_parse_complete(yajl_handle hand)
{
/* The particular case we want to handle is a trailing number.
* Further input consisting of digits could cause our interpretation
* of the number to change (buffered "1" but "2" comes in).
* A very simple approach to this is to inject whitespace to terminate
* any number in the lex buffer.
*/
return yajl_parse(hand, (const unsigned char *)" ", 1);
}
unsigned char *
yajl_get_error(yajl_handle hand, int verbose,
const unsigned char * jsonText, unsigned int jsonTextLen)
{
return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
}
unsigned int
yajl_get_bytes_consumed(yajl_handle hand)
{
if (!hand) return 0;
else return hand->bytesConsumed;
}
void
yajl_free_error(yajl_handle hand, unsigned char * str)
{
/* use memory allocation functions if set */
YA_FREE(&(hand->alloc), str);
}
/* XXX: add utility routines to parse from file */