Skip navigation.

蓝星のXSK'S BLOG

囧囧囧囧囧囧囧囧囧囧

Posts tagged with "programme"

关于MAGIC文件...

MAGIC文件来自Unix系统下file(1)命令...
作用是检查文件开始的几个字节,来判定文件的类型。

以下是magic文件在apache中的mime_magic_module模块的用法和定义...(译者:金步国)

Read more...

[转] Very Simple Guide To Xbox App/emulator Porting

from: xbox-scene
这篇文章是XBOX上最新的SFC模拟器 Zsnexbox 的移植作者 nes6502 写的,简单的介绍了如何移植一些程序到XBOX
The reason I wrote this guide was to explain the process of porting a game or an emulator to the Xbox. You don’t have to be a coding master. All you need is the tools to build an Xbox application, basic knowledge of C (and or C++), and some determination. I am not the authority on the subject, but I have ported an emulator to the Xbox, and I am writing from this experience. This is a VERY high level view. But the framework is here.

Why am I writing this and posting it in the emulators forum? I realize that many emulator users read this forum and might want their favorite application/game/emulator ported to the Xbox. In reality, the only way it may ever get ported is if they do it themselves. I have wanted ZSNES on the Xbox (native port) since I started using the Xbox, and I realised that the only way it was going to happen was if I did it myself. So I did. I had never ported anything to the Xbox (or any console) before and I am not an expert coder. With determination I was able to do it, and i think it turned out well. So if you want your favorite app/emulator/game on the Xbox, instead of waiting for a day that may never come, people might want to try and do it themselves. This is a basic guide for those people that don't know where to begin.

Tools:

1) XDK
2) Visual Studio 2003. NET
3) You do not need a debug XBOX (even though it is helpful). Without one, you will be burning CD’s every time you want to test a change.

Step 1) Decide what you want to port. For this example I will talk about ZSNES. ZSNES is written in C and Assembly. I’m pretty familiar with C and not very familiar with Assembly.

Step 2) Download the source code. It’s easiest if you can compile it on Windows first. After following the instructions, I was able to compile the windows version of ZSNES.

Step 3) Create a new Xbox application workspace in VS 2003. Add all the C/C++ files to the project. If there are assembly files (like in ZSNES), just add the “obj” files for the ASM ones generated from Step 2 to the project.

Step 4) Compile the Xbox project. This is where the fun starts. There will be lots of compile errors because the PC version is likely using code, functions, libraries that are not supported on the Xbox. For example, ZSNES uses DirectDraw code to draw the screen. There is no DirectDraw support on the Xbox, so I had to learn how to do the same thing with Direct3D. Basically: how to set the color of each pixel on the screen. Once I replaced all the DirectDraw code, that entire group of errors went away.

Another example is the input. ZSNES assumes there is a mouse used. I commented out all the code that used a mouse because there isn’t one on the Xbox. Another example is the keyboard. Since there is no Xbox keyboard, I replaced all the keyboard code with Xbox controller code. ZSNES still thinks there is a keyboard attached and checks to see if any buttons are pressed. I just monitor buttons on the Xbox controller, and when one is pressed, I tell ZSNES that one of the keyboard keys was pressed.

Step 5) Compile again. Now continue replacing code that gives errors with code that doesn’t.

Step 6) Repeat Step 5 until all errors are gone. Once all the errors are fixed, VS will generate an “xbe” file that can be run on the Xbox.

A great starting point is the Genadrive source code. It is easy to read and easy to compile. Try compiling it and running it on the Xbox. Then study what it is doing to draw pixels on the screen, read the controller, read files in a directory for the ROM browser, etc.. In fact I used this as my base for ZsnexBox and basically built around it, added to it, etc...This is the only thing I’ve ported to the Xbox and I am not a coding expert. You don’t have to be. If you have a basic understanding of C, the tools needed to compile the application, and the willingness to learn things you need (like basic Direct3D), then there is nothing stopping you from porting anything you want.

###############################################################################
这里还有一篇讲如何移植sdl程序的(使用lantus大大移植的SDLx)
Wondering if someone would be willing to write a "how I ported this game to the xbox" tutorial. I see some very simple demos and apps that look like they should be simple to port over, such as:

