⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gb_io.w

📁 模拟器提供了一个简单易用的平台
💻 W
📖 第 1 页 / 共 2 页
字号:
to specify digits greater than~9. (Thus, for example, |'A'| representsthe hexadecimal digit for decimal~10.)If the next character is a valid |d|-git,|cur_pos| moves to the next character and the numerical value is returned.Otherwise |cur_pos| stays in the same place and $-1$ is returned.The second routine, |gb_number(d)|, reads characters and forms anunsigned radix-|d| number until the first non-digit is encountered.The resulting number is returned; it is zero if no digits were found.No errors are possible with this routine, because it uses|unsigned long| arithmetic.@(gb_io.h@>=extern long gb_digit(); /* |gb_digit(d)| reads a digit between 0 and |d-1| */extern unsigned long gb_number(); /* |gb_number(d)| reads a radix-|d| number */@ The value of |d| should be at most 127, if users want their programs to beportable, because \CEE/ does not treat larger |char| values in awell-defined manner. In most applications, |d| is of course either 10 or 16.@<External f...@>=long gb_digit(d)    char d;{  icode[0]=d; /* make sure |'\0'| is a nondigit */  if (imap_ord(*cur_pos)<d) return icode[*cur_pos++];  return -1;}@#unsigned long gb_number(d)    char d;{@+register unsigned long a=0;  icode[0]=d; /* make sure |'\0'| is a nondigit */  while (imap_ord(*cur_pos)<d)    a=a*d+icode[*cur_pos++];  return a;}@ The final subroutine for fetching data is |gb_string(p,c)|, whichstores a null-terminated string into locations starting at~|p|.The string starts at |cur_pos| and ends just before the first appearanceof character |c|. If |c=='\n'|, the string will stop at the end of the line.If |c| doesn't appear in the buffer at or after |cur_pos|, the last characterof the string will be the |'\n'| that is always inserted at the endof a line, unless the entire line has already been read. (If the entireline has previously been read, the empty string is always returned.)After the string has been copied, |cur_pos| advances past it.In order to use this routine safely, the user should first check thatthere is room to store up to 81 characters beginning at location~|p|.A suitable place to put the result, called |str_buf|, is providedfor the user's convenience.The location following the stored string is returned. Thus, if thestored string has length~|l| (not counting the null character that isstored at the end), the value returned will be |p+l+1|.@(gb_io.h@>=#define STR_BUF_LENGTH 160extern char str_buf[]; /* safe place to receive output of |gb_string| */extern char *gb_string(); /* |gb_string(p,c)| reads a string delimited by |c|  into bytes starting at |p| */@ @d STR_BUF_LENGTH 160@<External f...@>=char str_buf[STR_BUF_LENGTH]; /* users can put strings here if they wish */char *gb_string(p,c)    char *p; /* where to put the result */    char c; /* character following the string */{  while (*cur_pos && *cur_pos!=c)    *p++=*cur_pos++;  *p++=0;  return p;}@ Here's how we test those routines in \.{test\_io}: The first line of testdata consists of 79 characters, beginning with 64 zeroes and ending with`\.{123456789ABCDEF}'. The second line is completely blank. The thirdand final line says `\.{Oops:(intentional mistake)}'.@<Test the sample data lines...@>=if (gb_number(10)!=123456789)  io_errors |= 1L<<20; /* decimal number not working */if (gb_digit(16)!=10)  io_errors |= 1L<<21; /* we missed the \.A following the decimal number */gb_backup();@+ gb_backup(); /* get set to read `\.{9A}' again */if (gb_number(16)!=0x9ABCDEF)  io_errors |= 1L<<22; /* hexadecimal number not working */gb_newline(); /* now we should be scanning a blank line */if (gb_char()!='\n')  io_errors |= 1L<<23; /* newline not inserted at end */if (gb_char()!='\n')  io_errors |= 1L<<24; /* newline not implied after end */if (gb_number(60)!=0)  io_errors |= 1L<<25; /* number should stop at null character */{@+char temp[100];  if (gb_string(temp,'\n')!=temp+1)    io_errors |= 1L<<26; /* string should be null after end of line */  gb_newline();  if (gb_string(temp,':')!=temp+5 || strcmp(temp,"Oops"))    io_errors |= 1L<<27; /* string not read properly */}if (io_errors)  exit_test("Sorry, it failed. Look at the error code for clues");if (gb_digit(10)!=-1) exit_test("Digit error not detected");if (gb_char()!=':')  io_errors |= 1L<<28; /* lost synch after |gb_string| and |gb_digit| */if (gb_eof())  io_errors |= 1L<<29; /* premature end-of-file indication */gb_newline();if (!gb_eof())  io_errors |= 1L<<30; /* postmature end-of-file indication */@* Opening a file. The call |gb_raw_open("foo")| will open file |"foo"| andinitialize the checksumming process. If the file cannot be opened,|io_errors| will be set to |cant_open_file|, otherwise|io_errors| will be initialized to zero.The call |gb_open("foo")| is a stronger version of |gb_raw_open|, whichis used for standard GraphBase data files like |"words.dat"| to makedoubly sure that they have not been corrupted. It returns the current valueof |io_errors|, which will be nonzero if any problems were detectedat the beginning of the file.@<Test the |gb_open| routine...@>=if (gb_open("test.dat")!=0)  exit_test("Can't open test.dat");@ @d gb_raw_open gb_r_open /* abbreviation for Procrustean external linkage */@(gb_io.h@>=#define gb_raw_open gb_r_openextern void gb_raw_open(); /* open a file for GraphBase input */extern long gb_open(); /* open a GraphBase data file; return 0 if OK */@ @<External f...@>=void gb_raw_open(f)    char *f;{  @<Make sure that |icode|...@>;  @<Try to open |f|@>;  if (cur_file) {    io_errors=0;    more_data=1;    line_no=magic=0;    tot_lines=0x7fffffff; /* allow ``infinitely many'' lines */    fill_buf();  }@+else io_errors=cant_open_file;}@ Here's a possibly system-dependent part of the code: We try first toopen the data file by using the file name itself as the path name;failing that, we try to prefix the file name with the name of thestandard directory for GraphBase data, if the program has been compiledwith |DATA_DIRECTORY| defined.@^system dependencies@>@<Try to open |f|@>=cur_file=fopen(f,"r");@^system dependencies@>#ifdef DATA_DIRECTORYif (!cur_file && (strlen(DATA_DIRECTORY)+strlen(f)<STR_BUF_LENGTH)) {  sprintf(str_buf,"%s%s",DATA_DIRECTORY,f);  cur_file=fopen(str_buf,"r");}#endif@ @<External f...@>=long gb_open(f)    char *f;{  strncpy(file_name,f,sizeof(file_name)-1);     /* save the name for use by |gb_close| */  gb_raw_open(f);  if (cur_file) {    @<Check the first line; return if unsuccessful@>;    @<Check the second line; return if unsuccessful@>;    @<Check the third line; return if unsuccessful@>;    @<Check the fourth line; return if unsuccessful@>;    gb_newline(); /* the first line of real data is now in the buffer */  }  return io_errors;}@ @<Private...@>=static char file_name[20]; /* name of the data file, without a prefix */@ The first four lines of a typical data file should look something like this:$$\halign{\hskip5em\.{#}\hfill\cr * File "words.dat" from the Stanford GraphBase (C) 1993 Stanford University\cr * A database of English five-letter words\cr * This file may be freely copied but please do not change it in any way!\cr * (Checksum parameters 5757,526296596)\cr}$$We actually verify only that the first four lines of a data file named |"foo"|begin respectively with the characters$$\halign{\hskip5em\.{#}\hfill\cr * File "foo"\cr *\cr *\cr * (Checksum parameters $l$,$m$)\cr}$$where $l$ and $m$ are decimal numbers. The values of $l$ and~$m$are stored away as |tot_lines| and |final_magic|, to be matched at theend of the file.@<Check the first line...@>=sprintf(str_buf,"* File \"%s\"",f);if (strncmp(buffer,str_buf,strlen(str_buf)))  return (io_errors |= bad_first_line);@ @<Check the second line...@>=fill_buf();if (*buffer!='*') return (io_errors |= bad_second_line);@ @<Check the third line...@>=fill_buf();if (*buffer!='*') return (io_errors |= bad_third_line);@ @<Check the fourth line; return if unsuccessful@>=fill_buf();if (strncmp(buffer,"* (Checksum parameters ",23))  return (io_errors |= bad_fourth_line);cur_pos +=23;tot_lines=gb_number(10);if (gb_char()!=',')  return (io_errors |= bad_fourth_line);final_magic=gb_number(10);if (gb_char()!=')')  return (io_errors |= bad_fourth_line);@* Closing a file. After all data has been input, or should have been input,we check that the file was open and that it had the correct number oflines, the correct magic number, and a correct final line.  Thesubroutine |gb_close|, like |gb_open|, returns the value of|io_errors|, which will be nonzero if at least one problem was noticed.@<Test the |gb_close| routine; exit if there's trouble@>=if (gb_close()!=0)  exit_test("Bad checksum, or difficulty closing the file");@ @<External f...@>=long gb_close(){  if (!cur_file)    return (io_errors |= no_file_open);  fill_buf();  sprintf(str_buf,"* End of file \"%s\"",file_name);  if (strncmp(buffer,str_buf,strlen(str_buf)))    io_errors |= bad_last_line;  more_data=buffer[0]=0;   /* now the {\sc GB\_\,IO} routines are effectively shut down */   /* we have |cur_pos=buffer| */  if (fclose(cur_file)!=0)    return (io_errors |= cant_close_file);  cur_file=NULL;  if (line_no!=tot_lines+1)    return (io_errors |= wrong_number_of_lines);  if (magic!=final_magic)    return (io_errors |= wrong_checksum);  return io_errors;}@ There is also a less paranoid routine, |gb_raw_close|, thatcloses user-generated files. It simply closes the current file, if any,and returns the value of the |magic| checksum.Example: The |restore_graph| subroutine in {\sc GB\_\,SAVE} uses|gb_raw_open| and |gb_raw_close| to provide system-independent inputthat is almost as foolproof as the reading of standard GraphBase data.@ @d gb_raw_close gb_r_close /* for Procrustean external linkage */@(gb_io.h@>=#define gb_raw_close gb_r_closeextern long gb_close(); /* close a GraphBase data file; return 0 if OK */extern long gb_raw_close(); /* close file and return the checksum */@ @<External f...@>=long gb_raw_close(){  if (cur_file) {    fclose(cur_file);    more_data=buffer[0]=0;    cur_pos=buffer;    cur_file=NULL;  }  return magic;}@* Index. Here is a list that shows where the identifiers of this program aredefined and used.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -