1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: /* $Header: b2fil.c,v 1.1 84/06/28 00:49:11 timo Exp $ */ 3: 4: /* Facilities supplied by the file system */ 5: 6: #include "b.h" 7: #include "b0con.h" 8: #include <sys/types.h> 9: #include <sys/stat.h> 10: #include "b1obj.h" 11: #include "b2fil.h" 12: #include "b2scr.h" 13: 14: /*This file defines the facilities needed for dealing with files, 15: apart from C's standard I/O facilities which are used throughout the system. 16: 17: Units are held on files in a 'workspace', which on Unix is modelled 18: using directories. The function 'f_uname' converts a unit name into a 19: unique filename. On Unix this is done by prepending a character to the unit 20: name to indicate the kind of unit (for how'to ', and for tests and yields 21: < for zeroadic, " for monadic and > for dyadic; these have been chosen as 22: characters that are not usually used in filenames), and truncating the 23: name if necessary. If the name does have to be truncated, then it is 24: hashed to produce a character that is appended to the filename, in an attempt 25: to produce a unique filename. Even so, it is still possible for different 26: unit names to produce the same filename, and in the unlikely event of this 27: happening you get an error message that the unit already exists when you 28: try to create the clashing unit name. 29: 30: Filenames are at most SAFEFNLEN characters long, which on standard Unix 31: systems gives you one spare character for making backups or whatever. 32: 33: It would be better if the B system effectively maintained its own directories 34: that mapped units onto files in the real file system, as is done for targets. 35: With operating systems with a more limited file system (eg even shorter 36: filenames) this is the only possibility. 37: 38: */ 39: 40: #define COML 60 41: char com_line[COML]; 42: #define At_eos(s) ((s)+= strlen(s)) 43: 44: Visible Procedure f_edit(fname, errline) value fname; intlet errline; { 45: /*The default editor is called with a first parameter of the line number 46: and a second parameter of the file name*/ 47: string cl= com_line; 48: int c; 49: if (filtered) { 50: ignsigs(); 51: printf("\001: +%d %s\n", errline, strval(fname)); 52: fflush(stdout); 53: do { c= fgetc(stdin); } while (c != '\n' && c != EOF); 54: re_sigs(); 55: return; 56: } 57: if (getenv("BEDITOR") == NULL) strcpy (cl, DEDI); 58: else strcpy(cl, getenv("BEDITOR")); 59: if (*(cl+strlen(cl)-1) == '+') { 60: if (errline != 0) sprintf(At_eos(cl), "%d", errline); 61: else *(cl+strlen(cl)-1)= ' '; 62: } 63: app_fname(At_eos(cl), fname); 64: system(com_line); 65: } 66: 67: Visible value f_save(fname) value fname; { 68: /* saves the file in a temporary file, whose name is returned */ 69: /* Here the OS does the copy: you may have to do this yourself */ 70: string cl; value sname= mk_text(SAVEFILE); 71: strcpy(cl= com_line, "cp"); 72: app_fname(At_eos(cl), fname); 73: app_fname(At_eos(cl), sname); 74: system(com_line); 75: return sname; 76: } 77: 78: Visible Procedure f_rename(fname, nfname) value fname, nfname; { 79: string cl; 80: strcpy(cl= com_line, "mv"); 81: app_fname(At_eos(cl), fname); 82: app_fname(At_eos(cl), nfname); 83: system(com_line); 84: /* what if mv fails??? */ 85: } 86: 87: Visible Procedure f_delete(fname) value fname; { 88: string cl; 89: strcpy(cl= com_line, "rm"); 90: app_fname(At_eos(cl), fname); 91: system(com_line); 92: } 93: 94: Visible bool f_exists(fname) value fname; { 95: FILE *f= fopen(strval(fname), "r"); 96: if (f==NULL) return No; 97: fclose(f); 98: return Yes; 99: } 100: 101: #define SAFEFNLEN 13 102: 103: Hidden double f_hash(v) value v; { 104: int len= length(v), k; double d= '"'+.404*len; 105: /*That '"' is strange I know, but it's necessary for compatibility*/ 106: value ch; 107: k_Over_len { 108: ch= thof(k+1, v); 109: d= .987*d+.277*charval(ch); 110: release(ch); 111: } 112: return d; 113: } 114: 115: Visible value f_uname(name, type) value name; literal type; { 116: static char fname[SAFEFNLEN+1]; string sfn= fname; 117: *sfn= type; 118: if (length(name) < SAFEFNLEN) strcpy(sfn+1, strval(name)); 119: else { 120: double hh= f_hash(name)*321.987; char h; 121: strncpy(sfn+1, strval(name), SAFEFNLEN-2); 122: hh= hh-floor(hh); h= (char) floor(hh*29) + '!'; 123: if (h >= '"') h++; 124: if (h >= '\'') h++; 125: if (h >= '/') h++; 126: if (h >= '0') h+= 10; 127: if (h >= 'A') h+= 26; 128: if (h >= 'a') h+= 26; 129: *(sfn+SAFEFNLEN-1)= h; *(sfn+SAFEFNLEN)= '\0'; 130: } 131: return mk_text(fname); 132: } 133: 134: Hidden value try(t, n) value t; intlet n; { 135: value eq= mk_text("="), fn, a, b, c; 136: int len= length(t); 137: if (n == 0) fn= concat(eq, t); 138: else { /* PUT "="^(n<<1)^t IN fn */ 139: fn= concat(eq, a= concat(b= convert(c= mk_integer(n), No, No), t)); 140: release(a); release(b); release(c); 141: } 142: release(eq); 143: if (len > SAFEFNLEN) { 144: fn= trim(a= fn, 0, len-SAFEFNLEN); 145: release(a); 146: } 147: return(fn); 148: } 149: 150: Visible value f_tname(t) value t; { 151: value fn= try(t, 0); 152: intlet i= 0; 153: while (f_exists(fn)) { 154: release(fn); 155: fn= try(t, ++i); 156: } 157: return(fn); 158: } 159: 160: Hidden Procedure app_fname(ceos, fname) string ceos; value fname; { 161: string fp= strval(fname); intlet k, len= strlen(fp); 162: *ceos++= ' '; 163: k_Over_len { 164: *ceos++= '\\'; 165: *ceos++= *fp++; /*should really use charval(thof(...))*/ 166: } 167: *ceos= '\0'; 168: } 169: 170: Visible unsigned f_size(ifile) FILE *ifile; { 171: struct stat sb; 172: if (fstat(fileno(ifile), &sb) != 0) syserr("can't stat file"); 173: return( (unsigned) (sb.st_size) ); 174: } 175: 176: Visible bool f_interactive(ifile) FILE *ifile; { 177: return isatty(fileno(ifile)); 178: } 179: 180: Visible Procedure lst_uhds() { 181: /*List the headings of the units in this workspace*/ 182: system("for i in \\'* \\<* \\\"* \\>*; do head -1 $i 2>/dev/null; done"); 183: /*just for now, you understand*/ 184: }