http://www.libsdl.org/projects/fire

I think this would help spark some more interest in porting already available SDL based games and apps to the XBOX.

-hurtz






qucik tutorial for converting the 'fire' app you suggested:

(this was far easier than i expected )

For fire, create a xbox application, set it to be an empty project (no pch headers). Add the fire.c file to it. Add the path of your SDLx includes to the path for library header in the project properties. This should compile now, but not link. To make it link add the libsdlx.lib (or whatever your copy is called) to the list of libs the linker will use (properties again). Build your project and you should have a sucessfully ported 'fire' sample app.

More Info:

First you need to get SDLx installed and compiled (or use the precompiled libs).

Then you need to determine what libraries the app you are porting uses. In the case of fire, this is none. For scummvm, this would be libmad, libmpeg2, and a few others.

For the libraries, create a visual studio project, xbox application, and set type to library without pch headers. Then add the source files to the project from the libraries, set the preprocessor defines from the original library in the new project, and compile. Hopefully this will create you lib for you.

For the main application, create a new project for an xbox game. make it an empty project. Add to this project all your files for the thing youre porting. Make sure you set and defines the project needs up. Scummvm needed several such as USE_MPEG2, USE_VORBIS, and USE_MAD. Put these defines in the properties of the project, c/c++, preprocessor, preprocessor definitions.

Your next step is getting the code to fully compile. I found on of the easiest ways to do this is comment out code chunk and functions that wont compile, marking them or writing them down so you can find em later.

Once compliled, you can try and run your app. Depending on how much you commented out, is how well it runs.

One thing that very usefull is the XKUtils package. Not sure where to get this, i blagged a copy within the source of guybrush port of scummvm.

If it need file or disk access, you need to mount your hard drives somewhere within your code. Generally this is done using the following code

XKUtils::MountAllDisks();

after includeing the xkutils.h header file.

File access has to be done using full paths. An Xbox cant use relative paths (WHY!!!!! its a pain).

If you want to pass command line arguments to your project:

char *x_argv[100];
int x_argc = 1;
DWORD dwLaunchType;
LAUNCH_DATA LaunchData;
XGetLaunchInfo(&dwLaunchType, &LaunchData);

if (dwLaunchType == LDT_FROM_DEBUGGER_CMDLINE)
{
x_argv[x_argc] = strtok(((PLD_FROM_DEBUGGER_CMDLINE)&LaunchData)->szCmdLine, " ");
while (x_argv[x_argc] != NULL) {
x_argc++;
x_argv[x_argc] = strtok(NULL, " ");
}
}

sould put command line args in x_argv[].

Theres no need to worry about full screen mode or anything similar, once sdlx is intialised, its always fullscreen and you screen res chosen is scaled.

Also use the following functions to control how much overscan is used etc.

SDL_XBOX_SetScreenPosition(x,y);
SDL_XBOX_SetScreenStretch(xs,ys);


Hope some of this helps.

Clarky

###################################################################

最近开始试着用CLANLIB....

ClanLib是一个主要针对游戏开发者的跨平台C++框架。尽管API主要为游戏开发设计,你照样可以容易地使用ClanLib来开发一个科学的3D可视化工具或多媒体应用程序(例如Gecko多媒体系统)。

  ClanLib拥有各种API-2D和3D图形,声音,网络,I/O,输入,GUI以及资源管理。它还提供透明的OpenGL支持,因此你可以使用本机OpenGL命令而让ClanLib处理依赖于操作系统的窗口管理和其它一切事情。ClanLib通过DirectX或简单的Direct Media Layer(一平台独立的多媒体库)生成2D图形。ClanLib游戏主页上列举了约50多个开发非常成功的游戏,包括以2D和3D形式完成的难题、策略以及射手类游戏。例如,Asteroid Arena(见图1)使用了ClanLib和OpenGL技术,实现了胜人一筹的经典街机游戏。


  ClanLib可以工作在Windows,Linux和MacOS操作系统之上,并且提供源码级的zip或tar文件支持。Windows开发者可以使用微软Visual Studio,Borland C++或者MinGW(小型GNU for Windows)编译器和环境。第三方的对于Ruby和Perl语言的绑定支持也是可用的。可选的特效程序包括一个Lua插件(流行的小脚本编程语言)和FreeType(一个免费的TrueType字体库)。





