1: /* 2: * Interpress utilities 3: * 4: * Written for Xerox Corporation by William LeFebvre 5: * 24-May-1984 6: * 7: * Copyright (c) 1984, 1985 Xerox Corp. 8: * 9: * HISTORY 10: * 15-Jan-86 lee at Xerox, WRC 11: * Removed the rest of the Vax dependencies. 12: * 13: * 10-sep-85 lee moore Removed some dependencies on the Vax. 14: * Plenty more to be removed 15: * 29-apr-85 ed flint add conditional compilation for vax-11 c (vms) 16: */ 17: 18: /* 19: * Subroutines to help build interpress files: 20: * 21: * literal interface level - these routines produce interpress output at 22: * the token level. 23: */ 24: 25: /* 26: * NOTE: Some of these "subroutines" are one-liners, so they are written 27: * as macros for better efficiency. 28: */ 29: 30: # define Rational_max 1073741824 31: # define ip_Buffsize 1024 32: 33: #ifndef vax11c 34: # include <sys/param.h> 35: # include <math.h> 36: # include <stdio.h> 37: #endif 38: 39: # include "iptokens.h" 40: # include "literal.h" /* macro definitions for some routines */ 41: 42: # ifndef NULL 43: # define NULL (char *)0 44: # endif 45: 46: #ifdef vax11c 47: # define NOFILE 20 48: #endif 49: 50: # define No 0 51: # define Yes 1 52: 53: static int ip_fd = -1; /* current Interpress file */ 54: static char ip_filebuff[ip_Buffsize]; /* file buffer */ 55: static char *ip_buffptr = NULL; /* points in to ip_filebuff */ 56: static int ip_bytecnt; /* number of bytes in ip_filebuff */ 57: static char ip_files[NOFILE] = { 0 }; /* marks which files are ip files */ 58: 59: /* 60: * Definitions for the primitives suggested in the Interpress standard 61: * (XSIS 048302). The following primitives are defined with macros in 62: * "literal.h": 63: * 64: * AppendComment 65: * AppendIdentifier 66: * AppendInsertFile 67: * AppendString 68: * 69: * Currently, AppendString will only handle byte values -- it will not 70: * try to insert any escape characters. The rationale for this is that 71: * ASCII (which is what this system uses) doesn't have character codes that 72: * high. 73: */ 74: 75: AppendOp(opcode) 76: 77: int opcode; 78: 79: { 80: if (opcode > SHORT_OP_LIMIT) 81: { 82: /* has to be coded as a long op */ 83: append_word((unsigned short)((LONG_OP << 8) | opcode)); 84: } 85: else 86: { 87: /* small enough to be a short op */ 88: append_byte((unsigned char)(SHORT_OP | opcode)); 89: } 90: } 91: 92: AppendNumber(number) 93: 94: double number; 95: 96: { 97: long d; 98: double r; 99: 100: if (number == (double)(d = (long)number)) 101: { 102: AppendInteger(d); 103: } 104: else 105: { 106: d = 1; 107: while ((fabs(r = number * d) < Rational_max) && 108: (d < Rational_max) && 109: (r != (float)((int)(r)))) 110: { 111: d <<= 1; 112: } 113: AppendRational((long)r, d); 114: } 115: } 116: 117: 118: /* 119: * note that although the routine is called AppendInteger, it is really 120: * AppendLong. This is because alot of code wants to use 32 bit numbers. 121: * If you want to pass it a 16bit int, that will work too. 122: */ 123: 124: AppendInteger(number) 125: 126: long number; 127: 128: { 129: if (number < INTEGER_MIN || number > INTEGER_MAX) 130: { 131: append_integer_sequence(number); 132: } 133: else 134: { 135: append_short_number((short) number); 136: } 137: } 138: 139: AppendRational(value, divisor) 140: 141: long value, divisor; 142: 143: { 144: int len_value, len_divisor, len; 145: 146: len_value = bytes_in_int(value); 147: len_divisor = bytes_in_int(divisor); 148: 149: len = len_value > len_divisor ? len_value : len_divisor; 150: append_Sequence(sequenceRational, len << 1, (unsigned char *)NULL); 151: append_n_byte_int(value, len); 152: append_n_byte_int(divisor, len); 153: } 154: 155: #ifdef notdef 156: AppendIntegerVector(vector, num) 157: 158: int *vector; /* ??? */ 159: int number; 160: 161: { 162: 163: } 164: #endif 165: 166: /* 167: * The remainder of this file contains lower level primitives: 168: */ 169: 170: /* 171: * append_Sequence(type, length, buff) 172: * 173: * Append a sequence descriptor and its data bytes. The descriptor is of 174: * type "type" and length "length". "Buff" points to the buffer containing 175: * the data. If "length" is negative, then bytes from "buffer" are written 176: * back to front (this makes writing integers easy). 177: */ 178: 179: append_Sequence(type, length, buff) 180: 181: int type; 182: int length; 183: unsigned char *buff; 184: 185: { 186: # ifdef notnow 187: /* some day, we should make this check, but not today */ 188: if ((length & 0x7f000000) != 0) 189: { 190: /* too big to fit in a long ... */ 191: } 192: # endif 193: 194: /* check for swapped byte correction */ 195: if (length < 0) 196: { 197: fprintf(stderr, "negative sequence!\n"); 198: abort(); 199: } 200: 201: if ((length & 0x7fffff00) != 0) 202: { 203: /* too big to fit in a short sequence */ 204: append_byte((unsigned char) (LONG_SEQUENCE | type)); 205: append_n_byte_int((long) length, 3); 206: } 207: else 208: { 209: append_byte((unsigned char) (SHORT_SEQUENCE | type)); 210: append_byte((unsigned char) length); 211: } 212: 213: /* tack on data, if any */ 214: if (buff != NULL) 215: append_bytes(length, buff); 216: } 217: 218: 219: /* 220: * append_integer_sequence(number) 221: * A special version of append_sequence that handles integers. Integers 222: * must be treated differently because the natural representation of an 223: * integer for a particular machine maybe byte swapped relative to the 224: * Xerox standard. 225: */ 226: append_integer_sequence(number) 227: 228: long number; 229: 230: { 231: int length = bytes_in_int(number); 232: 233: append_byte((unsigned char) (SHORT_SEQUENCE | sequenceInteger)); 234: append_byte((unsigned char) length); 235: append_n_byte_int(number, length); 236: } 237: 238: /* 239: * append_n_byte_int(number, length) 240: * Append N bytes of an integer to the interpress master. 241: */ 242: 243: append_n_byte_int(number, length) 244: 245: long number; 246: int length; /* measured in bytes */ 247: 248: { 249: int shift; 250: 251: #ifdef notdef 252: switch( length ) { 253: case 4: 254: append_byte((unsigned char) (number >> 24)); 255: case 3: 256: append_byte((unsigned char) (number >> 16)); 257: case 2: 258: append_byte((unsigned char) (number >> 8)); 259: case 1: 260: append_byte((unsigned char) number); 261: break; 262: default: 263: fprintf(stderr, "append_n_byte_int: asked to append %d bytes\n", length); 264: } 265: #else 266: if( length > sizeof(long) ) 267: fprintf(stderr, "append_n_byte_int: asked to append %d bytes\n", length); 268: 269: for( shift = (length - 1)*8; shift >= 0; shift -= 8 ) 270: append_byte((unsigned char) (number >> shift)); 271: #endif 272: } 273: 274: 275: /* 276: * append_word(value) - write the two byte (word) value "value" 277: */ 278: 279: append_word(value) 280: 281: unsigned short value; 282: 283: { 284: #ifdef notdef 285: append_n_byte_int(value, 2); 286: #else 287: append_byte((unsigned char) (value >> 8)); 288: append_byte((unsigned char) value); 289: #endif 290: } 291: 292: /* 293: * append_byte(value) - write out a byte 294: */ 295: 296: append_byte(value) 297: 298: unsigned char value; 299: 300: { 301: *ip_buffptr++ = value; 302: if (++ip_bytecnt == ip_Buffsize) 303: { 304: write(ip_fd, ip_filebuff, ip_Buffsize); 305: ip_bytecnt = 0; 306: ip_buffptr = ip_filebuff; 307: } 308: } 309: 310: /* 311: * append_bytes(length, buff) - write the buffer of bytes pointed to by 312: * "buff" with length "length". 313: */ 314: 315: append_bytes(length, buff) 316: 317: int length; 318: unsigned char *buff; 319: 320: { 321: while (length-- > 0) 322: { 323: append_byte(*buff++); 324: } 325: } 326: 327: 328: /* this routine assumes 4 bytes in an int and two's complement notation */ 329: /* this routine should be replaced! -lee */ 330: /* this routine sometime over estimates the size of an integer. why? */ 331: 332: bytes_in_int(value) 333: 334: long value; 335: 336: { 337: int i; 338: long mask; 339: 340: if (value < 0) 341: { 342: /* takes the same space as its one's complemented value */ 343: value = ~value; 344: } 345: if (value == 0) 346: { 347: /* avoids infinite looping */ 348: return(1); 349: } 350: for (i = 4, mask = 0xff800000; (value & mask) == 0; i--, mask >>= 8) 351: ; 352: return(i); 353: } 354: 355: /* 356: * ip_select(fd) - select file descriptor "fd" as the Interpress file for 357: * later use by the i/o routines supplied in this library. 358: */ 359: 360: ip_select(fd) 361: 362: int fd; 363: 364: { 365: if (ip_fd != -1) 366: { 367: ip_flush(); 368: } 369: 370: /* set our idea of current file descriptor and initialize the buffer */ 371: ip_fd = fd; 372: ip_buffptr = ip_filebuff; 373: ip_bytecnt = 0; 374: 375: /* check for initialization */ 376: if (!ip_files[fd]) 377: { 378: /* not an Intepress file -- initialize it */ 379: append_bytes(strlen(IP_Header), (unsigned char *) IP_Header); 380: ip_files[fd] = Yes; 381: } 382: } 383: 384: /* 385: * ip_raw_select(fd) - same as ip_select, but no header is placed at the 386: * front of the file. 387: */ 388: 389: ip_raw_select(fd) 390: 391: int fd; 392: 393: { 394: /* trick ip_select into thinking that it is already initialized */ 395: ip_files[fd] = Yes; 396: 397: /* do a normal select */ 398: ip_select(fd); 399: } 400: 401: ip_close() 402: 403: { 404: if (ip_fd != -1) 405: { 406: ip_flush(); 407: ip_files[ip_fd] = No; 408: close(ip_fd); 409: ip_fd = -1; 410: } 411: } 412: 413: ip_flush() 414: 415: { 416: /* flush the buffer */ 417: if (ip_Buffsize - ip_bytecnt > 0) 418: { 419: write(ip_fd, ip_filebuff, ip_bytecnt); 420: } 421: }