1 //-------------------------------------------------------------------------
\r
3 // This file contains some DataFlex 3.2 Console Mode classes
\r
4 // to provide some useful data structures.
\r
6 // This file is to be included in df32func.mk
\r
8 // Copyright (c) 2006-2015, glyn@8kb.co.uk
\r
10 // df32func/data.inc
\r
11 //-------------------------------------------------------------------------
\r
13 //-------------------------------------------------------------------------
\r
15 //-------------------------------------------------------------------------
\r
17 // Linked list class - impliments a linked list type structure in an array, unlike
\r
18 // traditional linked lists the data is actually the prev/next links (array indexes)
\r
20 // Prev and next addresses are stored as a string "prev,next" rather than using XORing;
\r
21 // this is so we can start traversal in either direction from a particular address
\r
22 // without having to also know the prev or next address.
\r
25 // probe_state - Returns a summary of the linked list state
\r
26 // first_link - Returns the first link in the list
\r
27 // last_link - Returns the last link in the list
\r
28 // link_count - Returns the total number of links
\r
29 // next_link <current_link> - Returns the next link after the link id passed in
\r
30 // prev_link <current_link> - Returns the previous link after the link id passed in
\r
32 // Set methods: (All of the following methods are intended to be private)
\r
33 // next_link <current_link> - Sets the next link after the link id passed in
\r
34 // prev_link <current_link> - Sets the previous link after the link id passed in
\r
35 // seek_link - Seeks out the position in the list for a new link
\r
37 // Send message methods:
\r
38 // insert_link - Insert a new item into the linked list
\r
39 // remove_link - Remove an item from the linked list
\r
45 // integer max min count i
\r
47 // object test is a linkedlist
\r
50 // // Create some links
\r
51 // for i from 10 to 15
\r
52 // send insert_link to test (i*100)
\r
54 // for i from 1 to 5
\r
55 // send insert_link to test (i*100)
\r
58 // send insert_link to test 750
\r
61 // send remove_link to test 300
\r
63 // // Access the list
\r
64 // get probe_state of test to buf
\r
65 // get first_link of test to min
\r
66 // get last_link of test to max
\r
67 // get link_count of test to count
\r
69 // showln "There are " count " items in the linked list"
\r
72 // show "Traverse forwards: "
\r
76 // get next_link of test item i to i
\r
80 // show "Traverse backwards: "
\r
84 // get prev_link of test item i to i
\r
88 class linkedlist is an array
\r
89 procedure construct_object integer argc
\r
90 object mTokens is a StringTokenizer
\r
93 forward send construct_object
\r
95 property integer c_iMinAddr
\r
96 property integer c_iMaxAddr
\r
97 property integer c_iCount
\r
98 property number c_nDist
\r
100 set c_iMinAddr to -1
\r
101 set c_iMaxAddr to -1
\r
106 procedure delete_data
\r
107 set c_iMinAddr to -1
\r
108 set c_iMaxAddr to -1
\r
111 forward send delete_data
\r
114 function probe_state returns string
\r
115 local integer l_iMinAddr l_iMaxAddr l_iCount
\r
116 local number l_nDist
\r
118 get c_iMaxAddr to l_iMaxAddr
\r
119 get c_iMinAddr to l_iMinAddr
\r
120 get c_iCount to l_iCount
\r
121 get c_nDist to l_nDist
\r
123 function_return ("Address range: "+string(l_iMinAddr)+"<->"+string(l_iMaxAddr)+" Items: "+string(l_iCount)+" Dist: "+string(l_nDist))
\r
126 function last_link returns integer
\r
127 local integer l_iMaxAddr
\r
129 get c_iMaxAddr to l_iMaxAddr
\r
131 function_return l_iMaxAddr
\r
134 function first_link returns integer
\r
135 local integer l_iMinAddr
\r
137 get c_iMinAddr to l_iMinAddr
\r
139 function_return l_iMinAddr
\r
142 function link_count returns integer
\r
143 local integer l_iCount
\r
145 get c_iCount to l_iCount
\r
147 function_return l_iCount
\r
150 function next_link integer l_iAddr returns integer
\r
151 local string l_sBuf
\r
152 local integer l_iNext
\r
154 forward get string_value item l_iAddr to l_sBuf
\r
155 if (l_sBuf = "") custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr
\r
156 move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext
\r
158 function_return l_iNext
\r
161 function prev_link integer l_iAddr returns integer
\r
162 local string l_sBuf
\r
163 local integer l_iPrev
\r
165 forward get string_value item l_iAddr to l_sBuf
\r
166 if (l_sBuf = "") custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr
\r
167 move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev
\r
169 function_return l_iPrev
\r
172 procedure set next_link integer l_iAddr integer l_iNext
\r
173 local string l_sBuf
\r
174 local integer l_iPrev
\r
176 forward get string_value item l_iAddr to l_sBuf
\r
177 move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev
\r
178 forward set array_value item l_iAddr to (string(l_iPrev)+","+string(l_iNext))
\r
182 procedure set prev_link integer l_iAddr integer l_iPrev
\r
183 local string l_sBuf
\r
184 local integer l_iNext
\r
186 forward get string_value item l_iAddr to l_sBuf
\r
187 move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext
\r
188 forward set array_value item l_iAddr to (string(l_iPrev)+","+string(l_iNext))
\r
192 function seek_link integer l_iAddr returns string
\r
193 local integer l_iOn l_iNext l_iPrev l_iMinAddr l_iMaxAddr
\r
194 local string l_sBuf
\r
195 local number l_nDist
\r
197 get c_iMaxAddr to l_iMaxAddr
\r
198 get c_iMinAddr to l_iMinAddr
\r
199 get c_nDist to l_nDist
\r
202 if (show_debug_lines) begin
\r
203 showln "DEBUG: Addr " l_iAddr
\r
204 showln "DEBUG: Range " l_iMinAddr " <-> " l_iMaxAddr
\r
205 showln "DEBUG: Dist " l_nDist
\r
208 move l_iMinAddr to l_iPrev
\r
209 move l_iMaxAddr to l_iNext
\r
211 if (l_iAddr > l_iMaxAddr) move l_iMaxAddr to l_iOn
\r
212 else move l_iMinAddr to l_iOn
\r
214 if (l_iOn > -1) begin
\r
215 while (l_iOn < l_iAddr)
\r
216 forward get string_value item l_iOn to l_sBuf
\r
217 if (l_sBuf = "") break
\r
219 move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev
\r
220 move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext
\r
222 if ((l_iNext = -1) or (l_iNext > l_iAddr)) break
\r
223 move l_iNext to l_iOn
\r
227 if (l_iPrev > l_iAddr) begin
\r
228 move l_iPrev to l_iNext
\r
233 function_return (string(l_iPrev)+","+string(l_iOn)+","+string(l_iNext))
\r
236 procedure insert_link integer l_iAddr
\r
237 local integer l_iMinAddr l_iMaxAddr l_iPrev l_iNext l_iOn l_iCount
\r
238 local string l_sBuf
\r
239 local number l_nDist
\r
241 if (l_iAddr < 0) custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr
\r
243 forward get string_value item l_iAddr to l_sBuf
\r
244 if (l_sBuf <> "") custom_error ERROR_CODE_ADDRESS_TAKEN$ ERROR_MSG_ADDRESS_TAKEN l_iAddr
\r
246 get c_iMaxAddr to l_iMaxAddr
\r
247 get c_iMinAddr to l_iMinAddr
\r
248 get seek_link item l_iAddr to l_sBuf
\r
250 send delete_data to (mTokens(current_object))
\r
251 send set_string to (mTokens(current_object)) l_sBuf ","
\r
252 get integer_value of (mTokens(current_object)) item 0 to l_iPrev
\r
253 get integer_value of (mTokens(current_object)) item 1 to l_iOn
\r
254 get integer_value of (mTokens(current_object)) item 2 to l_iNext
\r
256 if (show_debug_lines) begin
\r
257 showln "DEBUG: Insert address: " l_iAddr " Seek data '" l_sBuf "'"
\r
260 if (l_iOn <> -1) set next_link item l_iOn to l_iAddr
\r
261 forward set array_value item l_iAddr to (string(l_iOn)+","+string(l_iNext))
\r
262 if (l_iNext <> -1) set prev_link item l_iNext to l_iAddr
\r
264 if (l_iAddr > l_iMaxAddr) begin
\r
265 move l_iAddr to l_iMaxAddr
\r
266 set c_iMaxAddr to l_iMaxAddr
\r
268 if ((l_iAddr < l_iMinAddr) or (l_iMinAddr = -1)) begin
\r
269 move l_iAddr to l_iMinAddr
\r
270 set c_iMinAddr to l_iMinAddr
\r
272 get c_iCount to l_iCount
\r
273 get c_nDist to l_nDist
\r
275 set c_iCount to l_iCount
\r
276 set c_nDist to (number(l_iCount)/(l_iMaxAddr-l_iMinAddr))
\r
281 procedure remove_link integer l_iAddr
\r
282 local integer l_iMinAddr l_iMaxAddr l_iPrev l_iNext l_iOn l_iCount
\r
283 local string l_sBuf
\r
284 local number l_nDist
\r
286 if (l_iAddr < 0) custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr
\r
288 get c_iMaxAddr to l_iMaxAddr
\r
289 get c_iMinAddr to l_iMinAddr
\r
290 forward get string_value item l_iAddr to l_sBuf
\r
292 move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev
\r
293 move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext
\r
295 if (show_debug_lines) begin
\r
296 showln "DEBUG: Remove address: " l_iAddr " Link data '" l_sBuf "'"
\r
299 if (l_iPrev <> -1) set next_link item l_iPrev to l_iNext
\r
300 if (l_iNext <> -1) set prev_link item l_iNext to l_iPrev
\r
301 forward set array_value item l_iAddr to ""
\r
303 if (l_iMaxAddr = l_iAddr) set c_iMaxAddr to l_iPrev
\r
304 if (l_iMinAddr = l_iAddr) set c_iMinAddr to l_iNext
\r
306 get c_iCount to l_iCount
\r
307 get c_nDist to l_nDist
\r
309 set c_iCount to l_iCount
\r
310 set c_nDist to (number(l_iCount)/(l_iMaxAddr-l_iMinAddr))
\r
316 // Hashtable class - unlike other similar "hash" data structures which usually
\r
317 // store key/value pairs; the hashtable class was only initially intended to
\r
318 // store a key and return a hash index. Typical use would usually have been
\r
319 // to then store the value in an array at the hash index. (See the "hash" class
\r
320 // below for a key/value orientated class)
\r
321 // It is however possible to use insert_at_hash and find_at_hash to store a different
\r
322 // value at a particular key hash, this is however an afterthought and colisions are
\r
325 // Send message methods:
\r
326 // delete_data - Clear the hashtable
\r
327 // hash_algorithm - Set the hash algorithm, any of ("hash_for_df_arrays",
\r
328 // "hash_reduced_djb2", "hash_reduced_lazy", "hash_reduced_sdbm")
\r
329 // with "hash_for_df_arrays" being the default.
\r
330 // remove_hash - Removes an item from the hashtable.
\r
333 // item_ptr - Set the index of the current item_ptr (next_hash will return the next item from this)
\r
337 // insert_hash - Insert a value (where the key is equal to the value) and return hash index
\r
338 // insert_at_hash - Insert a value at the hash index of a key and return hash index
\r
339 // find_hash - Check if a value is stored in the hash (where the key is equal to the value) and return it's hash index
\r
340 // find_at_hash - Check if a value is stored in the hash at the hash index of a key and return it's hash index
\r
341 // value_at_index - Return the value stored at a particular hash index
\r
342 // string_at_index - Same as above, but specifically retun in string context
\r
343 // next_hash - Get the next value stored in the hash
\r
344 // item_ptr - Get the index of the last value returned by next_hash
\r
348 // object myHashtable is a hashTable
\r
355 // get insert_hash of (myHashtable(current_object)) item "ABC" to i
\r
356 // get insert_hash of (myHashtable(current_object)) item "HELLO" to ix
\r
357 // get insert_hash of (myHashtable(current_object)) item "ZZZ" to i
\r
358 // send remove_hash to (myHashtable(current_object)) ix
\r
359 // get item_count of (myHashtable(current_object)) to i
\r
361 // get find_hash of (myHashtable(current_object)) item "HELLO" to i
\r
364 // set item_ptr of (myHashTable(current_object)) to 0
\r
367 // get next_hash of (myHashtable(current_object)) to k
\r
368 // get item_ptr of (myHashtable(current_object)) to i
\r
370 // showln "*** " i " " k
\r
374 class hashtable is an array
\r
375 procedure construct_object integer argc
\r
376 forward send construct_object
\r
377 property integer c_iMaxHash public argc
\r
378 property integer c_iMinHash
\r
379 property integer c_iItems
\r
380 property integer c_iItemP
\r
381 property string c_sHashAlgorithm
\r
382 set c_sHashAlgorithm to "hash_for_df_arrays"
\r
383 set c_iMinHash to 99999999
\r
386 procedure delete_data
\r
387 set c_iMinHash to 0
\r
388 set c_iMaxHash to 0
\r
391 forward send delete_data
\r
394 procedure hash_algorithm string l_sType
\r
395 local integer l_iItems
\r
397 get c_iItems to l_iItems
\r
399 // Allow algorithm change only when empty.
\r
400 if (l_iItems = 0) begin
\r
401 if (trim(lowercase(l_sType)) = "hash_for_df_arrays") set c_sHashAlgorithm to "hash_for_df_arrays"
\r
402 if (trim(lowercase(l_sType)) = "hash_reduced_djb2") set c_sHashAlgorithm to "hash_reduced_djb2"
\r
403 if (trim(lowercase(l_sType)) = "hash_reduced_sdbm") set c_sHashAlgorithm to "hash_reduced_sdbm"
\r
404 if (trim(lowercase(l_sType)) = "hash_reduced_lazy") set c_sHashAlgorithm to "hash_reduced_lazy"
\r
408 procedure set item_ptr integer l_iItemP
\r
409 set c_iItemP to l_iItemp
\r
412 function item_ptr returns integer
\r
413 local integer l_iItemP
\r
414 get c_iItemP to l_iItemP
\r
415 function_return l_iItemP
\r
418 procedure remove_hash integer l_iHash
\r
419 local string l_sNext
\r
420 local integer l_iItems
\r
422 get c_iItems to l_iItems
\r
423 if (l_iItems > 0) begin
\r
424 forward get array_value item (l_iHash+1) to l_sNext
\r
425 if (trim(l_sNext) <> "") forward set array_value item l_iHash to "<!!#ITEM REMOVED#!!>"
\r
426 if (trim(l_sNext) = "") forward set array_value item l_iHash to ""
\r
427 set c_iItems to (l_iItems-1)
\r
431 function item_count returns integer
\r
432 local integer l_iItems
\r
433 get c_iItems to l_iItems
\r
434 function_return l_iItems
\r
437 function write_hash string l_sHash string l_sValue returns integer
\r
438 local integer l_iHash l_iMinHash l_iMaxHash l_iItems l_iReuse
\r
439 local string l_sTmp l_sHashAlgorithm l_sStorage
\r
441 if (l_sValue = "") begin
\r
442 move l_sHash to l_sStorage
\r
445 move l_sValue to l_sStorage
\r
448 // Get our object properties
\r
449 get c_iMaxHash to l_iMaxHash
\r
450 get c_iMinHash to l_iMinHash
\r
451 get c_iItems to l_iItems
\r
452 get c_sHashAlgorithm to l_sHashAlgorithm
\r
454 // Generate an initial hash
\r
458 case (l_sHashAlgorithm = "hash_reduced_djb2") move (reduce_hash(hash_djb2(l_sHash))) to l_iHash
\r
460 case (l_sHashAlgorithm = "hash_reduced_sdbm") move (reduce_hash(hash_sdbm(l_sHash))) to l_iHash
\r
462 case (l_sHashAlgorithm = "hash_reduced_lazy") move (reduce_hash(hash_lazy(l_sHash))) to l_iHash
\r
464 case else move (hash_for_df_arrays(l_sHash)) to l_iHash
\r
468 // Then we check in the array to see if out hash is available or equal
\r
469 // if not we bucket the value by moveing along into the next available slot
\r
472 forward get string_value item l_iHash to l_sTmp
\r
473 if ((l_sTmp <> "") and (l_sTmp <> l_sStorage)) begin
\r
474 // If we come across a removed item we may want to reuse the hash space
\r
475 if ((l_sTmp = "<!!#ITEM REMOVED#!!>") and (l_iReuse = 0)) move l_iHash to l_iReuse
\r
476 calc (l_iHash+1) to l_iHash
\r
480 // If this is a new object and we have a slot to reuse then do so here
\r
481 if ((l_iReuse <> 0) and (l_sTmp = "")) move l_iReuse to l_iHash
\r
482 if (l_iHash > l_iMaxHash) move l_iHash to l_iMaxHash
\r
483 if (l_iHash < l_iMinHash) move l_iHash to l_iMinHash
\r
484 forward set array_value item l_iHash to l_sStorage
\r
486 set c_iMaxHash to l_iMaxHash
\r
487 set c_iMinHash to l_iMinHash
\r
488 set c_iItems to (l_iItems+1)
\r
490 function_return l_iHash
\r
493 function insert_hash string l_sHash returns integer
\r
494 local integer l_iHash
\r
495 get write_hash item l_sHash item "" to l_iHash
\r
496 function_return l_iHash
\r
499 function insert_at_hash string l_sHash string l_sValue returns integer
\r
500 local integer l_iHash
\r
501 get write_hash item l_sHash item l_sValue to l_iHash
\r
502 function_return l_iHash
\r
505 function read_hash string l_sHash string l_sValue returns integer
\r
506 local integer l_iHash l_iMinHash l_iMaxHash l_iItems
\r
507 local string l_sTmp l_sHashAlgorithm l_sStorage
\r
509 if (l_sValue = "") begin
\r
510 move l_sHash to l_sStorage
\r
513 move l_sValue to l_sStorage
\r
516 // Get our object properties
\r
517 get c_iMaxHash to l_iMaxHash
\r
518 get c_iMinHash to l_iMinHash
\r
519 get c_iItems to l_iItems
\r
520 get c_sHashAlgorithm to l_sHashAlgorithm
\r
522 // Generate an initial hash
\r
526 case (l_sHashAlgorithm = "hash_reduced_djb2") move (reduce_hash(hash_djb2(l_sHash))) to l_iHash
\r
528 case (l_sHashAlgorithm = "hash_reduced_sdbm") move (reduce_hash(hash_sdbm(l_sHash))) to l_iHash
\r
530 case (l_sHashAlgorithm = "hash_reduced_lazy") move (reduce_hash(hash_lazy(l_sHash))) to l_iHash
\r
532 case else move (hash_for_df_arrays(l_sHash)) to l_iHash
\r
536 // Then we check in the array to see if our hash is available or equal
\r
537 // if not we bucket the value by moveing along into the next available slot
\r
539 forward get string_value item l_iHash to l_sTmp
\r
541 if ((l_sTmp <> "") and (l_sTmp <> l_sStorage)) begin
\r
542 calc (l_iHash+1) to l_iHash
\r
545 if (l_sTmp <> l_sStorage) move -1 to l_iHash
\r
547 function_return l_iHash
\r
550 function find_hash string l_sHash returns integer
\r
551 local integer l_iHash
\r
552 get read_hash item l_sHash item "" to l_iHash
\r
553 function_return l_iHash
\r
556 function find_at_hash string l_sHash string l_sValue returns integer
\r
557 local integer l_iHash
\r
558 get read_hash item l_sHash item l_sValue to l_iHash
\r
559 function_return l_iHash
\r
562 function value_at_index integer l_iHash returns string
\r
563 local string l_sBuf
\r
565 forward get array_value item l_iHash to l_sBuf
\r
567 function_return l_sBuf
\r
570 function string_at_index integer l_iHash returns string
\r
571 local string l_sBuf
\r
573 forward get string_value item l_iHash to l_sBuf
\r
575 function_return l_sBuf
\r
578 function next_hash returns string
\r
579 local string l_sBuf
\r
580 local integer l_iItemP l_iMaxHash l_iMinHash
\r
582 get c_iItemP to l_iItemP
\r
583 get c_iMaxHash to l_iMaxHash
\r
584 get c_iMinHash to l_iMinHash
\r
586 if (l_iMinHash > l_iItemP) move (l_iMinHash-1) to l_iItemP
\r
589 while ((l_sBuf = "") and (l_iItemP <= l_iMaxHash))
\r
590 increment l_iItemP
\r
591 forward get array_value item l_iItemP to l_sBuf
\r
592 if (trim(l_sBuf) = "<!!#ITEM REMOVED#!!>") move "" to l_sBuf
\r
595 if (l_iItemP > l_iMaxHash) move -1 to l_iItemP
\r
596 set c_iItemP to l_iItemP
\r
598 function_return l_sBuf
\r
603 // Hash class - more akin to similar "hash" data structures in other languages
\r
604 // which stores key/value pairs.
\r
605 // This is a quick 5 minute implementation, it depends on the hashtable object
\r
606 // above for it's hashing.
\r
608 // Send message methods:
\r
610 // truncate - Clear the hash
\r
611 // remove_key - Removes a key/value pair from the hash
\r
614 // value_at_key - Gets the value stored for a particular key
\r
617 // insert_key - Inserts a key/value pair into the hash
\r
618 // value_at_key - Retrieves the value stored for a particular key
\r
619 // item_count - Retrieves the count of items in the hash
\r
624 // string key iv buf
\r
627 // object test is a hash
\r
630 // send insert_key to test "INDEX 1" "VALUE 1"
\r
631 // send insert_key to test "INDEX 2" "VALUE 2"
\r
632 // send insert_key to test "INDEX 3" "VALUE 3"
\r
634 // get first_key of test to key
\r
635 // showln "KEY " key
\r
636 // get value_at_key of test item key to buf
\r
637 // showln "VALUE " buf
\r
639 // while (key <> "")
\r
640 // get next_key of test key to key
\r
641 // if (key <> "") begin
\r
642 // showln "KEY " key
\r
643 // get value_at_key of test item key to buf
\r
644 // showln "VALUE " buf
\r
648 // set value_at_key of test item "INDEX 2" item "VALUE TWO"
\r
649 // showln "SET VALUE AT 'INDEX 2'"
\r
651 // get value_at_key of test item "INDEX 1" to buf
\r
652 // showln "LOOKUP 'INDEX 1' = " buf
\r
653 // get value_at_key of test item "INDEX 2" to buf
\r
654 // showln "LOOKUP 'INDEX 2' = " buf
\r
656 // get item_count of test to i
\r
657 // showln "ITEM COUNT " i
\r
659 // send remove_key to test "INDEX 3"
\r
660 // showln "REMOVE AT KEY: 'INDEX 3'"
\r
662 // get item_count of test to i
\r
663 // showln "ITEM COUNT " i
\r
665 // get value_at_key of test item "INDEX 3" to buf
\r
666 // showln "LOOKUP 'INDEX 3' =" buf
\r
668 // send truncate to test
\r
669 // showln "TRUNCATED"
\r
671 // get value_at_key of test item "INDEX 1" to buf
\r
672 // showln "LOOKUP 'INDEX 1' = " buf
\r
674 // get item_count of test to i
\r
675 // showln "EMPTY COUNT " i
\r
677 class hash is an array
\r
678 procedure construct_object integer argc
\r
679 object keystore is a hashtable
\r
682 object linkstore is a linkedlist
\r
685 forward send construct_object
\r
689 send delete_data to (keystore(current_object))
\r
690 send delete_data to (linkstore(current_object))
\r
692 forward send delete_data
\r
695 procedure remove_key string l_sKey
\r
696 local integer l_iIndex
\r
697 get find_hash of (keystore(current_object)) item l_sKey to l_iIndex
\r
698 if (l_iIndex <> -1) begin
\r
699 send remove_hash to (keystore(current_object)) l_iIndex
\r
700 send remove_link to (linkstore(current_object)) l_iIndex
\r
701 forward set array_value item l_iIndex to ""
\r
705 procedure set value_at_key string l_sKey string l_sValue
\r
706 local integer l_iIndex
\r
708 get find_hash of (keystore(current_object)) item l_sKey to l_iIndex
\r
709 forward set array_value item l_iIndex to l_sValue
\r
713 procedure insert_key string l_sKey string l_sValue
\r
714 local integer l_iIndex
\r
716 get insert_hash of (keystore(current_object)) item l_sKey to l_iIndex
\r
717 send insert_link to (linkstore(current_object)) l_iIndex
\r
718 forward set array_value item l_iIndex to l_sValue
\r
722 function value_at_key string l_sKey returns string
\r
723 local integer l_iIndex
\r
724 local string l_sValue
\r
726 get find_hash of (keystore(current_object)) item l_sKey to l_iIndex
\r
727 forward get string_value item l_iIndex to l_sValue
\r
729 function_return l_sValue
\r
732 function first_key returns string
\r
733 local integer l_iIndex
\r
734 local string l_sKey
\r
736 get first_link of (linkstore(current_object)) to l_iIndex
\r
737 get string_at_index of (keystore(current_object)) item l_iIndex to l_sKey
\r
739 function_return l_sKey
\r
742 function next_key string l_sKey returns string
\r
743 local integer l_iIndex
\r
745 get find_hash of (keystore(current_object)) item l_sKey to l_iIndex
\r
746 get next_link of (linkstore(current_object)) item l_iIndex to l_iIndex
\r
747 get string_at_index of (keystore(current_object)) item l_iIndex to l_sKey
\r
749 function_return l_sKey
\r
752 function item_count returns integer
\r
753 local integer l_iResult
\r
754 get item_count of (keystore(current_object)) to l_iResult
\r
756 function_return l_iResult
\r
760 // Matrix class - Provides an indexed two-dimensional array / matrix class
\r
762 // This class is sensitive to ascii char 1, which is used for delimiting values
\r
763 // within the second dimension. The implimentation is rather unrefined and
\r
764 // stores delimited values within an array, thus the wider the matrix the
\r
765 // slower any adding removing or sorting will be.
\r
767 // This is designed purely as a convenience to provide something matrix like within
\r
768 // the limitations of DataFlex 3.2 Console Mode; be sure to keep this in mind before
\r
771 // To allow quick lookup of linked data, a hash index may be created on one column
\r
772 // of a matrix at a time.
\r
773 // A hash index may be added both before and after populating the matrix with your
\r
776 // As with a hash table the hasing algorithm may be set for the matrix, but to take
\r
777 // affect this must be called before the hash_on_column message. (see hash.inc
\r
778 // function for available algorithms)
\r
780 // The hash_is_unique and remove_hash_is_unique messages allow enforcement of unique
\r
781 // values in the hashed column. If the hash_is_unique message is sent after the
\r
782 // creation of a hash index on a matrix already populated with data the constraint will
\r
783 // only apply to new data.
\r
785 // The hash may also be removed from the column (freeing up any memory used, which can
\r
786 // be fairly large) at any time, this allows for removing the hash from one column and
\r
787 // re-assigning it to another or changing hash algorithm on the same data.
\r
789 // Lookups on the hash index are performed with the matrix_index_from_value, matrix_index_count_from_value
\r
791 // Send message methods:
\r
792 // delete_data - Clear the matrix
\r
793 // matrix_sort - Y pos to sort on
\r
794 // matrix_delete - X and Y pos to delete
\r
795 // delete_item - X position to delete (this reshuffles the matrix; avoid using)
\r
796 // hash_on_column_algorithm - Hash algorithm to use
\r
797 // hash_on_column - Y pos of column to hash
\r
798 // remove_hash_on_column - Remove the hash from the column
\r
799 // hash_is_unique - Add a unique constraint on the hash
\r
800 // remove_hash_is_unique - Remove a unique constraint from the hash
\r
801 // matrix_index_lookup_clear - Clear the lookup buffer
\r
802 // matrix_append_csv - Append some data in CSV format to the array E.g. ('My Name,"My,\"address\""')
\r
803 // matrix_copy_csv - Copy csv data from sprecified file into matrix
\r
806 // matrix_value - Set a value at X, Y
\r
810 // matrix_value - Get a value at X, Y
\r
811 // matrix_string - Get an string value at X, Y
\r
812 // matrix_integer - Get an integer value at X, Y
\r
813 // matrix_numeric - Get an numeric value at X, Y
\r
814 // matrix_real - Get an real value at X, Y
\r
815 // matrix_hash_from_value - Get the hash index value used for an indexed column value
\r
816 // matrix_indextable_from_value - Get list of matrix x pos indexes for a particular hashed value
\r
817 // matrix_index_lookup_clear - Clear the buffer for an indexed lookup
\r
818 // matrix_index_count_from_value - Get a count of rows with a particular value
\r
819 // matrix_index_from_value - Get the next X pos (row) with indexed value. Returns -1 when nothing left to find.
\r
820 // item_count - Get count of rows in matrix
\r
821 // item_width - Get count of columns in matrix
\r
825 // object test is a matrix
\r
828 // set matrix_value of (test(current_object)) item 0 item 1 to "1" - x then y pos to Value
\r
829 // get matrix_value of (test(current_object)) item 0 item 1 to tmpStr - x then y pos to Value
\r
830 // send matrix_append_csv to test ('My Name,"My,\"address\""') - Append CSV data to the end of the matrix
\r
831 // send matrix_copy_csv to (test(current_object)) "f:\data.csv" - Copy data from csv file into matrix
\r
832 // send matrix_sort to (test(current_object)) 1 - x then y pos to sort by
\r
833 // send matrix_delete to (test(current_object)) 1 1 - x then y pos to delete
\r
834 // send matrix_delete_row to (test(current_object)) 1 - x essentially blanks record out, no reshuffle
\r
835 // send delete_item to (test(current_object)) 1 - x pos (not v efficient), reshuffles
\r
837 // Hash indexed columns usage:
\r
839 // send hash_on_column_algorithm to (test(current_object)) "hash_reduced_lazy"
\r
840 // send hash_on_column to (test(current_object)) 0
\r
841 // send remove_hash_on_column to (test(current_object))
\r
842 // send hash_is_unique to (test(current_object))
\r
844 // send matrix_index_lookup_clear to (test(current_object))
\r
845 // get matrix_index_count_from_value of (test(current_object)) item "1" to count
\r
846 // get matrix_index_from_value of (test(current_object)) item "1" to x_pos
\r
847 // get matrix_indextable_from_value of (test(current_object)) item "1" to tmpStr
\r
848 // get matrix_hash_from_value of (test(current_object)) item "1" to tmpInt
\r
849 // get item_count of (test(current_object) to tmpInt
\r
850 // get item_width of (test(current_object) to tmpInt
\r
852 class matrix is an array
\r
853 procedure construct_object integer argc
\r
854 object mTokens is a StringTokenizer
\r
856 object mTokens2 is a StringTokenizer
\r
859 forward send construct_object
\r
860 property integer c_iWidth public argc
\r
861 property integer c_iHashOn
\r
862 property integer c_iLastIndexTableHash
\r
863 property integer c_iLastIndexTablePos
\r
864 property integer c_iEnforceUnique
\r
865 property string c_sHashAlgorithm
\r
867 set c_sHashAlgorithm to ""
\r
868 set c_iHashOn to -1
\r
869 set c_iLastIndexTableHash to -1
\r
870 set c_iLastIndexTablePos to -1
\r
871 set c_iEnforceUnique to 0
\r
874 procedure hash_on_column_algorithm string hashalg
\r
875 if ((hashalg = "hash_reduced_djb2") or (hashalg = "hash_reduced_sdbm") or (hashalg = "hash_reduced_lazy") or (hashalg = "hash_for_df_arrays") or (hashalg = "")) begin
\r
876 set c_sHashAlgorithm to hashalg
\r
880 procedure hash_is_unique
\r
881 set c_iEnforceUnique to 1
\r
884 procedure remove_hash_is_unique
\r
885 set c_iEnforceUnique to 0
\r
888 procedure hash_on_column integer l_iColumn
\r
889 local integer l_iMax l_iHashOn l_i l_iHash l_iEnforceUnique l_iHashError
\r
890 local string l_sBuf l_sTmp l_sHashAlgorithm
\r
892 forward get item_count to l_iMax
\r
893 get c_iHashOn to l_iHashOn
\r
895 // Allow adding hash only when no hash already set
\r
896 if ((l_iHashOn = -1) and (l_iColumn >= 0)) begin
\r
898 object mHash_array is an array
\r
901 object mHash_table is a hashTable
\r
904 get c_sHashAlgorithm to l_sHashAlgorithm
\r
905 get c_iEnforceUnique to l_iEnforceUnique
\r
907 if (l_sHashAlgorithm <> "") begin
\r
908 send hash_algorithm to (mHash_table(current_object)) l_sHashAlgorithm
\r
911 if (l_iMax <> 0) begin
\r
912 // Hash the current matrix if not empty
\r
913 move (l_iMax-1) to l_iMax
\r
915 for l_i from 0 to l_iMax
\r
916 forward get array_value item l_i to l_sBuf
\r
918 send delete_data to (mTokens(current_object))
\r
919 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
920 get token_value of (mTokens(current_object)) item l_iColumn to l_sTmp
\r
921 get insert_hash of (mHash_table(current_object)) item l_sTmp to l_iHash
\r
922 get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
924 if ((l_iEnforceUnique = 1) and (length(replace("|",l_sTmp,"")) <> 0)) begin
\r
925 custom_error ERROR_CODE_DUPLICATE_HASH_KEY$ ERROR_MSG_DUPLICATE_HASH_KEY ERROR_DETAIL_DUPLICATE_HASH_KEY l_iColumn
\r
926 move 1 to l_iHashError
\r
929 else if not (l_sTmp contains ("|"+string(l_i)+"|")) begin
\r
930 if (length(l_sTmp) = 0) move "|" to l_sTmp
\r
931 append l_sTmp (string(l_i)+"|")
\r
932 set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
937 if (l_iHashError = 0) begin
\r
938 set c_iHashOn to l_iColumn
\r
941 send destroy_object to (mHash_array(current_object))
\r
942 send destroy_object to (mHash_table(current_object))
\r
947 procedure remove_hash_on_column
\r
948 local integer l_iHashOn
\r
950 get c_iHashOn to l_iHashOn
\r
952 if (l_iHashOn <> -1) begin
\r
953 set c_iHashOn to -1
\r
954 send destroy_object to (mHash_array(current_object))
\r
955 send destroy_object to (mHash_table(current_object))
\r
959 procedure set matrix_value integer itemx integer itemy string val
\r
960 local string l_sBuf l_sTmp l_sOldVal
\r
961 local integer l_i l_iWidth l_iHashOn l_iHash l_iEnforceUnique l_iHashError
\r
963 move 0 to l_iHashError
\r
964 get c_iWidth to l_iWidth
\r
965 get c_iHashOn to l_iHashOn
\r
967 forward get array_value item itemx to l_sBuf
\r
969 if (itemy > l_iWidth) begin
\r
970 set c_iWidth to itemy
\r
971 move itemy to l_iWidth
\r
974 // Delimiter is ascii char 1 (start of heading/console interrupt)
\r
975 // so any values containing ascii 1 will, of course break the matrix
\r
976 send delete_data to (mTokens(current_object))
\r
977 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
979 if (l_iHashOn = itemy) begin
\r
980 get token_value of (mTokens(current_object)) item itemy to l_sOldVal
\r
982 if (val = "") set token_value of (mTokens(current_object)) item itemy to (character(3))
\r
983 else set token_value of (mTokens(current_object)) item itemy to (replaces(character(1),(replaces(character(3),val,"")),""))
\r
986 for l_i from 0 to l_iWidth
\r
987 get token_value of (mTokens(current_object)) item l_i to l_sTmp
\r
988 if (length(l_sTmp) = 0) move (character(3)) to l_sTmp
\r
989 if (length(l_sBuf) <> 0) append l_sBuf (character(1))
\r
990 append l_sBuf l_sTmp
\r
993 move (replaces(character(3),l_sBuf,"")) to l_sBuf
\r
995 // Insert/update in the value to the hash
\r
996 if ((l_iHashOn = itemy) and (l_sOldVal <> val)) begin
\r
997 get c_iEnforceUnique to l_iEnforceUnique
\r
998 get insert_hash of (mHash_table(current_object)) item val to l_iHash
\r
999 get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1001 if ((l_iEnforceUnique = 1) and (length(replace("|",l_sTmp,"")) <> 0)) begin
\r
1002 custom_error ERROR_CODE_DUPLICATE_HASH_KEY$ ERROR_MSG_DUPLICATE_HASH_KEY ERROR_DETAIL_DUPLICATE_HASH_KEY itemy
\r
1003 move 1 to l_iHashError
\r
1005 else if not (l_sTmp contains ("|"+string(itemx)+"|")) begin
\r
1006 if (length(l_sTmp) = 0) move "|" to l_sTmp
\r
1007 append l_sTmp (string(itemx)+"|")
\r
1008 set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1011 // Remove old hash (if any) when insert succeeds
\r
1012 if (l_iHashError = 0) begin
\r
1013 get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash
\r
1014 if (l_iHash <> 0) begin
\r
1015 get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1016 if (l_sTmp contains ("|"+string(itemx)+"|")) begin
\r
1017 move (replace(("|"+string(itemx)+"|"),l_sTmp,"")) to l_sTmp
\r
1018 if (l_sTmp = "") begin
\r
1019 send remove_hash to (mHash_table(current_object)) l_iHash
\r
1022 if (left(l_sTmp,1) <> "|") move ("|"+l_sTmp) to l_sTmp
\r
1023 else append l_sTmp "|"
\r
1025 set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1031 if (l_iHashError = 0) begin
\r
1032 forward set array_value item itemx to l_sBuf
\r
1036 procedure matrix_append_csv string row
\r
1037 local integer l_iMax l_iValues l_i
\r
1038 local string l_sBuf
\r
1040 forward get item_count to l_iMax
\r
1042 send delete_data to (mTokens2(current_object))
\r
1043 send set_string_csv to (mTokens2(current_object)) row
\r
1044 get token_count of (mTokens2(current_object)) to l_iValues
\r
1046 for l_i from 0 to l_iValues
\r
1047 get token_value of (mTokens2(current_object)) item l_i to l_sBuf
\r
1048 indicate err false
\r
1049 set matrix_value item l_iMax item l_i to l_sBuf
\r
1050 if (err) forward send delete_item l_iMax
\r
1056 procedure matrix_copy_csv string fname
\r
1057 local string l_sBuf
\r
1059 if (does_exist(fname)) begin
\r
1060 direct_input channel DEFAULT_FILE_CHANNEL fname
\r
1061 while not (seqeof)
\r
1062 readln channel DEFAULT_FILE_CHANNEL l_sBuf
\r
1064 if (trim(l_sBuf) <> "") begin
\r
1065 send matrix_append_csv l_sBuf
\r
1068 close_input channel DEFAULT_FILE_CHANNEL
\r
1071 custom_error ERROR_CODE_FILE_NOT_FOUND$ ERROR_MSG_FILE_NOT_FOUND ERROR_DETAIL_FILE_NOT_FOUND fname
\r
1074 function matrix_string integer itemx integer itemy returns string
\r
1075 local string l_sBuf l_sTmp
\r
1077 forward get array_value item itemx to l_sBuf
\r
1079 send delete_data to (mTokens(current_object))
\r
1080 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1081 get token_value of (mTokens(current_object)) item itemy to l_sTmp
\r
1083 function_return l_sTmp
\r
1086 function matrix_value integer itemx integer itemy returns string
\r
1087 local string l_sBuf l_sTmp
\r
1089 forward get array_value item itemx to l_sBuf
\r
1091 send delete_data to (mTokens(current_object))
\r
1092 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1093 get token_value of (mTokens(current_object)) item itemy to l_sTmp
\r
1095 function_return l_sTmp
\r
1098 function matrix_integer integer itemx integer itemy returns integer
\r
1099 local string l_sBuf
\r
1100 local integer l_iTmp
\r
1102 forward get array_value item itemx to l_sBuf
\r
1104 send delete_data to (mTokens(current_object))
\r
1105 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1106 get token_value of (mTokens(current_object)) item itemy to l_iTmp
\r
1108 function_return l_iTmp
\r
1111 function matrix_number integer itemx integer itemy returns number
\r
1112 local string l_sBuf
\r
1113 local number l_nTmp
\r
1115 forward get array_value item itemx to l_sBuf
\r
1117 send delete_data to (mTokens(current_object))
\r
1118 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1119 get token_value of (mTokens(current_object)) item itemy to l_nTmp
\r
1121 function_return l_nTmp
\r
1124 function matrix_real integer itemx integer itemy returns real
\r
1125 local string l_sBuf
\r
1128 forward get array_value item itemx to l_sBuf
\r
1130 send delete_data to (mTokens(current_object))
\r
1131 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1132 get token_value of (mTokens(current_object)) item itemy to l_rTmp
\r
1134 function_return l_rTmp
\r
1137 function matrix_hash_from_value string val returns integer
\r
1138 local integer l_iHash l_iHashOn
\r
1140 get c_iHashOn to l_iHashOn
\r
1142 if (l_iHashOn <> -1) begin
\r
1143 get find_hash of (mHash_table(current_object)) item val to l_iHash
\r
1146 function_return l_iHash
\r
1149 function matrix_indextable_from_value string val returns string
\r
1150 local integer l_iHashOn l_iHash
\r
1151 local string l_sIndexTable
\r
1153 get c_iHashOn to l_iHashOn
\r
1155 if (l_iHashOn <> -1) begin
\r
1156 get find_hash of (mHash_table(current_object)) item val to l_iHash
\r
1157 get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable
\r
1160 function_return l_sIndexTable
\r
1163 procedure matrix_index_lookup_clear
\r
1164 local integer l_iHashOn
\r
1166 get c_iHashOn to l_iHashOn
\r
1168 if (l_iHashOn <> -1) begin
\r
1169 set c_iLastIndexTableHash to -1
\r
1170 set c_iLastIndexTablePos to -1
\r
1174 function matrix_index_from_value string val returns integer
\r
1175 local integer l_iHashOn l_iHash l_iLastIndexTableHash l_iLastIndexTablePos l_iIndex l_iIndexValues
\r
1176 local string l_sIndexTable
\r
1178 get c_iHashOn to l_iHashOn
\r
1179 move -1 to l_iIndex
\r
1181 if (l_iHashOn <> -1) begin
\r
1182 get find_hash of (mHash_table(current_object)) item val to l_iHash
\r
1183 get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable
\r
1185 get c_iLastIndexTableHash to l_iLastIndexTableHash
\r
1187 if (l_iHash = l_iLastIndexTableHash) begin
\r
1188 get c_iLastIndexTablePos to l_iLastIndexTablePos
\r
1190 increment l_iLastIndexTablePos
\r
1192 send delete_data to (mTokens(current_object))
\r
1193 send set_string to (mTokens(current_object)) l_sIndexTable "|"
\r
1194 get token_count of (mTokens(current_object)) to l_iIndexValues
\r
1195 if (l_iLastIndexTablePos <= l_iIndexValues) begin
\r
1196 get token_value of (mTokens(current_object)) item l_iLastIndexTablePos to l_iIndex
\r
1197 set c_iLastIndexTableHash to l_iHash
\r
1198 set c_iLastIndexTablePos to l_iLastIndexTablePos
\r
1201 move -1 to l_iIndex
\r
1202 set c_iLastIndexTableHash to -1
\r
1203 set c_iLastIndexTablePos to -1
\r
1207 function_return l_iIndex
\r
1210 function matrix_index_count_from_value string val returns integer
\r
1211 local integer l_iHashOn l_iHash l_iIndexValues
\r
1212 local string l_sIndexTable
\r
1214 get c_iHashOn to l_iHashOn
\r
1216 if (l_iHashOn <> -1) begin
\r
1217 get find_hash of (mHash_table(current_object)) item val to l_iHash
\r
1218 get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable
\r
1220 send delete_data to (mTokens(current_object))
\r
1221 send set_string to (mTokens(current_object)) l_sIndexTable "|"
\r
1222 get token_count of (mTokens(current_object)) to l_iIndexValues
\r
1225 function_return l_iIndexValues
\r
1228 procedure set item_count integer newVal
\r
1229 forward set item_count to newVal
\r
1232 function item_width returns integer
\r
1233 local integer l_iWidth
\r
1234 get c_iWidth to l_iWidth
\r
1235 function_return l_iWidth
\r
1238 procedure matrix_delete integer itemx integer itemy
\r
1239 local string l_sBuf l_sTmp l_sOldVal
\r
1240 local integer l_i l_iWidth l_iHashOn l_iHash
\r
1242 get c_iWidth to l_iWidth
\r
1243 get c_iHashOn to l_iHashOn
\r
1245 forward get array_value item itemx to l_sBuf
\r
1247 send delete_data to (mTokens(current_object))
\r
1248 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1250 if (l_iHashOn = itemy) begin
\r
1251 get token_value of (mTokens(current_object)) item itemy to l_sOldVal
\r
1253 set token_value of (mTokens(current_object)) item itemy to (character(3))
\r
1256 for l_i from 0 to l_iWidth
\r
1257 get token_value of (mTokens(current_object)) item l_i to l_sTmp
\r
1258 if (length(l_sTmp) = 0) move (character(3)) to l_sTmp
\r
1259 if (length(l_sBuf) <> 0) append l_sBuf (character(1))
\r
1260 append l_sBuf l_sTmp
\r
1262 move (replaces(character(3),l_sBuf,"")) to l_sBuf
\r
1264 forward set array_value item itemx to l_sBuf
\r
1266 // Delete in the value to the hash
\r
1267 if (l_iHashOn = itemy) begin
\r
1268 get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash
\r
1269 if (l_iHash <> 0) begin
\r
1270 get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1271 if (l_sTmp contains ("|"+string(itemx)+"|")) begin
\r
1272 move (replace(("|"+string(itemx)+"|"),l_sTmp,"")) to l_sTmp
\r
1273 if (l_sTmp = "") begin
\r
1274 send remove_hash to (mHash_table(current_object)) l_iHash
\r
1277 if (left(l_sTmp,1) <> "|") move ("|"+l_sTmp) to l_sTmp
\r
1278 else append l_sTmp "|"
\r
1280 set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1287 procedure delete_item integer itemx
\r
1288 local string l_sBuf l_sOldVal l_sTmp l_sIndexTable
\r
1289 local integer l_iHashOn l_iHash l_i l_j l_iItems l_iIndexValues l_iIndex
\r
1291 get c_iHashOn to l_iHashOn
\r
1292 // Delete in the value to the hash
\r
1293 if (l_iHashOn <> -1) begin
\r
1294 forward get array_value item itemx to l_sBuf
\r
1295 send delete_data to (mTokens(current_object))
\r
1296 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1297 get token_value of (mTokens(current_object)) item l_iHashOn to l_sOldVal
\r
1298 get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash
\r
1299 if (l_iHash <> 0) begin
\r
1300 get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1301 if (l_sTmp contains ("|"+string(itemx)+"|")) begin
\r
1302 move (replace(("|"+string(itemx)+"|"),l_sTmp,"")) to l_sTmp
\r
1303 if (l_sTmp = "") begin
\r
1304 send remove_hash to (mHash_table(current_object)) l_iHash
\r
1307 if (left(l_sTmp,1) <> "|") move ("|"+l_sTmp) to l_sTmp
\r
1308 else append l_sTmp "|"
\r
1310 set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1314 forward get item_count to l_iItems
\r
1316 for l_i from (itemx+1) to l_iItems
\r
1318 forward get array_value item l_i to l_sBuf
\r
1319 send delete_data to (mTokens(current_object))
\r
1320 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1321 get token_value of (mTokens(current_object)) item l_iHashOn to l_sOldVal
\r
1322 get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash
\r
1324 if (l_iHash <> 0) begin
\r
1325 get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable
\r
1327 send delete_data to (mTokens(current_object))
\r
1328 send set_string to (mTokens(current_object)) l_sIndexTable "|"
\r
1329 get token_count of (mTokens(current_object)) to l_iIndexValues
\r
1330 move "|" to l_sIndexTable
\r
1331 for l_j from 1 to l_iIndexValues
\r
1332 get token_value of (mTokens(current_object)) item l_j to l_iIndex
\r
1333 if (l_iIndex = l_i) calc (l_iIndex-1) to l_iIndex
\r
1334 append l_sIndexTable (string(l_iIndex)+"|")
\r
1337 set array_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable
\r
1343 forward send delete_item to current_object itemx
\r
1346 procedure matrix_sort integer itemy string order
\r
1347 local string l_sBuf l_sTmp l_sTmp2 l_sHash
\r
1348 local integer l_iX l_i l_j l_iMax l_iPoolMax l_iWidth l_iThrow l_iNumCount l_iHashOn l_iHash
\r
1350 move (trim(uppercase(order))) to order
\r
1351 if ((order <> "ASCENDING") and (order <> "DESCENDING")) move "ASCENDING" to order
\r
1353 object mSort_array is an array
\r
1355 object mClone_array is an array
\r
1358 get c_iHashOn to l_iHashOn
\r
1359 get c_iWidth to l_iWidth
\r
1360 forward get item_count to l_iMax
\r
1362 send delete_data to (mSort_array(current_object))
\r
1363 send delete_data to (mClone_array(current_object))
\r
1365 if (l_iHashOn <> -1) begin
\r
1366 send delete_data to (mHash_array(current_object))
\r
1369 move (l_iMax-1) to l_iMax
\r
1371 for l_i from 0 to l_iMax
\r
1372 forward get array_value item l_i to l_sBuf
\r
1374 send delete_data to (mTokens(current_object))
\r
1375 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1376 get token_value of (mTokens(current_object)) item itemy to l_sTmp
\r
1378 move 0 to l_iNumCount
\r
1379 for l_j from 1 to (length(l_sTmp))
\r
1380 if (((ascii(mid(l_sTmp,1,l_j))) >= 48) and ((ascii(mid(l_sTmp,1,l_j))) <= 57) or ((ascii(mid(l_sTmp,1,l_j))) = 46)) begin
\r
1381 increment l_iNumCount
\r
1384 if ((length(l_sTmp) > 0) and (length(l_sTmp) = l_iNumCount)) begin
\r
1385 set array_value of (mSort_array(current_object)) item l_i to (number(l_sTmp))
\r
1388 if (length(l_sTmp) = 0) move (character(2)) to l_sTmp
\r
1389 set array_value of (mSort_array(current_object)) item l_i to l_sTmp
\r
1393 if (order = "ASCENDING") send sort_items to (mSort_array(current_object)) ascending
\r
1394 if (order = "DESCENDING") send sort_items to (mSort_array(current_object)) descending
\r
1396 move l_iMax to l_iPoolMax
\r
1398 for l_i from 0 to l_iMax
\r
1399 get array_value of (mSort_array(current_object)) item l_i to l_sTmp
\r
1400 if (l_sTmp = character(2)) move "" to l_sTmp
\r
1402 for l_j from 0 to l_iPoolMax
\r
1403 // Ideally we'd change the next 3 lines for a lookup table instead
\r
1404 forward get array_value item l_j to l_sBuf
\r
1406 send delete_data to (mTokens(current_object))
\r
1407 send set_string to (mTokens(current_object)) l_sBuf (character(1))
\r
1408 get token_value of (mTokens(current_object)) item itemy to l_sTmp2
\r
1410 if (l_sTmp = l_sTmp2) begin
\r
1411 set array_value of (mClone_array(current_object)) item l_i to l_sBuf
\r
1413 // On successful find shrink the sort pool here by moving max to l_j and decrementing max
\r
1414 forward get array_value item l_iPoolMax to l_sBuf
\r
1415 forward set array_value item l_j to l_sBuf
\r
1416 forward send delete_item to current_object l_iPoolMax
\r
1417 decrement l_iPoolMax
\r
1420 if (l_iHashOn <> -1) begin
\r
1421 get token_value of (mTokens(current_object)) item l_iHashOn to l_sHash
\r
1422 get find_hash of (mHash_table(current_object)) item l_sHash to l_iHash
\r
1423 get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1424 if not (l_sTmp contains ("|"+string(l_i)+"|")) begin
\r
1425 if (length(l_sTmp) = 0) move "|" to l_sTmp
\r
1426 append l_sTmp (string(l_i)+"|")
\r
1427 set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp
\r
1430 goto dirty_speedup_jump
\r
1433 dirty_speedup_jump:
\r
1435 send delete_data to (mSort_array(current_object))
\r
1437 for l_i from 0 to l_iMax
\r
1438 get array_value of (mClone_array(current_object)) item l_i to l_sBuf
\r
1439 forward set array_value item l_i to l_sBuf
\r
1442 send destroy_object to (mSort_array(current_object)) // Use "send request_destroy_object" to destroy object and all children.
\r
1443 send destroy_object to (mClone_array(current_object))
\r
1448 // Rss 2.0 data class - RFC-822 dates used
\r
1450 // Send message methods:
\r
1451 // init_rss - Initialise a new rss20 instance
\r
1452 // init_img - Initialise the image to be used in the feed
\r
1453 // add_item - Add an item to the feed
\r
1454 // write_rss - Write the feed out to disk
\r
1457 // set_ttl - Set the TTL/refresh rate of the feed
\r
1458 // set_contacts - Set admin contacts
\r
1464 // object test is an rss20
\r
1467 // move "" to link
\r
1470 // move "Google Maps" to title
\r
1471 // move ("http:/"+"/www.google.com/maps") to link
\r
1472 // move "Try out google maps" to desc
\r
1473 // send init_rss to (test(current_object)) title link desc
\r
1475 // move ("http:/"+"/www.google.com/images/srpr/logo11w.png") to url
\r
1478 // send init_img to (test(current_object)) url x y
\r
1480 // send set_ttl to (test(current_object)) 30
\r
1481 // send set_contacts to (test(current_object)) "maps@google.com" "search@google.com"
\r
1483 // for i from 1 to 15
\r
1484 // move "Test item " to title
\r
1486 // move ("http:/"+"/www.google.com") to link
\r
1487 // move "Test description " to desc
\r
1489 // move "NONE" to cat
\r
1491 // send add_item to (test(current_object)) title link desc cat (rssdate((now("date")),(now("longtime"))))
\r
1493 // send write_rss to (test(current_object)) "c:\google_maps.rss"
\r
1495 class rss20 is a matrix
\r
1496 procedure construct_object string argc
\r
1497 forward send construct_object argc
\r
1498 property string c_rssTitle
\r
1499 property string c_rssLink
\r
1500 property string c_rssDesc
\r
1502 property string c_imgTitle
\r
1503 property string c_imgUrl
\r
1504 property string c_imgLink
\r
1505 property string c_imgDesc
\r
1507 property string c_webMaster
\r
1508 property string c_manEditor
\r
1510 property integer c_imgx
\r
1511 property integer c_imgy
\r
1512 property integer c_ttl
\r
1514 property integer c_itemCount
\r
1517 procedure init_rss string rssTitle string rssLink string rssDesc
\r
1518 set c_rssTitle to rssTitle
\r
1519 set c_rssLink to rssLink
\r
1520 set c_rssDesc to rssDesc
\r
1521 set c_itemCount to 0
\r
1524 procedure init_img string imgUrl integer imgx integer imgy
\r
1525 local string imgTitle imgLink imgDesc
\r
1526 get c_rssTitle to imgTitle
\r
1527 get c_rssLink to imgLink
\r
1528 get c_rssDesc to imgDesc
\r
1530 set c_imgTitle to imgTitle
\r
1531 set c_imgUrl to imgUrl
\r
1532 set c_imgLink to imgLink
\r
1533 set c_imgDesc to imgDesc
\r
1534 set c_imgx to imgx
\r
1535 set c_imgy to imgy
\r
1538 procedure set_ttl integer ttl
\r
1539 if (ttl > 0) set c_ttl to ttl
\r
1542 procedure set_contacts string webMaster string manEditor
\r
1543 if (webMaster <> "") set c_webMaster to webMaster
\r
1544 if (manEditor <> "") set c_manEditor to manEditor
\r
1547 procedure add_item string itemTitle string itemLink string itemDesc string itemCat string pubDate string itemGuID
\r
1548 local integer l_itemCount
\r
1549 get c_itemCount to l_itemCount
\r
1551 // The standard says we should not have more than 15 items, but ignore this.
\r
1552 //if ((l_itemCount < 15) and (itemTitle <> "")) begin
\r
1553 if (itemTitle <> "") begin
\r
1554 increment l_itemCount
\r
1555 set c_itemCount to l_itemCount
\r
1557 forward set matrix_value item l_itemCount item 0 to itemTitle
\r
1558 forward set matrix_value item l_itemCount item 1 to itemLink
\r
1559 forward set matrix_value item l_itemCount item 2 to itemDesc
\r
1560 forward set matrix_value item l_itemCount item 3 to itemCat
\r
1561 forward set matrix_value item l_itemCount item 4 to itemGuID
\r
1562 if ((pubDate <> "") and (pubDate <> "NOW")) forward set matrix_value item l_itemCount item 6 to pubDate
\r
1566 procedure write_rss string rssFileName
\r
1567 local string l_rssTitle l_rssLink l_rssDesc l_imgTitle l_imgUrl l_imgLink l_itemTitle l_itemLink l_itemDesc l_itemCat l_sConflict l_property l_manEditor l_webMaster l_pubDate l_itemGuID l_itemCc
\r
1568 local integer l_imgx l_imgy l_itemcount l_i l_j l_iConflict l_iTtl
\r
1570 get c_rssTitle to l_rssTitle
\r
1571 get c_rssLink to l_rssLink
\r
1572 get c_rssDesc to l_rssDesc
\r
1574 get c_imgTitle to l_imgTitle
\r
1575 get c_imgUrl to l_imgUrl
\r
1576 get c_imgLink to l_imgLink
\r
1577 get c_manEditor to l_manEditor
\r
1578 get c_webMaster to l_webMaster
\r
1580 get c_imgx to l_imgx
\r
1581 get c_imgy to l_imgy
\r
1582 get c_itemCount to l_itemCount
\r
1583 get c_ttl to l_iTtl
\r
1585 direct_output channel DEFAULT_FILE_CHANNEL rssFileName
\r
1586 writeln channel DEFAULT_FILE_CHANNEL '<?xml version="1.0" ?>'
\r
1587 writeln channel DEFAULT_FILE_CHANNEL '<?xml-stylesheet type="text/xsl" href="rss.xsl" media="screen"?>'
\r
1588 write channel DEFAULT_FILE_CHANNEL '<rss version="2.0" xmlns:dc="http:/' '/purl.org/dc/elements/1.1/" xmlns:sy="http:/'
\r
1589 write channel DEFAULT_FILE_CHANNEL '/purl.org/rss/1.0/modules/syndication/" xmlns:admin="http:/' '/webns.net/mvcb/" xmlns:rdf="http:/'
\r
1590 writeln channel DEFAULT_FILE_CHANNEL '/www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http:/' '/purl.org/rss/1.0/modules/content/">'
\r
1592 // skipHours skipDays cloud - all currently not used
\r
1593 // Write out Channel
\r
1594 writeln channel DEFAULT_FILE_CHANNEL ' <channel>'
\r
1595 writeln channel DEFAULT_FILE_CHANNEL ' <title>' (trim(l_rssTitle)) '</title>'
\r
1596 writeln channel DEFAULT_FILE_CHANNEL ' <link>' (trim(l_rssLink)) '</link>'
\r
1597 writeln channel DEFAULT_FILE_CHANNEL ' <description>' (trim(l_rssDesc)) '</description>'
\r
1598 writeln channel DEFAULT_FILE_CHANNEL ' <language>en-gb</language>'
\r
1599 writeln channel DEFAULT_FILE_CHANNEL ' <generator>Df32func RSS Object Generator</generator>'
\r
1600 writeln channel DEFAULT_FILE_CHANNEL ' <copyright>Copyright ' (trim(l_rssTitle)) ' (C) ' (now("date")) '</copyright>'
\r
1601 writeln channel DEFAULT_FILE_CHANNEL ' <lastBuildDate>' (rssdate((now("date")),(now("longtime")))) '</lastBuildDate>'
\r
1602 writeln channel DEFAULT_FILE_CHANNEL ' <pubDate>' (rssdate((now("date")),(now("longtime")))) '</pubDate>'
\r
1604 if (l_manEditor <> "") writeln channel DEFAULT_FILE_CHANNEL ' <managingEditor>' l_manEditor '</managingEditor>'
\r
1605 if (l_webMaster <> "") writeln channel DEFAULT_FILE_CHANNEL ' <webMaster>' l_webMaster '</webMaster>'
\r
1606 if (l_iTtl <> 0) writeln channel DEFAULT_FILE_CHANNEL ' <ttl>' l_iTtl '</ttl>'
\r
1608 // Write out image
\r
1609 if ((l_imgUrl <> "") and (l_imgx > 0) and (l_imgy > 0)) begin
\r
1610 writeln channel DEFAULT_FILE_CHANNEL ' <image>'
\r
1611 writeln channel DEFAULT_FILE_CHANNEL ' <title>' (trim(l_imgTitle)) '</title>'
\r
1612 writeln channel DEFAULT_FILE_CHANNEL ' <url>' (trim(l_imgUrl)) '</url>'
\r
1613 writeln channel DEFAULT_FILE_CHANNEL ' <link>' (trim(l_imgLink)) '</link>'
\r
1614 writeln channel DEFAULT_FILE_CHANNEL ' <height>' l_imgx '</height>'
\r
1615 writeln channel DEFAULT_FILE_CHANNEL ' <width>' l_imgy '</width>'
\r
1616 writeln channel DEFAULT_FILE_CHANNEL ' <description>' (trim(l_rssDesc)) '</description>'
\r
1617 writeln channel DEFAULT_FILE_CHANNEL ' </image>'
\r
1620 // Write out items
\r
1621 for l_i from 1 to l_itemCount
\r
1622 forward get matrix_value item l_i item 0 to l_itemTitle
\r
1623 forward get matrix_value item l_i item 1 to l_itemLink
\r
1624 forward get matrix_value item l_i item 2 to l_itemDesc
\r
1625 forward get matrix_value item l_i item 3 to l_itemCat
\r
1626 forward get matrix_value item l_i item 4 to l_itemGuID
\r
1627 forward get matrix_value item l_i item 5 to l_itemCc
\r
1628 forward get matrix_value item l_i item 6 to l_pubDate
\r
1631 // Escape html in the description
\r
1632 move (replaces('"',l_itemDesc,""")) to l_itemDesc
\r
1633 move (replaces('<',l_itemDesc,"<")) to l_itemDesc
\r
1634 move (replaces('>',l_itemDesc,">")) to l_itemDesc
\r
1636 writeln channel DEFAULT_FILE_CHANNEL ' <item>'
\r
1637 writeln channel DEFAULT_FILE_CHANNEL ' <title>' l_itemTitle '</title>'
\r
1638 writeln channel DEFAULT_FILE_CHANNEL ' <link>' l_itemLink '</link>'
\r
1639 writeln channel DEFAULT_FILE_CHANNEL ' <description>' l_itemDesc '</description>'
\r
1641 if (l_itemGuID = "") begin
\r
1642 move 0 to l_iConflict
\r
1643 for l_j from 1 to (l_i-1)
\r
1644 forward get matrix_value item l_j item 1 to l_sConflict
\r
1645 if (l_sConflict = l_itemLink) increment l_iConflict
\r
1647 if (l_iConflict > 0) append l_iTemLink "#" l_iConflict
\r
1649 if (l_itemGuID <> "") append l_itemLink "#" l_itemGuID
\r
1651 writeln channel DEFAULT_FILE_CHANNEL ' <guid isPermaLink="false">' l_itemLink '</guid>'
\r
1652 if ((l_pubDate = "") or (l_pubDate = "NOW")) writeln channel DEFAULT_FILE_CHANNEL ' <pubDate>' (rssdate((now("date")),(now("longtime")))) '</pubDate>'
\r
1653 else writeln channel DEFAULT_FILE_CHANNEL ' <pubDate>' l_pubDate '</pubDate>'
\r
1654 writeln channel DEFAULT_FILE_CHANNEL ' <category>' l_itemCat '</category>'
\r
1655 writeln channel DEFAULT_FILE_CHANNEL ' </item>'
\r
1658 // Write out file/channel close
\r
1659 writeln channel DEFAULT_FILE_CHANNEL ' </channel>'
\r
1660 writeln channel DEFAULT_FILE_CHANNEL '</rss>'
\r
1661 close_output channel DEFAULT_FILE_CHANNEL
\r
1668 // File list - Returns the contents of the DataFlex filelist
\r
1670 // In order to retrieve file attributes including the file number the file needs to be opened.
\r
1672 // Send message methods:
\r
1673 // init - Initialize the matrix by reading the filelist
\r
1679 // item_count - Return the count of filelist items
\r
1680 // root_name - Get the root name of the file
\r
1681 // display_name - Get the user friendly name of the file
\r
1682 // system_name - Get the DataFlex friendly name of the table / file
\r
1683 // valid - Non-zero if the DataFlex FD file exists
\r
1687 // object test is a filelist
\r
1691 // string buf1 buf2 buf3 buf4
\r
1692 // send init to (test(current_object)) "c:\df32" "filelist.cfg"
\r
1693 // get item_count of test to x
\r
1695 // for i from 0 to x
\r
1696 // get root_name of (test(current_object)) item i to buf1
\r
1697 // get display_name of (test(current_object)) item i to buf2
\r
1698 // get system_name of (test(current_object)) item i to buf3
\r
1699 // get valid of (test(current_object)) item i to buf4
\r
1700 // showln buf1 " " buf2 " " buf3 " " buf4
\r
1704 class filelist is a matrix
\r
1705 procedure construct_object string argc
\r
1706 forward send construct_object argc
\r
1707 property string c_filelistDirectory
\r
1708 property string c_filelistName
\r
1709 property integer c_itemCount
\r
1712 function item_count returns integer
\r
1713 local integer l_iItems
\r
1714 get c_itemCount to l_iItems
\r
1715 function_return l_iItems
\r
1718 procedure init string filelistDirectory string filelistName
\r
1719 local integer l_iFileNumber
\r
1720 local string l_sRootName l_sUserDisplayName l_sFileName l_sHead l_sUrn
\r
1722 move 0 to l_iFileNumber
\r
1723 if (filelistName = "") begin
\r
1724 move "filelist.cfg" to filelistName
\r
1727 set c_filelistDirectory to filelistDirectory
\r
1728 set c_filelistName to filelistName
\r
1730 direct_input channel DEFAULT_FILE_CHANNEL (filelistDirectory+filelistName)
\r
1731 read_block l_sHead 256
\r
1732 while not (seqeof)
\r
1733 //Block of 128 split 41\33\54
\r
1734 read_block channel DEFAULT_FILE_CHANNEL l_sRootName 41
\r
1735 read_block channel DEFAULT_FILE_CHANNEL l_sUserDisplayName 33
\r
1736 read_block channel DEFAULT_FILE_CHANNEL l_sFileName 54
\r
1738 move filelistDirectory to l_sUrn
\r
1739 append l_sUrn (trim(cstring(l_sFileName))) ".FD"
\r
1741 if ((trim(cstring(l_sFileName))) <> "") begin
\r
1742 forward set matrix_value item l_iFileNumber item 0 to (trim(cstring(l_sRootName)))
\r
1743 forward set matrix_value item l_iFileNumber item 1 to (trim(cstring(l_sUserDisplayName)))
\r
1744 forward set matrix_value item l_iFileNumber item 2 to (trim(cstring(l_sFileName)))
\r
1745 if (does_exist(l_sUrn) = 1) begin
\r
1746 forward set matrix_value item l_iFileNumber item 3 to 1
\r
1749 forward set matrix_value item l_iFileNumber item 3 to 0
\r
1751 increment l_iFileNumber
\r
1754 close_input channel DEFAULT_FILE_CHANNEL
\r
1756 set c_itemCount to l_iFileNumber
\r
1759 function root_name integer itemx returns integer
\r
1760 local string l_sBuf
\r
1761 forward get matrix_value item itemx item 0 to l_sBuf
\r
1762 function_return l_sBuf
\r
1765 function display_name integer itemx returns integer
\r
1766 local string l_sBuf
\r
1767 forward get matrix_value item itemx item 1 to l_sBuf
\r
1768 function_return l_sBuf
\r
1771 function system_name integer itemx returns integer
\r
1772 local string l_sBuf
\r
1773 forward get matrix_value item itemx item 2 to l_sBuf
\r
1774 function_return l_sBuf
\r
1777 function valid integer itemx returns integer
\r
1778 local integer l_iTmp
\r
1779 forward get matrix_value item itemx item 3 to l_iTmp
\r
1780 function_return l_iTmp
\r
1785 //Class for reading unicode files when we know they have low ASCII only
\r
1789 // object test is a UnicodeReader
\r
1792 // local string asciiline
\r
1793 // local integer error i count channelx
\r
1795 // send open_file to (test(current_object)) 1 "c:\test_unicode.txt"
\r
1796 // while not (seqeof)
\r
1797 // get readline of (test(current_object)) 1 to asciiline
\r
1798 // showln asciiline
\r
1800 // send close_file to (test(current_object)) 1
\r
1802 class UnicodeReader is an array
\r
1803 procedure construct_object integer argc
\r
1804 forward send construct_object
\r
1805 property integer c_iSizeBytes public argc
\r
1806 property integer c_iBytesOn
\r
1807 property integer c_iOpen
\r
1808 property string c_sPeek
\r
1812 procedure open_file integer l_iChan string l_sFile
\r
1813 local integer l_iSizeBytes l_iOpen
\r
1814 local string l_sTmp l_sBom
\r
1815 get c_iOpen to l_iOpen
\r
1817 move (trim(l_sFile)) to l_sFile
\r
1818 if ((l_sFile <> "") and (l_iOpen = 0)) begin
\r
1819 move (file_size_bytes(l_sFile)-2) to l_iSizeBytes
\r
1820 direct_input channel l_iChan l_sFile
\r
1821 read_block channel l_iChan l_sTmp 1
\r
1822 if (ascii(l_sTmp) < 254) begin
\r
1823 set_channel_position l_iChan to 0
\r
1826 read_block channel l_iChan l_sTmp 1
\r
1829 set c_iSizeBytes to l_iSizeBytes
\r
1830 set c_iBytesOn to 0
\r
1835 procedure close_file integer l_iChan
\r
1836 local integer l_iOpen
\r
1838 get c_iOpen to l_iOpen
\r
1839 if (l_iOpen = 0) begin
\r
1840 close_input channel l_iChan
\r
1845 function readline global integer l_iChan returns string
\r
1846 local string l_sReturn l_sTmp
\r
1847 local integer l_iBytesOn l_iSizeBytes
\r
1850 move "" to l_sReturn
\r
1851 get c_iSizeBytes to l_iSizeBytes
\r
1852 get c_iBytesOn to l_iBytesOn
\r
1854 while ((l_sTmp <> character(13)) and (l_iBytesOn < l_iSizeBytes))
\r
1855 read_block channel l_iChan l_sTmp 1
\r
1856 increment l_iBytesOn
\r
1857 if ((l_sTmp <> character(13)) and (l_sTmp <> character(10)) and (l_sTmp <> character(0))) begin
\r
1858 move (l_sReturn+l_sTmp) to l_sReturn
\r
1862 function_return l_sReturn
\r
1867 // ListDirectory class - provides a directory listing
\r
1869 // Send message methods:
\r
1870 // delete_data - Clear the listing
\r
1871 // list_files - Read the directory listing into the object
\r
1872 // sort_files - Sort the file list on a particular property
\r
1878 // file_count - Return the count of files in the list
\r
1879 // filename - Get the base name of a file in the list
\r
1880 // filesize - Get the size of a file in the list
\r
1881 // file_created - Get the created timestamp of the file
\r
1882 // file_modified - Get the modification timestamp of the file
\r
1883 // file_accessed - Get the last access timestamp of the file
\r
1887 // object test is a ListDirectory
\r
1893 // send delete_data to test
\r
1894 // send list_files to (test(current_object)) "c:\*"
\r
1895 // get file_count of (test(current_object)) to x
\r
1896 // send sort_files to test "file_accesed" "ASCENDING"
\r
1898 // for i from 0 to x
\r
1899 // get filename of (test(current_object)) item i to tmp
\r
1900 // get filesize of (test(current_object)) item i to buf
\r
1901 // append tmp "," buf
\r
1902 // move (pad(tmp,35)) to tmp
\r
1903 // get file_created of (test(current_object)) item i to buf
\r
1904 // append tmp "," buf
\r
1905 // get file_modified of (test(current_object)) item i to buf
\r
1906 // append tmp "," buf
\r
1907 // get file_accessed of (test(current_object)) item i to buf
\r
1908 // append tmp "," buf
\r
1912 class ListDirectory is a matrix
\r
1913 procedure construct_object integer argc
\r
1914 forward send construct_object argc
\r
1915 property integer c_iFiles public argc
\r
1918 procedure delete_data
\r
1920 forward send delete_data
\r
1923 procedure list_files string sPathName
\r
1924 local string sWin32FindData sLine sLast sComment sFileName sModifiedDate sAccessDate sCreationDate k sLastFile
\r
1925 local integer l_01iResult iFileSize l_iFiles
\r
1926 local pointer pT5 pT6
\r
1927 local handle hFile
\r
1928 local dword dwFileSizeHigh dwFileSizeLow dwHighDateTime dwLowDateTime
\r
1930 forward send delete_data
\r
1932 zerotype _WIN32_FIND_DATA to sWin32FindData
\r
1933 getaddress of sWin32FindData to pT5
\r
1934 move (trim(sPathName)) to sPathName
\r
1935 getaddress of sPathName to pT6
\r
1936 move (FindFirstFile(pT6, pT5)) to hFile
\r
1937 //if (hFile = -1) showln "Invalid file handle!"
\r
1939 move -1 to l_iFiles
\r
1942 getbuff_String from sWin32FindData at WIN32_FIND_DATA.cFileName to sFileName
\r
1943 if ((sFileName <> ".") and (sFileName <> "..") and (sFileName <> "")) begin
\r
1944 increment l_iFiles
\r
1947 getbuff from sWin32FindData at WIN32_FIND_DATA.nFileSizeHigh to dwFileSizeHigh
\r
1948 getbuff from sWin32FindData at WIN32_FIND_DATA.nFileSizeLow to dwFileSizeLow
\r
1949 moveint ((dwFileSizeHigh*MaxDword)+dwFileSizeLow) to iFileSize
\r
1951 // File Modified Time
\r
1952 getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastWriteLowDateTime to dwLowDateTime
\r
1953 getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastWriteHighDateTime to dwHighDateTime
\r
1954 move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sModifiedDate
\r
1956 // File Accessed Time
\r
1957 getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastAccessLowDateTime to dwLowDateTime
\r
1958 getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastAccessHighDateTime to dwHighDateTime
\r
1959 move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sAccessDate
\r
1961 // File Creation Time
\r
1962 getbuff from sWin32FindData at WIN32_FIND_DATA.ftCreationLowDateTime to dwLowDateTime
\r
1963 getbuff from sWin32FindData at WIN32_FIND_DATA.ftCreationHighDateTime to dwHighDateTime
\r
1964 move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sCreationDate
\r
1966 move (cstring(sFileName)) to sFileName
\r
1967 forward set matrix_value item l_iFiles item 1 to sFileName
\r
1968 forward set matrix_value item l_iFiles item 2 to iFileSize
\r
1969 forward set matrix_value item l_iFiles item 3 to (integer(date(sModifiedDate)))
\r
1970 forward set matrix_value item l_iFiles item 4 to (integer(date(sAccessDate)))
\r
1971 forward set matrix_value item l_iFiles item 5 to (integer(date(sCreationDate)))
\r
1973 zerotype _WIN32_FIND_DATA to sWin32FindData
\r
1974 move (FindNextFile(hFile, pT5)) to l_01iResult
\r
1975 until (l_01iResult = 0)
\r
1976 move (FindClose(hFile)) to l_01iResult
\r
1978 set c_iFiles to l_iFiles
\r
1981 function filename integer itemx returns string
\r
1982 local string l_sBuf
\r
1984 forward get matrix_value item itemx item 1 to l_sBuf
\r
1985 function_return l_sBuf
\r
1988 function filesize integer itemx returns integer
\r
1989 local integer l_iBuf
\r
1990 forward get matrix_value item itemx item 2 to l_iBuf
\r
1991 function_return l_iBuf
\r
1994 function file_modified integer itemx returns date
\r
1995 local integer l_iBuf
\r
1996 forward get matrix_value item itemx item 3 to l_iBuf
\r
1997 function_return (date(l_iBuf))
\r
2000 function file_accessed integer itemx returns date
\r
2001 local integer l_iBuf
\r
2002 forward get matrix_value item itemx item 4 to l_iBuf
\r
2003 function_return (date(l_iBuf))
\r
2006 function file_created integer itemx returns date
\r
2007 local integer l_iBuf
\r
2008 forward get matrix_value item itemx item 5 to l_iBuf
\r
2009 function_return (date(l_iBuf))
\r
2012 procedure sort_files string sField string sOrder
\r
2013 local integer l_iSort
\r
2014 if ((sOrder <> "ASCENDING") and (sOrder <> "DESCENDING")) move "ASCENDING" to sOrder
\r
2016 if (sField = "filename") move 1 to l_iSort
\r
2017 if (sField = "filesize") move 2 to l_iSort
\r
2018 if (sField = "file_modified") move 3 to l_iSort
\r
2019 if (sField = "file_accessed") move 4 to l_iSort
\r
2020 if (sField = "file_created") move 5 to l_iSort
\r
2021 forward send matrix_sort l_iSort sOrder
\r
2024 function file_count returns integer
\r
2025 local integer l_iFiles
\r
2026 get c_iFiles to l_iFiles
\r
2027 function_return l_iFiles
\r
2031 // ProcessList class - provides a listing of running processes
\r
2033 // Experimental; all aspects reading process info appear to fail, it can
\r
2034 // be useful however to check if a particular process pid is still running.
\r
2036 // Send message methods:
\r
2037 // delete_data - Clear the listing
\r
2038 // init_processes - Read the process list table
\r
2044 // get_process_id - Return the PID of a particular process
\r
2045 // process_count - Return count of processes in the list
\r
2046 // process_handle - BROKEN
\r
2050 // object test is an ProcessList
\r
2053 // integer i x id hx
\r
2055 // send init_processes to test
\r
2056 // get process_count of (test(current_object)) to x
\r
2057 // showln "Processes in list = " x
\r
2059 // for i from 0 to x
\r
2060 // get process_id of (test(current_object)) item i to id
\r
2063 class ProcessList is an array
\r
2064 procedure construct_object integer argc
\r
2065 forward send construct_object
\r
2066 property integer c_iProcesses public argc
\r
2069 procedure delete_data
\r
2070 set c_iProcesses to 0
\r
2071 forward send delete_data
\r
2074 procedure init_processes
\r
2075 local string l_sProcesses l_sStructBytesBack l_sBuf l_sModules
\r
2076 local integer l_iThrow l_iBytes l_iBytes2 l_iBytesBack l_iBytesBack2 l_i l_j l_iPid l_iMid l_iProcesses
\r
2077 local pointer l_pProcesses l_pBytesBack l_pBytesBack2 l_pModules
\r
2078 local handle l_hProcess
\r
2080 move (1024*10) to l_iBytes
\r
2081 zerostring l_iBytes to l_sProcesses
\r
2082 move 0 to l_iBytesBack
\r
2083 move 0 to l_iProcesses
\r
2084 forward send delete_data
\r
2086 getAddress of l_sProcesses to l_pProcesses
\r
2087 zerotype _STRUCTBYTESBACK to l_sStructBytesBack
\r
2088 getaddress of l_sStructBytesBack to l_pBytesBack
\r
2090 move (EnumProcesses(l_pProcesses,l_iBytes,l_pBytesBack)) to l_iThrow
\r
2092 getbuff from l_sStructBytesBack at STRUCTBYTESBACK.integer0 to l_iBytesBack
\r
2094 if (mod(l_iBytesBack,4) = 0) begin
\r
2095 for l_i from 1 to (l_iBytesBack/4)
\r
2096 move (left(l_sProcesses,4)) to l_sBuf
\r
2097 move (mid(l_sProcesses,(length(l_sProcesses)-4),5)) to l_sProcesses
\r
2098 getbuff from l_sBuf at PROCESSARRAY.arrayItem to l_iPid
\r
2099 move (OpenProcess(PROCESS_QUERY_INFORMATION, 0,l_iPid)) to l_hProcess
\r
2101 // Fails to open the process for more info here unfortunately
\r
2102 //showln "LERR=" (get_last_error_detail(GetLastError())) " " l_ipid
\r
2104 move 1024 to l_iBytes2
\r
2105 zerostring l_iBytes2 to l_sModules
\r
2106 getAddress of l_sModules to l_pModules
\r
2107 zerotype _STRUCTBYTESBACK to l_sStructBytesBack
\r
2108 getaddress of l_sStructBytesBack to l_pBytesBack2
\r
2110 move (EnumProcessModules(l_hProcess,l_pModules,l_iBytes2,l_pBytesBack2)) to l_iThrow
\r
2111 getbuff from l_sStructBytesBack at STRUCTBYTESBACK.integer0 to l_iBytesBack2
\r
2113 increment l_iProcesses
\r
2114 forward set array_value item (l_i-1) to (string(l_iPid)+"|"+string(l_hProcess))
\r
2116 if (mod(l_iBytesBack2,4) = 0) begin
\r
2117 for l_j from 1 to (l_iBytesBack2/4)
\r
2118 move (left(l_sModules,4)) to l_sBuf
\r
2119 move (mid(l_sModules,(length(l_sModules)-4),5)) to l_sModules
\r
2120 getbuff from l_sBuf at PROCESSARRAY.arrayItem to l_iMid
\r
2123 move (CloseHandle(l_hProcess)) to l_iThrow
\r
2126 set c_iTokenOn to 0
\r
2127 set c_iProcesses to l_iProcesses
\r
2131 function process_id integer itemx returns integer
\r
2132 local string l_sBuf
\r
2133 forward get array_value item itemx to l_sBuf
\r
2134 function_return (integer(left(l_sBuf,pos("|",l_sBuf)-1)))
\r
2137 // There's not much point to this as we couldn't get the handle because OpenProcess failed.
\r
2138 function process_handle integer itemx returns integer
\r
2139 local string l_sBuf
\r
2140 forward get array_value item itemx to l_sBuf
\r
2141 function_return (integer(right(l_sBuf,length(l_sBuf)-pos("|",l_sBuf))))
\r
2144 function process_count returns integer
\r
2145 local integer l_iProcesses
\r
2146 get c_iProcesses to l_iProcesses
\r
2147 function_return l_iProcesses
\r