最新版本是0.8.....渣啊...我以后再也不敢用cygwin和mingw了....安装时间巨长...机不好的自己编译东西又慢...搭建一个开发环境都要用好几天时间....-_-b 还遇上automake什么的版本对应问题...
果然还是直接在LINUX开发好.....

这里是clanlib的官网
如果你在编译过程中碰到了问题可以给我留言...官网上有相关的配置教程..自己看...
有人用CLANLIB写了塞尔达四支剑的程序...虽然只是一部分...但大部分功能都实现了,你可以到SF上找到这个项目..貌似
官网上也有LINK...

今天查PSP资料的时候看到了这个很有意思的站...格志

地址是 http://gezhi.org/user/hui
如站上描述所讲的
格志从一个群组 blog 开始,现在希望成为一个面向科研人员,学生,和科学作家与记者的社区网站。我们在这里 blog on 科学 blog 圈;分享科技知识,新闻,努力做点高级科普;作为学术交流平台,网络上的 common room。我们欢迎任何对科学感兴趣,从事科学研究或者科技新闻报道的人参与我们,让这个地方变得更有用有趣。

这是一个团体BLOG,很有意思~XD

而HUI写的这篇关于PSP HAKING的文章非常的全...也很有水准
你可以参见这里
http://gezhi.org/node/211

[转]关于模板元编程

在1994年C++标准委员会的一次会议期间,Erwin Unruh展示了一个可以产生质数的程序。此程序特别之处在于质数的产生发生于编译期而非运行期。在编译器产生的一系列错误信息中间夹杂着从2到某个设定值之间的所有质数。它展示了可以利用模板实例化机制于编译期执行一些计算。这种通过模板实例化而执行的编译期计算技术,即是广为人知的模板元编程(Template Metaprogramming)。

当年Erwin Unruh凭借Metaware编译器展示了这一有趣的效果,幸运的是,今天触手可及的G++还能为我们完整再现之。也怪不得其他几款编译器,因为编译器的出错信息并未被标准化。

下面就是94年那次会议期间广为流传的代码之修订版(为了能够在今天符合标准的编译器上进行编译,做了少许修改):

// Prime number computation by Erwin Unruh 

template <int i> struct D { D(void*); operator int(); }; 

template <int p, int i> struct is_prime { 
  enum { prim = (p==2) || (p%i) && is_prime<(i>2?p:0), i-1> :: prim }; 
}; 

template <int i> struct Prime_print { 
  Prime_print<i-1> a; 
  enum { prim = is_prime<i, i-1>::prim }; 
  void f() { D<i> d = prim ? 1 : 0; a.f();} 
}; 

template<> struct is_prime<0,0> { enum {prim=1}; }; 
template<> struct is_prime<0,1> { enum {prim=1}; }; 

template<> struct Prime_print<1> { 
  enum {prim=0}; 
  void f() { D<1> d = prim ? 1 : 0; }; 
}; 

#ifndef LAST 
#define LAST 18 
#endif 

main() { 
  Prime_print<LAST> a; 
  a.f(); 
}

因为类模板D只有一个参数为void*的构造器,而只有0才能被合法转换为void*,因此,在g++上编译这段程序时,编译器将会给出如下错误信息(以及其他一些信息。简短起见,它们被删除了):

unruh.cpp:12: invalid conversion from `int' to `void*'
unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 17]'
unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 13]':
unruh.cpp:12: invalid conversion from `int' to `void*'
unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 13]'
unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 11]':
unruh.cpp:12: invalid conversion from `int' to `void*'
unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 11]'
unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 7]':
unruh.cpp:12: invalid conversion from `int' to `void*'
unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 7]'
unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 5]':
unruh.cpp:12: invalid conversion from `int' to `void*'
unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 5]'
unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 3]':
unruh.cpp:12: invalid conversion from `int' to `void*'
unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 3]'
unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 2]':


