;;; xlib-math.el --- icky math things such as 4 byte ints, and int->string stuff. ;; Copyright (C) 1996, 1997, 1998 Eric M. Ludlam ;; Copyright (C) 2003-2005 XWEM Org. ;; ;; Author: Eric M. Ludlam ;; Modified: Zajcev Evgeny ;; Keywords: xlib, xwem ;; X-RCS: $Id: xlib-math.el,v 1.8 2005-04-04 19:55:28 lg Exp $ ;; This file is part of XWEM. ;; XWEM is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; XWEM 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 General Public ;; License for more details. ;; You should have received a copy of the GNU General Public License ;; along with XEmacs; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ;; 02111-1307, USA. ;;; Synched up with: Not in FSF ;;; Commentary: ;; numbers->string string->numbers ;; ;; These routines are needed to convert numbers into strings which ;; are passed over the network. ;; ;;; Code: (defmacro Xtruncate (val) "Do a safe truncate of VAL that might be larger than MAXINT." `(truncate (if ,val (mod ,val 65536) 0))) (defmacro XCharacter (val) "Convert VAL (a float) into a truncated character value." (if (fboundp 'int-to-char) (list 'int-to-char (list 'logand (list 'truncate (list 'mod val 65536)) 255)) (if (>= emacs-major-version 20) (list 'logand (list 'truncate (list 'mod val 65536)) 255) (list 'truncate (list 'mod val 65536))))) (defmacro Xforcenum (val) "Force VAL (a character) to be a number. This macro forces XEmacs 20.3 to behave." (if (fboundp 'char-to-int) `(char-to-int ,val) val)) (defsubst int->string1 (num) "Convert NUM into a 1 byte string in network order and return." (char-to-string (XCharacter num))) (defsubst string1->int (string) "Convert STRING characters into an integer and return." (string->int string)) (defun int->string (num) "Convert NUM into a 2 byte string in network order and return." (setq num (truncate num)) (let ((l (logand num 255)) ;top byte (h (ash (mod num 65536) -8))) ;upper byte (concat (char-to-string l) (char-to-string h)))) (defalias 'int->string2 'int->string) (defun string->int (string) "Convert STRING 1st two characters into an integer and return." (let ((l (aref string 0)) (h (if (> (length string) 1) (aref string 1) 0))) (+ l (ash h 8)))) (defun int->string4 (num) "Convert NUM (a float or int) into a 4 byte network order string." (if (integerp num) ;; if it isn't a float, then do int things (concat (int->string num) (int->string 0)) ;0 upper part ; (if (> 0 num) ; (error "4 byte number is negative during conversion.")) (let ((tmp (float num)) (ts nil)) ;; We only need to truncate the first part. After the first ;; 8 bit shift, the number is small enought that a regular ;; truncate is safe. (setq ts (concat ts (char-to-string (XCharacter tmp)))) (setq tmp (/ tmp (float 256))) (setq ts (concat ts (char-to-string (XCharacter tmp)))) (setq tmp (/ tmp (float 256))) (setq ts (concat ts (char-to-string (XCharacter tmp)))) (setq tmp (/ tmp (float 256))) (setq ts (concat ts (char-to-string (XCharacter tmp))))))) (defun string4->int (string) "Convert STRING 1st four characters into a float and return." ;; do nothing yet until we know what we need to do. (+ (float (Xforcenum (aref string 0))) (* (float (Xforcenum (aref string 1))) 256) (* (float (Xforcenum (aref string 2))) 256 256) (* (float (Xforcenum (aref string 3))) 256 256 256))) (defun string2->number (string) "Convert 2 first bytes in STRING to number." (string->int string)) (defun string4->number (string) "Convert 4 first bytes in STRING to number. NOTE: Use `string4->int' when overflow may occur." (+ (Xforcenum (aref string 0)) (lsh (Xforcenum (aref string 1)) 8) (lsh (Xforcenum (aref string 2)) 16) (lsh (Xforcenum (aref string 3)) 24))) (defun int->string3 (num) "Convert 3 first bytes in STRING to integer." (string (logand num 255) (logand (lsh num -8) 255) (logand (lsh num -16) 255))) ;;; Converters (defun string->card8 (str) (Xforcenum (aref str 0))) (defun string->card16 (str) (+ (Xforcenum (aref str 0)) (lsh (Xforcenum (aref str 1)) 8))) (defun string->card32 (str) (+ (Xforcenum (aref str 0)) (lsh (Xforcenum (aref str 1)) 8) (lsh (Xforcenum (aref str 2)) 16) (lsh (Xforcenum (aref str 3)) 24))) (defun string->int8 (str) (let ((v (Xforcenum (aref str 0)))) (funcall (if (> v #x7f) '- '+) (logand v #x7f)))) (defun string->int16 (str) (let ((v (Xforcenum (aref str 1)))) (funcall (if (> v #x7f) '- '+) (+ (Xforcenum (aref str 0)) (lsh (logand v #x7f) 8))))) (defun string->int32 (str) (let ((v (Xforcenum (aref str 3)))) (funcall (if (> v #x7f) '- '+) (+ (Xforcenum (aref str 0)) (lsh (Xforcenum (aref str 1)) 8) (lsh (Xforcenum (aref str 2)) 16) (lsh (logand v #x7f) 24))))) ;;; Back coverters ;; TODO: - write (defun card8->string (card8) ) (defun card16->string (card16) ) (defun card32->string (card32) ) (defun int8->string (int8) ) (defun int16->string (int16) ) (defun int32->string (int32) ) (defun X-pad (number) "Return a number which is the padding for an X message of length NUMBER." (% (- 4 (% number 4)) 4)) (defun X-padlen (string) "Return a number which is length of STRING / 4. If string is not divisible by 4, return string/4 + 1" (if (= (% (length string) 4) 0) (/ (length string) 4) (+ (/ (length string) 4) 1))) ;;; MASK routines: ;; ;; These routines are needed to handle the 4 byte masks used in X. ;; We won't implement the whole set, just the functionality we need ;; to make the checks we want. ;; (defun Xmask (pos) "Create a mask with a bit set in position POS. This routine will not work for position 32 and up because we sim 4 bytes of info" (if (< pos 16) (float (lsh 1 pos)) ;put in first byte (setq pos (- pos 16)) ;divide pos by 16 (* (float (lsh 1 pos)) (float 65536)) ;push into high byte )) (defun Xmask-and (val &rest args) "Logically `and' VAL and MASK together. They are floats to be broken down into two two byte ints. MASK is stored in ARGS which is a list of *fill in when I remember*" (while args (let ((mask (car args))) (setq args (cdr args)) (let ((lv (logand (Xtruncate val) 65535)) (hv (Xtruncate (/ val (float 65536)))) (lm (logand (Xtruncate mask) 65535)) (hm (Xtruncate (/ mask (float 65536))))) (setq val (+ (float (logand lv lm)) (* (float (logand hv hm)) 65536)))))) val) (defun Xmask-or (val &rest args) "Logically or VAL and MASK together. They are floats to be broken down into two two byte ints. MASK is stored in ARGS which is a list of *fill in when I remember*" (while args (let ((mask (car args))) (setq args (cdr args)) (let ((lv (logand (Xtruncate val) 65535)) (hv (Xtruncate (/ val (float 65536)))) (lm (logand (Xtruncate mask) 65535)) (hm (Xtruncate (/ mask (float 65536))))) (setq val (+ (float (logior lv lm)) (* (float (logior hv hm)) 65536)))))) val) (defun Xtest (val flag) "Test value of bytes VAL for presence of FLAG. Return t if it exists, nil otherwise." (if (= (Xmask-and val flag) 0) nil t)) ;;; BITWISE routines: ;; ;; These routines are used to do other things to bits, necessary for ;; calculating out new resource IDs for objects. ;; (defun Xcount-bits-int (mask) "Count the number of bits in a given integer (16 bit) MASK." (let ((ret 0)) (while (/= mask 0) (if (Xtest mask 1) (setq ret (1+ ret))) (setq mask (ash mask -1))) ret)) (defun Xmask-count (mask) "Count the number of bits set in the mask MASK. This is needed to identify new objects (client-selectable) thingies." (let ((lv (Xtruncate mask)) (hv (Xtruncate (/ mask (float 65536))))) (+ (Xcount-bits-int lv) (Xcount-bits-int hv)))) (defun Xmask-int-string (mask) "Convert MASK as an integer into a string of 0s and 1s." (let ((cnt 15) (s nil)) (while (/= cnt -1) (setq s (concat s (if (= (logand mask (lsh 1 cnt)) 0) "0" "1"))) (setq cnt (1- cnt))) s)) (defun Xmask-string (mask) "Convert MASK into a string of 0s and 1s." (let ((lv (Xtruncate mask)) (hv (Xtruncate (/ mask (float 65536))))) (concat (Xmask-int-string hv) (Xmask-int-string lv)))) (defun Xmask-int-hex-string (mask &optional fill) "Convert the integer MASK into a full hexidecimal number. Optional argument FILL means to add 0s as necessary." (let ((s (format "%x" mask))) (if fill (substring (concat "0000" s) (length s)) s))) (defun Xmask-hex-string (mask) "Convert MASK into a hexidecimal string." (let ((lv (Xtruncate mask)) (hv (Xtruncate (/ mask (float 65536))))) (concat "0x" (Xmask-int-hex-string hv) (Xmask-int-hex-string lv (/= hv 0))))) (provide 'xlib-math) ;;; xmath.el ends here