home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 01e / miscfunc.zip / ASC3FUNC.PRG next >
Text File  |  1988-04-12  |  19KB  |  389 lines

  1. *************************************************************************
  2. *************************************************************************
  3. *
  4. * Copyright Steve Titterud 1987
  5. *           2157 Glenridge Ave.S.
  6. *           St. Paul, MN 55119
  7. *           (612)-739-7229
  8. *           Permission for non-commercial use granted.
  9. *
  10. ** ASC3FUNC.PRG - QS function file which has a variety of functions for
  11. **                conversion and deconversion of positive decimal integers into
  12. **                numbers expressed in a user-specified number base, and
  13. **                furthermore, stored as ASCII characters, where 3 digits'
  14. **                position are each filled with a character whose ASCII value
  15. **                less 1 actually stands for the decimal number in that digit
  16. **                position.
  17. **
  18. ** This allows storage of numbers up to 16,581,374 in 3 bytes, in a character
  19. ** form.  If dates are first converted to Julian date numbers, then these
  20. ** can be converted for storage as well.  Either Julian dates and numbers, 
  21. ** then, can be stored in 3 bytes on disk, and used directly with no conversion
  22. ** in index expressions.  The descend() function may be used to reverse the
  23. ** index order painlessly.
  24. **
  25. ** This is the type of thing that ought to be written in C or assembler,
  26. ** however, I don't know assembler, and until I can use Turbo C with QS,
  27. ** I guess I'll stick with these when needed.
  28. **
  29. ** Ordinarily, the user will use the number base 255, since it affords the
  30. ** most economical storage available, but the user may also select a different
  31. ** number base which may uniquely suit his application.
  32. **
  33. ** No provisions are made to manipulate negative nor fractional numbers
  34. ** in the selected number base; however, the user can readily modify the 
  35. ** source to add these capabilities.
  36. **
  37. ** This manner of storage offers both benefits and drawbacks.  On the one hand,
  38. ** numbers may be accurately stored in this manner more economically - using
  39. ** less disk space, for example.  Numbers stored in this fashion need no
  40. ** conversion to string form in order to be used in an index key, concatenated
  41. ** with other strings.  Julian dates (or dates derived from any base date) may
  42. ** be represented in this way, and date order may be painlessly reversed using
  43. ** the descend() function.  Moreover, the indexing operations will be faster,
  44. ** and the indexes themselves smaller, than if the numbers these functions
  45. ** transform were used instead of being converted to this form.
  46. **
  47. ** In addition, a date-time value may be derived, with accuracy to the second,
  48. ** using a value of only 6 bytes (Julian dates).  Furthermore, these values may
  49. ** be used as a universal source of unique ID values for all files
  50. ** in a system, subject to its reliance on the accuracy of the system's clock
  51. ** and calendar, of course, and also based upon the principle that the 
  52. ** essential requirement of an ID is that it be unique, and that no further
  53. ** meaning nor content is necessary nor desirable in an ID.  As long as the
  54. ** computer system has an accurate clock/calendar, this date-time stamp could
  55. ** serve as a perpetual generator of unique 6 byte ID values.
  56. **
  57. ** Actually, the time value in these 6 byte date-time variables could be
  58. ** maintained to an accuracy of .01 second, IF a system time could deliver a
  59. ** reading of time to that accuracy.  This is based upon the idea that you
  60. ** could store the number of .01 sec in any time value in 3 bytes of the 6 byte
  61. ** variable.  If an even more accurate time could be provided by a separate
  62. ** assembler routine, then a comparable 7 byte variable could store
  63. ** date-time values accurate to .0001 sec !!  But the functions here rely upon
  64. ** accuracy to the second, and in most applications, this will prove adequate.
  65. **
  66. ** On the other hand, the functions do consume some extra processor time in
  67. ** conversion to and deconversion from the decimal numbers which they represent.
  68. ** Moreover, the user may find them unreadable unless converted, so it is
  69. ** expected that all of these values need conversion prior to viewing by the
  70. ** user.
  71. ** 
  72. ** The functions store a numeric value in any digit position as the value
  73. ** of that digit +1.  The reason for this is to avoid chr(0), the 'null',
  74. ** which will not be correctly written to a field in a datafile.  Thus the
  75. ** offset of +1.  Before these stored values are used in arithmetic operations
  76. ** the offset is first removed.
  77. ** 
  78. ** The convention used in the functions for denoting the names of the variables
  79. ** representing the digit positions:
  80. ** 
  81. **          digit0 = digit * numbase^0  (always 1)
  82. **          digit1 = digit * numbase^1
  83. **          digit2 = digit * numbase^2
  84. ** 
  85. ** The functions also enforce upper and lower bounds to the numbers they
  86. ** process and also to those they return.  Any number passed to the functions
  87. ** for processing, or calculated as a return value, which is less than the
  88. ** minimum or greater than the maximum listed below is forced up to the
  89. ** minimum or forced down to the maximum:
  90. ** 
  91. **                minimum    maximum         base 255 maximum
  92. **                ───────    ─────────────   ─────────────────
  93. ** 
  94. **     (3 digits)    0       numbase^3 - 1       16,581,374
  95. ** 
  96. ** If the user desires, he may create error values for return in this case,
  97. ** or possibly modify the code in another way to suit his use.
  98. ** 
  99. ** 
  100. ** The functions rely upon prior global initialization of the
  101. ** following variables:
  102. **
  103. **
  104. **
  105. **               numbase - number base for counting; usually would be
  106. **                         255 for maximum effect, but could be any other
  107. **                         number base desired for a specific circumstance;
  108. **                         must be able to effectively deal with the size
  109. **                         of numbers passed to it, of course
  110. **              basedate - the date from which all dates are offset for
  111. **                         storing and comparing of values; could be the
  112. **                         Julian basedate corresponding to the number 0
  113. **                         for 3-byte storage;
  114. **               daysecs - the number of seconds in a day, 24*60*60
  115. **              hoursecs - the number of seconds in an hour, 60*60
  116. **               minsecs - the number of seconds in a minute, 60
  117. **
  118. ** In addition, naturally the date-time stamp functions require an accurate
  119. ** date() and time() from the system.  If the date-time stamp is used for
  120. ** purposes of generating IDs, the last ID generated or used in a session
  121. ** should be saved for comparison with a new date-time stamp upon startup
  122. ** of the next session.  If the new one is not greater than the old one,
  123. ** there is probably a problem with the system clock, and it may have started
  124. ** in the previous session.  In this case, the user might alter a variable
  125. ** which turns off the generation of new IDs from date-time stamps, and
  126. ** instead uses a successive incrementing of the last-used value until a
  127. ** session is started when the new date-time stamp IS greater than the
  128. ** last one used in a previous session.
  129. **
  130. ** FUNCTIONS AVAILABLE: (ASCIInum always assumes a constant numbase)
  131. **
  132. **
  133. **             num3asc(decimal number)
  134. **                     - creates 3 digit ASCIInum from decimal number
  135. **             asc3num(3 digit ASCIInum)
  136. **                     - creates decimal number from 3 digit ASCIInum 
  137. **             inc3asc(3 digit ASCIInum,decimal number,type return value)
  138. **                     - adds decimal number to 3 digit ASCIInum, returns either
  139. **                       decimal number or 3 digit ASCIInum
  140. **             dec3asc(3 digit ASCIInum,decimal number,type return value)
  141. **                     - subtracts decimal number from 3 digit ASCIInum, returns
  142. **                       either decimal number or 3 digit ASCIInum 
  143. **             add3asc(3 digit ASCIInum,3 digit ASCIInum,type return value)
  144. **                     - adds two 3 digit ASCIInums, returns either decimal number
  145. **                       or 3 digit ASCIInum
  146. **             sub3asc(3 digit ASCIInum,3 digit ASCIInum,type return value)
  147. **                     - finds difference between two 3 digit ASCIInums,
  148. **                       returns either decimal number or 3 digit ASCIInum
  149. **             dt3jasc(date, type of return value)
  150. **                     - calculates date as offset from base date, returns
  151. **                       either decimal number or 3 digit ASCIInum
  152. **             jasc3dt(number)
  153. **                     - accepts date either as decimal number offset from base date,
  154. **                       or as 3 digit ASCIInum representing same, returns
  155. **                       date variable in ordinary date format
  156. **            sub3jasc(date,date)
  157. **                     - accepts 2 dates either as decimal number offset from base date
  158. **                       or as 3 digit ASCIInums, returns difference in days
  159. **                       as decimal number
  160. **             dttmasc(date,time)
  161. **                     - accepts date() and time() values, computes date as
  162. **                       offset from base date, then represents as 3 digit
  163. **                       ASCIInum; computes time as decimal number of seconds since
  164. **                       midnight, then represents as 3 digit ASCIInum; and
  165. **                       finally, concatenates the two results to form a
  166. **                       6 byte date-time variable; use this function to
  167. **                       generate unique IDs based upon system clock
  168. **             ascdttm(6 digit ASCIInum)
  169. **                     - accepts 6 digit ASCIInum representation of date-time,
  170. **                       converts back to date() and time(), returns as 
  171. **                       concatenated string
  172. **            dttmdiff(6 digit ASCIInum,6 digit ASCIInum,type of return value)
  173. **                     - accepts 2 6 digit ASCIInum date-time variables,
  174. **                       computes their difference, and returns that difference
  175. **                       either as 6 digit ASCII number or as string
  176. **
  177. *************************************************************************
  178. ************************************************************************
  179. FUNCTION num3asc
  180. PARAMETERS numnum
  181. PRIVATE ascnum,digit2,digit2mod,digit1,digit1mod,digit0
  182. ** accepts decimal number, returns 3-byte ASCIInum in base numbase
  183. ** enforce upper, lower bounds to numnum
  184. numnum=iif(numnum>(numbase^3-1),(numbase^3-1),iif(numnum<0,0,numnum))
  185. digit2=int(numnum/(numbase^2))
  186. digit2mod=mod(numnum,(numbase^2))
  187. digit1=int(digit2mod/numbase)
  188. digit1mod=mod(digit2mod,numbase)
  189. digit0=digit1mod
  190. ascnum=chr(digit2+1)+chr(digit1+1)+chr(digit0+1)
  191. RETURN ascnum
  192. ************************************************************************
  193. FUNCTION asc3num
  194. PARAMETERS ascnum
  195. PRIVATE numnum,digit2,digit1,digit0
  196. ** accepts 3-byte ASCIInum in base numbase, returns decimal number
  197. digit2=(asc(right(ascnum,3))-1)
  198. digit1=(asc(right(ascnum,2))-1)
  199. digit0=(asc(right(ascnum,1))-1)
  200. numnum=(digit2*(numbase^2))+(digit1*numbase)+digit0
  201. RETURN numnum
  202. ************************************************************************
  203. FUNCTION inc3asc
  204. PARAMETERS ascvarval,howmuch,returnasc
  205. PRIVATE returnval,startval,sumval
  206. ** increments value of 3-byte ASCIInum in base numbase by decimal number howmuch
  207. ** sums > (numbase^3-1) forced to (numbase^3-1); negative howmuch forced to 0
  208. ** returnasc variable provides return of ASCIInum if .T., else decimal number
  209. howmuch=iif(howmuch<0,0,howmuch)
  210. startval=asc3num(ascvarval)
  211. sumval=startval+howmuch
  212. returnval=iif(returnasc,num3asc(sumval),iif(sumval>(numbase^3-1),(numbase^3-1),sumval))
  213. RETURN returnval
  214. ************************************************************************
  215. FUNCTION dec3asc
  216. PARAMETERS ascvarval,howmuch,returnasc
  217. PRIVATE returnval,startval,sumval
  218. ** decrements value of 3-byte ASCIInum in base numbase by decimal number howmuch
  219. ** negative howmuch forced to 0; negative result forced to 0
  220. ** returnasc variable provides return of ASCIInum if .T., else decimal number
  221. howmuch=iif(howmuch<0,0,howmuch)
  222. startval=asc3num(ascvarval)
  223. sumval=startval-howmuch
  224. sumval=iif(sumval<0,0,sumval)
  225. returnval=iif(returnasc,num3asc(sumval),sumval)
  226. RETURN returnval
  227. ************************************************************************
  228. FUNCTION add3asc
  229. PARAMETERS ascvarval,addvarval,returnasc
  230. PRIVATE adder1,adder2,sumadder,returnval
  231. ** adds two 3-byte ASCIInums in base numbase
  232. ** sums > (numbase^3-1) forced to (numbase^3-1)
  233. ** returnasc variable provides return of ASCIInum if .T., else decimal number
  234. adder1=asc3num(ascvarval)
  235. adder2=asc3num(addvarval)
  236. sumadder=adder1+adder2
  237. returnval=iif(returnasc,num3asc(sumadder),iif(sumadder>(numbase^3-1),(numbase^3-1),sumadder))
  238. RETURN returnval
  239. ************************************************************************
  240. FUNCTION sub3asc
  241. PARAMETERS ascvarval,addvarval,returnasc
  242. PRIVATE adder1,adder2,sumadder,returnval
  243. ** subtracts 3-byte ASCIInums in base numbase, returns difference
  244. ** negative values forced to 0; negative result forced to 0
  245. ** returnasc variable provides return of ASCIInum if .T., else decimal number
  246. adder1=asc3num(ascvarval)
  247. adder2=asc3num(addvarval)
  248. sumadder=adder1-adder2
  249. ** what type of return value requested?
  250. returnval=iif(returnasc,num3asc(sumadder),iif(sumadder<0,0,sumadder))
  251. RETURN returnval
  252. ************************************************************************
  253. FUNCTION dt3jasc
  254. PARAMETERS dt,returnasc
  255. PRIVATE mdate,ascdt
  256. ** 3-byte version
  257. ** accepts date value, returns offset from basedate
  258. ** returnasc variable provides return of ASCIInum if .T., else decimal number
  259. mdate=dt-basedate
  260. returnval=iif(returnasc,num3asc(mdate),mdate)
  261. RETURN returnval
  262. ************************************************************************
  263. FUNCTION jasc3dt
  264. PARAMETERS dtnum
  265. PRIVATE dayint,dtdate
  266. ** accepts date offset from basedate, either as 3-byte ASCIInum form of
  267. ** offset, or as decimal number, returns date
  268. if type('dtnum')="C"  && it's squeezed in ASCIInum
  269.    dayint=asc3num(dtnum)
  270. else  && it's a decimal number offset from basedate
  271.    dayint=dtnum
  272. endif
  273. dtdate=basedate+dayint
  274. RETURN dtdate
  275. ************************************************************************
  276. FUNCTION sub3jasc
  277. PARAMETERS dt1,dt2
  278. PRIVATE dtdiff,jdt1,jdt2
  279. ** accepts 2 dates either as 3-byte ASCIInum values or decimal numbers
  280. ** computes difference in days, forcing negative result to 0
  281. if dt1>=dt2
  282.    dtdiff=0
  283. else
  284.    if type('dt1')="C"  && it's squeezed in ASCIInum
  285.       jdt1=asc3num(dt1)
  286.       jdt2=asc3num(dt2)
  287.       dtdiff=jdt2-jdt1
  288.    else  && it's a julian date
  289.       dtdiff=dt2-dt1
  290.    endif
  291. endif
  292. RETURN dtdiff
  293. ************************************************************************
  294. FUNCTION dttmasc
  295. PARAMETERS dt,tm
  296. PRIVATE mdate,timestr,dayint,dayfract,dttm
  297. ** accepts date and time, returns two concatenated 3-byte ASCIInums
  298. ** in base numbase which represents a date/time stamp
  299. ** where date part is decimal number of days offset from basedate,
  300. ** and time part is decimal number of seconds offset from midnight of that day
  301. mdate=dt
  302. timestr=tm
  303. dayint=mdate-basedate
  304. dayfract=(val(substr(timestr,1,2))*hoursecs)+(val(substr(timestr,4,2))*minsecs)+(val(substr(timestr,7,2)))
  305. ** now, convert to strings, concatenate
  306. dttm=num3asc(dayint)+num3asc(dayfract)
  307. RETURN dttm
  308. ************************************************************************
  309. FUNCTION ascdttm
  310. PARAMETERS dttmasc
  311. PRIVATE dayasc,dayint,thisdate,timeasc,dayfract,hours,carry,mins,secs,thistime,dttmstr
  312. ** takes 6-byte ASCIInum representation of date/time and regenerates
  313. ** the date and time values from which it was derived, returns as string
  314. ** in format [date - time]
  315. ** first, date derived from offset to basedate:
  316. dayasc=left(dttmasc,3)
  317. dayint=asc3num(dayasc)
  318. thisdate=basedate+dayint
  319. ** next, time derived from # of seconds in each unit of time:
  320. timeasc=right(dttmasc,3)
  321. dayfract=asc3num(timeasc)  && decimal number of seconds
  322. hours=int(dayfract/hoursecs)
  323. carry=mod(dayfract,hoursecs)
  324. mins=int(carry/minsecs)
  325. carry=mod(carry,minsecs)
  326. secs=carry
  327. thistime=str(hours,2)+":"+str(mins,2)+":"+str(secs,2)
  328. do while at(" ",thistime)>0
  329.    thistime=stuff(thistime,at(" ",thistime),1,"0")
  330. enddo
  331. dttmstr=dtoc(thisdate)+" - "+thistime
  332. RETURN dttmstr
  333. **********************************************************************
  334. FUNCTION dttmdiff
  335. PARAMETERS dttm1,dttm2,returnasc
  336. PRIVATE day1asc,day1int,time1asc,day1fract,day2asc,day2int,time2asc,day2fract
  337. PRIVATE daysdiffstr,timediffstr,timesdiff,daysdiff,hoursdiff,minsdiff,secsdiff
  338. ** takes two 6-byte ASCIInum date/time values and returns their difference
  339. ** either as a string or as a 6-byte ASCIInum value
  340. ** this function presumes dttm2 >= dttm1
  341. ** DAY1...
  342. ** first, date derived from offset to basedate:
  343. if dttm2>dttm1
  344.    day1asc=left(dttm1,3)
  345.    day1int=asc3num(day1asc)
  346.    ** next, time derived from # of seconds in each unit of time:
  347.    time1asc=right(dttm1,3)
  348.    day1fract=asc3num(time1asc)
  349.    ** DAY2...
  350.    day2asc=left(dttm2,3)
  351.    day2int=asc3num(day2asc)
  352.    ** next, time derived from # of seconds in each unit of time:
  353.    time2asc=right(dttm2,3)
  354.    day2fract=asc3num(time2asc)
  355.    ** now, calculate difference
  356.    if day1fract>day2fract  && only case if day2int>day1int
  357.       timesdiff=(day2fract+daysecs)-day1fract  && borrow a day, in seconds, from days
  358.       daysdiff=day2int-day1int-1  && take off borrowed day
  359.    else
  360.       timesdiff=day2fract-day1fract
  361.       daysdiff=day2int-day1int
  362.    endif
  363.    ** values obtained; what kind of return value requested?
  364.    if returnasc  && convert to ASCIInum in same format as dttm variables
  365.       returnval=num3asc(daysdiff)+num3asc(timesdiff)
  366.    else  && return as string: #days - time string
  367.       ** calculate each unit of time, pass on any remainders
  368.       hoursdiff=int(timesdiff/hoursecs)
  369.       timesdiff=mod(timesdiff,hoursecs)
  370.       minsdiff=int(timesdiff/minsecs)
  371.       secsdiff=mod(timesdiff,minsecs)
  372.       ** now, calculate string representation of difference:
  373.       daysdiffst=str(daysdiff,8)+" - "
  374.       timediffst=str(hoursdiff,2)+":"+str(minsdiff,2)+":"+str(secsdiff,2)
  375.       do while at(" ",timediffst)>0
  376.          timediffst=stuff(timediffst,at(" ",timediffst),1,"0")
  377.       enddo
  378.       returnval=daysdiffst+timediffst
  379.    endif
  380. else
  381.    if returnasc
  382.       returnval=replicate(chr(1),6)
  383.    else
  384.       returnval=space(8)+" - "+"00:00:00"
  385.    endif
  386. endif
  387. RETURN returnval
  388. ************************************************************************
  389.