<html>

<head><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyFirstUnitAd -->
<ins class="adsbygoogle"
     style="display:inline-block;width:970px;height:250px"
     data-ad-client="ca-pub-5778386704669218"
     data-ad-slot="1503492166"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Linux file operations</title>
</head>

<body>



<p align="left"><font size="6" color="#FF0000"><span lang="en-ca"><b>&nbsp; 
 
</b></span><b>&nbsp;&nbsp;&nbsp; <span lang="en-ca">&nbsp;&nbsp; Dynamic Pointer 
Array</span></b></font></p>

<div align="left">
  <pre><b><font color="#ff0000" size="5">A. <span lang="en-ca">Second </span>Edition</font></b></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>This is comp444 lab1 and it is concentrated on file operations such as searching, replacing, copying...</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>I want to keep this simple version for possible future modification. In this version, I rearrange the structure</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>of &quot;fileBuf&quot; by seperating it from &quot;searchString&quot; module. And add a new dynamic array module.</b></span></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">B</span>.<span lang="en-ca"><a name="problem"></a>The problem</span></font></b></pre>
</div>
<div align="left">
  <p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>How to guarantee the 
  array is self-increasing? This kind of dynamic arrays have been written by me 
  many times.</b></font></span></p>
  <p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>The only difficulty is 
  how to program and debug C in Linux.</b></font></span></p>
  <b><font color="#ff0000" size="5"><span lang="en-ca"><a name="explain"></a>C</span>.<span lang="en-ca">The
  </span></font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>idea of 
  program</b></font></span></div>
<div align="left">
  　</div>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>To simulate a class in C++ 
by using a structure which book keeps the size of array. To make it general, I 
design</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>to ask user to pass its own 
comparing and display method.</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>The function pointer type 
in C is defined like:</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>typedef returnType 
funcTypeName(argType1,argType2...);</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>And when you are using 
function pointer, you need to declare it as pointer:</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>returnType 
realFunction(argType1, funcTypeName* funcPtr);</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>There is some subtle 
difference between C++.</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>It takes me more than two 
hours to find a simple pointer error with GDB. It is really a pain when you are
</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>starving.</b></font></span></p>
<div align="left">
  <pre><b><font color="#ff0000" size="5">D.<span lang="en-ca"><a name="Method"></a>The </span>major functions</font></b></pre>
</div>
<div align="left">
  <pre>　</pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">E</span>.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>Further improvement</b></font></span></pre>
</div>
<div align="left">
  <pre>　</pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">F</span>.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>File listing</b></font></span></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">1. myhead.h</span></b></font></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="3"><b>2</b></font></span><font size="3"><b><span lang="en-ca">. searchString.h</span></b></font></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="3"><b>3</b></font></span><font size="3"><b><span lang="en-ca">. searchString.c</span></b></font></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">4. main.c</span></b></font></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">5. errHandle.</span></b></font><span lang="en-ca"><font size="3"><b>c</b></font></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="3"><b>6</b></font></span><font size="3"><b><span lang="en-ca">. fileBuf.h</span></b></font></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">7. fileBuf.</span></b></font><span lang="en-ca"><font size="3"><b>c</b></font></span></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">8. dynaArray.h</span></b></font></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">9. dynaArray.</span></b></font><span lang="en-ca"><font size="3"><b>c</b></font></span></pre>
</div>
<div align="left">
  <pre><font size="3"><b><span lang="en-ca">10. makefile</span></b></font></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: myhead.h</b></font></span></pre>
</div>
<pre>#ifndef MYHEAD_H
#define MYHEAD_H

#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;
#include &lt;dirent.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;
#include &lt;fcntl.h&gt;

typedef int bool;

#define TRUE  1
#define FALSE 0

//for a particular file NAME, NOT path
//const int MaxNameLength=20;
#define MaxNameLength  20 
#define BuffSize   128

void errHandle(char* msg);
	
#endif
</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: searchString.h</b></font></span></pre>
<pre>#ifndef SEARCHSTRING_H
#define SEARCHSTRING_H

#include &quot;myhead.h&quot;
#include &quot;fileBuf.h&quot;

int findString(char* fileName, char* str);

//search in a file with my own file information struct FileBuf*, 
//target is the string for searching
//repeating call this function and return each location, 
//return -1 indicating end of file
int searchString(FilePtr stream, char* target);


#endif</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: searchString.c</b></font></span></pre>
<pre>#include &quot;myhead.h&quot;
#include &quot;searchString.h&quot;
#include &quot;fileBuf.h&quot;