C++模板元编程技术在Blitz++http://www.oonumerics.org/blitz/这样的数值矩阵库中得到了进一步的应用。如果你对编译期计算和模板元编程技术感兴趣,我推荐你阅读《C++ Templates: The Complete Guide》一书。幸运的是,内地和台湾年内都将出版这部著作的中文版。

(2)zile circular doubly-linked lists/queues ...

circular doubly-linked lists/queues的实现list结构的definition
typedef struct list_s *list;
struct list_s {
  list prev;
  list next;
  void *item;
};



创建一个空链表,返回一个指向list的指针,initialize list,分配一个header结点
/* Create an empty list, returning a pointer to the list */
list list_new(void)
{
  list l = zmalloc(sizeof(struct list_s)); //分配空间

  l->next = l->prev = l; 
  l->item = NULL;

  return l;
}

迭代删除这个链表..用2个指针P和Q
/* Delete a list, freeing its nodes */
void list_delete(list l)
{
  list p = l, q;

  do {
    q = p;
    p = p->next;
    free(q);
  } while (p != l);
}

用length遍历list记录表长
/* Return the length of a list */
size_t list_length(list l)
{
  list p;
  size_t length = 0;

  for (p = l->next; p != l; p = p->next)
    ++length;

  return length;
}

从表头插入一个数值为i的node
/* Add an item to the head of a list, returning the new list head */
list list_prepend(list l, void *i)
{
  list n = zmalloc(sizeof(struct list_s));

  n->next = l->next;
  n->prev = l;
  n->item = i;
  l->next = l->next->prev = n;

  return n;
}

从表尾插入i,把i的next指到header结点
/* Add an item to the tail of a list, returning the new list tail */
list list_append(list l, void *i)
{
  list n = zmalloc(sizeof(struct list_s));

  n->next = l;
  n->prev = l->prev;
  n->item = i;
  l->prev = l->prev->next = n;

  return n;
}


返回第一个item的值,list为空则返回NULL
/* Return the first item of a list, or NULL if the list is empty */
void *list_head(list l)
{
  list p = l->next;

  if (p == l)
    return NULL;

  return p->item;
}

移除第一个item,list为空则返回NULL
/* Remove the first item of a list, returning the item, or NULL if the
   list is empty */
void *list_behead(list l)
{
  void *i;
  list p = l->next;

  if (p == l)
    return NULL;
  i = p->item;
  l->next = l->next->next;
  l->next->prev = l;
  free(p);

  return i;
}

移除最后一个item
/* Remove the last item of a list, returning the item, or NULL if the
   list is empty */
void *list_betail(list l)
{
  void *i;
  list p = l->prev;

  if (p == l)
    return NULL;
  i = p->item;
  l->prev = l->prev->prev;
  l->prev->next = l;
  free(p);

  return i;
}


范围对应第N个元素的数值,越界操作则返回空
/* Return the nth item of l, or l->item (usually NULL) if that is out
   of range */
void *list_at(list l, size_t n)
{
  size_t i;
  list p;
        
  assert(l != NULL);

  for (p = list_first(l), i = 0; p != l && i < n; p = list_next(p), i++)
    ;
  
  return p->item;
}

通过cmp function对list进行排序,因为不能在list中直接进行排序,所以把每个元素迭代放入数组vec中进行
qsort(stdlib.c 快速排序)后再放回list
/* Sort list l with qsort using comparison function cmp */
void list_sort(list l, int (*cmp)(const void *p1, const void *p2))
{
  list p;
  void **vec;
  size_t i, len = list_length(l);

  assert(l != NULL && cmp != NULL); //assert传入数值不为空

  vec = (void **)zmalloc(sizeof(void *) * len);

  for (p = list_first(l), i = 0; i < len; p = list_next(p), ++i)
    vec[i] = (void *)p->item;

  qsort(vec, len, sizeof(void *), cmp);

  for (p = list_first(l), i = 0; i < len; p = list_next(p), ++i)
    p->item = vec[i];

  free(vec);
}


About qsort
七种qsort排序方法 

<本文中排序都是采用的从小到大排序> 

一、对int类型数组排序 

int num[100]; 

Sample: 

