# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. include include #task test = rng_test # Definitions for the RANGES structure. define LEN_RNG 2 # Length of main structure define RNG_ALLOC 10 # Allocation size define RNG_NPTS Memi[$1] # Number of points in ranges define RNG_NRNGS Memi[$1+1] # Number of range intervals define RNG_X1 Memr[$1+4*($2)-2] # Start of range define RNG_X2 Memr[$1+4*($2)-1] # End of range define RNG_DX Memr[$1+4*($2)] # Interval step define RNG_NX Memi[$1+4*($2)+1] # Number of intervals step procedure rng_test () char ranges[SZ_LINE] real r1, r2, dr, clgetr(), rng_nearest() bool rng_inrange() int i, rng_index() pointer rg, rng_open() begin call clgstr ("ranges", ranges, SZ_LINE) r1 = clgetr ("r1") r2 = clgetr ("r2") dr = clgetr ("dr") rg = rng_open (ranges, r1, r2, dr) for (i = 1; rng_index (rg, i, r1) != EOF; i = i + 1) { call printf ("%g\n") call pargr (r1) } repeat { r1 = clgetr ("x") dr = rng_nearest (rg, r1, i, r2) call printf ("%g: %d %g %g %b\n") call pargr (r1) call pargi (i) call pargr (r2) call pargr (dr) call pargb (rng_inrange (rg, r1)) } call rng_close (rg) end # RNG_OPEN -- Open a range string. Return a pointer to the ranges. pointer procedure rng_open (rstr, r1, r2, dr) char rstr[ARB] # Range string real r1, r2, dr # Default range and range limits pointer rg # Range pointer int i, fd, strlen(), open(), getline() real a, b, c pointer sp, str, ptr errchk open, rng_add begin call smark (sp) call salloc (str, max (strlen (rstr), SZ_LINE), TY_CHAR) call calloc (rg, LEN_RNG, TY_STRUCT) a = r1 b = r2 c = dr if (IS_INDEF(a)) a = 0 if (IS_INDEF(b)) b = MAX_INT - 1 if (IS_INDEF(c)) c = 1 i = 1 while (rstr[i] != EOS) { # Find beginning and end of a range and copy it to the work string while (IS_WHITE(rstr[i]) || rstr[i]==',' || rstr[i]=='\n') i = i + 1 if (rstr[i] == EOS) break ptr = str while (!(IS_WHITE(rstr[i]) || rstr[i]==',' || rstr[i]=='\n' || rstr[i]==EOS)) { Memc[ptr] = rstr[i] i = i + 1 ptr = ptr + 1 } Memc[ptr] = EOS # Add range(s) if (Memc[str] == '@') { fd = open (Memc[str+1], READ_ONLY, TEXT_FILE) while (getline (fd, Memc[str]) != EOF) call rng_add (rg, Memc[str], a, b, c) call close (fd) } else call rng_add (rg, Memc[str], a, b, c) } if (RNG_NRNGS(rg) == 0) call rng_add (rg, "*", a, b, c) call sfree (sp) return (rg) end # RNG_CLOSE -- Close range structure procedure rng_close (rg) pointer rg #I Range descriptor begin call mfree (rg, TY_STRUCT) end # RNG_INDEX -- Get ith range element. Return EOF if index is out of range. int procedure rng_index (rg, ival, rval) pointer rg #I Range descriptor int ival #I Range index real rval #O Range value int i, j begin if (ival < 1 || ival > RNG_NPTS(rg)) return (EOF) j = 1 + RNG_NPTS(rg) do i = RNG_NRNGS(rg), 1, -1 { j = j - RNG_NX(rg,i) if (ival >= j) { rval = RNG_X1(rg,i) + (ival - j) * RNG_DX(rg,i) return (ival) } } end # RNG_NEAREST -- Get nearest range index and value to input value. # Return the difference. real procedure rng_nearest (rg, x, ival, rval) pointer rg #I Range descriptor real x #I Value to be matched int ival #O Index to range values real rval #O Range value int i, j, k real drmin, dx begin ival = 1 rval = RNG_X1(rg,1) drmin = abs (x - rval) k = 1 do i = 1, RNG_NRNGS(rg) { dx = x - RNG_X1(rg,i) j = max (0, min (RNG_NX(rg,i)-1, nint (dx / RNG_DX(rg,i)))) dx = abs (dx + j * RNG_DX(rg,i)) if (dx < drmin) { drmin = dx ival = j + k rval = RNG_X1(rg,i) + j * RNG_DX(rg,i) } k = k + RNG_NX(rg,i) } return (x - rval) end # RNG_INRANGE -- Check if value is within a range bool procedure rng_inrange (rg, x) pointer rg #I Range descriptor real x #I Value to check int i real x1, x2 begin do i = 1, RNG_NRNGS(rg) { x1 = RNG_X1(rg,i) x2 = RNG_X2(rg,i) if (x >= min (x1, x2) && x <= max (x1, x2)) return (true) } return (false) end # RNG_ADD -- Add a range procedure rng_add (rg, rstr, r1, r2, dr) pointer rg # Range descriptor char rstr[ARB] # Range string real r1, r2, dr # Default range and range limits int i, j, nrgs, strlen(), ctor() real x1, x2, dx, nx pointer sp, str, ptr errchk rng_error begin call smark (sp) call salloc (str, strlen (rstr), TY_CHAR) i = 1 while (rstr[i] != EOS) { # Find beginning and end of a range and copy it to the work string while (IS_WHITE(rstr[i]) || rstr[i]==',' || rstr[i]=='\n') i = i + 1 if (rstr[i] == EOS) break # Convert colon syntax to hyphen/x syntax. j=0 ptr = str while (!(IS_WHITE(rstr[i]) || rstr[i]==',' || rstr[i]=='\n' || rstr[i]==EOS)) { if (rstr[i] == ':') { if (j == 0) Memc[ptr] = '-' else if (j == 1) Memc[ptr] = 'x' else call rng_error (1, rstr, r1, r2, dr, rg) j = j + 1 } else Memc[ptr] = rstr[i] i = i + 1 ptr = ptr + 1 } Memc[ptr] = EOS # Parse range if (Memc[str] == '@') call rng_error (2, rstr, r1, r2, dr, rg) else if (Memc[str] == '*') { x1 = r1 x2 = r2 dx = dr j = MAX_INT / 2 if ((x2 - x1) / dx + 1 > j) x2 = x1 + (j - 1) * dx } else { j = 1 if (ctor (Memc[str], j, x1) == 0) call rng_error (3, rstr, r1, r2, dr, rg) if (Memc[str+j-1] == '-') { j = j + 1 if (ctor (Memc[str], j, x2) == 0) call rng_error (3, rstr, r1, r2, dr, rg) if (Memc[str+j-1] == 'x') { j = j + 1 if (ctor (Memc[str], j, dx) == 0) call rng_error (3, rstr, r1, r2, dr, rg) } else dx = dr } else if (Memc[str+j-1] == 'x') { j = j + 1 if (ctor (Memc[str], j, dx) == 0) call rng_error (3, rstr, r1, r2, dr, rg) if (dx < 0) x2 = min (r1, r2) else x2 = max (r1, r2) j = MAX_INT / 2 if ((x2 - x1) / dx + 1 > j) x2 = x1 + (j - 1) * dx } else { x2 = x1 dx = dr } } if (x1 < min (r1, r2) || x1 > max (r1, r2) || x2 < min (r1, r2) || x2 > max (r1, r2)) call rng_error (4, rstr, r1, r2, dr, rg) nrgs = RNG_NRNGS(rg) if (mod (nrgs, RNG_ALLOC) == 0) call realloc (rg, LEN_RNG+4*(nrgs+RNG_ALLOC), TY_STRUCT) nrgs = nrgs + 1 RNG_NRNGS(rg) = nrgs RNG_X1(rg, nrgs) = x1 RNG_X2(rg, nrgs) = x2 RNG_DX(rg, nrgs) = dx j = MAX_INT / 2 nx = (x2 - x1) / dx + 1 if (nx > j) call rng_error (5, r1, r2, dr, rg) RNG_NX(rg, nrgs) = nx nx = nx + RNG_NPTS(rg) if (nx > j) call rng_error (5, r1, r2, dr, rg) RNG_NPTS(rg) = nx } call sfree (sp) end # RNG_ERROR -- Set error flag and free memory. # Note that the pointer is freed at this point. procedure rng_error (errnum, rstr, r1, r2, dr, rg) int errnum # Error number char rstr[ARB] # Range string real r1, r2, dr # Default range and range limits pointer rg # Range pointer to be freed. pointer errstr begin call salloc (errstr, SZ_LINE, TY_CHAR) switch (errnum) { case 1: call sprintf (Memc[errstr], SZ_LINE, "Range syntax error: Too many colons (%s)") call pargstr (rstr) case 2: call sprintf (Memc[errstr], SZ_LINE, "Range syntax error: Cannot nest @files (%s)") call pargstr (rstr) case 3: call sprintf (Memc[errstr], SZ_LINE, "Range syntax error: (%s)") call pargstr (rstr) case 4: call sprintf (Memc[errstr], SZ_LINE, "Range syntax error: Range out of bounds %g to %g (%s)") call pargr (min (r1, r2)) call pargr (max (r1, r2)) call pargstr (rstr) case 5: call sprintf (Memc[errstr], SZ_LINE, "Range syntax error: Too many range elements (%s)") call pargstr (rstr) } call rng_close (rg) call error (errnum, Memc[errstr]) end