bool findString(char* fileName, char* str)
{
	int fd, n=0;
	FilePtr stream;
	bool result=FALSE;
	if ((fd=open(fileName, O_RDONLY))&lt;0)
	{
		errHandle(&quot;cannot open searching files\n&quot;);
	}
	if ((stream=openFile(fd))==NULL)
	{
		errHandle(&quot;openfile error\n&quot;);
	}
	while ((n=searchString(stream, str))!=-1)
	{
		result=TRUE;
		printf(&quot;test: find target at %d\n&quot;, n);
	}
	return result;
}



//starting a particular file offset and search the target string
//if found return the file offset of target, else return -1
int searchString(FilePtr stream, char* target)
{
	int stringLength=strlen(target);
	char ch;
	int result=-1;//this is the starting offset of word
	//the length of word compared
	int length;
	int mode;
	length=0;
	mode=FindNextWord;//initial status
	//-1 means EOF
	while ((ch=nextChar(stream))!=-1)
	{
		switch (mode)
		{
		case FindNextWord:
			if (isChar(ch))
			{
				//check the very first 
				if (ch==target[0])
				{
					mode=Comparing;
					length=1;//need to compare with next
					result=stream-&gt;offset-1;//as it already passed it
				}
				else
				{
					mode=SkipTillNext;
				}				
			}
			//else keep going
			break;
		case SkipTillNext:
			if (isBreak(ch))
			{
				mode=FindNextWord;
			}
			break;				
		case Comparing:
			//it is a match
			if (ch==target[length])
			{
				//a match then keep going
				length++;
			        //a white space
                        	if (length==stringLength)
                        	{
                                	return result;
                        	}
			}
			else
			{
				//it means mis-match
				mode=SkipTillNext;
			}
			break;
		}//switch
	}//while					
	return -1;
}		
						

		
	</pre>
<pre>
		
<span lang="en-ca"><font size="3" color="#FF0000"><b>file name: errHandle.c</b></font></span></pre>
<pre>#include &quot;myhead.h&quot;


void errHandle(char* msg)
{
	if (msg!=NULL)
	{
		perror(msg);
	}
	else
	{
		strerror(errno);
	}		
	exit(errno);
}
	</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: fileBuf.h</b></font></span></pre>
<pre>#ifndef FILEBUF_H
#define FILEBUF_H

#include &quot;myhead.h&quot;


struct FileBuf
{
	int fd;
	int size;
	int offset;
	int cur;
	//char buf[128];
	char buf[BuffSize];
};

typedef struct FileBuf* FilePtr;


//define three mode and it is purely like DFA=Deterministic Finite Automaton
#define FindNextWord   	0
#define SkipTillNext	1
#define Comparing	2


//specify if it is white space char
//notice here, in C, there is no boolean type and I define it
//as alias of int in &quot;myhead.h&quot;
bool isBreak(char ch);

void copyFile(char* source, char* target);

void replace(int fd, int offset, char* str);

//my edition of getc
FilePtr openFile(int fd);

//a-z, A-Z
bool isChar(char ch);

//my edition of getc
char nextChar(struct FileBuf* stream);


//my version of fclose
void closeFile(FilePtr ptr);


#endif
		
</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: fileBuf.c</b></font></span></pre>
<pre>#include &quot;fileBuf.h&quot;

//the reason I don't want to combine both copy and replace together is
//that in the possible sorting like quick sort which is not stable sorting method
//the offset to be replaced in one file maybe sorted in different order,
//i.e. foo.txt 169 foo.txt 140 foo.txt 249
//in such situation, it is very unsafe to copy a chunk of file and then 
//replace. So, divide the job into TWO pass is a safe way.

//it is of course low efficiency to first copy and replace, but 
//it is easy to code
void copyFile(char* source, char* target)
{
	int fdOld, fdNew, n;
	char buf[BuffSize];
	if ((fdOld=open(source, O_RDONLY))&lt;0)
	{
		errHandle(&quot;open error when copying file\n&quot;);
	}
	if ((fdNew=open(target, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR))&lt;0)
	{
		errHandle(&quot;open error when copying file\n&quot;);
	}
	while ((n=read(fdOld, buf, BuffSize))!=0)
	{
		if (n!=write(fdNew, buf, n))
		{
			errHandle(&quot;write error when copying file\n&quot;);
		}
	}
}
	
void replace(int fd, int offset, char* str)
{
	int size;
	if (str==NULL)
	{
		printf(&quot;cannot replace empty string\n&quot;);
		return;
	}
	//strlen is just a function and it will be used more than once
	size=strlen(str);
	if (lseek(fd, offset, SEEK_SET)&lt;0)
	{
		errHandle(&quot;lseek error when replacing\n&quot;);
	}
	if (size!=write(fd, str, size))
	{
		errHandle(&quot;write error when replace\n&quot;);
	}
	
}


//my version of fclose
void closeFile(FilePtr ptr)
{
	free(ptr);
}