int cmp ( const void *a , const void *b ) 
{ 
return *(int *)a - *(int *)b; 
} 

qsort(num,100,sizeof(num[0]),cmp); 

二、对char类型数组排序(同int类型) 

char word[100]; 

Sample: 

int cmp( const void *a , const void *b ) 
{ 
return *(char *)a - *(int *)b; 
} 

qsort(word,100,sizeof(word[0]),cmp); 

三、对double类型数组排序(特别要注意) 

double in[100]; 

int cmp( const void *a , const void *b ) 
{ 
return *(double *)a > *(double *)b ? 1 : -1; 
} 

qsort(in,100,sizeof(in[0]),cmp); 

四、对结构体一级排序 

struct In 
{ 
double data; 
int other; 
}s[100] 

//按照data的值从小到大将结构体排序,关于结构体内的排序关键数据data的类型可以很多种,参考上面的例子写 

int cmp( const void *a ,const void *b) 
{ 
return (*(In *)a)->data > (*(In *)b)->data ? 1 : -1; 
} 

qsort(s,100,sizeof(s[0]),cmp); 

五、对结构体二级排序 

struct In 
{ 
int x; 
int y; 
}s[100]; 

//按照x从小到大排序,当x相等时按照y从大到小排序 

int cmp( const void *a , const void *b ) 
{ 
struct In *c = (In *)a; 
struct In *d = (In *)b; 
if(c->x != d->x) return c->x - d->x; 
else return d->y - c->y; 
} 

qsort(s,100,sizeof(s[0]),cmp); 

六、对字符串进行排序 

struct In 
{ 
int data; 
char str[100]; 
}s[100]; 

//按照结构体中字符串str的字典顺序排序 

int cmp ( const void *a , const void *b ) 
{ 
return strcmp( (*(In *)a)->str , (*(In *)b)->str ); 
} 

qsort(s,100,sizeof(s[0]),cmp); 

七、计算几何中求凸包的cmp 

int cmp(const void *a,const void *b) //重点cmp函数,把除了1点外的所有点,旋转角度排序 
{ 
struct point *c=(point *)a; 
struct point *d=(point *)b; 
if( calc(*c,*d,p[1]) < 0) return 1; 
else if( !calc(*c,*d,p[1]) && dis(c->x,c->y,p[1].x,p[1].y) < dis(d->x,d->y,p[1].x,p[1].y)) //如果在一条直线上,则把远的放在前面 
return 1; 
else return -1; 
} 

其中的qsort函数包含在<stdlib.h>的头文件里,strcmp包含在<string.h>的头文件里

关于qsort的实现
你可以参见opensolaris的qsort.c的实现
访问这里



Main types and definitions

这里声明了编辑器使用的结构类型
typedef struct Point Point;
typedef struct Marker Marker;
typedef struct list_s Line;   /* This is evil! */
typedef struct Undo Undo;
typedef struct Region Region;
typedef struct Buffer Buffer;
typedef struct Window Window;
typedef struct Completion Completion;
typedef struct History History;
typedef struct Terminal Terminal;



行列标记
/* Point and Marker. */
struct Point {
  Line *p;                      /* Line pointer.(list) */ 
  size_t n;                     /* Line number. */
  size_t o;                     /* Offset. */
};

astr strings source code of zile analysis...

-__- i've read zile source code by sourceinsight(a tool that read source code on windows perform) recently...
now i wanna write a read report on my blog...because it can advance my coding ability...

this is some about astr strings:

The astr library provides dynamically allcoated null-terminated C strings.
The string type, astr, is a pointer type.
String positions start at zero, as with ordinary C cstrings.
Negative values are also allowed, and count from the end of the string.
In particular, -1 refers to the last character of the string.(-1值的倒退到字符最后一位)
Where not otherwise specified, the functions return the first argument
string,usually named as in the function prototype.





Data struct of string:

/*Each time
  the string is enlarged beyond the current size of the buffer it is
  reallocated with realloc.*/
struct astr_s {
  char *  text;  // a buffer that contains the C string
  size_t  len;  // the  size of the string
  size_t  maxlen; //the buffer size
};

define dynamic string type astr:
typedef struct astr_s *astr;



