NAME protect - read or adjust protect status for a variable or named block SYNOPSIS protect(var [, N [, depth]) protect(nblk [, N [, depth]]) TYPES var lvalue nblk named block N integer, abs(N) < 65536 depth nonnegative integer return null value DESCRIPTION The protection status of the association of an lvalue A with its value is represented by a nonnegative integer less than 2^16. The current value sts of this status is returned by protect(A). Each nonzero bit of the low eight bits of sts corresponds to a builtin kind of protection as follows: bit value protection 1 no assign to A 2 no change of A by assignment 4 no change of type value of A 8 no error value for A 16 no copy to A 32 no relocation for A or its elements 64 no assign from A 128 no copy from A For example, A having protection status 65 = 1 + 64 prevents execution of assignments of the forms A = expression and V = A where V is an lvalue. Attempting either of these assignments will return an error value and leave the value of A or V unchanged. Initally, when created, any lvalue A has zero status corresponding to "no protection". This may be restored at any time by protect(A, 0). If N is positive and A does not already have the protection corresponding to a nonzero bit of N, protect(A, N) adds that protection to the status of A. For example, if protect(A) is 65, protect(A, 17) will add the no-copy-to protection so that the new protection status of A will be 81 = 1 + 16 + 64. Similarly, if N is negative and A has the protection corresponding to a nonzero bit of abs(N), protect(A,N) will remove that kind of protection. For example if protect(A) = 65, then protect(A, -17) will remove the no-assign-to protection and the new value of protect(A) will be 64. Note that protect(A, -65535) has the same effect as protect(A, 0). For the purposes of this function, the depth of a global or local variable is zero; if A has depth d and the value of A is a list, matrix, object or association, its elements have depth d + 1. For example, after obj point {x,y} X = mat[3] = {1, list(2,3), mat[2] = {obj point, obj point} } X has depth 0; X[0], X[1] and X[2] have depth 1; X[1][0], X[1][1], X[2][0] and X[2][1] have depth 2; X[2][0].x, X[2][0].y, X[2][1].x and X[2][1].y have depth 3. For any lvalue A, protect(A, N, depth) applies protect(A, N) to A and to all elements, elements of elements, etc., up tothe stated depth. In the above example, protect(X, 20, 2) gives no-type-change and no-copy-to protection to 8 of the listed lvalues, but not to the components of the objects X[2][0] and X[2][1]; With any d >= 3, protect(X, 20, d) would give that protection the 12 listed lvalues. If B is a variable with positive status and assignment of B to A is permitted, execution of the assignment A = B adds to the protections of A all protections of B that A does not already have. Except when the value returned is the result of the evqluation of an lvalue with positive status, calc's builtin operators and functions return values with zero protection status. For example, whatever the protection statuses of X and Y, X + sqrt(Y) will have zero status, but t ? X : Y may have nonzero status. The list, matrix, object or association returned by the use of list, mat, obj or assoc will have zero status, but any element specified by an lvalue will receive its status; e.g. after L = list(X, X^2) , protect(L[0]) equals protect(X) and both protect(L) and protect(L[1]) are zero. Users may define functions that return values with positive status, e.g. define noassigntovalue(x) {protect(x,1); return x}; S = noassigntovalue(42); will result in S having the value 42 and no-assign-to protection. By using a backquote with a variable as argument, an even simpler function: define noassignto(x) = protect(x, 1); gives no-assign-to protection to the variable; i.e. noassignto(`A) achieves the same as protect(A,1). In the brief descriptions above of builtin kinds of protectiopn, "assign" refers to use of '=' as in A = expr to assign the value of expr to A, and in A = {..., expr, ...} to assign the value of expr to some component of A, and to the assignments implicit in quomod(x, y, A, B), and pre or post ++ or --. Swapping of lvalues is prevented if either value has no-assign-to or no-assign-from protection. (Swapping of octets is prevented if at least one of them is in a string or block with no-copy-to or no-copy-from protection.) "Copying" refers to initialization using {...} and to the operations copy and blkcpy as applied to strings, blocks, lists and matrices. Although A = {..., expr, ...) assigns the value of expr to an elment of A, it is also regarded as copying to A. Thus, initialization of A may be prevented either by giving no-copy-to protection to A or no-assignment=to protection to the elements of A. Assignments to and from characters or octets in strings or blocks are also regarded as copying to or from the string or block. For example, after A = "abc", protect(A,16) would prevent the assignment A[0] = 'x'. (Note that in this example, A[0] is not an lvalue in the sense normally understood - the only values it can have are nonnegative integers less than 256. The only kinds of protection relevant to an octet are the no-copy-to, no-copy-from and no-change protections of the string or block in which the octet resides.) The no-relocate protection applies to lists and blocks. For lists, it refers to the operations push, pop, append, remove, insert and delete. For example, if A = list(2,3,5,7), protect(A, 32) will prevent any change in the content or size of the list. No-relocation protection of a block prevents reallocation of the memory used by a block and the freeing of a named block, For example, if a block B has maxsize 256, then after protect(B, 32); copy(A, B) will fail if the copying would cause size(B) to equal or exceed 256; if B is a named block, blkfree(B) will not be permitted. The elements of the list returned by list(...) will initially have zero protection status except when an argument is an lvalue with positive status, in which case the corresponding element will receive that status. E.g., L = list(A,B) will result in L[0] having status protect(A) and L[1] having status protect(B). L itself will have the status L had before the assignment. There is a similar copying of protection status when "= { ... }" initialization is used for matrices, lists or objects. For example, except when A or B has no-assign-from protection, M = mat [2] = {A,B} or mat M[2] = {A,B} will result in M[0] and M[1] having statuses protect(A) and protect(B) respectively. (If A or B has no-assign-from protection, mat[2] = {A,B} returns an error value.) Although M = mat[2] = {...} and mat M[2] = {...} do the same thing, these are different from (M = mat[2]) = {...} and (mat M[3]) = {...}. In the former pair of statements, the result of mat[2] = {...} is being assigned to M. In the latter statments, a matrix with zero elements is being assigned to M and then that matrix is being "reinitialized". Both will fail if M has no-asssign-to protection, but only the latter would be prevented by M having no-copy-to protection. When the functions which mave move elements like of sort, reverse, swap, insert, pop, remove, push and append. are evaluated, the protection statuses move with the values, e.g. if among the values and elements involved, there is just one with value 42, then the lvalue to which the value 42 is moved will get the status the lvalue with value 42 had before the evaluation of the function. This is relevant to evaluation of expressions like A = sort(A), append(A, pop(A)), insert(A,2,B,C). Note that when pop(A) is first evaluated it is located on the stack calc uses for calculating expressions rather than being the value of an lvalue. With an explicit assignment like X = pop(A) or the implied assignment in append(A, pop(A)), it becomes the value of an lvalue. Users may use higher bits values for other kinds of protection or simply to store information about an lvalue and its current value. For example 1024 might be used to indicate that the lvalue is always to have positive value. Then code for evaluating a function might include lines like if (protect(A) & 1024 && B <= 0) return newerror("Prohibited assignment"); A = B; When an operation forbidden by a particular bit in the protection status of A is attempted, an error value is created but unless this causes errcount to exceed errmax, the only immediate evidence for the error might be the incrementing of errcount. Sometimes the failure causes the return of the error value; e.g. swap(A,B) if not permitted returns an appropriate error value rather than the null value. If the value of A is a number and A has no-type-change protection, A = "abc" returns an error value. The error-number of the most recent error value is returned by errno(), a string describing it by strerror(). A named block may be referred to by using the blocks() or blk() functions, or by assigning it to a variable A and then using either A or *A. In the latter cases, protect(A, sts) sets the status for the variable A; protect(*A, sts) assigns the status for the named block. For example, protect(*A,16) will prevent any copying to the named block; protect(A,16) will prevent any copying to the named block only when it is referred to by A. EXAMPLE > A = 27 > protect(A,1) > A = 45 > A 27 > strerror() "No-assign-to destination for assign" > protect(A,64) > protect(A) 65 > X = A > X 0 > strerror() "No-assign-from source for assign" > protect(A,-1) > protect(A) 64 > protect(A,4) > protect(A) 68 > A = "abc" > A 27 > strerror() "No-type-change destination for assign" > B = 45 > swap(A,B) Error 10372 > strerror() "No-assign-to-or-from argument for swap" > protect(A,-64) > protect(A) 4 > swap(A,B) > A 45 > B 27 > A = mat[4] = {1,2,3,4} > B = list(5,6,7,8) > protect(A,16) > copy(B,A) Error 10226 > strerror() "No-copy-to destination variable" > A = list(1,2,3) > protect(A,32) < append(A,4) Error 10402 > strerror() "No-relocate for list append" > A = blk(0,5) > copy("abc", A) > copy("de",A) Error 10229 > strerror() "No-relocate destination variable" > A = blk("alpha") = {1,2,3,4,5} > protect(A,0) < protect(*A, 16) < copy("abc", A) Error 10228 > strerror() "No-copy-to destination named block" LIMITS none LINK LIBRARY none SEE ALSO assign, copy, blk, error, errno, strerror ## Copyright (C) 1999 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License ## as published by the Free Software Foundation. ## ## Calc is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General ## Public License for more details. ## ## A copy of version 2.1 of the GNU Lesser General Public License is ## distributed with calc under the filename COPYING-LGPL. You should have ## received a copy with calc; if not, write to Free Software Foundation, Inc. ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ## ## @(#) $Revision: 29.4 $ ## @(#) $Id: protect,v 29.4 2006/05/19 15:12:57 chongo Exp $ ## @(#) $Source: /usr/local/src/cmd/calc/help/RCS/protect,v $ ## ## Under source code control: 1997/07/10 22:38:44 ## File existed as early as: 1997 ## ## chongo /\oo/\ http://www.isthe.com/chongo/ ## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/