add lab answers
This commit is contained in:
528
labcodes_answer/lab5_result/kern/libs/rb_tree.c
Normal file
528
labcodes_answer/lab5_result/kern/libs/rb_tree.c
Normal file
@@ -0,0 +1,528 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <kmalloc.h>
|
||||
#include <rb_tree.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* rb_node_create - create a new rb_node */
|
||||
static inline rb_node *
|
||||
rb_node_create(void) {
|
||||
return kmalloc(sizeof(rb_node));
|
||||
}
|
||||
|
||||
/* rb_tree_empty - tests if tree is empty */
|
||||
static inline bool
|
||||
rb_tree_empty(rb_tree *tree) {
|
||||
rb_node *nil = tree->nil, *root = tree->root;
|
||||
return root->left == nil;
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_tree_create - creates a new red-black tree, the 'compare' function
|
||||
* is required and returns 'NULL' if failed.
|
||||
*
|
||||
* Note that, root->left should always point to the node that is the root
|
||||
* of the tree. And nil points to a 'NULL' node which should always be
|
||||
* black and may have arbitrary children and parent node.
|
||||
* */
|
||||
rb_tree *
|
||||
rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2)) {
|
||||
assert(compare != NULL);
|
||||
|
||||
rb_tree *tree;
|
||||
rb_node *nil, *root;
|
||||
|
||||
if ((tree = kmalloc(sizeof(rb_tree))) == NULL) {
|
||||
goto bad_tree;
|
||||
}
|
||||
|
||||
tree->compare = compare;
|
||||
|
||||
if ((nil = rb_node_create()) == NULL) {
|
||||
goto bad_node_cleanup_tree;
|
||||
}
|
||||
|
||||
nil->parent = nil->left = nil->right = nil;
|
||||
nil->red = 0;
|
||||
tree->nil = nil;
|
||||
|
||||
if ((root = rb_node_create()) == NULL) {
|
||||
goto bad_node_cleanup_nil;
|
||||
}
|
||||
|
||||
root->parent = root->left = root->right = nil;
|
||||
root->red = 0;
|
||||
tree->root = root;
|
||||
return tree;
|
||||
|
||||
bad_node_cleanup_nil:
|
||||
kfree(nil);
|
||||
bad_node_cleanup_tree:
|
||||
kfree(tree);
|
||||
bad_tree:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* *
|
||||
* FUNC_ROTATE - rotates as described in "Introduction to Algorithm".
|
||||
*
|
||||
* For example, FUNC_ROTATE(rb_left_rotate, left, right) can be expaned to a
|
||||
* left-rotate function, which requires an red-black 'tree' and a node 'x'
|
||||
* to be rotated on. Basically, this function, named rb_left_rotate, makes the
|
||||
* parent of 'x' be the left child of 'x', 'x' the parent of its parent before
|
||||
* rotation and finally fixes other nodes accordingly.
|
||||
*
|
||||
* FUNC_ROTATE(xx, left, right) means left-rotate,
|
||||
* and FUNC_ROTATE(xx, right, left) means right-rotate.
|
||||
* */
|
||||
#define FUNC_ROTATE(func_name, _left, _right) \
|
||||
static void \
|
||||
func_name(rb_tree *tree, rb_node *x) { \
|
||||
rb_node *nil = tree->nil, *y = x->_right; \
|
||||
assert(x != tree->root && x != nil && y != nil); \
|
||||
x->_right = y->_left; \
|
||||
if (y->_left != nil) { \
|
||||
y->_left->parent = x; \
|
||||
} \
|
||||
y->parent = x->parent; \
|
||||
if (x == x->parent->_left) { \
|
||||
x->parent->_left = y; \
|
||||
} \
|
||||
else { \
|
||||
x->parent->_right = y; \
|
||||
} \
|
||||
y->_left = x; \
|
||||
x->parent = y; \
|
||||
assert(!(nil->red)); \
|
||||
}
|
||||
|
||||
FUNC_ROTATE(rb_left_rotate, left, right);
|
||||
FUNC_ROTATE(rb_right_rotate, right, left);
|
||||
|
||||
#undef FUNC_ROTATE
|
||||
|
||||
#define COMPARE(tree, node1, node2) \
|
||||
((tree))->compare((node1), (node2))
|
||||
|
||||
/* *
|
||||
* rb_insert_binary - insert @node to red-black @tree as if it were
|
||||
* a regular binary tree. This function is only intended to be called
|
||||
* by function rb_insert.
|
||||
* */
|
||||
static inline void
|
||||
rb_insert_binary(rb_tree *tree, rb_node *node) {
|
||||
rb_node *x, *y, *z = node, *nil = tree->nil, *root = tree->root;
|
||||
|
||||
z->left = z->right = nil;
|
||||
y = root, x = y->left;
|
||||
while (x != nil) {
|
||||
y = x;
|
||||
x = (COMPARE(tree, x, node) > 0) ? x->left : x->right;
|
||||
}
|
||||
z->parent = y;
|
||||
if (y == root || COMPARE(tree, y, z) > 0) {
|
||||
y->left = z;
|
||||
}
|
||||
else {
|
||||
y->right = z;
|
||||
}
|
||||
}
|
||||
|
||||
/* rb_insert - insert a node to red-black tree */
|
||||
void
|
||||
rb_insert(rb_tree *tree, rb_node *node) {
|
||||
rb_insert_binary(tree, node);
|
||||
node->red = 1;
|
||||
|
||||
rb_node *x = node, *y;
|
||||
|
||||
#define RB_INSERT_SUB(_left, _right) \
|
||||
do { \
|
||||
y = x->parent->parent->_right; \
|
||||
if (y->red) { \
|
||||
x->parent->red = 0; \
|
||||
y->red = 0; \
|
||||
x->parent->parent->red = 1; \
|
||||
x = x->parent->parent; \
|
||||
} \
|
||||
else { \
|
||||
if (x == x->parent->_right) { \
|
||||
x = x->parent; \
|
||||
rb_##_left##_rotate(tree, x); \
|
||||
} \
|
||||
x->parent->red = 0; \
|
||||
x->parent->parent->red = 1; \
|
||||
rb_##_right##_rotate(tree, x->parent->parent); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
while (x->parent->red) {
|
||||
if (x->parent == x->parent->parent->left) {
|
||||
RB_INSERT_SUB(left, right);
|
||||
}
|
||||
else {
|
||||
RB_INSERT_SUB(right, left);
|
||||
}
|
||||
}
|
||||
tree->root->left->red = 0;
|
||||
assert(!(tree->nil->red) && !(tree->root->red));
|
||||
|
||||
#undef RB_INSERT_SUB
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_tree_successor - returns the successor of @node, or nil
|
||||
* if no successor exists. Make sure that @node must belong to @tree,
|
||||
* and this function should only be called by rb_node_prev.
|
||||
* */
|
||||
static inline rb_node *
|
||||
rb_tree_successor(rb_tree *tree, rb_node *node) {
|
||||
rb_node *x = node, *y, *nil = tree->nil;
|
||||
|
||||
if ((y = x->right) != nil) {
|
||||
while (y->left != nil) {
|
||||
y = y->left;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
else {
|
||||
y = x->parent;
|
||||
while (x == y->right) {
|
||||
x = y, y = y->parent;
|
||||
}
|
||||
if (y == tree->root) {
|
||||
return nil;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_tree_predecessor - returns the predecessor of @node, or nil
|
||||
* if no predecessor exists, likes rb_tree_successor.
|
||||
* */
|
||||
static inline rb_node *
|
||||
rb_tree_predecessor(rb_tree *tree, rb_node *node) {
|
||||
rb_node *x = node, *y, *nil = tree->nil;
|
||||
|
||||
if ((y = x->left) != nil) {
|
||||
while (y->right != nil) {
|
||||
y = y->right;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
else {
|
||||
y = x->parent;
|
||||
while (x == y->left) {
|
||||
if (y == tree->root) {
|
||||
return nil;
|
||||
}
|
||||
x = y, y = y->parent;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_search - returns a node with value 'equal' to @key (according to
|
||||
* function @compare). If there're multiple nodes with value 'equal' to @key,
|
||||
* the functions returns the one highest in the tree.
|
||||
* */
|
||||
rb_node *
|
||||
rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key) {
|
||||
rb_node *nil = tree->nil, *node = tree->root->left;
|
||||
int r;
|
||||
while (node != nil && (r = compare(node, key)) != 0) {
|
||||
node = (r > 0) ? node->left : node->right;
|
||||
}
|
||||
return (node != nil) ? node : NULL;
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_delete_fixup - performs rotations and changes colors to restore
|
||||
* red-black properties after a node is deleted.
|
||||
* */
|
||||
static void
|
||||
rb_delete_fixup(rb_tree *tree, rb_node *node) {
|
||||
rb_node *x = node, *w, *root = tree->root->left;
|
||||
|
||||
#define RB_DELETE_FIXUP_SUB(_left, _right) \
|
||||
do { \
|
||||
w = x->parent->_right; \
|
||||
if (w->red) { \
|
||||
w->red = 0; \
|
||||
x->parent->red = 1; \
|
||||
rb_##_left##_rotate(tree, x->parent); \
|
||||
w = x->parent->_right; \
|
||||
} \
|
||||
if (!w->_left->red && !w->_right->red) { \
|
||||
w->red = 1; \
|
||||
x = x->parent; \
|
||||
} \
|
||||
else { \
|
||||
if (!w->_right->red) { \
|
||||
w->_left->red = 0; \
|
||||
w->red = 1; \
|
||||
rb_##_right##_rotate(tree, w); \
|
||||
w = x->parent->_right; \
|
||||
} \
|
||||
w->red = x->parent->red; \
|
||||
x->parent->red = 0; \
|
||||
w->_right->red = 0; \
|
||||
rb_##_left##_rotate(tree, x->parent); \
|
||||
x = root; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
while (x != root && !x->red) {
|
||||
if (x == x->parent->left) {
|
||||
RB_DELETE_FIXUP_SUB(left, right);
|
||||
}
|
||||
else {
|
||||
RB_DELETE_FIXUP_SUB(right, left);
|
||||
}
|
||||
}
|
||||
x->red = 0;
|
||||
|
||||
#undef RB_DELETE_FIXUP_SUB
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_delete - deletes @node from @tree, and calls rb_delete_fixup to
|
||||
* restore red-black properties.
|
||||
* */
|
||||
void
|
||||
rb_delete(rb_tree *tree, rb_node *node) {
|
||||
rb_node *x, *y, *z = node;
|
||||
rb_node *nil = tree->nil, *root = tree->root;
|
||||
|
||||
y = (z->left == nil || z->right == nil) ? z : rb_tree_successor(tree, z);
|
||||
x = (y->left != nil) ? y->left : y->right;
|
||||
|
||||
assert(y != root && y != nil);
|
||||
|
||||
x->parent = y->parent;
|
||||
if (y == y->parent->left) {
|
||||
y->parent->left = x;
|
||||
}
|
||||
else {
|
||||
y->parent->right = x;
|
||||
}
|
||||
|
||||
bool need_fixup = !(y->red);
|
||||
|
||||
if (y != z) {
|
||||
if (z == z->parent->left) {
|
||||
z->parent->left = y;
|
||||
}
|
||||
else {
|
||||
z->parent->right = y;
|
||||
}
|
||||
z->left->parent = z->right->parent = y;
|
||||
*y = *z;
|
||||
}
|
||||
if (need_fixup) {
|
||||
rb_delete_fixup(tree, x);
|
||||
}
|
||||
}
|
||||
|
||||
/* rb_tree_destroy - destroy a tree and free memory */
|
||||
void
|
||||
rb_tree_destroy(rb_tree *tree) {
|
||||
kfree(tree->root);
|
||||
kfree(tree->nil);
|
||||
kfree(tree);
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_node_prev - returns the predecessor node of @node in @tree,
|
||||
* or 'NULL' if no predecessor exists.
|
||||
* */
|
||||
rb_node *
|
||||
rb_node_prev(rb_tree *tree, rb_node *node) {
|
||||
rb_node *prev = rb_tree_predecessor(tree, node);
|
||||
return (prev != tree->nil) ? prev : NULL;
|
||||
}
|
||||
|
||||
/* *
|
||||
* rb_node_next - returns the successor node of @node in @tree,
|
||||
* or 'NULL' if no successor exists.
|
||||
* */
|
||||
rb_node *
|
||||
rb_node_next(rb_tree *tree, rb_node *node) {
|
||||
rb_node *next = rb_tree_successor(tree, node);
|
||||
return (next != tree->nil) ? next : NULL;
|
||||
}
|
||||
|
||||
/* rb_node_root - returns the root node of a @tree, or 'NULL' if tree is empty */
|
||||
rb_node *
|
||||
rb_node_root(rb_tree *tree) {
|
||||
rb_node *node = tree->root->left;
|
||||
return (node != tree->nil) ? node : NULL;
|
||||
}
|
||||
|
||||
/* rb_node_left - gets the left child of @node, or 'NULL' if no such node */
|
||||
rb_node *
|
||||
rb_node_left(rb_tree *tree, rb_node *node) {
|
||||
rb_node *left = node->left;
|
||||
return (left != tree->nil) ? left : NULL;
|
||||
}
|
||||
|
||||
/* rb_node_right - gets the right child of @node, or 'NULL' if no such node */
|
||||
rb_node *
|
||||
rb_node_right(rb_tree *tree, rb_node *node) {
|
||||
rb_node *right = node->right;
|
||||
return (right != tree->nil) ? right : NULL;
|
||||
}
|
||||
|
||||
int
|
||||
check_tree(rb_tree *tree, rb_node *node) {
|
||||
rb_node *nil = tree->nil;
|
||||
if (node == nil) {
|
||||
assert(!node->red);
|
||||
return 1;
|
||||
}
|
||||
if (node->left != nil) {
|
||||
assert(COMPARE(tree, node, node->left) >= 0);
|
||||
assert(node->left->parent == node);
|
||||
}
|
||||
if (node->right != nil) {
|
||||
assert(COMPARE(tree, node, node->right) <= 0);
|
||||
assert(node->right->parent == node);
|
||||
}
|
||||
if (node->red) {
|
||||
assert(!node->left->red && !node->right->red);
|
||||
}
|
||||
int hb_left = check_tree(tree, node->left);
|
||||
int hb_right = check_tree(tree, node->right);
|
||||
assert(hb_left == hb_right);
|
||||
int hb = hb_left;
|
||||
if (!node->red) {
|
||||
hb ++;
|
||||
}
|
||||
return hb;
|
||||
}
|
||||
|
||||
static void *
|
||||
check_safe_kmalloc(size_t size) {
|
||||
void *ret = kmalloc(size);
|
||||
assert(ret != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct check_data {
|
||||
long data;
|
||||
rb_node rb_link;
|
||||
};
|
||||
|
||||
#define rbn2data(node) \
|
||||
(to_struct(node, struct check_data, rb_link))
|
||||
|
||||
static inline int
|
||||
check_compare1(rb_node *node1, rb_node *node2) {
|
||||
return rbn2data(node1)->data - rbn2data(node2)->data;
|
||||
}
|
||||
|
||||
static inline int
|
||||
check_compare2(rb_node *node, void *key) {
|
||||
return rbn2data(node)->data - (long)key;
|
||||
}
|
||||
|
||||
void
|
||||
check_rb_tree(void) {
|
||||
rb_tree *tree = rb_tree_create(check_compare1);
|
||||
assert(tree != NULL);
|
||||
|
||||
rb_node *nil = tree->nil, *root = tree->root;
|
||||
assert(!nil->red && root->left == nil);
|
||||
|
||||
int total = 1000;
|
||||
struct check_data **all = check_safe_kmalloc(sizeof(struct check_data *) * total);
|
||||
|
||||
long i;
|
||||
for (i = 0; i < total; i ++) {
|
||||
all[i] = check_safe_kmalloc(sizeof(struct check_data));
|
||||
all[i]->data = i;
|
||||
}
|
||||
|
||||
int *mark = check_safe_kmalloc(sizeof(int) * total);
|
||||
memset(mark, 0, sizeof(int) * total);
|
||||
|
||||
for (i = 0; i < total; i ++) {
|
||||
mark[all[i]->data] = 1;
|
||||
}
|
||||
for (i = 0; i < total; i ++) {
|
||||
assert(mark[i] == 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < total; i ++) {
|
||||
int j = (rand() % (total - i)) + i;
|
||||
struct check_data *z = all[i];
|
||||
all[i] = all[j];
|
||||
all[j] = z;
|
||||
}
|
||||
|
||||
memset(mark, 0, sizeof(int) * total);
|
||||
for (i = 0; i < total; i ++) {
|
||||
mark[all[i]->data] = 1;
|
||||
}
|
||||
for (i = 0; i < total; i ++) {
|
||||
assert(mark[i] == 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < total; i ++) {
|
||||
rb_insert(tree, &(all[i]->rb_link));
|
||||
check_tree(tree, root->left);
|
||||
}
|
||||
|
||||
rb_node *node;
|
||||
for (i = 0; i < total; i ++) {
|
||||
node = rb_search(tree, check_compare2, (void *)(all[i]->data));
|
||||
assert(node != NULL && node == &(all[i]->rb_link));
|
||||
}
|
||||
|
||||
for (i = 0; i < total; i ++) {
|
||||
node = rb_search(tree, check_compare2, (void *)i);
|
||||
assert(node != NULL && rbn2data(node)->data == i);
|
||||
rb_delete(tree, node);
|
||||
check_tree(tree, root->left);
|
||||
}
|
||||
|
||||
assert(!nil->red && root->left == nil);
|
||||
|
||||
long max = 32;
|
||||
if (max > total) {
|
||||
max = total;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i ++) {
|
||||
all[i]->data = max;
|
||||
rb_insert(tree, &(all[i]->rb_link));
|
||||
check_tree(tree, root->left);
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i ++) {
|
||||
node = rb_search(tree, check_compare2, (void *)max);
|
||||
assert(node != NULL && rbn2data(node)->data == max);
|
||||
rb_delete(tree, node);
|
||||
check_tree(tree, root->left);
|
||||
}
|
||||
|
||||
assert(rb_tree_empty(tree));
|
||||
|
||||
for (i = 0; i < total; i ++) {
|
||||
rb_insert(tree, &(all[i]->rb_link));
|
||||
check_tree(tree, root->left);
|
||||
}
|
||||
|
||||
rb_tree_destroy(tree);
|
||||
|
||||
for (i = 0; i < total; i ++) {
|
||||
kfree(all[i]);
|
||||
}
|
||||
|
||||
kfree(mark);
|
||||
kfree(all);
|
||||
}
|
||||
|
||||
32
labcodes_answer/lab5_result/kern/libs/rb_tree.h
Normal file
32
labcodes_answer/lab5_result/kern/libs/rb_tree.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef __KERN_LIBS_RB_TREE_H__
|
||||
#define __KERN_LIBS_RB_TREE_H__
|
||||
|
||||
#include <defs.h>
|
||||
|
||||
typedef struct rb_node {
|
||||
bool red; // if red = 0, it's a black node
|
||||
struct rb_node *parent;
|
||||
struct rb_node *left, *right;
|
||||
} rb_node;
|
||||
|
||||
typedef struct rb_tree {
|
||||
// compare function should return -1 if *node1 < *node2, 1 if *node1 > *node2, and 0 otherwise
|
||||
int (*compare)(rb_node *node1, rb_node *node2);
|
||||
struct rb_node *nil, *root;
|
||||
} rb_tree;
|
||||
|
||||
rb_tree *rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2));
|
||||
void rb_tree_destroy(rb_tree *tree);
|
||||
void rb_insert(rb_tree *tree, rb_node *node);
|
||||
void rb_delete(rb_tree *tree, rb_node *node);
|
||||
rb_node *rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key);
|
||||
rb_node *rb_node_prev(rb_tree *tree, rb_node *node);
|
||||
rb_node *rb_node_next(rb_tree *tree, rb_node *node);
|
||||
rb_node *rb_node_root(rb_tree *tree);
|
||||
rb_node *rb_node_left(rb_tree *tree, rb_node *node);
|
||||
rb_node *rb_node_right(rb_tree *tree, rb_node *node);
|
||||
|
||||
void check_rb_tree(void);
|
||||
|
||||
#endif /* !__KERN_LIBS_RBTREE_H__ */
|
||||
|
||||
50
labcodes_answer/lab5_result/kern/libs/readline.c
Normal file
50
labcodes_answer/lab5_result/kern/libs/readline.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define BUFSIZE 1024
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
/* *
|
||||
* readline - get a line from stdin
|
||||
* @prompt: the string to be written to stdout
|
||||
*
|
||||
* The readline() function will write the input string @prompt to
|
||||
* stdout first. If the @prompt is NULL or the empty string,
|
||||
* no prompt is issued.
|
||||
*
|
||||
* This function will keep on reading characters and saving them to buffer
|
||||
* 'buf' until '\n' or '\r' is encountered.
|
||||
*
|
||||
* Note that, if the length of string that will be read is longer than
|
||||
* buffer size, the end of string will be discarded.
|
||||
*
|
||||
* The readline() function returns the text of the line read. If some errors
|
||||
* are happened, NULL is returned. The return value is a global variable,
|
||||
* thus it should be copied before it is used.
|
||||
* */
|
||||
char *
|
||||
readline(const char *prompt) {
|
||||
if (prompt != NULL) {
|
||||
cprintf("%s", prompt);
|
||||
}
|
||||
int i = 0, c;
|
||||
while (1) {
|
||||
c = getchar();
|
||||
if (c < 0) {
|
||||
return NULL;
|
||||
}
|
||||
else if (c >= ' ' && i < BUFSIZE - 1) {
|
||||
cputchar(c);
|
||||
buf[i ++] = c;
|
||||
}
|
||||
else if (c == '\b' && i > 0) {
|
||||
cputchar(c);
|
||||
i --;
|
||||
}
|
||||
else if (c == '\n' || c == '\r') {
|
||||
cputchar(c);
|
||||
buf[i] = '\0';
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
78
labcodes_answer/lab5_result/kern/libs/stdio.c
Normal file
78
labcodes_answer/lab5_result/kern/libs/stdio.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <console.h>
|
||||
|
||||
/* HIGH level console I/O */
|
||||
|
||||
/* *
|
||||
* cputch - writes a single character @c to stdout, and it will
|
||||
* increace the value of counter pointed by @cnt.
|
||||
* */
|
||||
static void
|
||||
cputch(int c, int *cnt) {
|
||||
cons_putc(c);
|
||||
(*cnt) ++;
|
||||
}
|
||||
|
||||
/* *
|
||||
* vcprintf - format a string and writes it to stdout
|
||||
*
|
||||
* The return value is the number of characters which would be
|
||||
* written to stdout.
|
||||
*
|
||||
* Call this function if you are already dealing with a va_list.
|
||||
* Or you probably want cprintf() instead.
|
||||
* */
|
||||
int
|
||||
vcprintf(const char *fmt, va_list ap) {
|
||||
int cnt = 0;
|
||||
vprintfmt((void*)cputch, &cnt, fmt, ap);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* *
|
||||
* cprintf - formats a string and writes it to stdout
|
||||
*
|
||||
* The return value is the number of characters which would be
|
||||
* written to stdout.
|
||||
* */
|
||||
int
|
||||
cprintf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
int cnt;
|
||||
va_start(ap, fmt);
|
||||
cnt = vcprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* cputchar - writes a single character to stdout */
|
||||
void
|
||||
cputchar(int c) {
|
||||
cons_putc(c);
|
||||
}
|
||||
|
||||
/* *
|
||||
* cputs- writes the string pointed by @str to stdout and
|
||||
* appends a newline character.
|
||||
* */
|
||||
int
|
||||
cputs(const char *str) {
|
||||
int cnt = 0;
|
||||
char c;
|
||||
while ((c = *str ++) != '\0') {
|
||||
cputch(c, &cnt);
|
||||
}
|
||||
cputch('\n', &cnt);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* getchar - reads a single non-zero character from stdin */
|
||||
int
|
||||
getchar(void) {
|
||||
int c;
|
||||
while ((c = cons_getc()) == 0)
|
||||
/* do nothing */;
|
||||
return c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user