allocate funciton
Allocate a new string with zero length.
extern astr   astr_new(void);
//implement

astr astr_new(void)
{
  astr as;
  as = (astr)zmalloc(sizeof *as);
  as->maxlen = ALLOCATION_CHUNK_SIZE;
  as->len = 0;
  as->text = (char *)zmalloc(as->maxlen + 1);
  memset(as->text, 0, as->maxlen + 1);
  return as;
}

//ALLOCATION_CHUNK_SIZE定义了string buffer的大小...
#define ALLOCATION_CHUNK_SIZE16

-----------------------------------------
zmalloc is from zmalloc.c,this is memory allocation functions, zmalloc Return a zeroed allocated memory area.:
void *zmalloc(size_t size)
{
  void *ptr;

  assert(size > 0); //assert(断言) size_t, string size of allocation

 //calloc函数分配足够大的内存区来存储size个元素的数组,每个元素的长度为1
  if ((ptr = calloc(size, (size_t)1)) == NULL) {   
    fprintf(stderr, "zile: cannot allocate memory\n");
    zile_exit(1);  //-_-b i've discover 3 zile_exit(exitcode) prototype...node temporarily
  }

  return ptr;
}

i've found zmalloc code in opensolaris,
you can find it in this link:http://cvs.opensolaris.org/source/xref/on/usr/src/cmd/sgs/tsort/common/zmalloc.c
42 void *
     43 zmalloc(int severity, size_t n)
     44 {
     45 void*p;
     46 
     47 if ((p = malloc(n)) == NULL)  //malloc分配存储n长度的内存
     48 _errmsg("UXzmalloc1", severity,
     49 "Cannot allocate a block of %d bytes.",
     50 n);
     51 return (p);
     52 }
     

----------------------------------------
resize string....
static void astr_resize(astr as, size_t reqsize)
{
  assert(as != NULL);
  if (reqsize > as->maxlen) {
//重新分配大小,STL中Vector的分配方法是成对应比例加倍,而这里是用分配的空间加上初始大小
    as->maxlen = reqsize + ALLOCATION_CHUNK_SIZE; 
    as->text = (char *)zrealloc(as->text, as->maxlen + 1);
  }
}

这里调用了zrealloc函数..
让我们来看看zmalloc.c下zrealloc的实现.
/*
 * Resize an allocated memory area.
 */
void *zrealloc(void *ptr, size_t size)
{
  void *newptr;

  assert(size > 0);

  if ((newptr = realloc(ptr, size)) == NULL) {
    fprintf(stderr, "zile: cannot reallocate memory\n");
    zile_exit(1);
  }
  return newptr;
}

关于包裹函数
而在zmalloc.c下的的大部分代码都用了这种结构的方法对C函数进行封装,这类似于UNIX下包裹函数(wrapper function)的用法,wrapper function调用实际函数,检查返回值,并在发生错误时终止进程..
在UNIX下的wrapper function的用法约定是大写实际函数的第一个字符;
如实际函数socket()的包裹函数为Socket();

astr_pos check pos whether in astr string:
static int astr_pos(astr as, ptrdiff_t pos)
{
  assert(as != NULL);
  if (pos < 0) // deal with negative....eg: -1 pos in last position of string 
    pos = as->len + pos; 
  assert(pos >=0 && pos <= (int)as->len); //assert pos in astr string
  return pos;
}

//What is ptrdiff_t?ptrdiff_t is portable code, it defined in stddef.h, you can visit this link : http://www.cs.odu.edu/~zeil/cs361/Lectures-f02/00faq/faq/ptrdiff.html

return pointer at pos in string as:
char *astr_char(const astr as, ptrdiff_t pos)
{
  assert(as != NULL);
  pos = astr_pos(as, pos);
  return as->text + pos;
}

free astr, point text to NULL and free as struct:
void astr_delete(astr as)
{
  assert(as != NULL);
  free(as->text);
  as->text = NULL;
  free(as);
}