//my edition of &quot;fopen&quot;
FilePtr openFile(int fd)
{
	FilePtr result=(FilePtr)malloc(sizeof(struct FileBuf));
	if (result==NULL)
	{
		errHandle(&quot;cannot allocate memory for FileBuf\n&quot;);
	}
	result-&gt;fd=fd;
	result-&gt;offset=0;
	if ((result-&gt;size=read(fd, result-&gt;buf, BuffSize))&lt;0)
	{
		free(result);
		return NULL;
	}
	result-&gt;cur=0;
	return result;
}

//getc
char nextChar(FilePtr stream)
{
	//if buff is fully read
	if (stream-&gt;cur &gt;= stream-&gt;size)
	{
		if (stream-&gt;size==0)//must be end of file
		{
			return -1;
			//return EOF;
		}
		//if erro happened during reading
		if ((stream-&gt;size=read(stream-&gt;fd, stream-&gt;buf, BuffSize))&lt;0)
		{
			errHandle(&quot;read error of file buf\n&quot;);
		}
		//reset cur
		stream-&gt;cur=0;
	}
	//offset is always inc for each call
	stream-&gt;offset++;
	return stream-&gt;buf[stream-&gt;cur++];
}
	
//what is white space
bool isBreak(char ch)
{
	return (ch==' '||ch=='\t'||ch=='\n');
}

bool isChar(char ch)
{
	return ((ch&gt;='A'&amp;&amp;ch&lt;='Z')||(ch&gt;='a'&amp;&amp;ch&lt;='z'));
}

</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: dynaArray.h</b></font></span></pre>
<pre>#ifndef DYNAARRAY_H
#define DYNAARRAY_H

#include &quot;myhead.h&quot;

#define DefaultLength  20

//each is a pointer
struct DynaArray
{
	void** ptr;
	int len;//max size, the index of last node
	int cur;//current position, relative index of last node
	int fold;
};

typedef struct DynaArray* DynaArrayPtr;

//define a function pointer for comparing in sorting
typedef bool CompFunc(void* first, void* second);

//define a show func type
typedef void ShowFunc(void* ptr); 

//create with default length and fold is 1
DynaArrayPtr createArray();

//this can be only called internally after a node is added
void expand(DynaArrayPtr arrayPtr);


//this is typical C++ member function, 
void addEnd(DynaArrayPtr arrayPtr, void* ptr);//without sorting

//user need to supply with comp function, return true for first '&lt;' second
//it must be strictly smaller, as equal used to indicate it is a copy
//the addOne function should return the index of node inserted, -1 if already there
int addOne(DynaArrayPtr arrayPtr, void* ptr, CompFunc* compFunc);

void displayArray(DynaArrayPtr arrayPtr, ShowFunc* showFunc); 
		
#endif	</pre>
<pre>　</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: dynaArray.c</b></font></span></pre>
<pre>#include &quot;dynaArray.h&quot;

//user need to supply with comp function, return true for first '&lt;' second
//it must be strictly smaller, as equal used to indicate it is a copy
//the addOne function should return the index of node inserted, -1 if already there
int addOne(DynaArrayPtr arrayPtr, void* ptr, CompFunc* compFunc)
{
	int pos=0, i;
	//1st case, there is no node in array
	while (pos&lt;arrayPtr-&gt;len)
	{
		if (!compFunc(ptr, arrayPtr-&gt;ptr[pos]))
		{
			pos++;
		}
		else
		{
			if (ptr==arrayPtr-&gt;ptr[pos])
			{
				//2nd case, it is already there
				return -1;//it is a copy
			}
			//should insert here, and there must have space, shift first
			for (i=arrayPtr-&gt;len; i&gt;pos; i--)
			{
				arrayPtr-&gt;ptr[i]=arrayPtr-&gt;ptr[i-1];
			}
			//3rd case, it is shifted first
			break;
		}
	}	
	arrayPtr-&gt;ptr[pos]=ptr;//insert
	arrayPtr-&gt;len++;
	arrayPtr-&gt;cur++;
	if (arrayPtr-&gt;cur==DefaultLength)
	{
		expand(arrayPtr);
	}		
}
		
//create with default length and fold is 1
DynaArrayPtr createArray()
{
	DynaArrayPtr result;
	if ((result=(DynaArrayPtr)malloc(DefaultLength*sizeof(void*)))==NULL)
	{
		errHandle(&quot;cannot alloc memory for dyna array creation\n&quot;);
	}
	result-&gt;len=0;//the actual number of pointers in array
	result-&gt;cur=0;//internal use only
	result-&gt;fold=1;
	
	if ((result-&gt;ptr=(void**)malloc(DefaultLength*sizeof(void*)))==NULL)
	{
		errHandle(&quot;cannot alloc memory for dyna array\n&quot;);
	}
	return result;
}

