Changes

Jump to navigation Jump to search
4,619 bytes added ,  14:30, 13 March 2007
no edit summary
The routines in TabText allow you to acquire a lines of text (terminated by <tt>\r</tt> or <tt>\n</tt> from a file, and then parse tab-delimited fields within the line. The input file is specificed by a <tt>FILE * </tt> pointer, and the file should be opened prior to calling the TabText routines.

Your program is responsible for allocating a LineBuffer to hold the line of data, and for disposing of the LineBuffer when no longer needed.

== File Format ==

Tabtext assumes the following ascii text file format:

<tt> Line 1 Field 1 \t Field 2 \t Field 3 \t … Line 1 Field n \r

Line 2 Field 1 \t Field 2 \t Field 3 \t … Line 2 Field n \r



Line n Field 1 \t Field 2 \t Field 3 \t … Line n Field n \r </tt>

Note that lines can be terminated by <tt>\r</tt> or <tt>\n</tt> or <tt>\r\n</tt> or the end of the file.

==Example Code==

<tt>

- (BOOL)readFile:(NSString *)filename returnError:(NSMutableString *)errorString

{
:unsigned long i;

:unsigned long num_lines, num_rows, lines_to_skip;

:unsigned long row,column;

:FILE *fp;

:[errorString setString:@"no error"];

:fp = fopen([filename cStringUsingEncoding:NSASCIIStringEncoding],"r");

:// set up a line buffer

:LineBuffer *line = NewLineBuffer(1000);

:// how many lines in the file

:num_lines = CountLinesInFile(line,fp);

:// count lines rewinds the file, so we're back at the beginning..

:lines_to_skip = NUM_HEADER_LINES;

:num_rows = num_lines – lines_to_skip;

:// skip the header lines, if they exist

:for (i=0;i<lines_to_skip;i++) GetNextLine(line,fp);

:// read in all the rows and columns

:column = 0;

:for(row=0;row<num_rows;row++) {

::if (GetNextLine(line,fp)) {

:::while (GetNextTabField(line, tabtext)) {

::::SetRowColumnText(row,column,tabtext);

::::column++;

:::}

::}

:}


:// all the rows have been read in

:// done reading from the file, so dispose of file stuff

:fclose(fp);

:DisposeLineBuffer(line);

:return(TRUE);

}
</tt>

==LineBuffer data structure==
<blockquote>
<tt> typedef struct {


:unsigned long max; // maximum size of the line (i.e. size of buffer pointed to by text)

:char *text; // the buffer that contains the last line read from the file

:char *textptr; // for internal use; a ptr to the start of the next tab field

:char *textend; // for internal use; a pointer to the end of the line

:unsigned long length; // the length of the line, ie. the number of characters that were read in from the file


} LineBuffer;
</tt>
</blockquote>

==Routines==

===<tt>LineBuffer *NewLineBuffer(unsigned long size); </tt>===
<blockquote>
uses <tt>malloc</tt> to allocate a LineBuffer, and malloc to allocate a buffer (lineBuffer->text) that is size bytes long.
</blockquote>

===<tt>void DisposeLineBuffer(LineBuffer *line);</tt>===
<blockquote>
uses <tt>free</tt> to dispose of the text buffer and the LineBuffer itself.
</blockquote>

===<tt>Boolean GetNextLine(LineBuffer *line,FILE *fp);</tt>===
<blockquote>
Reads characters from the file pointed to by <tt>fp</tt>, beginning at the current position of the file, until one of 3 end-of-line characters are encountered: <tt>\r</tt> or <tt>\n</tt> or <tt>\r\n</tt> or the end of the file (when <tt>feof(fp)</tt> is <tt>TRUE</tt>). The line is transferred to the <tt>text</tt> buffer of the <tt>line</tt>. The end of line character is replaced with a null to make a null terminated string.
</blockquote>

===<tt>Boolean GetNextTabField(LineBuffer *line, char *text);</tt>===
<blockquote>
Copies the next series of characters in <tt>line-text</tt> into <tt>text</tt>, terminating when either a tab character <tt>\t</tt> or the end of the line is encountered. Returns <tt>TRUE</tt> if a tab field is found, or <tt>FALSE</tt> if we have already incremented through the entire line. The internal variable <tt>line-textptr</tt> is updated to point to the beginning of the next tab field.
</blockquote>

===<tt>void ResetTabFields(LineBuffer *line);</tt>===

<blockquote>
Rewind the internal pointer, so that the next tab field returned by <tt>GetNextTabField</tt> is the first tabfield in the line. NB: this only rewinds the current line, not the whole file – use <tt>rewind(fp) </tt> for that.
</blockquote>

===<tt>unsigned long CountLinesInFile(LineBuffer *line,FILE *fp);</tt>===
<blockquote>
A utility routine to increment through the entire file just to count how many lines of text are in the file (i.e. how many lines are terminated by <tt>\r</tt> or <tt>\n</tt>. This routine DOES call <tt>rewind(fp) </tt> before returning, so <tt>fp</tt> points to the start of the file upon returning.
</blockquote>

Navigation menu