copy funciton
copy c style string to astr string and return as,specify copy size:
static astr astr_cpy_x(astr as, const char *s, size_t csize)
{
  astr_resize(as, csize);      //1 resize string text size
  memcpy(as->text, s, csize);  //2 memory copy s(csize) to as->text;
  as->len = csize;             //3 reset len of text
  as->text[csize] = '\0';      //4 add NULL character to text
  return as;
}

copy astr string to astr string:
astr astr_cpy(astr as, const astr src)
{
  assert(src != NULL);
  return astr_cpy_x(as, src->text, src->len);
}

copy c style string to astr string,size is strlen(c style string):
astr astr_cpy_cstr(astr as, const char *s)
{
  assert(s != NULL);
  return astr_cpy_x(as, s, strlen(s));
}

cat function
cat c style string s to the tail of astr string as:
//1
static astr astr_cat_x(astr as, const char *s, size_t csize)
{ 
  astr_resize(as, as->len + csize);
  memcpy(as->text + as->len, s, csize); // different copy at this position
  as->len += csize;
  as->text[as->len] = '\0';
  return as;
}
//2
astr astr_cat(astr as, const astr src)
{
  assert(src != NULL);
  return astr_cat_x(as, src->text, src->len);
}
//3
astr astr_ncat_cstr(astr as, const char *s, size_t len)
{
  return astr_cat_x(as, s, len);
}

//cat a char to astr string
astr astr_cat_char(astr as, int c)
{
  assert(as != NULL);
  astr_resize(as, as->len + 1);
  as->text[as->len] = (char)c;
  as->text[++as->len] = '\0';
  return as;
}
//cat astr src to astr as and delete src
astr astr_cat_delete(astr as, const astr src)
{
  assert(src != NULL);
  astr_cat_x(as, src->text, src->len);
  astr_delete(src);
  return as;
}

find function
求substring:(最终通过CAT调用C函数memcopy)
astr astr_substr(const astr as, ptrdiff_t pos, size_t size)
{
  assert(as != NULL);
  pos = astr_pos(as, pos); // location
  assert(pos + size <= as->len); //assert substring not longer than astring len
  return astr_ncat_cstr(astr_new(), astr_char(as, pos), size); //allocation  new astr for memory space...
}

通过strstr获得第一个匹配C指针, sp - as->text为当前位置值:
int astr_find_cstr(const astr as, const char *s)
{
  char *sp;
  assert(as != NULL && s != NULL);
  sp = strstr(as->text, s);
  return (sp == NULL) ? -1 : sp - as->text;
}

invoke c function strrstr find last match:
int astr_rfind(const astr as, const astr src)
{
  return astr_rfind_cstr(as, src->text);
}

int astr_rfind_cstr(const astr as, const char *s)
{
  char *sp;
  assert(as != NULL && s != NULL);
  sp = strrstr(as->text, s);
  return (sp == NULL) ? -1 : sp - as->text;
}

replace算法
这里的replace算法是通过把对应位用s串填入, 再把复制出size后再填入实现的
eg:as为ABCDEFG, pos为2, size为4, s为RRR, csize为3
则整个实现过程为
1 通过substr()复制2+4也就是as的第6个位置后的串到新建的tail结构中
2 截断as得到AB
3 在AB后加上RRR得到ABRRR
4 再把tail cat到ABRRR后得到ABRRRG, 也就实现用RRR替换CDEF 4个字符的过程

static astr astr_replace_x(astr as, ptrdiff_t pos, size_t size, const char *s, size_t csize)
{
  astr tail;

  assert(as != NULL);

  pos = astr_pos(as, pos); //broudary of position  check
  if (as->len - pos < size)
    size = as->len - pos;  //if size beyond, cut

   //这里获得as的最后一个字符,分配一个新astr struct把tail string放入, 这里的tail char是指在pos+size截断后的字符,比如ABCDE中pos为2,size为1,则tail string DE
  tail = astr_substr(as, pos + (ptrdiff_t)size, astr_len(as) - (pos + size)); 

  astr_truncate(as, pos); // 截断string在pos位置
  astr_ncat_cstr(as, s, csize); //把c style string cat到pos后
  astr_cat(as, tail);  //cat回tail string
  astr_delete(tail); //释放astr tail

  return as;
}
December 2009
S M T W T F S
November 2009January 2010
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31