//user must pass a user-defined function pointer for displaying struct
void displayArray(DynaArrayPtr arrayPtr, ShowFunc* showFunc)
{
	int i;
	for (i=0; i&lt;arrayPtr-&gt;len; i++)
	{
		showFunc(arrayPtr-&gt;ptr[i]);
	}
}


//this is typical C++ member function, 
void addEnd(DynaArrayPtr arrayPtr, void* ptr)
{
	arrayPtr-&gt;ptr[arrayPtr-&gt;len++]=ptr;
	arrayPtr-&gt;cur++;
	if (arrayPtr-&gt;cur==DefaultLength)
        {
                expand(arrayPtr);
        }

}

void expand(DynaArrayPtr arrayPtr)
{
	arrayPtr-&gt;fold++;
	if ((arrayPtr-&gt;ptr=realloc(arrayPtr-&gt;ptr, arrayPtr-&gt;fold*DefaultLength*sizeof(void*)))==NULL)
	{
		errHandle(&quot;expand error for dyna array\n&quot;);
	}
	arrayPtr-&gt;cur=0;//it should be
}	</pre>
<pre>　</pre>
<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: makefile</b></font></span></pre>
<pre>all:    main.o 
	@echo &quot;make complete for main.o &quot;

fileBuf.o : fileBuf.c fileBuf.h myhead.h
	@echo &quot;compiling fileBuf.o...&quot;
	gcc -g -c fileBuf.c -o fileBuf.o

errHandle.o : errHandle.c myhead.h
	@echo &quot;compiling errHanle module...&quot;
	gcc -g -c errHandle.c -o errHandle.o

main.o : searchString.o main.c errHandle.o myhead.h fileBuf.o dynaArray.o
	@echo &quot;compiling main.o...&quot; 
	gcc -g main.c searchString.o errHandle.o fileBuf.o dynaArray.o -o main.o

searchString.o : searchString.h searchString.c myhead.h
	@echo &quot;compiling searchString.o...&quot;
	gcc -g -c searchString.c -o searchString.o

dynaArray.o : dynaArray.h dynaArray.c myhead.h
	@echo &quot;compiling dynaArray.o...&quot;
	gcc -g -c dynaArray.c -o dynaArray.o

clear :
	@echo &quot;clear up...\n&quot;
	rm *.o
</pre>
<pre>　</pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre><span lang="en-ca"><font color="#0000FF"><b>How to run?</b></font></span></pre>
<pre><span lang="en-ca"><font color="#0000FF"><b>1. Just run make and main.o</b></font></span></pre>

<pre>[qingz_hu@alamanni ~/lab1] % make
compiling main.o...
gcc -g main.c searchString.o errHandle.o fileBuf.o dynaArray.o -o main.o
make complete for main.o 
[qingz_hu@alamanni ~/lab1] % ./main.o
the following is the random generated array
84, 87, 78, 16, 94, 36, 87, 93, 50, 22, 63, 28, 91, 60, 64, 27, 41, 27, 73, 37, 12, 69, 68, 30, 83, 31, 63, 24, 68, 36, 30, 3, </pre>

<pre>23, 59, 70, 68, 94, 57, 12, 43, 30, 74, 22, 20, 85, 38, 99, 25, 16, 71, 14, 27, 92, 81, 57, 74, 63, 71, 97, 82, 6, 26, 85, 28, </pre>

<pre>37, 6, 47, 30, 14, 58, 25, 96, 83, 46, 15, 68, 35, 65, 44, 51, 88, 9, 77, 79, 89, 85, 4, 52, 55, 100, 33, 61, 77, 69, 40, 13, </pre>

<pre>27, 87, 95, 40, 
now display the sorted array
3,4,6,6,9,12,12,13,14,14,15,16,16,20,22,22,23,24,25,25,26,27,27,27,27,28,28,30,30,30,30,31,33,35,36,36,37,37,38,40,40,41,43,</pre>

<pre>44,46,47,50,51,52,55,57,57,58,59,60,61,63,63,63,64,65,68,68,68,68,69,69,70,71,71,73,74,74,77,77,78,79,81,82,83,83,84,85,85,85,</pre>

<pre>87,87,87,88,89,91,92,93,94,94,95,96,97,99,100,

</pre>

<pre></pre>

<pre></pre>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                                   
&nbsp;&nbsp;&nbsp; <a href="PocketRuler.htm">                  







                       <img src="picture/back.gif" style="border: medium none" alt="back.gif (341 bytes)" width="32" height="35"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<a href="index.htm">
<img src="picture/up.gif" style="border: medium none" alt="up.gif (335 bytes)" width="35" height="32"></a>       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                         
<img src="picture/next.gif" style="border: medium none" alt="next.gif (337 bytes)" width="32" height="35">          


</p>

</body>

</html>